Reaching backingbean method in datatable column JSF/PrimeFaces - jsf

I am unable to reach my backing beans method when calling it in a <p:commandLink> inside a datatable column.
My commandlink works fine when put outside the datatable, but then I cannot directly pass the selected row variable.
Here is my code:
<h:form id="reviewLists" prependId="false">
<p:messages />
<p:panel header="Beoordelingen" style="margin-bottom:10px;">
<p:dataTable value="#{reviewFinderBean.employees}" var="employee" >
<p:column headerText="Medewerker" >
<h:commandLink value="#{employee.name}" action="#{reviewFinderBean.showReviewsForEmployee(employee)}" />
</p:column>
</p:dataTable>
</p:panel>
</h:form>
When checking the http requests my browser makes I see it does another post (ajax) as expected, I have tried to use prependId="false" as I thaught the generated component names might have been unresovable but that didnt help.
The ajax post is fired but somehow is never resolved to the correct backingbean method on the server
<f:setPropertyActionListener> also doesnt resolve to any property when set correctly and used in the the datatable column.

First of all, get rid of prependId="false". It makes things worse in ajax processing and updates.
In order to fix the problem, you need to rewrite the bean in such way that it returns exactly the same data model (the value behind #{reviewFinderBean.employees}") during processing the form submit as it was during displaying the form. JSF will namely re-iterate over it in order to find the associated row where the command is been invoked.
If you want to keep the bean in the request scope, then you need to recreate exactly the same datamodel in its (post)constructor. If your bean is already in the view scope, then you need to make sure that the getter method is totally free of business logic so that the data model don't potentially change.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4

Related

Setting f:setPropertyActionListener value with a f:param value

I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.

ui:repeat with a list sending right object to a p:dialog

I currently have a giant ui:repeat. Within this ui:repeat, some of the repeated objects have a url to a popup image associated with them. When someone clicks display under that particular object, I need the url to popup in a p:dialog.
<ui:repeat var="thing" value="#{bean.thingList}">
<p:commandLink value="details" onclick="miniImage.show();"
update=":#{p:component('chart')}"
action="#{bean.setCurrentImg(thing.imageUrl)}"
rendered="#{thing.includeImage}">
</p:commandLink>
</ui:repeat>
and at the bottom of the page:
<p:dialog id="chart" widgetVar="miniImage" >
<h:graphicImage value="#{bean.currentImg}"/>
</p:dialog>
And in the backing bean I tried using a simple setter and getter for currentImg.
I am a bit confused on this now and would like to accomplish this without having to submit the entire form as well. Any help is greatly appreciated.
If you're using PrimeFaces 3.3 or newer, you could just add partialSubmit="true" to the command component. You can then control the to-be-processed components in process attribute. In this particular case, just the current component (the command component itself) is sufficient, thus so process="#this":
<p:commandLink ... process="#this" partialSubmit="true" />
This way only the request parameters which are really necessary for the process will be sent.
Unrelated to the concrete problem, I suggest to use oncomplete instead of onclick to open the dialog. Otherwise the dialog is opened before update takes place and may cause poor user experience as the enduser would see the image instantly changing.

PrimeFaces dialog validation errors

What i want to do is like basic row selection example at Primefaces showcase(http://www.primefaces.org/showcase/ui/datatableRowSelectionByColumn.jsf) I want to update my datatable's row. The problem is when i click to update button at datatable, dialogbox appears with validation errors.
Second thing is what is the order of method execution times.(action-update-onclick-f:setPropertyActionListener)
<p:commandButton id="updateButtonId"
action="#{myController.showCompanyEditPanel}"
update=":tabView:companyForm:companyEditPanel"
onclick="companyDialog.show()"
icon="ui-icon-pencil" title="update">
<f:setPropertyActionListener value="#{company}" target="#{myController.selectedCompany}" />
</p:commandButton>
<p:dialog id="editCompanyDialogId" header="CompanyEdit" widgetVar="companyDialog" resizable="false">
<p:panel id="companyEditPanel" >
//some stuff here
</p:panel>
</p:dialog>
You seem to be missing a major point of using a <p:commandButton> here, as well as seem to be mixing client-side and server-side events.
First on <p:commandButton>. This component is designed to POST (partial) form data to the current URL, do business job in action(listener) method and return updated components / perform navigation. You can of course 'attach' JavaScript events to all those attributes.
Second, onclick, oncomplete, and other on... attribute are corresponding to some client-side events. In particular, onclick function is triggered when button was clicked, oncomplete function is called when DOM was updated after the AJAX call, i.e. the elements specified in <p:ajax update="..."> or simply in update="..." attribute of <p:commandButton>.
Third, all action listeners (thus, actionListener attribute, <f:actionListener> tag, <f:setPropertyActionListener> tag) will be executed right in the order they are specified in your tag, see this answer for more elaboration. The last one to be executed is action method, after which response is sent back.

Why does a h:commandButton fail to submit the form if it's parent is dynamically rendered?

This JSF1 code has me totally puzzled for hours. The basic setup is this page displayed with Seam2:
<h:form encType="multipart/form-data">
<rich:dataTable value="#{results}">
...
</rich:dataTable>
<h:selectOneMenu value="#{contact.type}">
<s:selectItems value="#{contactTypes}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<h:selectOneMenu value="#{template}">
<s:selectItems value="#{allTemplates}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<a4j:outputPanel id="submitControls" layout="block">
<a4j:outputPanel rendered="#{null != results and results.size gt 0 and ('ONE' == contact.type.label or template != null)}">
<h:commandButton value="submit" action="#{manager.generate}" />
</a4j:outputPanel>
<h:outputText value="Search first" rendered="#{results == null or results.size == 0}" />
<h:outputText value="Select template first" rendered="#{'ONE' == contact.type.label and template == null}" />
</a4j:outputPanel>
</h:form>
Obviously, the original page is a bit larger. What has me scratching my head is that if I don't change contact.type (leave it at a default selected by the backing bean) the form submits fine. If I switch the type to ONE this correctly renders the "Select template first" text instead of the submit control. Restoring the submit button by selecting another type re-produces the <input> BUT without the onclick handler that was there when the form was first rendered.
Now a click on the <h:commandButton> sends a request to the server but does NOT trigger the associated action. However, it now restores the onclick handler and a second click triggers a proper submit.
I'm at a loss why this is so. Any suggestions?
EDIT: moving the rendered attribute to the button results in the same behavior (even if it did work, the original panels contain more controls that share the same condition, so they do serve a purpose)
EDIT2: I've just tested that simply re-adding the "lost" onclick handler (via firebug) that gets rendered on the submit button makes the action work as intended. I'm beginning to suspect a bad interaction between richfaces and the trinidad libs also included in this project (but not used on this page).
It's a safeguard against tampered/hacked requests. Otherwise a hacker would be able to invoke actions s/he isn't allowed to invoke by just editing the sent HTTP request parameters accordingly that the non-rendered (e.g. due to missing "ADMIN" role) command button will be invoked.
You need to make sure that you prepare the same model (managed bean instance with all properties responsible holding the conditions behind rendered attribute) during the HTTP request of processing the form submit as it was during the HTTP request of displaying the form. In JSF2, this is easy achievable by placing the bean in the view scope instead of the request scope. The view scope lives as long as you're interacting with the same view. In JSF1, you'd need to grab a 3rd party framework tag like Tomahawk's <t:saveState> or RichFaces' <a4j:keepAlive> in order to simulate the JSF2 view scope.
<a4j:keepAlive beanName="results" />
The same story applies to disabled attribute by the way.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
I think that with the rendered attribute and anything inside you have to take care that the evaluation of it is the same on the initial request AND the submit. It may change just before the render phase but if its not the same during application invoke it will most likely ignore the action if in this phase the button would not be rendered.
As far as i remember this happend for me mostly when the rendered expression uses something like an entity attribute that will be changed during the apply request values phase already.

JSF ViewScope and Bean creation

I have a problem that i don't understand:
I request a new site. A site has a link that opens a dialog. The link is inside a form.
The dialog is not inside the form.
A reduced code example:
<p:outputPanel id="layout-center" >
<h:form>
<p:commandLink id="option_field_user_profile" actionListener="#{controllerBean.getBean('userProfileBean', component).init}" oncomplete="#{controllerBean.getBean('userProfileBean', component).show}" >
<h:outputText value="#{msg.mProfile}"/>
</p:commandLink>
</h:form>
</p:outputPanel>
<p:dialog header="#{userPreferencesBean.header}" widgetVar="#{userPreferencesBean.widgetVar}" appendToBody="#{userPreferencesBean.appendToBody}" resizable="#{userPreferencesBean.resizable}" id="#{userPreferencesBean.xhtmlId}" dynamic="#{userPreferencesBean.dynamic}" modal="#{userPreferencesBean.modal}" closable="#{userPreferenceBean.closable}">
<ui:include src="/WEB-INF/templates/modification/userPreferences.xhtml" />
</p:dialog>
UserPreferencesBean is in ViewScope. My problem is now that the #PostConstruct method from the UserPreferencesBean is called twice with the non-postback request i.e. the Bean is constructed twice although it should be the same view. If i move the dialog inside the form for testing purposes it is called once, like expected. But since the dialog has its own form this is not a solution, for sure.
When the site is loaded and I hit F5, the PostConstruct method is executed once.
Has somebody an idea?
This is caused because you referenced a view scoped bean property in the view build time attribute id of the <p:dialog>. If you fix the id to be static, or to reference a request or application scoped bean property instead, then your view scoped bean will behave as expected.
See also:
JSTL in JSF2 Facelets... makes sense? - for some background explanation on view build time and view render time; the id and binding attributes of UI components are evaluated during view build time.

Resources