<f:ajax> contains an unknown id :someid when used in <ui:repeat> - jsf-2

My code snippet:
<ui:repeat var="o">
<h:panelGroup id="someid">
<ui:repeat>
// HTML
</ui:repeat>
</h:panelGroup>
<div>
<h:form>
<h:commandButton action="#{o.doSomething}">
<f:ajax event="action" render=":someid" />
</h:commandButton>
<h:form>
</div>
</ui:repeat>
Why didn't <f:ajax> find someid?

That's not possible. The <ui:repeat> prepends the client ID with its own ID and an index. All those panelgroups get IDs like j_id1:0:someid, j_id1:1:someid, j_id1:2:someid, etc. The following is supposed to work in your particular construct:
<f:ajax render=":#{component.parent.parent.clientId}:someid" />
This will prepend the <ui:repeat>'s current client ID dynamically. It however only works when you're using with MyFaces instead of Mojarra. The <ui:repeat> is broken in many ways in Mojarra. They have scheduled many fixes for 2.2.
An alternative is to group them in a common NamingContainer component like <h:form>, so that you can use a relative ID.
<ui:repeat var="o">
<h:form>
<h:panelGroup id="someid">
<ui:repeat>
// HTML
</ui:repeat>
</h:panelGroup>
<div>
<h:commandButton action="#{o.doSomething}">
<f:ajax event="action" render="someid" />
</h:commandButton>
</div>
<h:form>
</ui:repeat>

Related

<h:commandButton> not working inside <ui:define>

I created a facelet template called loginRegisterTemplate.xhtml. When I use it in a template client and I place a in it, the method in the managed bean is not invoked. Without the template the button is working fine. Why is this happening?
<ui:composition template="resources/css/faceletsTemplates/loginRegisterTemplate.xhtml">
<ui:define name="top">
Login Page
</ui:define>
<ui:define name="content">
<div align="center">
<h:panelGrid columns="3" columnClasses="rightalign,leftalign,leftalign">
<h:outputLabel value="Username:" for="userName"/>
<h:inputText id="userName" label="Username" required="true" value="#{loginBean.userName}" />
<h:message for="userName" />
<h:outputLabel value="Password:" for="password"/>
<h:inputText id="password" label="Password" required="true" value="#{loginBean.password}" />
<h:message for="password" />
</h:panelGrid><br/>
<h:button value="Back to Home" outcome="home"/>
<h:commandButton id="login" value="Login" action="#{loginBean.doLogin}"/>
</div>
</ui:define>
</ui:composition>
</h:body>
The simple <h:button> next to it, on the other side, is working fine.
Here is the body of my template file:
<h:body>
<div id="top">
<ui:insert name="top">Top</ui:insert>
</div>
<div id="content" class="center_content">
<ui:insert name="content">Content</ui:insert>
</div>
</h:body>
I have looked here: h:commandLink / h:commandButton is not being invoked but I couldn't find which problem causes that.
Thanks!
Why is the h:commandButton not working?
Your problem is number 1 in the answer you have checked.
UICommand and UIInput components must be placed inside an UIForm
component, e.g. <h:form>.
Why is the h:button working then ?
from the h:button docs:
Render an HTML "input" element of type "button". The value of the
component is rendered as the button text and the outcome of the
component is used to determine the target URL which is activated by
onclick.
So ...
JSF will put your h:button outcome value in a javascript function that will be executed at an onclick event. But it will execute the action of the h:commandButton on the form submit with the POST method, so there should be a form to submit.

Why <h:panelGroup> id is not found when I access through <f:subview> tag?

<h:panelGroup id="userPanel"><f:subview rendered="#{searchView.isUser}">
<h:commandButton value="test" action="#{searchAction.doFindUsers}" >
<f:ajax execute="#this" event="action" render="userPanel" />
</h:commandButton> </f:subview></h:panelGroup>
I am getting the error as: cannot locate it in the context of the component j_idt26
Because the <f:subview> is a NamingContainer.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Just use <h:panelGroup>,
<h:panelGroup id="userPanel">
<h:panelGroup rendered="#{searchView.isUser}">
<h:commandButton value="test" action="#{searchAction.doFindUsers}">
<f:ajax execute="#this" event="action" render="userPanel" />
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
or <ui:fragment> (which has only a little less overhead)
<h:panelGroup id="userPanel">
<ui:fragment rendered="#{searchView.isUser}">
<h:commandButton value="test" action="#{searchAction.doFindUsers}">
<f:ajax execute="#this" event="action" render="userPanel" />
</h:commandButton>
</ui:fragment>
</h:panelGroup>
or in this specific example just directly on command button (surely your case is more complex than that)
<h:panelGroup id="userPanel">
<h:commandButton value="test" action="#{searchAction.doFindUsers}" rendered="#{searchView.isUser}">
<f:ajax execute="#this" event="action" render="userPanel" />
</h:commandButton>
</h:panelGroup>
See also:
Alternative to ui:fragment in JSF
Conditional rendering of non-JSF components (plain vanilla HTML and template text)

Invoke a backing bean action method on click of a <h:panelGroup layout="block">

How can I make the mainDiv clickable and invoke a backing bean action method?
<h:panelGroup layout="block" id="mainDiv">
<h:panelGroup layout="block" style="float:left;">
<h:outputText value="#{messageItem.sendBy.registerName}"/>
</h:panelGroup>
<h:panelGroup layout="block" style="float:right;">
<h:outputText value="#{messageItem.sendDate}">
<f:convertDateTime pattern="HH:mm"/>
</h:outputText>
</h:panelGroup>
</h:panelGroup>
The simplest way would be to wrap its contents in a <h:commandLink>, if necessary with <f:ajax>. Use CSS display:block to let the link span the entire div.
<h:panelGroup layout="block" id="mainDiv">
<h:commandLink action="#{bean.action}" style="display:block;">
<f:ajax />
...
</h:commandLink>
</h:panelGroup>
Or, given your question history you're using PrimeFaces, you can also use <p:remoteCommand>.
<h:panelGroup layout="block" id="mainDiv" onclick="functionName()">
...
</h:panelGroup>
<p:remoteCommand name="functionName" action="#{bean.action}" />
You can use f:ajax on panelGroup
<h:panelGroup>
<f:ajax event="click" listener="#{adminPanel.test}"></f:ajax>
xxx
</h:panelGroup>
resulting html :
<span id="j_idt169" onclick="mojarra.ab(this,event,'click',0,0)">
xxx
</span>

Show/hide JSF2 form using <p:selectBooleanButton>

I need to show and hide component in my JSF 2-PrimeFaces application, please find my code below for the same:
<p:outputLabel for="online_offer" value="Online offer#{msg._question_mark}" styleClass="font-size-1em font-weight-bold input-panel-main" />
<p:panel>
<h:panelGrid columns="1">
<p:selectBooleanButton id="online_offer" value="#{QckPstBen.offer.isExpired}" onLabel="Yes" offLabel="No" onIcon="ui-icon-check" offIcon="ui-icon-close" >
<f:ajax event="click" render="#form" />
</p:selectBooleanButton>
</h:panelGrid>
</p:panel>
<h:outputLabel value=" " />
<h:panelGroup rendered="#{QckPstBen.offer.isExpired}">
<p:outputLabel for="website" value="Website/link to the offer#{msg._colon}" styleClass="font-size-1em font-weight-bold input-panel-main" />
<p:panel>
<h:panelGrid columns="1">
<p:inputText id="website" required="true" size="38" />
<p:watermark for="website" value="www.discountbox.in" />
</h:panelGrid>
</p:panel>
</h:panelGroup>
But it doesnt work, any clue
PrimeFaces components doesn't support <f:ajax>. Use <p:ajax> instead.
<p:selectBooleanButton ...>
<p:ajax update="#form" />
</p:selectBooleanButton>
Note that I omitted the event attribute, it defaults here to click already.
Place rendered on children of <h:panelGroup> instead or place a container of some sort around it, for example p:panel.
This may be OBE by now but...
When referencing the page bean, don't I recall in the #{} context, the convention of using lowercase for class names and method/attributes of the page bean (i.e. not #{QckPstBen.offer.isExpired} but #{qckPstBen.offer.isExpired}?

Can't call ajax method with param using in ui:repeat using f:ajax

I have a list of links rendered in a loop. On click of the link I want to set a bean property selectedIndex. I am trying to do it by passing it on Ajax parameter, but the full form is getting refreshed. Even then the notificationPreferencesBean.retrievePreferences is not getting fired. Is this approach correct?
Here is my template snippet:
<ui:repeat value="#{notificationPreferencesBean.userNotificationPreferences}"
var="userNotificationPreferenceVar" varStatus="idx">
<li>
<h:commandLink
value="#{userNotificationPreferenceVar.notificationClassName.label}"
styleClass="#{userNotificationPreferenceVar.cssClassName}"
action="#{notificationPreferencesBean.retrievePreferences}">
<f:ajax execute="#form" render="#none">
<f:param value="#{idx}" name="idx" />
</f:ajax>
</h:commandLink>
</li>
</ui:repeat>
and here is the bean declaration:
#ManagedProperty(value = "#{param.idx}")
private Integer selectedIndex;
Interestingly the following code works Ajaxfully but it just calls the notificationPreferencesBean.retrievePreferences and doesn't set the selectedIndex(as expected because I am not passing any param)
<ui:repeat value="#{notificationPreferencesBean.userNotificationPreferences}"
var="userNotificationPreferenceVar" varStatus="idx">
<li>
<h:commandLink
value="#{userNotificationPreferenceVar.notificationClassName.label}"
styleClass="#{userNotificationPreferenceVar.cssClassName}"
action="#{notificationPreferencesBean.retrievePreferences}">
<f:ajax execute="#form" render="#none" />
</h:commandLink>
</li>
</ui:repeat>
Is there any other way of doing it?
I just want to set selectedIndex property on click of the link ajaxfully.
You don't need to use the annotation #ManagedProperty for that.
Just use a f:setPropertyActionListener:
<ui:repeat value="#{notificationPreferencesBean.userNotificationPreferences}"
var="userNotificationPreferenceVar" varStatus="idx">
<li>
<h:commandLink
value="#{userNotificationPreferenceVar.notificationClassName.label}"
styleClass="#{userNotificationPreferenceVar.cssClassName}"
action="#{notificationPreferencesBean.retrievePreferences}">
<f:setPropertyActionListener value="#{idx}"
target="#{notificationPreferencesBean.selectedIndex}" />
<f:ajax execute="#form" render="#none" />
</h:commandLink>
</li>
</ui:repeat>

Resources