Unique ID for JSF composite component inside dataTable - jsf-2

I am using PrimeFaces 3.2 with JSF 2 in a glassfish 3.1.2.
I have a <p:dataTable> which displays search results containing information on different issues (the issues are assigned to users).
If somebody clicks on the icon of the assigned user a <p:dialog> pops up.
The user icon and the according dialog are implemented using a composite.
Inside the composite I am using some jQuery functions which need a unique ID for each dialog component - I am not able to find a way to solve this problem.
My investigations so far:
I need to set the widgetVar attribute, which works fine as long as I have only one user in the list but it seems that inside a dataTable the widgetVar is not unique for many composites.
Since the user can be displayed more than one time inside the search result, I am not able to setup an widgetVar like this:
<ui:param name="myWidgetVar" value="widget_#{user.id}" />
and use it this way
<p:dialog widgetVar="#{myWidgetVar}">
also using #{cc.id} does not resolve the problem 'cause it only returns the id of the widget without the naming-container part which is always the same.
I need the complete id as displayed in html (e.g.: form:jdt123:dialog:456) - how can I get this?
Does anyone know what to do?
Thanks Pete

My solution is using #{cc.clientId} which I did not know yet.
This gives me the complete html element id constisting of the series of identifiers glued with the UINamingContainer#getSeparatorChar (e.g.: form:jdt123:dialog:jdt456)

Thanks for the answer. You solved my unrelated problem, but I think I stumbled on another solution for your problem.
From the PrimeFaces user guide (http://primefaces.org/documentation.html):
8.2 EL Functions
PrimeFaces provides built-in EL extensions that are helpers to common use cases.
Common Functions
Component
<h:form id="form1">
<h:inputText id="name" />
</h:form>
//#{p:component(‘name’)} returns ‘form1:name’
WidgetVar
<p:dialog id="dlg">
//contents
</p:dialog>
<p:commandButton type="button" value="Show" onclick="#{p:widgetVar(‘dlg’)}.show()" />
It looks like you would be most interested in the WidgetVar implementation.

Related

p:inputText does not remember values(autofill does not work)

How to make p:inputText remember values? I have autocomplete="on" in there but it doesnot work.
Please find the code below:
<p:inputText id="username_email" value="#{BsnsSgnupLgnBen.userName}" required="true" size="25" autocomplete="on" >
<f:validateLength minimum="0" maximum="50" />
</p:inputText>
Any clue?
Browser-builtin autocomplete/autofill is only triggered during synchronous page load. So, if you're loading your forms by ajax, then autocomplete/autofill is not triggered. Apparently that's what happening here. The solution is obvious: you need to load your forms on which you need autocomplete/autofill synchronously. E.g. by <h:link>, <h|p:button>, etc or a navigation with faces-redirect=true.
As the particular input field seems to be part of a login form, I just want to add for sake of completeness, another thing to take into account is that usernames/passwords of login forms (a form is considered a login form when it has at least one <input type="password"> field) are not remembered for autocomplete/autofill when the login itself is submitted by ajax. You should perform the actual login synchronously. You can use <p:commandButton ajax="false"> for this.
Please do note that the concrete problem has completely nothing to do with JSF. It's in the context of this question merely a HTML code generator. You'd have had exactly the same problem when using a different server side language generating the very same HTML output and even when using plain vanilla HTML.
I think you should use the autoComplete component from Primefaces http://www.primefaces.org/showcase/ui/autocompleteHome.jsf

wrong ids when render h:panelGroup's inside c:forEach

I have page where I render some h:panelGroup panels. Those panels are realized as plugins registered in a plugin registry on startup.
Part of the plugins api is a custom jsf component where I get the registered plugins for extension point and include their facelet templates by path:
<c:forEach items="#{pluginRegistry.getPlugins(point)}" var="extension">
<ui:include src="#{extension.path}" />
</c:forEach>
The page where I include the panels looks like:
<h:panelGrid id="dashboard" columns="3">
<cmf:insertPageFragments point="dashboardExtensionPoint" />
</h:panelGrid>
For every panel there are facelet templates like the one below:
<rich:panel id="caseDetailsPanel" header="panel label">
<!-- panel content -->
</rich:panel>
Now, the problem is that the very first panel in the list returned by the pluginsRegistry is rendered in the page with the provided id like formId:caseDetailsPanel for example. The rest of them have generated ids like formId:j_idt223 !!! Obviously if I want to rerender some of the panels, I can't do that.
That happens when environment is jboss AS 7.1 with JSF 2.1, richfaces 4.2.3.Final.
When deployed on jboss-eap-6.1 everything looks fine but for now I can't use this jboss version.
Any suggestions on how to workaround this issue?
There can not be multiple JSF components with the same ID. Each JSF component must have an unique ID. When dynamically creating JSF components using JSTL, you need to manually assign and ensure an unique ID, otherwise JSF will discard the provided ID and autogenerate an unique ID.
There are several ways to achieve this, depending on the concrete functional requirement and the existing code.
Use use the iteration index of <c:forEach>.
<c:forEach ... varStatus="loop">
...
<rich:panel id="caseDetailsPanel_#{loop.index}" ...>
This will generate caseDetailsPanel_0, caseDetailsPanel_1, etc depending on the current iteration index.
Use the unique identifier of the currently iterated item. It isn't clear based on the information provided so far if you have any, so here's just a fictive example assuming that the class behind #{extension} has an id property representing the technical DB identifier.
<c:forEach ... var="extension">
...
<rich:panel id="caseDetailsPanel_#{extension.id}" ...>
Wrap #1 or #2 if necessary in a <f:subview> with an unique identifier, so that you don't need to modify the includes.
<c:forEach ... varStatus="loop">
<f:subview id="panel_#{loop.index}">
<ui:include ... />
The <f:subview> creates a new NamingContainer around it, so you end up getting formId:panel_0:caseDetailsPanel, formId:panel_1:caseDetailsPanel and so on.
A completely different alternative would be to use <ui:repeat> instead of <c:forEach>. The <ui:repeat> does not run during view build time, but during view render time. This way there's physically only one <rich:panel id="caseDetailsPanel"> component in the component tree which is reused multiple times during generating HTML whereby JSF will take care of generating the right IDs with the <ui:repeat> index like so formId:repeatId:0:caseDetailsPanel. However, this in turn may cause trouble with <ui:include> as it also runs during view build time and thus can't get the #{extension} at hands.

inital value with setBooleanButton in primefaces

I'm using Primefaces and MyFaces. I would like to use the selectBooleanButton component, to control visibility of other components within a long and rather complex form.
simplified sample code:
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="#{not empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />
<h:panelGroup id="commentPanel"
style="display:#{empty myBean.comment ? 'none' : 'block'}">
<p:inputTextarea value="{myBean.comment}"/>
</h:panelGroup>
The javascript in the onchange attribute simply toggles the display style from none to block and vice-versa to hide or unhide the panel group. I want/need the components to remain in the view, I do not want to use rendered attributes to remove them completely.
Where I get into trouble is because of the EL construct used in the value attribute of the setBooleanButton component. I do realize that this EL statement is not compatible with the set operation, and this results in an exception.
What I want to be able to do is when the form is loaded, have the initial status of the selectBooleanButton components set to 'on' when the comment property has some existing text it, and 'off' when it is empty. I am looking for a way to work around this that would not require me to create a property in the model for each and every instance where I want to hide the panel, as that would result in dozens and dozens of properties because my real world form is very large with many of these comment sections.
I also posted this question on Primefaces forum, and did not receive any answers there either, so at this time there may not be a great solution to this problem, or at least not one that has been shared. What I ended up doing to work around this is to create two versions of the component, and use the rendered attribute to control which one is used, like this:
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="true" rendered="#{not empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="false" rendered="#{empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />

A better way to get the real ID of an component in a naming container

I got the following scenario:
I got several tabs (TabView is a naming container )
and in one of the I got a p:inputText which shows a dialog(which is located in other xhtml file) , now I want the dialog to update the p:inputText , the thing is that the id of the p:inputText is unknow (JSF adds some prefix to it)
<h:form id="hoursReportFrm">
<p:inputText id="comment4Dialog" value="#{hoursReportBean.aComment}"
onfocus="dlg1.show();"/>
I can't use this update="hoursReportFrm:comment4Dialog" in the dialog
ATM i looked at the example of this site JSF: working with component IDs (id vs clientId) (its from 2009)
and added binding to to inputtext , like thisbinding="#{lookup.components.comment4Dialog}" and in the p:commandButton of the dialog I changed to update="#{lookup.clientIds.comment4Dialog}"
and It works just fine, but I'm looking for a better way , without the need to bind every component that I would like to access later...
Thanks ahead,
To be quite honest, I think the binding is probably the easiest route, however when I've been in that situation I've found composite components often offer a better solution than bindings. Depending on the situation (and again, its totally case by case) you can use a composite component to get around this problem. This allows you to reuse parts of a page creatively so that your specific updates don't take a lot of work and you can reuse the code.
An example of this might be:
//comp:myDialog
...
<composite:interface>
<composite:attribute name="update" />
<!-- Other attributes -->
</composite:interface>
<composite:implementation>
...
<!-- Implementation -->
<p:commandButton update="#{cc.attrs.update}"/>
...
</composite:implementation>
And here might be the component in use:
//for the sake of argument 'comp' as your library
<h:form id="someForm">
<p:inputText value="#{bean.changeMe}" id="changeMe"/>
</h:form>
<h:form id="dialog">
<!-- dialog here -->
<comp:myDialog update="someForm:changeMe" />
</h:form>
By separating this view into a piece of reusable code you might be able to get around the burden of specifying the full path because it is now much easier to reuse. However, I think it is a toss up of a binding or the composite component depending on the specific case. For reuse, make a new object (component) and reuse it. If you're dealing with a highly dynamic environment: bind it.
I'm not an expert by any means, but generally speaking the above has gotten me out of a lot of tough situations.
EDIT: on a re-read you should also make sure that the tab-view isn't lazily loaded and take a look at the rendering to make sure the path is correct (inspect the ID). I've had problems (in older versions of Primefaces) where sometimes the id was nested inside a p:outputPanel or in rare cases the subview id. It might be a very simple fix by specifying the full path ':subview:form:component' though that shouldn't be the case.

Update UI on JSF 2

Is there a way to update UI elements asynchronously in JSF 2?
For example a person is looking on the screen and some pieces on the screen get updated, when say a batch job changes some value.
There are a couple of solutions. One is e.g. a4j:push, which is further described here.
IceFaces is also known for this. Note that some of the components essentially do polling via AJAX, while others actually use reverse ajax/comet.
You can also use the <p:poll> provided by PrimeFaces.
Here is a working example:
<h:form>
<h:outputText id="txt_count" value="#{counterView.number}" />
<p:poll interval="3" listener="#{counterView.increment}" update="txt_count" />
</h:form>

Resources