I have a strange problem which I have been trying to fix for some time but am stuck in one place and don't quite understand what's going on here.
My index page looks like this:
<h:selectOneMenu id="selectMenu" value="#{indexBean.model.selected_id}" styleClass="indexItems">
<f:selectItems value="#{indexBean.myModelValues}" />
<a4j:support event="onchange" reRender="peek" />
</h:selectOneMenu>
<br>
<h:outputText id="peek" value ="#{indexBean.model.selected_id}"/>
<br>
<a4j:commandButton value="Go to Form" action="form" styleClass="indexItems">
<f:param name="selected" value="#{indexBean.model.selected_id}" />
</a4j:commandButton>
The commandButton sends the user to a next page when I want to get the selected position from the selectOneMenu. The problem is that nothing is sent. When I select some value from the Menu the 'peek' outputText is rerendered properly and I can see the correct selection. However it is not sent to the next page and Bean. Surprisingly when I change the value of the parameter to a fixed String it works!!! So i.e. this:
<f:param name="selected" value="someValue1" />
Is read correctly in the next Bean!!! All of the beans are requested scoped with RichFaces #KeepAlive annotation (I tried without the annotation and it's the same). Ihave treied:
-changing a4j:commandButton to h:commandLink or h:outputLink
-changing indexBean.model.selected_id to indexBean.selected_id
-finally changing the input source from h:selectOneMenu to h:inputText
Nothing helps - it is still the same - a hardcoded String is passed correctly to the next page, but when I try to use the expresion the parameter is always empty.
Here I post a snippet of the faces-config.xml:
<managed-bean>
<managed-bean-name>indexBean</managed-bean-name>
<managed-bean-class>id.webapp.beans.IndexBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>model</managed-bean-name>
<managed-bean-class>id.webapp.beans.Model</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>formBean</managed-bean-name>
<managed-bean-class>id.webapp.beans.FormBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>selectedValue</property-name>
<value>#{param.selected}</value>
</managed-property>
</managed-bean>
Does any one have an idea why this doesn't work? I have used the managed-properties parameters like that in the past and it worked (meaning using some dynamically changed values not a static String).
The <f:param> is evaluated during the initial request (when the form is to be displayed), not during the form submit request. So it still remains the initial value, not the changed value.
Give the <a4j:commandButton> an id and refer it in the reRender as well so that its <f:param> get re-evaluated before you press the button.
<h:selectOneMenu id="selectMenu" value="#{indexBean.model.selected_id}" styleClass="indexItems">
<f:selectItems value="#{indexBean.myModelValues}" />
<a4j:support event="onchange" reRender="peek,button" />
</h:selectOneMenu>
<br>
<h:outputText id="peek" value ="#{indexBean.model.selected_id}"/>
<br>
<a4j:commandButton id="button" value="Go to Form" action="form" styleClass="indexItems">
<f:param name="selected" value="#{indexBean.model.selected_id}" />
</a4j:commandButton>
Related
Here is code:
<ui:repeat var="entity" varStatus="status" value="#{myentityListView.someList}">
<h:form>
<h:commandLink value="Go!" action="mypage.xhtml" >
<c:if test="#{entity.entityType=='Comment'}"><f:param name="productId" value="#{entity.product.getId()}"/></c:if>
<f:param name="userId" value="#{entity.user.getId()}"/>
</h:commandLink>
</h:form>
</ui:repeat>
Maybe its cause is that h:commandLink is in ui:repeat.
mypage.xhtml is an exixting page.
Thanks
You need to make sure that #{myentityListView.someList} returns exactly the same value during the form submit request as it was during the request of displaying the page. Putting the bean in the view scope (just mark it #ViewScoped) and ensuring that you preserve the list during (post)constructor or in an action method should fix it.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
However, in your particular case, it's much better to just use <h:link> instead as you don't seem to need to send a POST request at all. This way you end up with nice bookmarkable and searchbot-chipherable links.
<ui:repeat var="entity" varStatus="status" value="#{myentityListView.someList}">
<h:form>
<h:link value="Go!" outcome="mypage.xhtml">
<f:param name="userId" value="#{entity.user.id}" />
<f:param name="productId" value="#{entity.product.id}" disable="#{entity.entityType != 'Comment'}" />
</h:link>
</h:form>
</ui:repeat>
Also note that I fixed your <c:if> approach by removing it as it won't work as you'd expect. It would always evaluate false. See also JSTL in JSF2 Facelets... makes sense?
See also:
When should I use h:outputLink instead of h:commandLink?
While calling the ValueChangeListener in JSF based on value change in dropdown, it is calling all the ValueChangeListner that are on that page.
There are two valueChangeListener in DataTable, while changing value in one dropdwon the 2nd one also executing.
<t:column id="avlId" styleClass="coltextcenteralign">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="#{bundle['travelLocalAccommodation.title.availability']}" />
<h:outputText value="*" style="color:red" />
</h:panelGroup>
</f:facet>
<t:selectOneMenu value="#{accomDtls.availability}" immediate="true"
valueChangeListener="#{TravelProcessingBB.localAccommodationBB.setAvailableFlag}" forceid="true" id="avl"
onchange="return availabilityAlert('#{accomDtls.prepopulatedFlag}','avl[#{table_count}]')"
styleClass="dropDownStyle" style="width:50">
<f:selectItem itemValue="Y" itemLabel="Yes" />
<f:selectItem itemValue="N" itemLabel="No" />
</t:selectOneMenu>
</t:column>
The value change alone won't automatically call the valueChangeListener. You need to submit the form as well. A commonly used "hack" is to call form.submit() using JavaScript during the onchange event. This will however submit the entire form. Truly the valueChangeListener will be triggered for all changed fields of the form.
To fix this in JSF 1.x, you need to hassle somewhat with the immediate attribute to skip all other form components from validating and with component binding so that you can properly get/set the other component's value. Long story short, I ever wrote an article about that: populate child menus in JSF 1.2.
In JSF 2.0, this is however easier to achieve with help of <f:ajax> tag. If you're really using JSF 2.0 (your current question doesn't indicate that), then let me know if you need an example.
I'd like to do client side component updates. Example: disable a button when a checkbox is clicked:
<h:selectBooleanCheckbox value="true" onchange="button.disabled=true" />
<h:commandButton id="button" value="Save" />
The above doesn't work. Is there a way to do this declaratively in JSF?
It doesn't work because the JSF component ID is not necessarily the same as the generated HTML ID. JSF composes the HTML element ID and form element name based on the ID's of all UINamingContainer components in the tree -if any. The UIForm component is one of them. Rightclick the page in webbrowser and choose View Source. See and learn.
There are two ways to solve this problem:
Set prependId attribtue of <h:form> to false.
<h:form prependId="false">
<h:selectBooleanCheckbox value="true" onclick="button.disabled=true" />
<h:commandButton id="button" value="Save" />
</h:form>
Note that I'd rather use onclick="button.disabled=!checked" instead. The onchange is only fired when the input element loses focus and that is non-intuitive in case of checkboxes and radiobuttons. Also, you'd like to turn it back on when the checkbox is checked again, right?
Give the <h:form> a fixed ID so that you know how the generated form element name look like:
<h:form id="form">
<h:selectBooleanCheckbox value="true" onclick="form['form:button'].disabled=true" />
<h:commandButton id="button" value="Save" />
</h:form>
The brace notation is mandatory because the : is an illegal identifier character and just onclick="form:button.disabled=true" won't work. Also here, I'd rather use onclick="form['form:button'].disabled=!checked instead.
The same problem applies on document.getElementById() as well. So simply replacing button by document.getElementById('button') alone won't fix the problem.
simply use javascript
document.getElementById("buttonId").disabled="true";
Check this
I have a a4j:commandButton which is supposed to redirect me to an appropriate "Edit" page based on an Id, which I wanted to pass as a parameter, something like this:
<h:commandButton action="/details.jsf?faces-redirect=true" value="details">
<f:attribute name="id" value="#{bean.id}" />
</h:commandButton>
The problem is, it doesn't work. I also tried replacing f:attribute with "f:param name="id" value="#{bean.id}" ", but it also failed. The only thing I got to work is an outputLink:
<h:outputLink value="/details.jsf">
link
<f:param name="id" value="#{bean.id}" />
</h:outputLink>
But I'm not really happy with a link, so is there a way to make the commandButton work?
Oh and I also have a bean which is supposed to get that "id" after the redirect:
#PostConstruct
public void init(){
id= resolve("id");
}
Have a look at this article about communication in JSF, by BalusC
f:param only works with h:commandLink and h:outputLink.
You can use an input hidden:
<h:form>
<h:commandButton action="/details.jsf?faces-redirect=true" value="details"/>
<input type="hidden" name="id" value="#{bean.id}" />
</h:form>
And then in your faces-config, I guess is request scoped. If you use the annotations of JSF2, just translate this to the proper annotations.
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>mypackage.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
You need obviously to have getters and setters for that field in the backing bean.
or try to "paint" the link as a button through CSS.
Unless my JSF is extremely rusty, the action attribute on a command button or command link is used to specify the outcome string defined in your faces-config-nav file, or it should point to a method on the bean which will return an outcome (or redirect/whatever).
In your case, if you want to redirect to another page... you should define that in your config file, as a navigation link (with redirect if necessary). Then in your action button you should have something like
<h:commandButton action="showDetails" value="details">
...
<navigation-case>
<from-outcome>showDetails</from-outcome>
<to-view-id>/details.jsf?faces-redirect=true</to-view-id>
</navigation-case>
As an aside, the <f:atribute> tag will work, but it will only set the attribute onto the component. So if you got a hold of the command button in your bean, you could be able to get the attribute value by name. To pass a request param, use the hidden field technique like pakore mentioned
I'm attempting to put a few drop down menus inside of an a4j:repeat. The values for the second drop down are dependent on the value selected in the first. Below is the code I am attempting to use, but it passes a blank parameter:
<a4j:repeat id="localRepeat" var="local" value="#{InstanceController.instance.locations}" rowKeyVar="row">
<h:panelGrid columns="2">
<h:outputLabel value="Theater:" />
<h:selectOneMenu id="theater" converter="#{TheaterConverter}" value="#{local.theater}">
<f:selectItems id="theaters" value="#{InstanceController.allTheaters}" />
<a4j:support event="onchange" action="#{InstanceController.getAllCountriesInTheater}" reRender="country" >
<f:param name="theater" value="#{local.theater.id}"/>
</a4j:support>
</h:selectOneMenu>
<h:outputLabel value="Country:" />
<h:selectOneMenu immediate="true" id="country" converter="#{CountryConverter}" value="#{local.country}">
<f:selectItems value="#{InstanceController.allCountriesInTheater}" />
<a4j:support event="onchange" reRender="state" />
</h:selectOneMenu>
</h:panelGrid>
<rich:spacer height="10px" />
</a4j:repeat>
If I change the f:param to send "1" instead of "#{local.theater.id}" it works as expected.
Is there a way to get the selected value of the first drop down and send it as a parameter?
This reason this doesn't work is that when the f:param tag is rendered, the current value of local.theater.id is already assigned to the parameter. So the theater param will contain the id of the theater that was selected when the page was rendered - probably null because no theater has been selected yet.
What you are trying to do is far more easy:
Just remove the f:param and use the property directly. When the a4j:support tag triggers because the selectbox value was changed, jsf will validate your form tags and assign the appropriate model values. So, when the getAllCountriesInTheater action gets executed, the local.theater property will already contain the selected theater.
Depending on how your backing beans are designed, you will probably need a parameter to identify the location for which the selectbox was changed, so the getAllCountriesInTheater action will know in which of the locations to look for the selected theater.