How to invoke JSF backing bean method from link/non-faces-request - jsf-2

The use case is calling a method on a JSF 2.x Backing Bean directly from a hyperlink (Non-Faces-Request). What is the best way to do this?
I imagine to do something like this:
The Link:
http://localhost/show.xhtml?id=30&backingbeanname=loaddata&method=load
The Backing Bean:
#Named (value = "loaddata")
public class DataLoader {
public void load(int id){ ... }
}

Use <f:viewParam> in the target view to set GET parameters as bean properties and use <f:event type="preRenderView"> to invoke an action on them.
In show.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" required="true" />
<f:event type="preRenderView" listener="#{bean.load}" />
</f:metadata>
<h:message for="id" />
In managed bean:
private Integer id;
private Data data;
public void load() {
data = service.find(id);
}
Note that in the above example the URL http://localhost/show.xhtml?id=30 is sufficient. You can always set more parameters as bean properties and have one "God" bean which delegates everything, but that's after all likely clumsy.
Also note that you can just attach a Converter to the <f:viewParam> (like as you could do in <h:inputText>). The load() method is then most likely entirely superfluous.
<f:metadata>
<f:viewParam name="id" value="#{bean.data}"
converter="dataConverter" converterMessage="Bad request. Unknown data."
required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:message for="id" />
See also:
Communication in JSF 2 - Processing GET request parameters
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

Related

JSF: f:viewParam doesn't call setter, f:viewAction doesn't call business-method [duplicate]

Can anyone clarify how we can use in general, or a in real world example, this snippet?
<f:metadata>
<f:viewParam id="id" value="#{bean.id}" />
<f:viewAction action="#{bean.init}" />
</f:metadata>
Process GET parameters
The <f:viewParam> manages the setting, conversion and validation of GET parameters. It's like the <h:inputText>, but then for GET parameters.
The following example
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" />
</f:metadata>
does basically the following:
Get the request parameter value by name id.
Convert and validate it if necessary (you can use required, validator and converter attributes and nest a <f:converter> and <f:validator> in it like as with <h:inputText>)
If conversion and validation succeeds, then set it as a bean property represented by #{bean.id} value, or if the value attribute is absent, then set it as request attribtue on name id so that it's available by #{id} in the view.
So when you open the page as foo.xhtml?id=10 then the parameter value 10 get set in the bean this way, right before the view is rendered.
As to validation, the following example sets the param to required="true" and allows only values between 10 and 20. Any validation failure will result in a message being displayed.
<f:metadata>
<f:viewParam id="id" name="id" value="#{bean.id}" required="true">
<f:validateLongRange minimum="10" maximum="20" />
</f:viewParam>
</f:metadata>
<h:message for="id" />
Performing business action on GET parameters
You can use the <f:viewAction> for this.
<f:metadata>
<f:viewParam id="id" name="id" value="#{bean.id}" required="true">
<f:validateLongRange minimum="10" maximum="20" />
</f:viewParam>
<f:viewAction action="#{bean.onload}" />
</f:metadata>
<h:message for="id" />
with
public void onload() {
// ...
}
The <f:viewAction> is however new since JSF 2.2 (the <f:viewParam> already exists since JSF 2.0). If you can't upgrade, then your best bet is using <f:event> instead.
<f:event type="preRenderView" listener="#{bean.onload}" />
This is however invoked on every request. You need to explicitly check if the request isn't a postback:
public void onload() {
if (!FacesContext.getCurrentInstance().isPostback()) {
// ...
}
}
When you would like to skip "Conversion/Validation failed" cases as well, then do as follows:
public void onload() {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (!facesContext.isPostback() && !facesContext.isValidationFailed()) {
// ...
}
}
Using <f:event> this way is in essence a workaround/hack, that's exactly why the <f:viewAction> was introduced in JSF 2.2.
Pass view parameters to next view
You can "pass-through" the view parameters in navigation links by setting includeViewParams attribute to true or by adding includeViewParams=true request parameter.
<h:link outcome="next" includeViewParams="true">
<!-- Or -->
<h:link outcome="next?includeViewParams=true">
which generates with the above <f:metadata> example basically the following link
<a href="next.xhtml?id=10">
with the original parameter value.
This approach only requires that next.xhtml has also a <f:viewParam> on the very same parameter, otherwise it won't be passed through.
Use GET forms in JSF
The <f:viewParam> can also be used in combination with "plain HTML" GET forms.
<f:metadata>
<f:viewParam id="query" name="query" value="#{bean.query}" />
<f:viewAction action="#{bean.search}" />
</f:metadata>
...
<form>
<label for="query">Query</label>
<input type="text" name="query" value="#{empty bean.query ? param.query : bean.query}" />
<input type="submit" value="Search" />
<h:message for="query" />
</form>
...
<h:dataTable value="#{bean.results}" var="result" rendered="#{not empty bean.results}">
...
</h:dataTable>
With basically this #RequestScoped bean:
private String query;
private List<Result> results;
public void search() {
results = service.search(query);
}
Note that the <h:message> is for the <f:viewParam>, not the plain HTML <input type="text">! Also note that the input value displays #{param.query} when #{bean.query} is empty, because the submitted value would otherwise not show up at all when there's a validation or conversion error. Please note that this construct is invalid for JSF input components (it is doing that "under the covers" already).
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")
Communication in JSF 2.0 - Processing GET request parameters
Send params from View to an other View, from Sender View to Receiver View use viewParam and includeViewParams=true
In Sender
Declare params to be sent. We can send String, Object,…
Sender.xhtml
<f:metadata>
<f:viewParam name="ID" value="#{senderMB._strID}" />
</f:metadata>
We’re going send param ID, it will be included with “includeViewParams=true” in return String of click button event
Click button fire senderMB.clickBtnDetail(dto) with dto from senderMB._arrData
Sender.xhtml
<p:dataTable rowIndexVar="index" id="dataTale"value="#{senderMB._arrData}" var="dto">
<p:commandButton action="#{senderMB.clickBtnDetail(dto)}" value="見る"
ajax="false"/>
</p:dataTable>
In senderMB.clickBtnDetail(dto) we assign _strID with argument we got from button event (dto), here this is Sender_DTO and assign to senderMB._strID
Sender_MB.java
public String clickBtnDetail(sender_DTO sender_dto) {
this._strID = sender_dto.getStrID();
return "Receiver?faces-redirect=true&includeViewParams=true";
}
The link when clicked will become http://localhost:8080/my_project/view/Receiver.xhtml?*ID=12345*
In Recever
Get viewParam
Receiver.xhtml
In Receiver we declare f:viewParam to get param from get request (receive), the name of param of receiver must be the same with sender (page)
Receiver.xhtml
<f:metadata><f:viewParam name="ID" value="#{receiver_MB._strID}"/></f:metadata>
It will get param ID from sender View and assign to receiver_MB._strID
Use viewParam
In Receiver, we want to use this param in sql query before the page render, so that we use preRenderView event. We are not going to use constructor because constructor will be invoked before viewParam is received
So that we add
Receiver.xhtml
<f:event listener="#{receiver_MB.preRenderView}" type="preRenderView" />
into f:metadata tag
Receiver.xhtml
<f:metadata>
<f:viewParam name="ID" value="#{receiver_MB._strID}" />
<f:event listener="#{receiver_MB.preRenderView}"
type="preRenderView" />
</f:metadata>
Now we want to use this param in our read database method, it is available to use
Receiver_MB.java
public void preRenderView(ComponentSystemEvent event) throws Exception {
if (FacesContext.getCurrentInstance().isPostback()) {
return;
}
readFromDatabase();
}
private void readFromDatabase() {
//use _strID to read and set property
}

JSF2.2 Multiple field validation message not appearing.. the message is associated to a component [duplicate]

JSF 2.0 only allows you to validate the input on one field, like check to see if it's a certain length. It doesn't allow you to have a form that says, "enter city and state, or enter just a zip code."
How have you gotten around this? I'm only interested in answers that involve the validation phase of JSF. I'm not interested in putting validation logic in Managed Beans.
The easiest custom approach I've seen and used as far is to create a <h:inputHidden> field with a <f:validator> wherein you reference all involved components as <f:attribute>. If you declare it before the to-be-validated components, then you can obtain the submitted values inside the validator by UIInput#getSubmittedValue().
E.g.
<h:form>
<h:inputHidden id="foo" value="true">
<f:validator validatorId="fooValidator" />
<f:attribute name="input1" value="#{input1}" />
<f:attribute name="input2" value="#{input2}" />
<f:attribute name="input3" value="#{input3}" />
</h:inputHidden>
<h:inputText binding="#{input1}" value="#{bean.input1}" />
<h:inputText binding="#{input2}" value="#{bean.input2}" />
<h:inputText binding="#{input3}" value="#{bean.input3}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:message for="foo" />
</h:form>
(please note the value="true" on the hidden input; the actual value actually doesn't matter, but keep in mind that the validator won't necessarily be fired when it's null or empty, depending on the JSF version and configuration)
with
#FacesValidator(value="fooValidator")
public class FooValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput input1 = (UIInput) component.getAttributes().get("input1");
UIInput input2 = (UIInput) component.getAttributes().get("input2");
UIInput input3 = (UIInput) component.getAttributes().get("input3");
// ...
Object value1 = input1.getSubmittedValue();
Object value2 = input2.getSubmittedValue();
Object value3 = input3.getSubmittedValue();
// ...
}
}
If you declare the <h:inputHidden> after the to-be-validated components, then the values of the involved components are already converted and validated and you should obtain them by UIInput#getValue() or maybe UIInput#getLocalValue() (in case the UIInput isn't isValid()) instead.
See also:
Validator for multiple fields (JSF 1.2 targeted)
Alternatively, you can use 3rd party tags/components for that. RichFaces for example has a <rich:graphValidator> tag for this, Seam3 has a <s:validateForm> for this, and OmniFaces has several standard <o:validateXxx> components for this which are all showcased here. OmniFaces uses a component based approach whereby the job is done in UIComponent#processValidators(). It also allows customizing it in such way so that the above can be achieved as below:
<h:form>
<o:validateMultiple id="foo" components="input1 input2 input3" validator="#{fooValidator}" />
<h:inputText id="input1" value="#{bean.input1}" />
<h:inputText id="input2" value="#{bean.input2}" />
<h:inputText id="input3" value="#{bean.input3}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:message for="foo" />
</h:form>
with
#ManagedBean
#RequestScoped
public class FooValidator implements MultiFieldValidator {
#Override
public boolean validateValues(FacesContext context, List<UIInput> components, List<Object> values) {
// ...
}
}
The only difference is that it returns a boolean and that the message should be specified as message attribute in <o:validateMultiple>.
Apache ExtVal was not mentioned here.
There are some cross validations in it (among other validations which might be useful):
https://cwiki.apache.org/confluence/display/EXTVAL/Property+Validation+Usage#PropertyValidationUsage-CrossValidation

How to get command link value(display name) from backing bean?

I have a p:commandLink in my xhtml with the value toggling between "Show"/"Hide".
Is there any way by which I can get the value of this commandlink from the backing bean?
I mean, I want to know what value the command link is showing currently i.e. Show/Hide?
To the point, the invoking component is just available in ActionEvent argument:
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle}" />
with
public void toggle(ActionEvent event) {
UIComponent component = event.getComponent();
String value = (String) component.getAttributes().get("value");
// ...
}
However, this is a poor design. Localizable text should absolutely not be used as part of business logic.
Rather, either hook on component ID:
String id = (String) component.getId();
or pass a method argument (EL 2.2 or JBoss EL required):
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle(false)}" />
with
public void toggle(boolean show) {
this.show = show;
}
or even just call the setter method directly without the need for an additional action listener method:
<h:commandLink id="show" value="Show it" actionListener="#{bean.setShow(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.setShow(false)}" />
As #BalusC suggested, your approach is not a good solution. But if you really want to do that, you can bind the component (p:commandLink) to your backingbean, as seen in What is the advantages of using binding attribute in JSF?.
After the component was bound, you can access the value attribute from the p:commandLink.

JSF Core Tag :setPropertyActionListener vs attribute vs param

What is the difference between setPropertyActionListener vs attribute vs param?
When would use the setPropertyActionListener?
1. f:setPropertyActionListener:
With this tag, you can directly set property in you backing bean. Example:
xhtml:
<h:commandButton action="page.xhtml" value="OK">
<f:setPropertyActionListener target="#{myBean.name}" value="myname"/>
</h:commandButton>
backing bean:
#ManagedBean
#SessionScoped
public class MyBean{
public String name;
public void setName(String name) {
this.name= name;
}
}
This will set name property of backing bean to value myname.
2. f:param:
This tag simple sets the request parameter. Example:
xhtml:
<h:commandButton action="page.xhtml">
<f:param name="myparam" value="myvalue" />
</h:commandButton>
so you can get this parameter in backing bean:
FacesContext.getExternalContext().getRequestParameterMap().get("myparam")
3. f:attribute:
With this tag you can pass attribute so you can grab that attribute from action listener method of your backing bean.
xhtml:
<h:commandButton action="page.xhtml" actionListener="#{myBean.doSomething}">
<f:attribute name="myattribute" value="myvalue" />
</h:commandButton>
so you can get this attribute from action listener method:
public void doSomething(ActionEvent event){
String myattr = (String)event.getComponent().getAttributes().get("myattribute");
}
You should use f:setPropertyActionListener whenever you want to set property of the backing bean. If you want to pass parameter to backing bean consider f:param and f:attribute. Also, it is important to know that with f:param you can just pass String values, and with f:attribute you can pass objects.

How to use Primefaces autocomplete with a POJO List and a POJO's property as selection value

In our current project we want to replace a <h:selectOneMenu> with Primefaces's <p:autocomplete>. The select items are a list of Pojos (JPA Entities). The difference to the given examples in primefaces showcases is, that we want the primary key property (id) of the entity as selection value, so it can be easily passed as view param:
<f:metadata>
<f:viewParam name="playerId" value="#{playerPreRenderViewListener.searchCriteria.playerId}" />
<f:viewParam name="year" value="#{playerPreRenderViewListener.searchCriteria.year}" />
</f:metadata>
<h:form>
<h:inputText value="#{playerPreRenderViewListener.searchCriteria.year}"/>
<p:autoComplete var="player" itemLabel="#{player.name}" itemValue="#{player.id}"
completeMethod="#{playerBean.completePlayer}" forceSelection="true"
converter="#{playerConverter}"
value="#{playerPreRenderViewListener.searchCriteria.playerId}">
</p:autoComplete>
<h:commandButton value="Submit" action="showTeam?faces-redirect=true&includeViewParams=true" />
</h:form>
Unfortunately the example above will lead to a PropertyNotFoundException:
itemLabel="#{player.name}": Property 'name' not found on type java.lang.Long'
The problem is that the var attribute is of Type Long and not Player. When using a simple <h:selectMenu> it works in conjunction with <f:selectItems>:
<f:selectItems var="player" value="#{playerBean.listPlayers}" itemLabel="#{player.name}" itemValue="#{player.id}" />
Does anybody know how to handle this issue?
You could add a backing bean method that returns the player belonging to the currently active playerId and set this currentPlayer as value attribute of your backing bean:
public Player getCurrentPlayer() {
// find player by playerId and return
}
And in the view:
<p:autoComplete var="player" itemLabel="#{player.name}" itemValue="#{player}"
completeMethod="#{playerBean.completePlayer}" forceSelection="true"
converter="#{playerConverter}"
value="#{playerPreRenderViewListener.currentPlayer}">

Resources