How to reset input components on change of <p:selectOneMenu> after certain validations are violated - jsf

I'm populating <p:selectOneMenu> from a database which contains a list of zones, when a JSF page loaded.
When a zone in this menu is selected, a set of <p:inputText> is displayed in which a user can insert charge that corresponds to product weight which is to be transferred by a transporter to the selected zone in the menu. This can be shown in the following snap shot.
As can be seen, when non numeric values are entered by a user, validation violations occurs, when the given save button <p:commandButton> is pressed (the numbers displayed on top of each text field correspond to weight).
If a user now change the zone in the menu - the first panel without pressing the reset button, the data corresponds to that newly selected zone is loaded in these text fields only when the reset button is pressed as follows (because of validation violation)..
So, how to load data after previous validation violation, if an item (zone) is changed in the menu?
The change event of <p:selectOneMenu>, in this case should do the function something like which is done by <p:resetInput>.
Hope you will be able to understand what I mean :).

Basically, you need the functionality provided by <p:resetInput> inside <p:ajax> of a <p:selectOneMenu>. This is indeed not possible as <p:resetInput> requires being placed in a component implementing ActionSource such as UICommand components.
Your best bet is to let <p:remoteCommand> take over the <p:ajax> change listener job. Therein you can put a <p:resetInput>.
Imagine that you currently have a:
<h:form>
<p:selectOneMenu id="zone">
<f:selectItems ... />
<p:ajax listener="#{bean.changeZone}" update="data" />
</p:selectOneMenu>
<p:panel id="data">
...
</p:panel>
</h:form>
Then this change should do:
<h:form>
<p:selectOneMenu id="zone" onchange="changeZone()">
<f:selectItems ... />
</p:selectOneMenu>
<p:remoteCommand name="changeZone" process="#this zone" action="#{bean.changeZone}" update="data">
<p:resetInput target="data" />
</p:remoteCommand>
<p:panel id="data">
...
</p:panel>
</h:form>
Don't forget to remove the AjaxBehaviorEvent argument from the listener method. It's useless in this particular case anyway.

Related

I can't update my components when I change the state of selectOneButton component

I'm using primefaces to implement my web site and I'm facing an issue.
I've used selectOneButton component and depending on which button is selected I want to show a specific datatable. So when I click the button1 I want to show table1, and table2 when I click the button2.
This is the code I am using:
<p:selectOneButton
value="#{myBean.dataTableType}"
valueChangeListener="#{myBean.dataTableTypeChange}">
<f:selectItems value="#{myBean.dataTableTypes}"
var="type"
itemLabel="#{msg['datatable.type.'.concat(type)]}"
itemValue="#{type}" />
<p:ajax update="table1 table2"/>
</p:selectOneButton>
With this code, I'm unable to reach what I want :(
I think you can very well look at the following example and keep a render flag for your tables in the listener invoked in the bean.
https://stackoverflow.com/a/8409360/3403415
Hope it helps!!
You should declare an attribute process for ajax with value #this. This attribute say to selectOneButton to set value into bean when will happen some event for selectOneButtton. And you will have an actual value for datatable type.
Now you don't have it. And if you have a condition for example:
<ui:fragment rendered="#{myBean.dataTableType eq FirstTable}">
<p:datatable id="first_table">
...
</p:datatable>
</ui:framgent>
Condition return false..

Conditionally rendering p:commandLinks

I'm implementing some search filters. A <p:commandLink> is displayed beside each search component (<p:inputText>, <p:selectOneMenu> etc).
<p:inputText id="text" value="#{bean.text}" required="true"/>
<h:panelGroup id="panelGroup">
<p:commandLink process="#this text" update="panelGroup text" actionListener="#{bean.action}" rendered="#{empty param['form:text']}">
<h:outputText styleClass="ui-icon ui-icon-search"/>
</p:commandLink>
<p:commandLink process="#this" update="panelGroup text" actionListener="#{bean.resetAction}" rendered="#{not empty param['form:text']}">
<h:outputText styleClass="ui-icon ui-icon-trash"/>
<p:resetInput target="text"/>
</p:commandLink>
</h:panelGroup>
When the first <p:commandLink> (the one with the search icon) is clicked and the given <p:inputText> is not empty, the link is expected to disappear and another link (the one with the trash icon) is expected to be rendered (and vice versa).
This happens but the action listener as indicated by the first link (actionListener="#{bean.action}") is not invoked because the link is rendered based on the value of <p:inputText>. rendered="#{empty param['form:text']}" is responsible for preventing the listener from being invoked.
Also when the link with the trash icon appears, it resets the input component, if it is clicked but it does not disappear. it disappears only when it is clicked once again (and then the search appears).
How to handle this situation correctly? If no validation/conversion is violated and the search link is clicked then, the link should disappear and the trash link should be rendered.
On the contrary, when the trash link appears and if it is clicked, it should reset the <p:inputText> and then disappear so that the search link can be rendered.
You actually want to toggle the rendering only after the action is invoked. The rendered attribute is namely also obeyed during apply request values phase, when the action event is about to be queued. If it evaluates false, then the action event won't be queued and therefore the action won't be invoked during invoke application phase.
Better just check the model value directly. The action is queued before the model value is set. And, this should also work better when there's conversion/validation on the model value.
<p:inputText ... value="#{bean.text}" />
<p:commandLink ... rendered="#{empty bean.text}" />
<p:commandLink ... rendered="#{not empty bean.text}" />

PrimeFaces autocomplete: itemSelect versus change events

I need to trigger an ajax update upon change to a text box, which is a <p:autoComplete> component. I have observed that if the user opts to type the text manually, the event is a change, whereas if the user clicks one of the suggestions for the autocomplete, the event is itemSelect. So I added two <p:ajax> children to the input, each calling the same method and having the same update list, but one having event="change" and the other event="itemSelect".
However, I now discover something odd. For example, while in normal server mode I opened my page and typed "12". The autocomplete offered "1233" and "1234" as suggestions. I clicked "1233" and seemingly nothing happened. I clicked again and everything else filled in.
Repeat this in the debugger with a breakpoint on the event handler, and I can see that after the first click, the value is "12" and on the second click, it becomes "1233".
By switching commenting out the two different <p:ajax> I can see the different consequences. Without the "change" one, the handler is never called if the user selects an autocomplete suggestion, and without the "itemSelect" one, the handler is never called if the user types manually. But with both of them, there are two calls, and I'm sure there will be complaints about the double-click.
Some pseudo-code for those that like, first the xhtml:
<p:autoComplete id="itemId" value="#{myBacker.myBean.itemNumber}"
required="true" completeMethod="#{myBacker.idAutoComplete}">
<p:ajax event="itemSelect" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
<p:ajax event="change" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
</p:autoComplete>
<h:panelGroup id="beanDetails">
<h:panelGroup rendered="#{not empty myBacker.myBean.institutionName}">
<h:outputText value="#{myBacker.myBean.institutionName}" />
<!-- Continues with address, phone, etc.. -->
</h:panelGroup>
</h:panelGroup>
Then the Java backing bean code:
public void idChangeEventListener() {
myBean = myDAO.getDetails(myBean);
// another couple of init-type method calls
}
Give the parent tag a widgetVar attribute, then add this little attribute to the <p:ajax event="change" ...> child tag:
onstart="if(widgetVarName.panel.is(':visible')) return false;"
When the question was written, we were on PrimeFaces version 3.5, if I recall correctly. Since then, we need to update the solution to:
onstart="if(PF('widgetVarName').panel.is(':visible')) return false;"
with thanks to mwalter for pointing out the change.

Richfaces: rich:select click event fails

I am using a rich:select, which I want to repopulate when it is clicked on the page. I tried this using a4j:ajax listening for the onClick-Event, but it seems like it is never received. For testing purposes I added an alert to the control, that is shown after an unpredictable number of clicks. The code in my Backing Bean is never called.
If I change the control to h:selectOneMenu it works, but the list collapses immediately so that the users cannot select an item. Additionally the manual input is a required feature.
Code in my JSF-Page:
<rich:select id="auftragsIdsCombo" value="#{einsatzController.einsatz.auftrag.id}" enableManualInput="true" onclick="alert('hi')">
<f:selectItem itemLabel="" noSelectionOption="true" />
<f:selectItems value="#{einsatzController.auftragsIds}" />
<a4j:ajax event="click" render="auftragsIdsCombo" listener="#{einsatzController.loadAuftragsIds()}"/>
</rich:select>
Maybe there is another way of doing this, wich I am not aware of. I just want to load the items after clicking on the Dropdownbox, so that the users can either select one or use autocompletion by typing into the control.
Regards

Dynamically updating a4j:repeat using data from form

I have a page where the user can upload a file to the server. He can set which groups/users can read/write (to) the file.
This is done by selects. One select holds the names of the groups the user is currently in, and on the same row is a select with options Read and Write. On the second row is the corresponding stuff for selecting users.
When the user selects a group and either Read or Write for said group, he then presses a button. After pressing the button I would like to show the user a list of permissions below the select. The list would have a group name, access setting for said group and a button to remove the permission item.
My problem is, I'm not able to update the page and show the list of permissions. Server side the permissions are added to an ArrayList, but I can't get the contents to show in a4j:repeat. How can I get the repeat tag to update?
Here is what I've been trying to do so far:
<h:form>
<h:selectOneMenu value="#{assetUploadForm.currentGroupName}" valueChangeListener="#{assetUploadForm.groupNameChanged}">
<f:selectItem itemValue="users" itemLabel="users" />
<f:selectItem itemValue="foobar" itemLabel="Foobar" />
<a4j:ajax event="valueChange" render="second" execute="#this" />
</h:selectOneMenu>
<h:selectOneMenu value="#{assetUploadForm.currentGroupRW}" valueChangeListener="#{assetUploadForm.groupRWChanged}">
<f:selectItem itemValue="R" itemLabel="Read"/>
<f:selectItem itemValue="W" itemLabel="Write"/>
<a4j:ajax event="valueChange" render="second" execute="#this" />
</h:selectOneMenu>
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<ul>
<a4j:repeat value="#{assetUploadForm.groupPermissions}" var="permission" id="groupList">
<li><h:outputText value="#{permission.permissionSetItemId}"/></li>
</a4j:repeat>
</ul>
</h:form>
So, the problem is a4j:repeat is never updated. If I replace the repeat with an outputtext, and set the commandbutton to render it, the page is updated "correctly".
The <a4j:repeat> does not render any HTML to the response. The render attribute of <a4j:ajax> however expects a component with that ID being physically present in the HTML DOM tree (it is namely behind the scenes using JavaScript document.getElementById() stuff to get the element which needs to be updated after the ajax response has returned). This is thus not possible in combination with <a4j:repeat>. You would need to specify its parentmost JSF HTML component instead, or at least to wrap it in a new one.
E.g.
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<h:panelGroup id="groupList">
<ul>
<a4j:repeat value="#{assetUploadForm.groupPermissions}" var="permission">
<li><h:outputText value="#{permission.permissionSetItemId}"/></li>
</a4j:repeat>
</ul>
</h:panelGroup>
As a different alternative, you can also just use the <rich:list> component instead which renders the complete <ul><li> for you already. You're then basically updating the <ul> directly.
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<rich:list id="groupList">
<h:outputText value="#{permission.permissionSetItemId}"/>
</rich:list>
To learn about which components all are available and how to use them, peek around in the showcase site and the component reference.
I don't know why it does not work but as a work-around you could probably use h:dataTable for this. With some css tweaking that could be rendered with the same looks.
Or wrap a a4j:outputPanel around the a4j:repeat and try what happens if you render that.
MAG,
Milo van der Zee

Resources