nested ui:repeat issue (or f:ajax) - jsf-2

i have 2 ui:repeat nested like this:
<ui:repeat var="father" value="#{miuchile3.getMenusPadre(miuchile3.keyModulo)}" >
<li>
<h:commandLink value="#{father.nombre}" action="#{miuchile3.setMenu(father)}">
<f:ajax render=":menupags:menuDetalle" />
</h:commandLink>
<ul>
<ui:repeat var="submenu" value="#{miuchile3.getHijos(father.id)}" >
<li><h:commandLink value="#{submenu.nombre}" actionListener="#{miuchile3.setMenu(submenu)}">
<f:ajax render=":menupags:menuDetalle" />
</h:commandLink></li>
</ui:repeat>
</ul>
</li>
</ui:repeat>
this generate a menu with this format
father menu 1
son menu_1
son menu_2
father menu 2
son menu2_1
son menu2_2
son menu2_3
etc..
when i click in this submenus i use f:ajax to render a panelgroup with details of the selected menus (it shows the pages associated to them), the problem is that it only works properly for father menu 1 and its submenus, but for father menu 2, it works ok for its 2 first submenus, if there is a third submenu associated to "father menu 2" and i click on it, it doesn't do anything.
im not sure if it is a issue with the nested ui:repeat or with f:ajax, but i think ui:repeat stop working properly after the second iteration or something like that.. the "setMenu()" function (inside the nested ui:repeat) stop working for some reason. but it could be f:ajax too.. i dont really know.
EDIT:
now i found the issue but i dont know how to solve it yet.
the problem is that for the first iteration (frist menu and its submenus) the method im calling in the action "setMenu()" works ok, but for the second iteration (father menu 2, and its submenus) the setMenu() method is called only 2 times, if there are more than 2 submenus, the method im calling in the action (setMenu())doesn't work, i mean the iteration works because it prints all the names of the menus and submenus , but the action after the first iteration only works for 2 submenus.

i changed the ui:repeat for a datatable, and it worked as i wanted.. i would not recomment to use ui:repeat nested if you need to invoke some action inside, it has weird behavior.

Related

Dropmenu with if clauses

I am trying to make my dropmenu whenever I select the number 30 to print hello,however it always shows Hello,any idea why it doesn't work
<g:select name="user.age" from="${18..65}" value="${age}"
noSelection="['':'-Choose your age-']"/>
<g:if test="${age==30} ">
Hello
</g:if>
That should be <g:if test="${user.age==30} ">. The problem here is as per your last post, a user changing the value of a select box on the front end has not been registered or sent to your grails controller. When you next do <g:if It is checking the same value as was provided by your controller in the instance of
<g:select name="user.age" from="${18..65}" value="${age}" age here.. again this is wrong since you have called name user.age
So unless your g:select on change submits it to the controller then your gsp is reloaded so <g:if test="${user.age==30} "> can now pickup the new value.
It is a static value received by your view at the time controller called it VS your user dynamically changing the content of the select box. For which the change behaviour is handled by jquery as explained in previous answer to your previous question

p:commandlink inside ui:repeat

In our application we are displaying the menus dynamically. We have the menu object(menuitems in below code) populated with all the menu items (read from an xml). The home page then generates the menus by usinng ui:repeat. Insdie ui:repeat there are p:commandlink.
Below is the code
<h:form id="mainMenu">
<h:panelGroup id="MMPanel" layout="block" styleClass="left_menu">
<ui:repeat var="node" value="#{menuitems.level1menus}">
<p:commandLink immediate="true" styleClass="menu"
action="#{menuitems.onLevel1MenuChange(node.id)}"
update=":pageTitle :menuLevel2 :menuLevel3" title="#{node.name}"
rendered="#{menuitems.selectedLevel1.id!=node.id}" onclick="menuSelect(this)">
<span class="icon icon_#{node.name}"></span>
<span class="text">#{node.name}</span>
</p:commandLink>
<p:commandLink immediate="true" styleClass="menu activelink"
action="#{menuitems.onLevel1MenuChange(node.id)}"
update=":pageTitle :menuLevel2 :menuLevel3" title="#{node.name}"
rendered="#{menuitems.selectedLevel1.id==node.id}" onclick="menuSelect(this)">
<span class="icon icon_#{node.name}"></span>
<span class="text">#{node.name}</span>
</p:commandLink>
</ui:repeat>
</h:panelGroup>
</h:form>
The menuitems bean is at Session level.
There are two diffeent p:commandlink inside ui:repeat. The only difference between the 2 is in the styleclass and rendered attribute. This is done to identify the default menu item when the user logs for the first time and give it an extra css of "activeLink".
The java script called on onclick is given below (in case it is required)
function menuSelect(selectOne){
$(".left_menu>a").removeClass("activelink");
$(selectOne).addClass("activelink");
removeAllChannels();
}
function removeAllChannels(){
$.atmosphere.unsubscribe();
}
The removeAllChannels is to remove primepush autorefresh channels we have.
The issue i am facing is this.
All the links are getting rendered correctly and in Firebug i see all of them have the same html.
But the one which is generated with the extra css "activeLink" (through rendered condition -- menuitems.selectedLevel1.id==node.id) is not working. Nothing happens when i click this default link. All other links work fine.
So when i click on a different link, it takes me to the required page. But when i click back on the menu which was default, nothing happens
I added a Custom phase listener and saw that all the lifecyle stages are called when this link is clicked but the action method is not.
I went through the links this and this but could not figure out the issue.
Please help.
Do tell me if something is not clear
As part of safeguard against tampered/hacked requests, the JSF component's rendered attribute is re-evaluated during processing the form submit. In case of a command link/button, if it evaluates false, then its action won't be queued/invoked. This matches the symptoms you're seeing.
This can in turn happen if the managed bean #{menuitems} is request scoped and/or when the properties behind #{menuitems.level1menus} or #{menuitems.selectedLevel1} are incompatibly changed during the postback request.
Putting the bean in the view scope and ensuring that the getters do not do any business job should fix this problem.
See also:
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5 applies to you

Unique ID for JSF composite component inside dataTable

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.

JSF rendered attribute

I have a couple of panel groups, one with "register" and "log in" links, and the other with "log out". When I log in only the "log in" link disappears, the "register" stays rendered, and the "log out" never gets rendered. The #{user.loggedIn}" returns true when the user is logged in. And when refreshing the screen in debug mode I can see that method is being run. Any suggestions for how to get this to work correctly. The code should be explanatory, please let me know if it isn't.
<h:panelGroup rendered="#{!user.loggedIn}">
<li>
<h:outputLink id="loginLink" value="javascript:void(0)" onclick="dlg.show()" title="login" styleClass="loginpanelclass">Log In</h:outputLink>
</li>
<li>
<h:link value="Register" outcome="/registration/register.xhtml" />
</li>
</h:panelGroup>
<h:panelGroup rendered="#{user.loggedIn}">
<li>
<h:commandLink action="#{user.logout()}">Logout</h:commandLink>
</li>
</h:panelGroup>
The elements you want to reference have to be in a naming container if they are not in the same naming container you are referencing them from. For me I launch a login dialog using primefaces when the first link in my question is clicked. Inside the dialog is a form. When that form completes it tells the panels in my question above to render or not by using the p:dialog update attribute. I had to put the panels in my question inside a naming container and then was able to successfully reference them using the ':' notation through the hierarchy.
If anyone is having trouble look for articles on component hierarchies and naming containers in JSF. With the hints given by Daniel in his comments above and the stuff I found looking at hierarchies and naming containers I figured this one out good enough for now. Still a few uncertainties but my code does what I want it to do for now. :) I'm marking the answer Daniel gave in his linked question up by one.

Close all expanded rows inside a ui:repeat

I have a ui:repeat of auction items inside a table. It is a regular html table because when you click on a Bid commandLink a row opens right under the selected auction item, and displays a bidding component. The Bid commandLink is using ajax like this:
<f:ajax listener="#{bean.addBidView(lot)}" render="bidView" />
addBidView is updating a map of auctionItems and that's how the correct selected row opens up. When the user clicks on the same Bid link again, the addBidView figures it out and closes the bidding component.
Now let's say the user clicks on several rows, and thus opens several bidding components. They all open, but only one is active. So here's my question: how do I get the entire loop to render when I use the above ajax, so that opening a bidding component would automatically close the other open ones. (the auction items map is reflecting the correct bidding component, but only this one bidding area is rendered, so the others aren't effected. If I'm refreshing the whole page, the display is correct, and the problem only exists when I'm using ajax.)
This is the structure of the elements on the page (all this is inside an h:form:)
<table id="bidstable">
<h:panelGroup id="entireLoop">
<ui:repeat id="repeatAuctionItems" var="auctionItem" varStatus="status" value="#{bean.auctionItems}">
<td>... a bunch of td's with the auction item values ... and then:
<h:commandLink id="bid" rendered="#{some conditions}">
<f:ajax listener="#{bean.addBidView(auctionItem)}" render="bidView"/>
</h:commandLink>
</td>
</ui:repeat>
</h:panelGroup>
</table>
I tried pretty much every combination of elements in the "render" -- for example:
render="bidView bidsTable"
or
render="bidView bidsTable:entireLoop:repeateAuctionItems"
and every other trail I can think of. Nothing works. Any ideas?
You have specified a client ID in the <f:ajax render> attribute which is relative to the current NamingContainer component. Client IDs which do not start with the naming container separator character, which defaults to :, are relative to the current NamingContainer component. The <ui:repeat> is such a component. So the client ID has to refer a child of <ui:repeat>. But the component which you are trying to reference is actually outside the <ui:repeat>. You'd need to reference it with an absolute client ID instead.
To find the absolute client ID, you need to open the page in the browser, rightclick and do View Source and then locate the generated HTML of the closest parent JSF component outside <ui:repeat>, which is in your particular case the <h:panelGroup id="entireLoop">. It'll look something like:
<span id="someId:possiblyOtherId:entireLoop">
Take exactly this client ID and prefix it with : for usage in <f:ajax render>.
<f:ajax ... render=":someId:possiblyOtherId:entireLoop" />
If it contains a dynamically generated ID like j_id_123, then you'd need to give all parent NamingContainer components like <h:form> a fixed ID like <h:form id="someId">.
Note that it is not possible to reference the client ID of a plain HTML element like <table id="bidsTable">. It has to be a fullworthy JSF component like <h:dataTable id="bidsTable">.

Resources