Access JSF Custom Tag's id - jsf

TL;DR
Is there something like composite's cc.clientId that will give me the id of a custom tag?
Details:
I'd like a custom tag that will render a label, a value, and an icon. When the icon is clicked, a Bootstrap modal is supposed to open up that will edit the value.
<ui:composition>
<div> #{field.label}: #{field.value}
<a class="icon-pencil" data-target="#editForm" data-toggle="modal">
</div>
<h:form id="editForm" class="modal hide fade" role="dialog" ...>
... there's an input here linked to field.value ...
</h:form>
</ui:composition>
I can use the tag with <my:editor />. When I do so within a ui:repeat, an id is prepended to the editForm so that it renders with id j_idt104:editForm. So I need to modify the data-target to include the id.
This would be really easy with a composite component because I have access to the id via cc.clientId:
data-target="\##{cc.clientId}\:editForm"
However, I can't get it to work with a custom tag because I don't know of an EL expression (or something) that will give me access to the id. I could probably wait until after the page is loaded, then use jQuery to inspect the id and set the data-target after the fact, but I was hoping for a more pure-JSF solution.
I'm using JSF 2.1 and Bootstrap 2.3, at the moment.

Answer seems to be no. BalusC says you should replace things like custom tags with "normal" JSF components. In this case, that would mean using the composite component.
If you're deadset on using custom tag, I worked around the issue (with lots of help from the answer here) by using an index in the form's id:
I replaced the ui:repeat with a c:forEach that has access to the item's index:
<table>
<c:forEach items="#{bean.items}" var="item" varStatus="status">
<my:editor index="#{status.index}" ... />
</c:forEach>
</table>
And in the custom tag, I used the index in the data-target:
<tr>
<td>#{label}: #{value}</td>
<td>
<a data-target="\#editForm-#{index}" ... ></a>
<h:form id="editForm-#{index}" ... >
...
</h:form>
</td>
</tr>
The only catch is that c:forEach is a build-time construct (see details in this answer), which is a problem if you need any render-time data (like if you build information up in preRenderView). If you do, then you're better off using ui:repeat with a custom component, and relying on the cc.clientId.

Related

JSF id value to the component behaves different

I have the following code in my xhtml
<h:form id="xyForm">
<p:dataGrid id="xyGrid" ....>
<p:selectOneMenu id="code" ...> </p:selectOneMenu>
</p:dataGrid>
</h:form>
But when I saw the code generated, it looks like the following
<select name="xyForm:xyGrid:0:code_input" tabindex="-1" id="xyForm:xyGrid:0:code_input"> </select>
My question here is: why _input is getting appended with name and id.
As per my understanding id should be only xyForm:xyGrid:0:code not with appended _input. Could someone please clarify or tell me how to remove that _input?
An id attribute should be unique within an html page.
While rendering the SelectOneMenu, the select tag is wrapped inside a div tag. The div tag will have the id of the component i.e. xyForm:xyGrid:0:code, and so it makes sense that the select tag should have a different id.
Also, this is a common pattern in Primefaces, observed in other components like SelectBooleanCheckbox etc.
Instead of trying to removing _input, you will have to figure around how to work around it.

How can I show/hide row of table in jsf? [duplicate]

I'm trying to conditionally render a <tr> therefore I cannot use <h:panelGroup> as it will render to <span> or <div>
My current (working) approach is the following:
<h:outputFormat rendered="#{negotiator.maySend}">
<tr> my tr stuff </tr>
</h:outputFormat>
This works, but I'm not sure if that's the way to abuse <h:outputFormat> - before that I used <h:outputLabel> but this was rendered to <label> in IE.
I have also read the answers to this question, but as mentioned above, they won't work for me because of the <tr>: How to not render whole block in JSF?
I cannot use <h:panelGroup> as it will render to <span> or <div>
Apparently you didn't test it carefully. The <h:panelGroup> won't render anything if you don't specify attributes which should end up in the client side, like layout, id, styleClass, etc.
Thus, this should technically perfectly work fine.
<h:panelGroup rendered="#{negotiator.maySend}">
<tr> my tr stuff </tr>
</h:panelGroup>
However, better for the main purpose would be to use <ui:fragment>.
<ui:fragment rendered="#{negotiator.maySend}">
<tr> my tr stuff </tr>
</ui:fragment>
This is by the way also possible with <f:verbatim>, but this is deprecated since JSF 2.0 as it's designed specifically for usage in JSP.
See also:
Alternative to ui:fragment in JSF
Conditionally displaying JSF components
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Ajax update/render does not work on a component which has rendered attribute

accessing var outside ui:repeat JSF2

I want to access a variable through out my page. The var is declared inside a ui:repeat element. Heard that the scope of the variable in only inside the repeat tag. I want to load another div on the same page which need the details inside this var. How can I achieve this.
<ui:repeat var="errorDetails"
value="#{adminDashboardController.errorDetails}" varStatus="status">
<tr>
<td>#{errorDetails.issueName}</td>
<td>#{errorDetails.priority}</td>
<td>#{errorDetails.comments}</td>
<td><h:commandButton class="btn btn-primary btn-xs view-issue"
value="View" /></td>
</tr>
</ui:repeat>
<h4 class="modal-title" id="myModalLabel">#{errorDetails.issueName}</h4>
The errorDetails variable is only available in the scope of the ui:repeat.
You have here two options:
HTML/JS solution: Generate HTML code which contains one <h4...>#{errorDetails.issueName}</h4> for each line of your table and use JavaScript to display the right block when pressing on the command button.
I think that this option should be only used for performance reason, because you will generate lot of HTML and because as a JSF developer you usually prefer to avoid coding custom things in JavaScript.
JSF solution (my preferred one): use a backing bean to hold the currently viewed error detail. That would be something like this:
<ui:repeat var="errorDetails" value="#{adminDashboardController.errorDetails}" varStatus="status">
...
<h:commandButton ... action="#{adminDashboardController.showDetails(errorDetails)" update="myModalLabel" />
...
</ui:repeat>
...
<h:panelGroup rendered="#{adminDashboardController.currentDetail != null}">
<h4 class="modal-title" id="myModalLabel">#{adminDashboardController.currentDetail.issueName}</h4>
</h:panelGroup>
The AdminDashboardController.showDetails methods would save the given error detail in a the field currentDetail.

Duplicated ID on JSF custom tag when nesting tags

I'm migrating some composites to custom tags because of performance issues. When using composites all Ids are properly generated, but when using custom tags I'm having the duplicated Id Exception, even I created a custom EL expression for generating a new ID.
After some research, it seems it's because the tags attributes are inherited when nesting the tag:
<far:fcontainer name="**father1**" type="panel">
<far:fcontainer type="panel">
<far:fcontainer type="panel">child 3</farTag:fcontainer>
</far:fcontainer>
</far:fcontainer>
In the example, the first fcontainer should have the id father1 and the nested ones should have the ID generated, but this is what I have:
<div id="**father1**" class="ui-widget-content">
<div id="**father1**" class="ui-widget-content">
<div id="**father1**" class="ui-widget-content">child3</div>
</div>
</div>
The custom tag is:
<ui:composition>
<p:outputPanel layout="block" styleClass="#{type == 'panel'?'ui-widget-content':''}"
id="#{empty name ? far:generateId() : name}">
<ui:insert />
</p:outputPanel>
<ui:composition>
Is this normal? Is there any workaround?
Tested on Mojarra 2.1.26.
Thanks in advance.
Update: tested on MyFaces 2.1.12 and seems to work fine, Mojarra's bug?
A workaround to this bug would be to always use the custom EL expression, and in it you can first check whether the parent component has the attribute set or not.

how to place dynamic href from a tag in JSF?

I want to use a tag in my JSF page, but i also want to have dynamic href content. I know there is a h:commandLink in JSF but i don`t want use it for my purposes. I have t:dataTable elemet which iterates via results and shows them on my page. Here is the situation:
<t:dataList id="dataTable" value="#{manBean.fullResult}" var="element" first="0" rows="10">
<div class="photos">
<img src="myimages/IN THIS TOO.../image.jpg"
</div>
...
</t:dataList>
I have tried code like this:
<img src="myimages/#element[0]/image.jpg"
. #element[0] is an element of result list from dataTable and contains values like: 0,1,2,3... etc.
this ends witch error that i could not use #{...} in a template. What should i do? Anybody knows a good solution for this?
If you're using JSF on JSP, use <h:outputLink> and <h:graphicImage> instead of <a> and <img>.
<h:outputLink value="myimages/#{element}/image.jpg">
<h:graphicImage value="myimages/#{element}/image.jpg" />
</h:outputLink>
If you're using JSF on Facelets, you can just use EL in template text.
<a href="myimages/#{element}/image.jpg">
<img src="myimages/#{element}/image.jpg" />
</a>

Resources