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.
Related
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
}
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
We are upgrading from jsf 1.2 to jsf 2.
We are using apache myfaces 2.1 and rich faces 4.3.
Below is the xhtml code :
Prior to Migration :
<h:selectBooleanCheckbox id="comp1" value="#{bean.select}">
<a4j:support event="onclick" ajaxSingle="true" actionListener="#{bean.processInput}" reRender="compId">
<f:param name="name" value="paramValue"/>
</a4j:support>
</h:selectBooleanCheckbox>
We are passing one parameter with and accept the parameter in actionListener method as : (String)context.getExternalContext().getRequestParameterMap().get("name1");
After Migration :
<h:selectBooleanCheckbox id="comp1" value="#{bean.select}">
<a4j:ajax event="click" listener="#{bean.processInput}" execute="#this" render="compId"/>
</h:selectBooleanCheckbox>
I want to pass a parameter to bean.processInput method which has following signature :
public void processInput(AjaxBehaviorEvent event){
According to this post - Issues in passing parameter in f:ajax , we cannot use <f:param> (its not working
also) and we are not using EL 2.2 which rules out passing parameter in method signature.
Since we cannot use context.getApplication().evaluateExpressionGet due to constraints in our xhtml page only option available is
use <a4j:param name="" value="" assignTo=""/>.
But this needs to have one variable defined in bean requiring code change.
So my question is can we pass a parameter from UI to listener in second case and without changing the code.
You can use f:attribute like this :
<h:selectBooleanCheckbox id="comp1" value="#{bean.select}">
<a4j:ajax event="click" listener="#{bean.processInput}" execute="#this" render="compId"/>
<f:attribute name="name" value="paramValue" />
</h:selectBooleanCheckbox>
And use it in your bean :
public void processInput(AjaxBehaviorEvent event)
{
System.out.println(event.getComponent().getAttributes().get("name"));
}
Make sure that f:attribute component is not a child component of a4j:ajax.
it should be immediate child component of h:selectBooleanCheckBox, if not listener wont trigger.
we are still in a JSF 1.2 to 2.0 migration scenario and we are now facing a problem related to c:set or ui:param variables used inside an EL expression.
Here are the facts. There is a button as composite component:
<cc:interface name="button" shortDescription="A button.">
...
<cc:attribute
name="disabled"
required="false"
default="false"
shortDescription="The disabled flag." />
...
</cc:interface>
<cc:implementation>
<ice:commandButton
...
disabled="#{cc.attrs.disabled}"
... />
</cc:implementation>
Now we are trying to use this button component inside a toolbar. The disabled state of the button is determined inside the toolbar using a c:set or a ui:param (we already tried both ways).
<c:set var="isButtonEnabled" value="#{backingBean.buttonEnabled}" />
or
<ui:param name="isButtonEnabled" value="#{backingBean.buttonEnabled}" />
#{isButtonEnabled}
<ctrl:button
...
disabled="#{!isButtonEnabled}"
... />
So here is our problem. If we simple print out the value of "isButtonEnabled" in the toolbar, it is always correct. So the backing bean is ok. But when we try to pass this value to the composite component, it is not working. "Disabled" is always evaluated to false.
Sure we could pass the method expression directly (#{!backingBean.isButtonEnabled}) and this will work fine. But in our scenario the determination of the enabled-flag is much more complicated and I just tried to keep the example as simple as possible. Aditionally this flag is used for multiple buttons inside the toolbar, so we wanted to keep the code maintainable by using a c:set or ui:param. Is this the wrong way to handle this? What do you recommend?
Thanks in advance.
SlimShady
Your problem is the way value binding is done in JSF. The prefered way is to retrieve the EL Expression an attribute was populated with by invoking getValueExpression("attributeName"). Then this EL Expression can be used to get or set the value in the backing bean. As your not passing #{!isButtonEnabled} but #{cc.attrs.disabled} to ice:commandButton the binding fails.
I solved this for the p:selectOneMenu component of Primefaces by writing a wrapping UIComponent which defines a property wrappedValue and passed that property to the p:selectOneMenu. In the getter and setter of that property I then used getValueExpression to retieve the real EL Expression for the attribute.
<composite:interface componentType="de.gw2tome.component.valuewrapper">
<composite:attribute name="value" type="de.gw2tome.models.Rarity"
required="true" />
</composite:interface>
<composite:implementation>
<p:selectOneMenu value="#{cc.wrappedValue}"/>
...
</composite:implementation>
#FacesComponent("de.gw2tome.component.valuewrapper")
public class ValueWrapper extends UINamingContainer {
public void setWrappedValue(Object wrappedValue) {
ValueExpression expr = getValueExpression("value");
ELContext ctx = getFacesContext().getELContext();
expr.setValue(ctx, wrappedValue);
}
public Object getWrappedValue() {
ValueExpression expr = getValueExpression("value");
ELContext ctx = getFacesContext().getELContext();
return expr.getValue(ctx);
}
}
The component can now be used the following way:
<g:rarityChooser value="#{itemSearchBean.minRarity}" />
I'm building on BalusC's solution to highlight and focus fields in JSF. My plan is to output a JSON array with ids and then have a method be called which will process this array. This works fine when I don't use <f:ajax/>
Here is my phase listener solution:
public void beforePhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
List<String> highlightFields = new ArrayList<String>();
Iterator<String> highlightFieldsItr = facesContext
.getClientIdsWithMessages();
while (highlightFieldsItr.hasNext()) {
StringBuilder sb = new StringBuilder();
sb.append("#");
sb.append(highlightFieldsItr.next().replaceAll(":", "\\\\:"));
highlightFields.add(sb.toString());
}
JSONArray jsonHighlightFields = new JSONArray(highlightFields);
facesContext.getExternalContext().getRequestMap()
.put("errorFields", jsonHighlightFields.toString());
}
Basically this would produce errorFields value with something like ["#some\:id1", "#some\id2"]. Then I can do something like this in my root layout file:
<script>
var errorFields = ${errorFields}; // This will xlate to ["#some\\:id1", "#some\\:id2"
$(document).ready(function(){
processInputErrors(errorFields);
});
</script>
With a processInputErrors function like this:
function processInputErrors(ids) {
for (id in ids) {
if (focus == false) {
jQuery(ids[id]).focus();
focus = true;
}
jQuery(ids[id]).addClass('input-error');
}
}
However, I need to somehow obtain this list in the function which gets called on success of an ajax post.
Now f:ajax does have the onevent attribute and this function does get called, but I'm not sure exactly what it gets passed. How would I be able somehow pass the invalid Ids from the phase listener to this function? It seems to be passed an object which represents the HTMLInputElement?
<f:ajax event="change" onevent="test" render="test test_msg" immediate="true" />
Happy to hear about alternative suggestions or ideas. The goal is basically to focus and highlight the field(s) which are invalid not only on a full post-back but also when using f:ajax.
Thanks!
That article was more targeted on JSF 1.x. JSF 2.x offers now a lot of advantages of which the following are beneficial for your particular requirement:
You can refer the current component in EL by #{component}. In case of input components this is the UIInput which in turn has an isValid() method. This could be used in styleClass attribute.
You can use <f:ajax> to re-render parts of the view, also <script> elements.
1+1 is...
<h:inputText id="input1" value="#{bean.input1}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input1message focus" />
</h:inputText>
<h:message id="input1message" for="input1" />
...
<h:inputText id="input2" value="#{bean.input2}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input2message focus" />
</h:inputText>
<h:message id="input2message" for="input2" />
...
<h:panelGroup id="focus"><script>jQuery(":input.error:first").focus();</script></h:panelGroup>
No need for a PhaseListener anymore. You could if necessary wrap the input markup boilerplate in a composite component or a tag file.
Back to your concrete question about the onevent attribute, check this answer: JSF 2: How show different ajax status in same input?