How to make a conditionally required element un-required based on condition - jsf

In my application I have a check box that sets a variable in my controller, and a selectOneMenu that will only render based on the value of said variable. Per #BalusC's answer here I put the same condition in the required attribute because when it's selected, it needs to be required. My issue is that once it's rendered, when I un check the box, the select one menu doesn't go away because it's now also required. Before I added the condition to the required attribute, the select one menu would hide/go away as expected.
xhtml:
<h:panelGroup rendered="#{kaizenEntry.isDealer()}">
<div class="ui-g-4 ui-lg-3">
<p:outputLabel value="Is This a Customer Shop Site?" for="shopSiteBox" />
</div>
<div class="ui-g-4 ui-lg-3">
<p:selectBooleanCheckbox id="shopSiteBox" value="#{kaizenEntry.checked}" onchange="waitThenHideModal()" disabled="#{kaizenEntry.disabled}" process="#form">
<f:ajax render="shopSitePanel" execute="shopSitePanel" />
</p:selectBooleanCheckbox>
</div>
<h:panelGroup id="shopSitePanel" layout="block">
<div class="ui-g-4 ui-lg-3">
<p:outputLabel rendered="#{kaizenEntry.checked}" value="Shop Site" for="shopSitesDropdown" />
</div>
<div class="ui-g-8 ui-lg-3">
<p:selectOneMenu rendered="#{kaizenEntry.checked}"
required="#{kaizenEntry.checked}"
disabled="#{kaizenEntry.disabled}"
id="shopSitesDropdown"
styleClass="categoryClass"
style="width:150px"
value="#{kaizenEntry.kaizenMain.shopSite}"
filter="true"
filterMatchMode="startsWith">
<f:selectItem itemLabel="--Select--" itemValue="#{null}"/>
<f:selectItems value="#{kaizenEntry.shopSiteList}" var="c"
itemLabel="#{c.storeNumber} - #{c.addressLine1} - #{c.city} #{c.st}, #{c.zip}"
itemValue="#{c.storeNumber} - #{c.addressLine1} - #{c.city} #{c.st}, #{c.zip}" />
</p:selectOneMenu>
</div>
</h:panelGroup>
</h:panelGroup>
Controller:
private boolean checked;
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
In short, I am trying to make the select one menu go away when the box is unchecked, like it did before I added the condition to the required attribute, but it won't because it's now required. How can I accomplish this?

Its your execute="shopSitePanel" that is causing the "Required" trigger to happen. For the SelectOne you just want to show or hide the value not to process it also. Change your code to this...
<p:selectBooleanCheckbox id="shopSiteBox" value="#{kaizenEntry.checked}" onchange="waitThenHideModal()" disabled="#{kaizenEntry.disabled}" process="#form">
<p:ajax update="shopSitePanel" process="#this" />
</p:selectBooleanCheckbox>

Related

Primefaces make button enable on entering text

I have a primefaces input text area and a primefaces button. I want the button to be enabled only when there is any value entered in the text area.
<p:inputTextarea id="dumpnotes" rows="10" cols="90" value="#{postProcessedDump.keyedinContent}" style="color: #000000" styleClass="inputarea" />
<p:commandButton value="Save" actionListener="#{dumpController.saveDumpNotesContent}" update="dumpnotes" oncomplete="PF('dumpNotesSaveSuccessDialog').show();"/>
<p:inputTextarea id="dumpnotes" rows="10" cols="90" value="#{postProcessedDump.keyedinContent}" style="color: #000000" styleClass="inputarea">
<p:ajax event="keyup" update="saveButton" />
</p:inputTextarea>
<p:commandButton id="saveButton" value="Save" actionListener="#{dumpController.saveDumpNotesContent}" update="dumpnotes" oncomplete="PF('dumpNotesSaveSuccessDialog').show();" disabled="#{empty postProcessedDump.keyedinContent}" />
Edit (based on your comment):
Try to add global="false" to not trigger ajaxStatus <p:ajax event="keyup" global="false" update="saveButton" />. Depending on your PrimeFaces version, you may need to strip out the event name and only write <p:ajax global="false" update="saveButton" />
The questions seems to be rather JavaScript related so I would try the following approach.
First I would define a JavaScript function which checks whether to enable the commandButton or not:
function validateInput() {
if(document.getElementById('dumpnotes').value == '') {
document.getElementById('button').disabled = true;
} else {
document.getElementById('button').disabled = false;
}
}
So you just have to give commandButton a id (e.g. id="button") and use onkeyup event at inputTextarea like this:
<p:inputTextarea id="dumpnotes" onkeyup="validateInput()" ... />
I hope this is what you were looking for.

Omit validation for p:selectOneMenu, for Ajax requests

I have a Jsf page with a fragment with <p:selectOneMenu/> (Prime faces) and an Ajax associated with it. It have the default select item "--- Select One ---" and others items that were created dynamically.
This field is required, so if users submit the form without select, the page show a error message.
The problem occurs when I select one of this others options and go back selecting "--- Select One ---" again. Then the page shows the required field message, even before I submit the form. I try different ways of immediate in <p:ajax> and <p:selectOneMenu> tags but none of them has the expected behavior.
The <p:messages> is declared as below:
-- list.xhtml
<p:messages id="messages" autoUpdate="true" closable="true" escape="false" />
<.... include fragment.xhtml ....>
And the fragment:
-- fragment.xhtml
<p:selectOneMenu id="selectTipoCarro"
value="#{carroBean.carro.tipoCarroEnum}"
required="true">
<f:selectItems value="#{carroBean.listaSelectItemTipoCarroInclusao}" />
<p:ajax update="outputInicioVigenciaWrapper outputLabelCalendarInicioVigenciaWrapper"
listener="#{carroBean.aoMudarTipoCarro}" />
</p:selectOneMenu>
<h:panelGroup id="outputLabelCalendarInicioVigenciaWrapper">
<h:outputLabel id="outputLabelCalendarInicioVigencia"
rendered="#{carroBean.edicaoDataInicioVigenciaDisponivel}"
for="calendarInicioVigencia">
<span>*
#{labels['carro.inicio.vigencia']}: </span>
<p:calendar id="calendarInicioVigencia"
value="#{carroBean.carro.dataInicioVigencia}"
showOn="button"
pattern="dd/MM/yyyy" mask="true"
required="true"/>
</h:outputLabel>
</h:panelGroup>
<h:panelGroup id="outputInicioVigenciaWrapper">
<h:outputLabel for="outputInicioVigencia"
rendered="#{not carroBean.edicaoDataInicioVigenciaDisponivel}">
<span aria-live="polite">
<h:outputText id="outputInicioVigencia"
value="#{carroBean.carro.dataInicioVigencia}"
styleClass="dataFormat"
</h:outputText>
</span>
</h:outputLabel>
</h:panelGroup>
private SelectItem obterSelectItemSelecione() {
SelectItem selectItem = new SelectItem("", "-- Select One --");
return selectItem;
}
private void preencherListaSelectItemTipoCarro(List<SelectItem> select, TipoCarroEnum[] tiposCarrosConsiderados) {
select.clear();
select.add(obterSelectItemSelecione());
for (TipoCarroEnum tipoCarro : tiposCarrosConsiderados) {
select.add(new SelectItem(tipoCarro, tipoCarro.getNome()));
}
}
public void aoMudarTipoCarro() {
getCarro().setDataInicioVigencia(carroService.obterProximaDataInicioVigenciaDisponivel(getCarro().getTipoCarroEnum()));
}
That's the expected behaviour. When adding a p:ajax tag to your p:selectOneMenu you make the value be processed everytime the user changes the input, so it will be validated and rejected if you mark it as required. My favourite workaround for this cases is to include a request param in the button to submit the whole form and check for it in the required attribute. That's it:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:comp="http://java.sun.com/jsf/composite/comp"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<p:messages autoUpdate="true" />
<p:selectOneMenu value="#{val}"
required="#{param['validate']}">
<p:ajax event="change" />
<f:selectItem itemLabel="None" noSelectionOption="true" />
<f:selectItem itemLabel="val1" itemValue="val1" />
</p:selectOneMenu>
<p:commandButton value="Submit" ajax="false">
<f:param name="validate" value="true" />
</p:commandButton>
</h:form>
</h:body>
</html>
See also:
Conditionally skip JSF validation but perform model updates
Explanation
This happens because you have a p:messages component with autoUpdate set to true and you have attached p:ajax to your selectOneMenu so anytime your value changes, p:messages is updated. Therefore, due to the use of required="true" an error messages is shown as soon as you have selected "--- Select One ---".
Solution
Add ignoreAutoUpdate="true" to your p:ajax or
Remove autoUpdate="true" if not necessary

How to disable UI components based on value in selectOneMenu

With the value I get from my combobox, I need to unlock 1 of the elements (inputText) and block the other:e.g
if selecOnMenu value is "A" then inputText with idA is unlocked and the other's blocked
xhtml code:
<h:form prependId="false">
<p:selectOneMenu id="enviado" value="#{combo.valor}">
<f:ajax event="change" execute="enviado" render="saida" />
<f:selectItem itemValue="#{null}" itemLabel="Selecione um item" />
<f:selectItems value="#{combo.disponiveis}" />
</p:selectOneMenu>
<br></br>
<h:outputText id="saida" value="opção: #{combo.valor}" />
<div>
<p> Opção A -- Falta implementar</p>
<p:inputText id="idA" value="Insira texto aqui" disabled="??????" />
</div>
<div>
<p>Opção B -- Flta implementar</p>
<p:inputText id="idB" value="Insira texto aqui" disabled="??????" />
</div>
</h:form>
</h:body>
</html>
UPDATE:
I make it work now using on disable = "#{combo.valor != 'idB'}"
now only need to make the ajax work with it
UPDATE 2:
Well, when using <p:inputText> didn't work, but with <h:inputText> works fine.
UPDATE 3:
I just need to use the right ajax element, i was using jsf just trying to re-render a primefaces element, with the primeFaces ajax worked
Thank you

<a4j:commandbutton> action property isn't called after adding <h:message> and ajax event to a required inputtext

Inside a <a4j:outputPanel> I have a disabled inputtext that displays Authors from a List<Author> that belongs to the class DocumentBean. I have also a <h:selectOneMenu> that displays names of Authors. When an Author from the menu is selected the Author is added to the List<Author> I mentioned above, and a new disabled inputtext appears.
Here's the code described above:
Autor:
<a4j:outputPanel id="teste">
<a4j:repeat value="#{insertDocController.docController.documentBean.authorList}" var="author">
<br />
<h:inputText value="#{author.name}" disabled="true" />
<br />
<a4j:commandButton type="submit" action="#{insertDocController.removeAutor(author.uri)}"
value="Remover" render="teste" />
</a4j:repeat>
<br />
<h:selectOneMenu id="chooseAuthor" value="#{insertDocController.selectedAuthorUri}">
<f:selectItem noSelectionOption="true" itemLabel="selecione" itemValue=""/>
<f:selectItems value="#{insertDocController.authorValues}" var="author"
itemValue="#{author.uri}" itemLabel="#{author.name}"/>
</h:selectOneMenu>
<a4j:commandButton type="submit" action="#{insertDocController.addAuthor()}"
value="Inserir" render="teste" />
<br />
</a4j:outputPanel>
Here's the addAuthor() from insertDocController:
public void addAuthor() {
if(this.selectedAuthorUri != null) {
AuthorBean a = new AuthorBean();
a.setUri(this.selectedAuthorUri);
a.setName(this.authMapper.searchNameByAuthorUri(this.selectedAuthorUri));
this.docController.getDocumentBean().addAuthor(a);
}
}
On that same xhtml page there's an inputtext. Everything was working properly, when the inputtext was like this:
Title: <h:inputText id="input"
value="#{insertDocController.docController.documentBean.title}">
</h:inputText>
But stopped working properly since I set the inputtext to be required and added a message to it, like this:
Title: <h:inputText id="input"
value="#{insertDocController.docController.documentBean.title}"
required="true" requiredMessage="Campo Obrigatorio">
<f:ajax execute="#this input" render="message" event="blur"/>
</h:inputText>
<h:message for="input" id="message" style="color:red"/>
After I changed the title inputtext, when I choose an Author on the <h:selectedOneMenu> it simply doesn't call the action method addAuthor() from the <a4j:commandbutton> inside the <h:selectedOneMenu>.
(That's the line with the action method that isn't called - It was extracted from the above code I gave you at first):
<a4j:commandButton type="submit" action="#{insertDocController.removeAutor(author.uri)}"
value="Remover" render="teste" />
If I turn the inputtext as it was before it starts to work again.
What may be the problem? Thank you!
You need to specify the execute attribute.
Delete Author
<a4j:commandButton type="submit" action="#{insertDocController.removeAutor(author.uri)}"
value="Remover" render="teste" execute="#this">
</a4j:commandButton>
For the add author button
<a4j:commandButton type="submit" action="#{insertDocController.addAuthor()}"
value="Inserir" render="teste" execute="#this, chooseAuthor">
</a4j:commandButton>
Hope it helps.

h:selectOneMenu labels not changing on a4j rerender

I have an h:selectOneMenu set up that looks something like this:
<f:view>
<h:form id="tehForm">
<h2>Header</h2><br/>
<a4j:outputPanel id="msgPanel" ajaxRendered="true">
<h:messages styleClass="message"/>
</a4j:outputPanel>
<a4j:outputPanel id="mainPanel" ajaxRendered="true"><br/>
Select an item:<br/>
<h:selectOneMenu id="itemMenu" value="#{bean.itemId}">
<f:selectItem itemValue="-1" itemLabel="Please Select..."/>
<s:selectItems value="#{bean.item}" itemValue="#{item.id}" var="item" label="#{item.name}"/>
<a4j:support event="onchange" action="#{bean.selectItem}"/>
</h:selectOneMenu>
<rich:spacer width="10px"/>
<a4j:commandLink value="Create New" action="#{bean.createNew}"
rendered="#{bean.selectedItemId != 0}"/>
<h:outputText rendered="#{bean.selectedItemId gt -1}" value="Item Name: "/><br/>
<h:inputText rendered="#{bean.selectedItemId gt -1}" value="#{bean.selectedItem.name}" maxlength="50" size="75"/><br/><br/>
<a4j:commandButton value="Save New" action="#{bean.save}" rendered="#{bean.selectedItemId == 0}"/>
<a4j:commandButton value="Save Changes" action="#{bean.save}" rendered="#{bean.selectedItemId gt 0}" oncomplete="jsRerender();" />
<a4j:jsFunction name="jsRerender" rerender="mainPanel"/>
</a4j:outputPanel>
</h:form>
</f:view>
When creating new items, the new item does show up in the drop-down, but if I change the "name" attribute of my item and save, the label doesn't change to the new name until after the next request, despite the data in the bean having changed.
So I worked around it by forcing a second call to rerender again when saving changes is complete. The trouble is, this rerenders the messages panel as well, so I nuke any messages that may have been displayed. Using limitToList="true" in the a4j:jsFunction has the same effect as not calling it.
I need suggestions; either a new target for the rerender function, or another way of approaching the problem. Thanks in advance!
Try removing the oncomplete javascript and using reRender="mainPanel":
<a4j:commandButton value="Save Changes"
action="#{bean.save}"
rendered="#{bean.selectedItemId gt 0}"
reRender="mainPanel" />
In your version I think that "Save Changes" button without reRender attribute will rerenders all the page, thus refreshing the messages.

Resources