JSF input to multiple backing bean properties - jsf

I have some cases where I have a JSF page and for a single input I'd like to set more than one value on the backing bean without doing code in the backing bean.
I can set a single value:
<h:selectOneRadio id="selectMembershipLevel" class="TODO_SELECT"
value="#{joinBackingBean.map[joinBackingBean.map.primary_memberInfo_membershipType_code]}">
<f:selectItem id="basic" itemLabel="#{overrideMsg.pbBasic}" itemValue="B" />
<f:selectItem id="plus" itemLabel="#{overrideMsg.pbPlus}" itemValue="P" />
<f:selectItem id="plusRV" itemLabel="#{overrideMsg.pbPlusRV}" itemValue="RV" />
But if I wanted to set more than one at once can that be done on the JSF page?
#{joinBackingBean.map[joinBackingBean.map.primary_memberInfo_membershipType_code]}
#{joinBackingBean.map[joinBackingBean.map.primary_memberInfo_membershipType_desc]}//Bdesc
#{joinBackingBean.map[joinBackingBean.map.primary_memberInfo_membershipType_type]}//Btype

Bind the other properties via <h:inputHidden> and use JavaScript during change event of the first input to manipulate the value of those hidden inputs to the same as the first input's current value.
Here's a kickoff example:
<h:form id="form">
<h:selectOneRadio value="#{bean.input1}" onchange="document.getElementById('form:input2').value = document.getElementById('form:input3').value = this.value">
<f:selectItem itemValue="one" />
<f:selectItem itemValue="two" />
<f:selectItem itemValue="three" />
</h:selectOneRadio>
<h:inputHidden id="input2" value="#{bean.input2}" />
<h:inputHidden id="input3" value="#{bean.input3}" />
...
</h:form>
Obviously, feel free to refactor to a JS function or throw in some jQuery. Keep in mind that this all won't work if client has JS disabled, and that the enduser could manipulate JS code and request parameters. A server side solution is more robust if you absolutely need the values to be equal.

Related

Add some action in SelectOneMenu

I need that the variable inside selectItems be available inside selectOneMenu or other way that I can grab what were selected by the user.
I need this because this item need to pass trough an Hibernate.initialize(item)
So I need to call the view (bean) method that I have build that does it.
<h:selectOneMenu
id="dependenteSalvar"
value="#{pessoaView.registro}"
styleClass="form-control"
converter="indexConverter">
<f:selectItem itemValue="#{null}" itemLabel="Selecione..."></f:selectItem>
<t:selectItems
value="#{pessoaView.pessoasAtivas}"
var="dependente"
itemLabel="#{dependente.nome} (#{dependente.documento})"
itemValue="#{dependente}">
</t:selectItems>
</h:selectOneMenu >
Is it possible?
You can use <f:ajax> tag to listen the events of selectOneMenu in your backend.
<h:selectOneMenu
id="dependenteSalvar"
value="#{pessoaView.registro}"
styleClass="form-control"
converter="indexConverter">
<f:selectItem itemValue="#{null}" itemLabel="Selecione..."></f:selectItem>
<t:selectItems
value="#{pessoaView.pessoasAtivas}"
var="dependente"
itemLabel="#{dependente.nome} (#{dependente.documento})"
itemValue="#{dependente}">
</t:selectItems>
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu >
Take into account that <f:ajax> requires jsf.js file is included in the HTML <h:head>. Basically, this file contains the Javascript functions to perform the magic.
Another option if you are using primefaces is to use
<p:ajax event="change" listener... /> instead of f:ajax, to listen the value change events as follows:
<p:selectOneMenu
id="dependenteSalvar"
value="#{pessoaView.registro}"
styleClass="form-control">
<f:selectItem itemValue="#{null}" itemLabel="Selecione..."></f:selectItem>
<f:selectItems
value="#{pessoaView.pessoasAtivas}"
var="dependente"
itemLabel="#{dependente.nome} (#{dependente.documento})"
itemValue="#{dependente}">
</f:selectItems>
<p:ajax listener="#{bean.listener}" event="change" />
</p:selectOneMenu >

Why is only the getter invoked on the inputText value expression?

<h:form>
First Name: <h:inputText value="#{studentFormBean.fname}" /> <br/><br/>
Last Name: <h:inputText value="#{studentFormBean.lname}" /> <br/><br/>
Country :
<h:selectOneMenu value="#{studentBean.country}">
<f:selectItem itemValue="Brazil" itemLabel="Brazil" />
<f:selectItem itemValue="US" itemLabel="US" />
<f:selectItem itemValue="UK" itemLabel="UK" />
<f:selectItem itemValue="Myanmar" itemLabel="Myanmar" />
</h:selectOneMenu>
<h:commandButton value="Submit" action="FormResponse"/>
</h:form>
At this code, "#{studentFormBean.fname}" should point to setFname() in StudentFormBean.java but it point to getFname(). Why is this happened and how can I solve it?
#{studentFormBean.fname} will use both the getter and setter if used in an editable value holder like h:inputText. It will get the current value when the input is rendered. It will set the submitted when the for is submitted (and validation and conversion have passed).
See also:
Debugging JSF Life Cycle - what exactly happens in each phase

JSF component loses CSS style after AJAX render call

I have a big complex form with validation on most of the fields. Somewhere I have <h:selectOneMenu> where if I select a certain value, I want another <h:selectOneMenu> to appear under it. The second list is initially invisible (I set it with rerender property to false and I make it true with clickListener() function and render it an ajax call).
<o:form>
<h:panelGroup id="group" >
<label>Status</label>
<h:selectOneMenu id="status" immediate="true" label="Status" value="#{candidateBean.statusVO}" converter="omnifaces.SelectItemsConverter" required="true" requiredMessage="The field is empty">
<f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
<f:selectItems value="#{settingsBean.settings.statusListVO.statusVO}" var="status" itemValue="#{status}" itemLabel="#{status.name}"/>
<f:ajax event="valueChange" listener="#{candidateBean.clickListener}" execute="form" render="group" />
</h:selectOneMenu>
<h:messages for="status" style="color:red" />
<label>Invalidation Reason</label>
<h:selectOneMenu id="invalidationReason" rendered="#{candidateBean.falseTest}" label="Invalidation Reason" value="#{candidateBean.invalidationReasonVO}" converter="omnifaces.SelectItemsConverter" requiredMessage="The field is empty">
<f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
<f:selectItems value="#{settingsBean.settings.invalidationReasonListVO.invalidationReasonVO}" var="invalidation" itemValue="#{invalidation}" itemLabel="#{invalidation.name}"/>
</h:selectOneMenu>
</h:panelGroup>
</o:form>
I used <o:form> instead of <h:form> because somewhere in the form I used <o:ignoreValidationFailed> because I needed to update a dataTable with values from a <h:selectOneMenu> and force update on my model.
Everything works except when I select a value from the list, the elements inside the panelGroup are rendered without any style at all and I can't figure out why. If I refresh the page the CSS is loaded on the elements but this is not an option.
My bean is #SessionScoped.

Conditionally render depend on p:selectOneMenu value

I'm trying to build a custom component from existing Primefaces components and I need some help here. I have a selectOneMenu and I want it to render or not (and disable or enable) other components according to which option is selected in the menu. The hard thing here is that I can't do it using a Managed Bean (I have a few reasons for that), I need a pure xhtml code.
I tried some <c:choose> and <ui:parameter> stuff to create booleans but for some reason that I can't see it's not working. Could you guys take a look at my code and see if you have any ideas? It may be something simple that I can't figure or something I don't know yet.
<h:body>
<h:form id="abc">
<ui:repeat var="pd" value="#{produtoMB.produtos}">
<h:panelGroup id="linha">
<c:choose>
<c:when test="#{pd.marca == X1}">
<c:set var="render" value="#{true}" />
</c:when>
<c:otherwise>
<c:set var="render" value="#{false}" />
</c:otherwise>
</c:choose>
<p:selectOneMenu value="#{pd.marca}">
<f:selectItem itemLabel="Select One" itemValue="" noSelectionOption="true"/>
<f:selectItem itemLabel="Xbox One" itemValue="X1" />
<f:selectItem itemLabel="PlayStation 4" itemValue="PS4" />
<f:selectItem itemLabel="Wii U" itemValue="WU" />
<p:ajax update="linha" />
</p:selectOneMenu>
<p:inputText value="#{pd.aparelho}" disabled="#{render}"/>
<h:outputText value="Microsoft" rendered="#{render}"/>
<p:commandButton value="X" />
</h:panelGroup>
<br />
</ui:repeat>
<br />
<p:commandButton actionListener="#{produtoMB.botaoMais}" value="+" update="abc"/>
<p:commandButton actionListener="#{produtoMB.botaoMenos}" value="-" update="abc"/>
</h:form>
There are a couple of issues here.
First,
<ui:repeat ...>
<c:choose>
...
</c:choose>
</ui:repeat>
JSTL tags run during view build time. It's executed only once before all JSF component runs. So, on contrary to what you'd intuitively expect from the XML code flow, it isn't executed when the <ui:repeat> component runs and iterates. See also JSTL in JSF2 Facelets... makes sense?
Second,
<c:when test="#{pd.marca == X1}">
...
<f:selectItem ... itemValue="X1" />
The itemValue="X1" represents a String. The EL expression #{X1} basically looks for a variable named X1 in respectively the facelet, request, view, session, and application scopes until the first non-null value is found. In order to represent a String value in EL, you need to quote it with singlequotes like so #{'X1'}. So, you should have used #{pd.marca == 'X1'} instead. Nonetheless, this still won't work for the reason mentioned in the first point. See also Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work.
You can however use <c:set> to create an alias in the EL scope, as long as you don't set its scope attribute. See also Defining and reusing an EL variable in JSF page.
After removing JSTL <c:choose> and fixing the EL expression #{X1} to represent a real String literal #{'X1'}, here's how it should look like:
<ui:repeat var="pd" value="#{produtoMB.produtos}">
<p:selectOneMenu value="#{pd.marca}">
<f:selectItem itemLabel="Select One" itemValue="#{null}" />
<f:selectItem itemLabel="Xbox One" itemValue="X1" />
<f:selectItem itemLabel="PlayStation 4" itemValue="PS4" />
<f:selectItem itemLabel="Wii U" itemValue="WU" />
<p:ajax update="linha" />
</p:selectOneMenu>
<h:panelGroup id="linha">
<c:set var="marcaIsX1" value="#{pd.marca eq 'X1'}" />
<p:inputText value="#{pd.aparelho}" disabled="#{marcaIsX1}" />
<h:outputText value="Microsoft" rendered="#{marcaIsX1}" />
</h:panelGroup>
<p:commandButton value="X" />
</ui:repeat>
Note that I also removed the unused noSelectionOption="true" and moved the <h:panelGroup id="linha"> to wrap only the components which really need to be updated.

Dynamic navigation with parameter passing in JSF

I want to pass the "title" parameter in the following listing dynamicaly to another jsf Facelet, depending on the selection of the selectOneMenu. My first approach looks like this:
<h:form id="form">
<p:selectOneMenu value="#{exerciseEditorBean.selectedExerciseType}" >
<f:selectItem itemLabel="Multiple Choice Exercise" itemValue="MultipleChoiceExercise" />
<f:selectItem itemLabel="Vocabulary Test" itemValue="VocabularyTest" />
</p:selectOneMenu>
<h:outputText value="Enter Title of your Exercise: " />
<h:inputText id="title" value="#{exerciseEditorBean.exerciseTitle}" />
<h:commandButton value="Next" action="#{exerciseEditorBean.openEditor()}" />
</h:form>
The ExerciseEditorBean is ViewScoped.
The openEditor() function then decides by the selectedExerciseType attribute which Facelet to show next and returns something like "multipleChoiceEditor.xhtml".
How can I now pass the titel attribute to this Facelet?
I now use the f:ViewParam in the target servelet, which works well except, that "multipleChoiceEditor.xhtml?includeViewParams=true" does not work, but this is another issue. Thanks for the discussion!

Resources