问题
I want to change the inputTexts' values when I choose another Skin from my selectOneMenu. Everything is doing well, my Converter gives back the right Object from the menu, but the inputTexts are not updated.
<h:form>
<h:selectOneMenu id="dropdownSkin"
value="#{helloBean.currentSkin}" defaultLabel="Select a skin.."
valueChangeListener="#{helloBean.skinValueChanged}" immediate="true"
onchange="this.form.submit()" converter="SkinConverter" >
<f:selectItems value="#{helloBean.mySkinsSI}" var="c"
itemValue="#{c.value}" />
</h:selectOneMenu>
<br />
<h:inputText id="name" value="#{helloBean.currentSkin.title}"></h:inputText>
<br />
<h:inputText id="tcolor" value="#{helloBean.currentSkin.titleBar.textColor}"></h:inputText>
<br />
<h:inputText id="bcolor" value="#{helloBean.currentSkin.titleBar.backgroundColorStart}"></h:inputText>
</h:form>
Here is what my Bean looks like. I debugged it and the Object currentSkin is set correctly. Now i need to know how to update the textfields content.
@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<ExtendedSkin> mySkins;
private List<SelectItem> mySkinsSI;
private ExtendedSkin currentSkin;
public void skinValueChanged(ValueChangeEvent e) {
currentSkin = (ExtendedSkin) e.getNewValue();
FacesContext.getCurrentInstance().renderResponse();
}
public List<ExtendedSkin> getMySkins() {
mySkins = XMLParser.readExtendedSkins();
return mySkins;
}
public List<SelectItem> getMySkinsSI() {
mySkinsSI = new LinkedList<SelectItem>();
for (ExtendedSkin s : getMySkins()) {
mySkinsSI.add(new SelectItem(s, s.getTitle()));
}
return mySkinsSI;
}
public void setMySkinsSI(List<SelectItem> myItems) {
this.mySkinsSI = myItems;
}
public ExtendedSkin getCurrentSkin() {
if (currentSkin == null) {
currentSkin = getMySkins().get(0);
}
return currentSkin;
}
public void setCurrentSkin(ExtendedSkin currentSkin) {
this.currentSkin = currentSkin;
}
}
回答1:
The problem here is that the converter is doing its work filling the helloBean.currentSkin
object, but the values in the <h:inputText>
that are bounded to this helloBean.currentSkin
: title
, textColor
and backgroundColorStart
will be send to the server and replace the actual values that were loaded by the converter
. In other words:
- The converter is executed and builds the
helloBean.currentSkin
based on the selected value. - The
<h:inputText id="name">
empty value is sent to server and will be injected inhelloBean.currentSkin.title
. Same behavior for the other 2<h:inputText>
s. - The view will be loaded using the selected
helloBean.currentSkin
and it will load thehelloBean.currentSkin.title
with the empty value. Same behavior for the other 2<h:inputText>
s.
There are two possible solutions to this problem:
Move the
<h:inputText>
s outside the form, so the empty values won't be send to the server. When loading the view, it will maintain the values loaded in the converter.<h:form> <h:selectOneMenu id="dropdownSkin" value="#{helloBean.currentSkin}" defaultLabel="Select a skin.." valueChangeListener="#{helloBean.skinValueChanged}" immediate="true" onchange="this.form.submit()" converter="SkinConverter" > <f:selectItems value="#{helloBean.mySkinsSI}" var="c" itemValue="#{c.value}" /> </h:selectOneMenu> </h:form> <br /> <h:inputText id="name" value="#{helloBean.currentSkin.title}"></h:inputText> <!-- rest of Facelets code... -->
Since you're loading the
helloBean.currentSkin
while changing the selected value on your dropdownlist, you can add ajax behavior using <f:ajax> tag component inside the<h:selectOneMenu>
and update the fields in a cleaner way. I would opt for this solution.<h:form> <!-- Note that there's no need of the onchange JavaScript function --> <h:selectOneMenu id="dropdownSkin" value="#{helloBean.currentSkin}" defaultLabel="Select a skin.." valueChangeListener="#{helloBean.skinValueChanged}" immediate="true" converter="SkinConverter" > <f:selectItems value="#{helloBean.mySkinsSI}" var="c" itemValue="#{c.value}" /> <f:ajax process="@this" render="name tcolor bcolor" /> </h:selectOneMenu> <br /> <h:inputText id="name" value="#{helloBean.currentSkin.title}" /> <h:inputText id="tcolor" value="#{helloBean.currentSkin.titleBar.textColor}" /> <br /> <h:inputText id="bcolor" value="#{helloBean.currentSkin.titleBar.backgroundColorStart}" /> </h:form>
You can learn more about <f:ajax>
in online tutorial like this one.
Since you're going to use an ajax call in your page, you should change your managed bean scope from @SessionScoped
to @ViewScoped
. More info about this here: Communication in JSF 2
来源:https://stackoverflow.com/questions/15024183/jsf-update-inputtext-after-selectonemenu-choice