How to change order in which the components are processed - jsf

I have a selectOneMenu and an editor. What I want is to submit the value of the editor before the value of the selectOneMenu. The code looks like this
<p:selectOneMenu value="#{myBB.selectedItem}">
<f:selectItems value="#{myBB.selectItems}"/>
<p:ajax event="change" process="itemText #this" update=":mainForm"/>
</p:selectOneMenu>
<p:editor id="itemText" value="#{myBB.selectedItem.text}"/>
It looks like the order of elements in process="itemText #this" doesn't matter, because when I change it, the values are submitted in unchanged order.
The problem is, that the selectedItem of the editor is changed by the selection before the value from the editor is submitted.
Am I right, that the order doesn't matter and it is submitted based on the order in the DOM tree? (When I change order of the input fields it's working as I would like to)
What is the best way to work around this?

You shouldn't rely on things like layout or processing order in your code. If the problem is that itemText value is reset when selectedItem is changed, then bind the text to separate String text bean variable, and update selectedItem.text in some other code, maybe <p:ajax listener="#{...}".

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..

How to change OneMenu element to outputText in JSF

I would like my page to be user friendly as much as possible and I have an idea but its a little bit harder in the way I want to solve it.
I'm using primefaces and I would like to have a selectOneMenu element which changes to just an outputText with the value of the selected variable in the selectOneMenu. Anyone have some nifty ideas?
This can be done with ajax and partial rendering. Here is a sketch of my idea (untested and in plain JSF):
<h:panelGroup id="wrapper">
<h:selectOneMenu value="#{myBean.myValue}"
rendered="#{myBean.myValue == someInitialValue}" ...>
<f:ajax render="wrapper"/>
... (your select items here)
</h:selectOneMenu>
<h:outputText value="#{myBean.myValue}"
rendered="#{myBean.myValue != someInitialValue}" .../>
</h:panelGroup>
And that's what it does:
The value of h:selectOneMenu will be initialized and the menu will be rendered only if it is the initial value.
On change of the value, the surrounding panelgroup will be re-rendered, hides the menu and lets the h:outputText appear.
You need a wrapping panelGroup for this because the outputText is not there at page load. If your form is small you could also render=#form or any other surrounding container instead. Then you wouldn't need the wrapper.

Displaying read-only forms (values are shown as text instead of disabled input controls) with JSF?

I have a data entry form where user enters lots of data. When user comes to the page to view existing data, the page should be displayed in read-only mode (all values shown as text), when he clicks 'Edit' button, normal form with all input controls should be shown so that user can change and save data.
We are using JSF 2.0 with PrimeFaces library. It is easy to achieve above behavior for text box and text area but not for Checkbox, multi-select, radio,..... controls. Is there any easy way available to achieve above behavior rather than writing our own code (which may run into lot of lines thus making backing bean code ugly)
Thanks for your help...
I'm not sure why you think that you need additional backing bean code for this. You've all the needed values in the backing bean already. Your problem is more in the presentation of those values. Just display them in the desired format by writing the view code accordingly. Perhaps you were thinking it too the hard way.
Instead of a select boolean checkbox, you could display for example a "Yes" or "No" value.
<h:selectBooleanCheckbox value="#{bean.checked}" rendered="#{bean.edit}" />
<h:outputText value="#{bean.checked ? 'Yes' : 'No'}" rendered="#{not bean.edit}" />
Instead of a select one menu/radio, you could just display the value in an output text.
<h:selectOneMenu value="#{bean.selectedItem}" rendered="#{bean.edit}">
<f:selectItems value="#{data.availableItems}" />
</h:selectOneMenu>
<h:outputText value="#{bean.selectedItem}" rendered="#{not bean.edit}" />
Instead of a select many listbox/checkbox, you could just display for example all values comma separated in a loop.
<h:selectManyListbox value="#{bean.selectedItems}" rendered="#{bean.edit}">
<f:selectItems value="#{data.availableItems}" />
</h:selectManyListbox>
<h:panelGroup rendered="#{not bean.edit}">
<ui:repeat value="#{bean.selectedItems}" var="selectedItem" varStatus="loop">
#{selectedItem}#{not loop.last ? ', ' : ''}
</ui:repeat>
</h:panelGroup>
You could wrap it all in a tag file or a composite to minimize boilerplate and code repetition.
I've done this in my last project using composite components which has a "preview" attribute and in the implementation I render a text when this attribute is true and the real (editing) when the attribute is false. For checkbox in preview mode you could show the checkbox itself but disabled, for radio - show the selected item.
MyFaces Tomahawk library [1] contains an extended version of the standard components that adds displayValueOnly attribute for this purpose. This might help you (I haven't used them).
[1] - http://myfaces.apache.org/tomahawk-project/tomahawk20/index.html

<h:selectOneMenu> with temporary disabled SelectItems

I have a <h:selectOneMenu> that renders the value of the cardStatus from my object model.
A CardStatus has an boolean attribute 'temporaryDisabled' that means that the value is still valid but should not be used by the user.
Now, if my model has cardStatus set to a temporary disabled value, how can I show this value in the dropdown combobox and still prevent the user from changing the value to another temporary disabled status?
If I just delete the disabled card statuses from the list of SelectItems that I feed to <h:selectOneMenu> then when the select gets rendered it will automatically select the first item in the list an submit it next time consequently wrongly changing my value in the model.
If I include the disabled card statuses in the list of SelectItems but set the value of the disabled attribute to true for their corresponding items, they are rendered in HTML disabled and not submitted so I get a null value in my model which is also wrong.
I am stuck. Any advice is kindly appreciated.
Best regards,
Dan.
Finally what I did was to use a piece of jQuery code that gets executed after the page is loaded.
<h:selectOneMenu
id="cardStatus"
value="#{someBean.cardStatus}"
converter="selectItemConverter">
<f:selectItem itemValue="E|A" itemLabel="Active" />
<f:selectItem itemValue="E|S" itemLabel="Stolen" />
<f:selectItem itemValue="D|B" itemLabel="Blocked" />
<f:selectItem itemValue="E|L" itemLabel="Lost" />
<f:selectItem itemValue="D|C" itemLabel="Counterfeit" />
</h:selectOneMenu>
What the javascript code does is to scan all the items and for each item with a value starting with the prefix D| hide the item using jQuery's hide() function. This way the combobox is acting as all values would be valid/enabled, but the user will not be able to select inactive values because they are not visible. Furthermore, if the default selected value is one of the values starting with D|, the value will still be shown as default value but the user is not able to see it in the list of options he/she can choose from.
"that means that the value is still valid but should not be used by the user"
Help me understand this piece. You want to display these choices in an h:selectOneMenu but not allow the user to select them? I guess I don't understand why you would present them to the user if they are invalid options for them?
You could always create a validator that validates against "temporaryDisabled" if that's what you're trying to accomplish ... let me know more about what you want the end-user to see and I can probably help.
<h:selectOneMenu
id="cardStatus"
value="#{someBean.cardStatus}"
converter="selectItemConverter">
<f:selectItem itemValue="#{null}" itemLabel="" />
<f:selectItems
value="#{cardStatusBean.cardStatuses}"
var="cardStatus"
itemValue="#{cardStatus}"
itemLabel="#{cardStatus.name}"
itemDisabled="#{cardStatus.temporaryDisabled}"/>
</h:selectOneMenu>
This would give you a default choice with a value of null and an empty label. Would that accomplish what you are looking for?
For the record, if using JSF 2.0, f:selectItem and f:selectItems have an "itemDisabled" attribute that produces the desired behavior.

JSF selectOneMenu is refreshing and going back to its previous state rather than showing the new value

I have a datatable where a lot of selectOneMenu items are available , for example, for 10 items each having one selectOneMenu combo. now if i click on any of the combos, they are supposed to save the value in the database and they do it. but after saving the changed value the selectOneMenu is returning back to its previous state. I want the selectOneMenu to keep its current state. also, the method is being invoked for every single combo in the datatable. i really wonder why!! i have been banging my head for the last 2 weeks. any help would be really appreciated. thanks in advance.
this is my first post here. this is my jsf datatable:
<h:dataTable value="#{careNeedBean.controlledCareNeedsList}" var="careNeed"
id="careneed_table" binding="#{careNeedBean.dataTable}">
<h:column>
<f:facet name="header">
<h:outputText value="NeedsLevel"/>
</f:facet>
<h:selectOneMenu id="needs_level_combo" style="width:200px;font-size:9px;"
onchange="submit()"
valueChangeListener="#{careNeedBean.saveTaskAsessment}"
binding="#{careNeedBean.selectOneMenu}">
<f:selectItem itemValue="not_assessed" itemLabel="----Not assessed----"/>
<f:selectItems value="#{careNeed.humanReadableNeedsList}" />
</h:selectOneMenu>
</h:column>
This is my bean code:
public String saveTaskAsessment(ValueChangeEvent event) {
//does some things
return "Success";
}
The valueChangeListener doesn't run on the recently changed component only. In fact, you're using JavaScript submit() function to submit the entire form. The valueChangeListener will always be executed whenever the new selected value differs from the old value as is been declared in the value attribute.
You don't have declared a value attribute, so its default value is effectively null. If the default selected item of the list is not null, then the valueChangeListener will be invoked.
To fix this, you need to assign a value attribute to the component
<h:selectOneMenu value="#{careNeed.needsLevel}">
and you need to prefill it with the same value as the default value of the dropdown list.
this.needsLevel = "not_assessed";
Alternatively, you can also make the default value null.
<f:selectItem itemValue="${null}" itemLabel="----Not assessed----"/>
Unrelated to the problem, since you're already on JSF 2.0, I'd suggest to use <f:ajax> to submit only the recently changed dropdown by ajaxical powers instead of using onchange="submit()" to submit the entire form. That's after all better for user experience.
<h:selectOneMenu>
<f:ajax />
</h:selectOneMenu>
Also, the valueChangeListener method doesn't need to return anything. It will be ignored anyway. Just declare it void.
You can use AjaxSingle="true" and onsubmit="form.refresh();" on your ajax request.
So that it will process only the current component.
form.refresh(); will remove the old cache value.
You will get the refreshed bean value.

Resources