How to get p:inputText value and set it as f:param value? - jsf

I have an xhtml page as follows
<p:inputText id="inputFilterKey" name="inputFilterKey" value="#{key}" />
<p:commandButton id="filterByKey" action="searchByKey" value="Search" ajax="false">
<f:param name="filterKey" value=? />
</p:commandButton>
The parameter 'filterKey' should have the value which is provided by user in the inputText. Value '#{key}' is the flow scope variable which is defined in spring webflow. That is, it is not taken from a back bean. How should I get the value of the inputText? Here is the flow definition in case it is need.
<transition on="searchByKey" to="editTexts" >
<set name="flowScope.key" value="requestParameters.filterKey"/>
<evaluate expression="textManager.searchByKey(key)" result="viewScope.textsByKey" result-type="dataModel"/>
</transition>
Thanks

That isn't possible. The <f:param value> is evaluated when the form is rendered/displayed, not when the form is submitted/processed.
I'm not familiar with Spring Webflow, but this is IMO a really strange design. You might want to confirm with the SWF guys if you're doing things the right way. Perhaps you should rather inject the SWF variable as a managed bean property during its construction/initialization or something?
Anyway, there are ways to get the submitted value without binding the input component's value to a managed bean property. One of them is just getting it straight from the request parameter map by #ManagedProperty:
#ManagedProperty("#{param['formId:inputFilterKey']}")
private String key; // +setter
or when the managed bean has a broader scope than the request scope:
String key = externalContext.getRequestParameterMap().get("formId:inputFilterKey");
The formId:inputFilterKey is just the name of the generated HTML <input> element representation of the <p:inputText> component.

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.

Pass an input value directly as action method argument

Is there a way to do pass an input value as a action's parameter without using managed properties?
i.e.
<h:form>
<h:inputText id="input" />
<h:commandButton action="#{someBean.doSome(input)}" />
</h:form>
Yes, it's during the form submit already there in the JSF component state. Just bind the input component to the view by binding attribute, which will reference an UIInput instance, which in turn has a getValue() method for the very purpose of retrieving the input value (so that you can pass it as action method argument):
<h:form>
<h:inputText ... binding="#{input}" />
<h:commandButton ... action="#{someBean.doSome(input.value)}" />
</h:form>
The properness of this approach is however highly questionable and depends on concrete functional requirements. This approach is namely basically tight-coupling the view with the model and therefore considered a bad practice.
See also:
How to send form input values and invoke a method in JSF bean
How does the 'binding' attribute work in JSF? When and how should it be used?

When is a f:param actually sent?

I've got the following h:commandButton:
<h:commandButton action="#{myBean.myAction}" value="Send">
<f:param name="myFlag" value="true" />
</h:commandButton>
I want to gain access to myFlag insinde a Validator, that's attached to another element with f:validator.
Unfortunately, when I want to retrieve the parameter through the FacesContext, I only get null returned.
Is it that the parameters are only sent once all validators have been invoked?
The <f:param> inside <h:commandButton> is only supported since JSF 2.0, but you're using JSF 1.2. The <f:param> is then only supported in <h:commandLink>.
<h:commandLink action="#{myBean.myAction}" value="Send">
<f:param name="myFlag" value="true" />
</h:commandLink>
There are alternatives, such as a <h:inputHidden> or <f:setPropertyActionListener> or <f:attribute> or in this case perhaps just plain <input type="hidden"> (the hidden input component and the action listener will only set their value during update model values which is later than validations phase; the attribute tag has better to be set on the component which invokes the validator). As the functional requirement is unclear, it's not possible to suggest the best alternative.
Update as per the comments, apparently all you need to know is if the particular button is pressed or not; in that case just give it and the parent form a fixed ID
<h:form id="form">
<h:commandButton id="send" ...>
this way it will have a fixed request parameter name of form:send and you could check on that in the validator:
if (externalContext.getRequestParameterMap().containsKey("form:send")) {
// Send button is pressed.
}
You can by the way also check for that in the required validators as follows:
<h:inputText ... required="#{not empty param['form:send']}" />
See also:
Action dependent requireness

f:setPropertyActionListener sets null value instead of intended value

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).

What is the JSF behaviour, if you bind the same backing bean property to two input fields in the same form?

Is there a defined behaviour in JSF, if two input fields are bound to the same session scoped Backing Bean property.
Here is my code snippet
<h:form id="myForm">
<h:inputText id="field1" value="#{TheBackingBean.theProperty}" />
<h:inputText id="field2" value="#{TheBackingBean.theProperty}" />
<h:commandButton id="continueButton" action="#{TheBackingBean.doSomething}" />
</h:form>
My question: If field1 and field2 receive different values, what will be bound to the backing bean property? Is this even allowed?
I know this is a crude scenario. My motivation is, that we have htmlunit tests running for our application. In our JSF application we want to use a cool ajaxified custom component. This doesnt work together very well with htmlunit. So my idea was, I just put in a hidden field that binds to the same property. The unit test then fills the hidden field instead of the "real" thing.
Regards
I think this kind of code is allowed, but I am not sure of the value of theProperty after the submission. What I think is that JSF will do the following:
TheBackingBean.setTheProperty(field1.value);
TheBackingBean.setTheProperty(field2.value);
However, nothing - as far as I know - specifies the order of the setter calls. Thus, after the update values JSF phase, you will not be sure if theProperty will be equal to field1.value or field2.value.
Concerning your scenario, you say that you want to bind the same property to an inputText and an hiddenText. As the hiddenText will not submit its value, unlike the inputText, this problem will not occur. Indeed, if you have this kind of JSF code:
<h:inputText id="field1" value="#{TheBackingBean.theProperty}"/>
<h:inputHidden id="field2" value="#{TheBackingBean.theProperty}"/>
then JSF will only do:
TheBackingBean.setTheProperty(field1.value);
during the submission phase.

Resources