I am working with JSF and Primefaces. I used setPropertyActionListener from a JSF demo example. It is working, but I don't understand the specific purpose of it.
<p:commandButton value="Search" ajax="false"
action="#{scmAirLiftApprovalRequestManager.search}">
<f:setPropertyActionListener value="true"
target="#{scmAirLiftApprovalRequestManager.isSearching}" />
</p:commandButton>
Can anyone explain in simple what actually it doing?
<f:setPropertyActionListener> sets directly a property in the managed bean.
In the provided snippet of yours, the #{scmAirLiftApprovalRequestManager.isSearching} property will be set to true when the <p:commandButton>'s action is invoked.
More info:
JSF's setPropertyActionListener attribute
It is used to set a value directly into the property of your backing bean before calling the action.
So, here only after setting the value true to scmAirLiftApprovalRequestManager.isSearching , a method scmAirLiftApprovalRequestManager.search is called.
Related
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.
I need to set a boolean field whenever p:fieldset is toggled. I tried out following code but the field is never set by f:setPropertyActionListener although p:ajax listener is invoked on toggle. I tried out following code.
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="..">
<f:setPropertyActionListener target="#{viewScope.rendrUsrProjctsList}" value="#{true}"/>
</p:ajax>
</p:fieldset>
However when I tried modifying the code as below then field is successfully set:
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="#{view.viewMap.put('rendrUsrProjctsList', true)}" />
<p:ajax event="toggle" listener=".."/>
</p:ajax>
</p:fieldset>
I want to ask:
Why 1st way doesn't work ?
Is it bad attaching multiple p:ajax to
single parent as done in 2nd way ?
The <f:setPropertyActionListener> works as being an ActionListener implementation only on components implementing ActionSource interface, such as UICommand, i.e. <h:commandXxx>, <p:commandXxx>, etc. The <p:ajax> does not implement this interface and therefore the <f:setPropertyActionListener> is basically completely ignored.
As to your workaround, you could do so although I'd rather just use a concrete view scoped bean or wrap it in a composite with a backing component.
<h:form>
<h:messages />
<h:selectOneRadio value="#{bean.selectedValue}" id="selectId"
layout="pageDirection">
<f:selectItems value="#{bean.values}" var="value"
itemLabel="#{value.text}" itemValue="{value}" />
</h:selectOneRadio>
<h:commandButton value="Press Me" >
<f:ajax listener="#{bean.btn_action}" execute="#form"/>
</h:commandButton>
</h:form>
Below are code details.
Bean is backing bean in #ViewScope.
bean.values is list of another managed bean which is in #RequestScope.
Radio button value is binded to above #RequestScope managed bean in backing bean. #{bean.selectedValue}
selectedValue is reference to object in backing bean having getter/setter.
Issues.
- When execute=#form is added to ajax tag, listener is not even called.
- After execute-#form, listener is getting called however radio button selected value is not updated in backing bean.
- When i debug getter is always called for selectedValue never the setter.
Any help will be appreciated.
Thanks.
Assuming that itemValue="{value}" is just a careless typo and that you never paid attention to the server logs, then this construct will silently fail if #{value} represents a non-standard type and you don't have a Converter for that type or didn't implement the type's equals() method properly.
First step would be adding render="#form" to <f:ajax>, so that <h:messages> get updated as well, so that you don't need to look into server logs for conversion/validation errors.
<f:ajax execute="#form" listener="#{bean.btn_action}" render="#form" />
Second step would be fixing the problem based on the shown conversion/validation error. Most likely you've a conversion error "null converter" or maybe you already have one, but you're getting a validation error "value is not valid" instead.
Both potential problems are answered in detail in the following answers:
How to populate options of h:selectOneMenu from database?
Using JSF Converter in h:selectOneMenu results in Validation Error: Value not valid
My view is:
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:setPropertyActionListener target="#{bookSeatController.flightNumber}"
value="#{flightInfoController.flight.number}" />
</h:commandLink>
My setter is:
public void setFlightNumber(String flightNumber) {
this.flightNumber = flightNumber;
}
When I use the debugger I get a flightNumber of null in the setter. However, if I change the view to the following:
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:setPropertyActionListener target="#{bookSeatController.flightNumber}"
value="122334" />
</h:commandLink>
The flightNumber property is set to 122334. How is this caused and how can I solve it to set the intended value instead of null?
If the #{flightInfoController.flight.number} is request scoped, then it has to preserve exactly the same flight in during the request of processing the form submit as it was during the request of displaying the form. This has to happen in the bean's (post)constructor.
If that is not an option, because it depends on some request based variables, then your best bet is to put the bean in the view scope instead (I however still assume that your bean is properly designed that it doesn't do any business/preloading job in getters).
If putting the bean in the view scope is in turn not an option, then you'd need to pass it as a fullworthy request parameter instead. You can do that by <f:param>.
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:param name="flightNumber" value="#{flightInfoController.flight.number}" />
</h:commandLink>
You can let JSF set it by #ManagedProperty in the BookSeatController or by <f:viewParam> in the current view.
See also:
How can I pass selected row to commandLink inside dataTable?
ViewParam vs #ManagedProperty(value = "#{param.id}")
If it's working when assigning "122334" but when assigning flightInfoController.flight.number it's "null" and since you are not receiving any exception, then it means probably your flightInfoController is not properly initialized (regarding it's field flight and hence number in the flight).
Just make sure the bean is properly initialized (or update your OP with the bean code).
Please have a look at the code below. The function generateCoupon is never invoked.
processCouponGeneration and userPageBacking are in viewScope, but headerBacking is in requestScope. tried changing primefaces p:commandButton to h:commandButton, but it does not work.
Using c:set if I copy the headerBacking.currentUser to a viewScoped variable; use this variable instead of headerBacking.currentUser, the function generateCoupon is fired. So, wanted to confirm if this is an expected behavior. These are the problems troubling me a lot in JSF and I do not know if that can be debugged.
<p:commandButton value="Correct"
action="#{processCouponGeneration.generateCoupon}">
<f:setPropertyActionListener
target="#{processCouponGeneration.bpd}"
value="#{userPageBacking.selectedPromoToDisplay.wupdBrandpromo}" />
<f:setPropertyActionListener
target="#{processCouponGeneration.bpdd}"
value="#{bpddVar}" />
<f:setPropertyActionListener
target="#{processCouponGeneration.promoter}"
value="#{userPageBacking.user}" />
<f:setPropertyActionListener
target="#{processCouponGeneration.buyer}"
value="#{headerBacking.currentUser}" />
</p:commandButton>
It should work. Make sure you have all the getters and setters in all of you managed beans.