<a jsf:rendered="#{...}"> is not interpreted as passthrough element - jsf

I don't understand why this piece of code is working:
<h:link value="Login" rendered="#{sessionBean.userInSessionBean == null}" />
and this piece of code is not working:
<a jsf:rendered="#{sessionBean.userInSessionBean == null}">Login</a>

A HTML element will only become a passthrough element if following conditions are met:
There's at least one jsf:xxx attribute from http://xmlns.jcp.org/jsf namespace.
There's at least one "identifying attribute" associated with a specific JSF component.
For the <a> element an identifying attribute is necessary so JSF can decide whether to interpret it as <h:commandLink>, <h:outputLink> or <h:link>. Without an identifying attribute, JSF wouldn't have any idea what component you actually meant to use, so any jsf:xxx attributes will be ignored. The jsf:rendered is not sufficient as identifying attribute because it appears on every single JSF component, so JSF would still have no idea which one you meant.
Given that you seem to intend to have a <h:link>, then use jsf:outcome as identifying attribute.
<a jsf:outcome="login" jsf:rendered="#{empty sessionBean.userInSessionBean}">Login</a>
A completely different alternative is to wrap plain HTML in an <ui:fragment rendered>. See also How to conditionally render plain HTML elements like <div>s?

Related

Turn a facelet tag into composite component

Some time ago, based on one of #BalusC answers (really don't know which one of them) I wrote a facelet tag that is a kind of a button generator, that generates a variable number of buttons disposed side-by-side, each one with some parameters passed through the attributes.
Now I want to turn the facelet tag into a composite component (because on the latter, I have the cc:interface tag, that provides information to others developers who wants to use the custom component).
In the rewriting process I must deal with the actions attributes of the dynamically generated buttons. In the facelet tag approach I don't have to declare them as methods, so I can pass their names as simple strings and process them inside the facelet tag also as simple strings and call the action methods. In the composite component approach it seems that I must pass the methods names as actual methods names (by using the method-signature attribute of cc:attribute). The problem is: as I don't know previously the number of buttons (it generates the buttons dinamically), I'm not able to declare the action methods in the cc:interface section.
A simplified version of my working facelet tag is:
<c:set var="idValues" value="#{fn:split(ids,',')}" />
<c:set var="actionValues" value="#{fn:split(actions,',')}" />
<c:set var="numberOfButtons" value="#{fn:length(idValues)}" />
<h:panelGrid id="#{id}" columns="#{numberOfButtons}">
<c:forEach begin="0" end="#{numberOfButtons-1}" varStatus="i">
<p:commandButton id="#{idValues[i.index]}"
action="#{bean[actionValues[i.index]]}" />
</c:forEach>
</h:panelGrid>
and the facelet tag can be used like this:
<my:button id="idButton"
ids="btnSave,btnCancel"
actions="onSave,onCancel"
bean="#{myBean}" />
[EDIT]
As sugested by #BalusC in the answers, adding code like below in the taglib.xml file was enough for the Eclipse autocompletion to work fine:
<tag>
<tag-name>button</tag-name>
<source>tags/bottons.xhtml</source>
<attribute><name>id</name></attribute>
<attribute><name>ids</name></attribute>
<attribute><name>actions</name></attribute>
<attribute><name>bean</name></attribute>
</tag>

primefaces update attribute not working on modal dialog opened from modal dialog [duplicate]

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

JSF h:link rendered span [duplicate]

I'm getting this warning in my application
JSF1090: Navigation case not resolved for component j_idt51
What is the reason for this warning and how can I resolve it? The strange thing is that the component id j_idt51 is not in the rendered page. If I look to the HTML of the generated page there is no element with id j_idt51.
This warning will occur whenever you use an (implicit) navigation outcome in the outcome attribute of <h:link> or <h:button>, which does not represent a valid view ID.
E.g.
<h:link ... outcome="viewIdWhichDoesNotExist" />
<h:button ... outcome="viewIdWhichDoesNotExist" />
Additionally, the <h:link> will render a <span> element instead of an <a> element.
The solution is obvious: use a valid view ID, or make at least sure that the desired view is resolveable by ConfigurableNavigationHandler#getNavigationCase().
Note that some starters use for an unknown reason even a full URL like http://google.com as outcome value of <h:link>:
<h:link value="Go to Google" outcome="http://google.com" />
This abuse would then also yield exactly this warning. You should be using <h:outputLink> or just <a> instead.
As to the absence of a HTML element with the same ID as the JSF component, this may happen when you didn't explicitly specify the JSF component's id attribute. The JSF component ID does then not necessarily end up in the generated HTML output. Assigning those components a fixed ID should help better in nailing down the cause.

commandlink in JSF not generating the intended HTML tag

I'm trying to call a managed bean from h:commandLink in JSF. But I don't see href attribute in the rendered HTML a tag.
Am I missing something?
There is a ManagedBean called AccountSetupController with a signUp method in it.
This is the tag I used in JSF:
<h:form prependId="false">
<h:commandLink action="#{accountSetupController.signUp()}"
value="#{msg['homepage.createaccount']}" styleClass="button large">
</h:commandLink>
</h:form>
This is the rendered tag. See there is nothing in href attribute.
<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt15'),
{'j_idt33':'j_idt33'},'');return false"
class="button large">CREATE MY ACCOUNT</a>
This is the form tag that is generated
<form id="j_idt15" name="j_idt15"
method="post" action="/myproject/faces/homepage/homepage.xhtml"
enctype="application/x-www-form-urlencoded"> .... </form>
As you can see, the form action is pointing to some place I don't need.
Am I missing something?
Command links in JSF are rendered that way. The form will be submitted by JSF via JavaScript's onclick method using JSF JS library, while the href will always stay #.
Moreover, you won't find the bound action / action listener method names in browser tools due to understandable reasons. Rather, JSF will find the id of a clicked link on the server and will trigger all of the component's action(listeners).
All in all, reading <h:commandLink> documentation unsurprisingly helps a lot (all emphasis mine):
General behavior: Both the encode and decode behavior require the ability to get the id/name for a hidden field, which may be rendered in markup or which may be programmatically added via client DOM manipulation, whose value is set by the JavaScript form submit (further referred to as hiddenFieldName.
Decode behavior: Obtain the "clientId" property of the component. Obtain the Map from the "requestParameterMap" property of the ExternalContext. Derive hiddenFieldName as above. Get the entry in the Map under the key that is the hiddenFieldName. If the there is no entry, or the entry is the empty String, or the entry is not equal to the value of the "clientId" property, return immediately. If there is an entry, and its value is equal to the value of the "clientId" property, create a new javax.faces.event.ActionEvent instance around the component and call queueActionEvent() on the component, passing the event.
Encode behavior: Render "#" as the value of the "href" attribute. Render the current value of the component as the link text if it is specified. Render JavaScript that is functionally equivalent to the following as the value of the "onclick" attribute: document.forms['CLIENT_ID']['hiddenFieldName'].value='CLIENT_ID'; ocument.forms['CLIENT_ID']['PARAM1_NAME'].value='PARAM1_VALUE'; document.forms['CLIENT_ID']['PARAM2_NAME'].value='PARAM2_VALUE'; return false; document.forms['CLIENT_ID'].submit()" where hiddenFieldName is as described above, CLIENT_ID is the clientId of the UICommand component, PARAM*_NAME and PARAM*_VALUE are the names and values, respectively, of any nested UIParameter children.

JSF same ID on rendered

Let's say I am using rendered as basically a case statement. I have a label and message for an input field, but I want the field itself to change depending on the case. As such:
<p:inputText id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsInput}" />
<p:calendar id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsCalendar}" />
If I do that then I get the following error: java.lang.IllegalStateException: Component ID j_idt64:foo has already been found in the view.
As a workaround I created lots of labels/messages for each param type and changed their ids. But this brings my question. If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file? Is there a way to keep them with all the same ID?
JSF component IDs are supposed to be unique during view build time already, not during view render time only. This way you effectively end up with two JSF components with the same ID which is indeed invalid. You'd like to effectively end up with one JSF component with the desired ID in the JSF component tree after view build time.
You can achieve this by populating the component during the view build time instead of generating its HTML output conditionally during the view render time. You can use the JSTL <c:if> tag for this.
<c:if test="#{paramIsInput}">
<p:inputText id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
<c:if test="#{paramIsCalendar}">
<p:calendar id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
This has however caveats: the <c:if test> condition can't depend on a variable which is only known during JSF render time. So it has not to depend on var of a JSF iterating component, or to be a property of a view scoped bean, etc.
See also:
JSTL in JSF2 Facelets... makes sense?
If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file?
How would JSF know that only one component will be rendered? You are using EL in rendered and both can evaluate to true. Here is the documentation which says you can't have duplicate ids inside a naming container.
The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer.
-
Is there a way to keep them with all the same ID?
In case you still want to have same ids on more than one components you need to separate the naming container.
You can use PanelGrid as a naming container.

Resources