Is EL #{myBean.property} evaluated in example below? If yes, that means all ELs on page are evaluated regardless of value of their 'rendered' (or any other) attribute?
<h:panelGroup rendered="false">
<h:outputText value="#{myBean.property}" />
</h:panelGroup>
Is EL #{myBean.property} evaluated in example below?
No. You could also easily answer it yourself by putting a debug breakpoint on the getter method.
If yes, that means all ELs on page are evaluated regardless of value of their 'rendered' (or any other) attribute?
That basically depends on how well designed the component is. The standard JSF components doesn't do that, but if it's for example a custom component which doesn't check isRendered() inside processXxx methods before continuing processing itself and children, then all the EL of the children may be evaluated.
Related
there are already a lot of questions concerning the usage of:
EL in attributes (How to use EL with <ui:repeat var> in id attribute of a JSF component)
JSTL in Facelets (JSTL in JSF2 Facelets... makes sense?)
view build time (What's the view build time?)
My question should address the general usage of an EL expression in the id attribute of a JSF component.
Assume we have the following example code (the usefulness of this code should not be questioned):
<h:form id="#{bean.property}">
<h:outputText value="#{bean.property}" />
</h:form>
Now I have the following questions:
Is it okay to use an EL expression in the id attribute of h:form or other JSF components?
What are the things to keep in mind if one uses EL expressions in the id attribute?
The id attribute of a JSF component has to be available at view build time. A deferred EL expressions, like above, is evaluated when the attribute is accessed. Consequently, if you have an EL expression in id attribute the result of the EL expression is available at view build time?
I read that an EL expression can be used in attributes of type javax.el.ValueExpression, but the id is often of type String (https://coderanch.com/t/550270/java/null-variable-id-attribute). Consequently you can only use EL expressions in id attribute, if the expression evaluates to a String?
If you google for "EL expression in id attribute", there are people stating you cannot use EL expressions in id attribute, but the above example code works totally fine. This question is mainly intended for a discussion about the recommendability of the usage of EL expressions in id attribute.
Thanks for your answers!
No, never do it, id should not be dynamic . QA team will reject it.
I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards
Mojarra 2.1.
I checked the method public void execute(FacesContext facesContext) throws FacesException in the class com.sun.faces.lifecycle.RestoreViewPhase. Now, once the view's restored by the invokation viewRoot = viewHandler.restoreView(facesContext, viewId); we have the compelete tree from the previous request (if it's a postback).
I checked that tree (manually iterate through the children properties of the components in a debugger) and found that the composite components, declared as follows:
<h:panelGroup rendered="#{bean.id == 1}">
<utils:dropDownListFilterItem />
</h:panelGroup>
<h:panelGroup rendered="#{bean.id == 2}">
<utils:dateFilterItem />
</h:panelGroup>
<h:panelGroup rendered="#{bean.id == 3}">
<utils:fieldFilterItem />
</h:panelGroup>
were all in that tree. It happaned in spite of the fact that #{bean.id} was evaluated to 2. I expceted that the only <utils:dateFilterItem /> instance would be in the tree.
So, my question is how the rendered attribute is handled by Mojarra? Is the attribute infuences the only render-responces phase?
The rendered attribute is not used during the RestoreView-Phase. The first time it is evaluated is in the ApplyRequestValue-Phase. This is because during the RestoreView-Phase there are no Request Values applied. Thus the rendered-attribute which might depend on these values cannot be evaluated.
were all in that tree. It happaned in spite of the fact that #{bean.id} was evaluated to 2. I expceted that the only instance would be in the tree.
The component tree of JSF is aware of all components, no matter if they are rendered or not. This allows you to rerender a certain component with all it's inner components (often used with checkboxes etc.) If the inner - not yet rendered components - would be missing inside the component tree, the usage of render="outerComponent" would not be able to show the inner components if their rendered-attribute now evaluates to true.
To avoid a component beeing added to that tree at all, you have to use a JSTL-Tag such as <c:if > - if this evaluates to false, the component would not be added to the component tree at all, so JSF would start processing the tree without knowing about a certain component.
You may also want to read this post, where the difference is explained with examples and much more detail:
JSTL in JSF2 Facelets... makes sense?
I have to check inserted date and modified date values, which both are string. If they are equal then i wont display edited email or else i will display edited email too. So i have used the below code to validate it.
<b>Created By - </b><h:outputText value="#{o.createdEmail}" /> : <h:outputText value="#{o.createdDateTime}" /><br/>
<c:set var="createdDate" value="#{o.createdDateTime}"/>
<c:set var="modifiedDate" value="#{o.modifiedDateTime}"/>
<c:if test="#{createdDate eq modifiedDate}">
<b>Edited By - </b><h:outputText value="#{o.lastModifiedEmail}" /> : <h:outputText value="#{o.lastModifiedDateTime}" />
</c:if>
Note: o is the variable reference the backend bean.
But it is always displaying it as true even though both values are different. How is this caused and how can I solve it?
Given the way how the code is written (a managed bean with name o makes no utter sense), I do a educated guess that #{o} is declared as var of <h:dataTable> or <ui:repeat>. If that is indeed the case, then that would totally explain the symptoms. JSTL tags runs during view build time, that moment when the JSF component tree is built based on XHTML source code. However, JSF components such as <h:dataTable> and <ui:repeat> runs during view render time, that moment when the JSF component tree needs to produce HTML output.
So, in effects, the #{o} is not available at the moment JSTL <c:if> runs during view build time. You should instead be using a JSF component with rendered attribute which runs during view render time, the same moment as #{o} is been put in the EL variable scope based on current iteration round.
<ui:fragment rendered="#{createdDate eq modifiedDate}">
<b>Edited By - </b><h:outputText value="#{o.lastModifiedEmail}" /> : <h:outputText value="#{o.lastModifiedDateTime}" />
</ui:fragment>
Note: this doesn't affect <c:set>. It merely creates an "alias" to the EL expression, it doesn't immediately evaluate the EL expression, so the <c:set> is completely safe here, albeit somewhat unnecessary as the value doesn't represent such a complex EL expression.
See also:
JSTL in JSF2 Facelets... makes sense?
I have an Action in request scope. The return value of one of its methods is passed around to a custom facelet tag. This tag then extracts several attributes of the returned object and displays them. The problem is the EL expression which has the method call on the Action is called for every evaluation of the attribute of the returned object. I will put the relevent pieces of code here.
some.xhtml
<ui:include src="someOther.xhtml">
<ui:param name="profileUri" value="#{param['relateToProfile']}"/>
<ui:param name="qualifier" value="#{param['qualifier']}"/>
<ui:param name="cellStyleClass" value="#{param['cellStyle']}"/>
</ui:include>
someOther.xhtml (approach 1) Note that ProfileAction is in #RequestScoped
<tenui:entityCard profileEntity="#{profileAction.getProfileMetadata(profileUri)}"
qualifier="#{qualifier}"
cellStyleClass="#{cellStyleClass}"/>
enityCard.xhtml(facelet custom tag)
<ui:fragment rendered="#{profileEntity.featured}">...
<tenui:gridCell id="#{profileEntity.profileId}#{qualifier}" ...
<tenui:metaunit ..content="#{profileEntity.getMeta('memberName')}"
href="/#{profileEntity.profileDisplayUri}"
hrefStyleClass="a-styled grid-cell-name"/>
.....
...several other EL expressions including #{profileEntity.xxx}
The problem is #{profileAction.getProfileMetadata(profileUri)} is being called for every attribute evaluation in entityCard.xhtml Then, I thought I would save the return value of method call in a c:set var(approach 2 as noted below) but it doesn't help.
someOther.xhtml (approach 2)
<c:set var="profileMetadata"
value="#{profileAction.getProfileMetadata(profileUri)}"/>
<tenui:entityCard profileEntity="#{profielMetadata}"
qualifier="#{qualifier}"
cellStyleClass="#{cellStyleClass}"/>
The action method calls a Stored proc which is quite expensive and the returned object has over 20 attributes that get evaluated in ELs in entityCard.xhtml.
I also tried another approach with resolving teh value at ui:param itself by calling the action method directly, but of no avail at all. The problem remained.
Can someone point to what could I be doing wrong? Or, how I could avoid the multiple calls to profileAction.getProfileMetadata call?
You need to set the scope attribute of <c:set> to one of the desired scopes, request, view, session or application. Otherwise it defaults to none.
Assuming that you want it to be request, this should do:
<c:set var="profileMetadata" scope="request"
value="#{profileAction.getProfileMetadata(profileUri)}" />