I suspect about 2 way of passing value through attribute.
First: f:param
<p:inputText value="#{inputTextView.inputVal}">
<f:param name="fieldA" value="inputA" />
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
Second: custom field
<p:inputText value="#{inputTextView.inputVal}"
fieldB="inputB">
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
The first way, I can get value of attribute by using
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("fieldA");
While the second way use
UIComponent.getCurrentComponent(FacesContext.getCurrentInstance()).getAttributes().get("fieldB");
Does anyone know what different between first and second?
What situation which appropriate for use the first approach?
First of all, if you want to set a custom attribute, you cannot just add a random new attribute to a tag because JSF ignores unsupported tag attributes. BalusC gives some options on how to work around this in this answer.
f:param should be used if you want to add values to the query string or request parameters. It should be used with command components (e.g. h:commandButton, h:commandLink or h:outputLink).
f:attribute on the other hand, adds entries to the attribute Map of a component.
Related
I have a JSF composite component which renders only some parts based on the attribute cc.attrs.list passed to it.
In one of the components I want to update a set of other components based on the attribute. So something like this:
<p:ajax event="dialogReturn" listener="#{cc.listener}"
update="#{cc.attrs.id2}_input #{cc.attrs.id2}_resultTable"/>
The problem is that the resultTable is not rendered all the time and when the resultTable is not there, I get an exception Cannot find component with expression "id_resultTable", which is not surprising. So my idea was to create a variable which will contain id of the attribute or empty String like this:
<c:if test="#{cc.attrs.list}">
<ui:param name="updateTable" value="#{cc.attrs.id2}_resultTable"/>
</c:if>
<c:otherwise>
<ui:param name="updateTable" value=""/>
</c:otherwise>
and then do the ajax update like this:
<p:ajax event="dialogReturn" listener="#{cc.listener}"
update="#{cc.attrs.id2}_input #{updateTable}"/>
The problem is, that the #{updateTable} variable is always an empty String(I've tried to put it as a content of outputText) and I have no idea why.
You can just omit the ui:param and do the check directly in the p:ajax:
<p:ajax event="dialogReturn" listener="#{cc.listener}"
update="#{cc.attrs.id2}_input #{cc.attrs.list ? cc.attrs.id2.concat('_resultTable') : ''}"/>
A problem with the c:if-approach could be, that when you update this section via ajax the condition is not re-checked as JSTL-tags are evaluated at view build time. Have a look at JSTL in JSF2 Facelets... makes sense? for further information.
This is not really a solution, but I've done a workaround for the problem which works. I've added h:panelGroup with id around the table and I'm updating this instead of the table.
Iam iterate a list of objects with ui:repeat.
For each Object h:form, h:inputText (for order value) and the commandLink for adding the Item will be generated.
<ui:repeat var="article" value="#{someDataBean.myArrayList}">
<h:form>
Value: <h:inputText value="#{baskedBean.articleValue"} />
<h:commandLink value="add" action="#{baskedBean.addArticel(article)}" />
</h:form>
</ui:repeat>
Lets suppose we have only one article, the order value (baskedBean.articleValue) is submitted and setted correctly.
If we have more than one article in the ui:repeat value list, the submitted value isnt setted. Expect i use the last article.
It looks like, that the other h:inputText components (under the current) will overwrite the value (baskedBean.articleValue)
I tought, that i could handle the problem by sourrunding the related article h:input and commandLink components by a dedicated h:form (only for the article) but it didn't work.
Iam using mojarra 2.2.4 (and testet it also with 2.2.3)
thanks
thanks for your help
I am trying to get an h:textInput to rerender on change, I have tried it with a4j:ajax and f:ajax.
When using a4j:ajax:
<h:panelGroup id="xyzPG">
<ui:repeat var="var" ... >
...
<h:inputText id="#{idController.getIdXYZ(var.id)}"
value="#{someModel.value}"
size="3"
styleClass="#{errorController.getErrorStateStyleId(idController.getIdXYZ())}">
<a4j:ajax event="change" render="xyzPG" listener="#{listener.doSomeStuff}" />
</h:inputText>
...
</ui:repeat>
</h:panelGroup>
This works the first time, after the panel has updated the first time it stops updating the modell and the listener isn't called either. However the render is triggered causing the old values to be displayed.
Now when I replace a4j:ajax with f:ajax I get the error message that the id xyzPG cannot be found within xyzInput.
<f:ajax event="change" render="#this" listener="#{listener.doSomeStuff}" />
When I try limiting the rerender to the inputText it always updates the model and the listener is called, however the h:inputText is not rerendered.
I have already tried placing another panelGroup around the inputText but that didn't work either.
The reason why we are not using h:dataTable is because we have to produce a Table with the following layout:
----------------------------
| dataSet1 | dataSet 2 |
----------------------------
| dataSet3 | dataSet 4 |
etc...
Hence we are using the offset and step attributes of ui:repeat.
By design, you can't dynamically generate id attributes using a render-time tag like <ui:repeat/>
Compile-time V Render-time tags
For the purposes of view construction and ajax-updates, the ids of components must be available during view construction before a view is rendered. <ui:repeat/> already caters for uniqueness in the ids of it's child components. But if you require control of the ids, you need to use a compile-time tag handler like <c:forEach/>:
<c:forEach items="#{idController.itemsList}" var="theVar">
<h:inputText id="#{idController.getIdXYZ(theVar.id)}" value="#{someModel.value}" size="3" styleClass="#{errorController.getErrorStateStyleId(idController.getIdXYZ())}">
<a4j:ajax event="change" render="xyzPG" listener="#{listener.doSomeStuff}" />
</h:inputText>
<c:forEach/>
It's unlikely that you'll be able to reach xyzPG from within the <ui:repeat/> because the <ui:repeat/> is also a naming container, just like <h:panelGrid/> and so forth. The ajax update works with Richfaces because they've made special provisions for such use cases. <f:ajax/> however will not tolerate it. xyzPG is outside the scope of the <ui:repeat/> so to reach that component, you need to use a qualified naming convention:
<f:ajax event="change" render=":form1:xyzPG" listener="#{listener.doSomeStuff}"/>
This assumes that xyzPG is directly contained within an <h:form id="form1"/>
without seeing your backing bean code , I think you should use
<h:inputText id="#{idController.idXYZ}"
instead of
<h:inputText id="#{idController.getIdXYZ()}"
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.
I have a situation in my form that the user must fill at least one of the fields. Using "required" command, i cannot do that. What is the best way to validate this in seam ? i dont want to use javascript.
Thanks!
Just let the required attribute depend its outcome on the presence of the other input fields in the request parameter map.
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" required="#{empty param['form:input2'] and empty param['form:input3']}" />
<h:inputText id="input2" value="#{bean.input2}" required="#{empty param['form:input1'] and empty param['form:input3']}" />
<h:inputText id="input3" value="#{bean.input3}" required="#{empty param['form:input1'] and empty param['form:input2']}" />
</h:form>
Alternatively you could also make use of component binding and use UIInput#getValue() to check the value of the previous components and UIInput#getSubmittedValue() to check them for the yet-to-be-validated components (components are processed in the order as they appear in the component tree). This way you don't need to hardcode client ID's. You only need to ensure that binding names doesn't conflict with existing managed bean names.
<h:form>
<h:inputText binding="#{input1}" required="#{empty input2.submittedValue and empty input3.submittedValue}" />
<h:inputText binding="#{input2}" required="#{empty input1.value and empty input3.submittedValue}" />
<h:inputText binding="#{input3}" required="#{empty input1.value and empty input2.value}" />
</h:form>
JSF2 will let you do a form-level validation. For now, you'll have to make do with either:
Validate in a Bean after form
submission and populate a
FacesMessage to the user if it fails.
Add a validator to one field and in
that validator load in the other
fields and check their values.
If you dont want to use required attribute or javascript, then there are two ways.
One of them is creating a validator, but in my opinion that is too overkill.
I would just check if the input is null or empty in your bean.
if ("".equals(theFieldYouWantToCheck) || theFieldYouWantToCheck == null) {
//Either throw exception or return "false" so that you can handle it
}
If you are using RichFaces then you could perform the validation as follows (see http://mkblog.exadel.com/ria/richfaces-ria/richfaces-built-in-client-functions/):
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" />
<h:inputText id="input2" value="#{bean.input2}"
required="#{empty rich:findComponent('input1').submittedValue}"
requiredMessage="At least one of the fields input1 and input2 must be filled."/>
</h:form>
Note that the expression rich:findComponent('input1') is equivalent to uiComponent['input1']. The reason is that Seam provides the dynamic map uiComponent to look up UI components.