Question

I have a view(control) in panel with default value rendered="true"; and a button with getComponent(viewPanel1).setRendered(false); which is SSJS code.

This is what happens. When I click a button I still see this view, which I dont want. After some testing results are as follows:

Console output test, where I print(getComponent("viewPanel1").isRendered + " TEST"); shows that rendered attribute is set to false in all lifecycles of JSF. Also there is html code for a view in response header when I check it in browser.

It seems to me that default value somehow overrides or bypasses value set by button. If so why and how do I fix this.

Was it helpful?

Solution

Rather than talking to the component directly, bind the rendered attribute of the view panel to a data property and update that property.

For example, in your XPage source:

<xp:viewPanel rendered="#{not(viewScope.hideRelatedDocuments)}">

Then, in your button:

viewScope.put("hideRelatedDocuments", true);

When the page updates, the component will be skipped because it will recalculate the value binding for rendered, which will now evaluate to false (since the expression is flipping the boolean value stored in the scope).

Instead of storing this in a scope variable, you could also apply it to a property of a data source or managed bean... you'll just need to adjust the syntax of the button code accordingly to account for the API of the object storing the value; e.g.:

userSettings.setValue("hideRelatedDocuments", true); // document data source
// or...
settingsBean.setHideRelatedDocuments(true); // managed bean

In any of these scenarios, the same principle applies: binding a visual characteristic to a data model, and updating your event code to modify that data model, simplifies achieving the desired behavior.

There are (at least) two reasons why this approach is preferable:

1. Performance

getComponent() is computationally expensive. This isn't noticeable on simple pages, or under minimal user load (for example, during unit testing), but as the application grows in complexity, adoption, or both, calling getComponent() can negatively impact response time. Reading or writing properties of a scope variable, data source, or managed bean, always* executes faster than getComponent(), regardless of page complexity or user load. So even if you're certain that this page will never become complicated or need to support 1000 concurrent users, switching to the better pattern now establishes a habit that will pay off when performance is a key consideration.

2. Maintainability

Presumably, there's some business process connotation associated with a user's decision regarding whether or not they want this specific view panel to display on the page. Making this decision a named property of a data model allows all components, events, and data impacted by that facet of the business process to be aware of a centrally stored value, rather than having to inform all of them in the same button: just update the one property, and then everything that needs to know it can reference it without, in turn, having to go ask a component whether or not it's rendered... depending on where the component is located, in fact, other components might not even be able to find it. Conversely, you determine the scope of the data that would store this property, so you can ensure that everything that needs to know its value can find it, and find it efficiently (see previous point).

As mentioned above, this consideration might not be a factor in the one specific use case you're attempting to address this time, but if you (or others reading this answer) find yourself in a situation where it is a factor, you're already using a pattern that makes that easy.


*...unless your bean or data source has custom side effects, like storing the value of the property you're modifying outside of Domino, etc. But the base computational burden of addressing one of these in-memory objects is always lower than hierarchically traversing the component tree to locate the one component you care about... which is precisely what getComponent() does.

OTHER TIPS

After I removed id collision i solved the problem. I binded rendered property of display components to viewScope variable. ViewScope variable is set with buttons.

Here is jss code:

function calcRendered(caller, renderMe)
{
    if (caller == renderMe) return true;
    else false;
}

which is called on each display component for rendering

<xp:this.rendered>
    <![CDATA[#{javascript:
        calcRendered(this.id, viewScope.RenderMe);}
    ]]>
</xp:this.rendered>

Code for button to change rendered property.

<xp:this.action>
    <![CDATA[#{javascript:
        viewScope.RenderMe = "viewPanel3";}
    ]]>
</xp:this.action>

Im sure this can be done better. Display component should calculate rendered property only when called. IE: button tells component container to render component instead of themselves (components) calculating rendered property each time for themselves.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top