How to make some button which can skip web required validation(but still I want to process all data, so immediate and so on cannot be true).
Important is that it must be universal. At the moment I am using in every required field condition with some request param. Code example below
<p:inputText value="#{cc.attrs.data.exampleData1}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{param['onlySave'] == null}"/>
<p:commandButton value="Zapisz zmiany"
action="#{cc.attrs.controller.save()}"
update="#form">
<f:param name="onlySave" value="true"/>
</p:commandButton>
This solution is fine cause I can in every page just add this param to button and it skips validation, but when my save button not making any redirect, in case of failed some java validation in save method, I am just adding some message without redirect and then I lost all required styles from inputs.
Is there any possibility to set onlySave param to null in save method when validation failed or maybe some better solutions?
Edit: Balus answer great, but with bean validation like:
#Pattern(regexp = "^([^0-9]*)$", message = "only non numbers")
String field;
It processes to bean all data beyond that field. The best would be ignore only required field property, not validation etc.
Edit2:
<tr>
<td class="label">
<p:outputLabel id="label" for="#{cc.attrs.componentId}" value="#{cc.attrs.label}"/>
</td>
<td class="value">
<cc:insertChildren/> --here component with componentId
</td>
</tr>
<tr class="errorMessage">
<td class="label"/>
<td class="value">
<p:message id="error" for="#{cc.attrs.componentId}" />
</td>
</tr>
Please see below modified code for required fields. You can use #{empty param.onlySave} for the fields which you want to skip the validation and as per your requirements.
<p:inputText value="#{cc.attrs.data.exampleData1}"
required="#{not empty param.onlySave}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{not empty param.onlySave}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{not empty param.onlySave}"/>
<p:commandButton value="Zapisz zmiany"
action="#{cc.attrs.controller.save()}"
update="#form">
<f:param name="onlySave" value="true"/>
</p:commandButton>
So far the best solution i figured out is:
//p:label and p:message with property for=someId for each input above
<p:inputText id="someId" value="#{cc.attrs.data.exampleData1}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{param['onlySave'] == null}"/>
<p:commandButton value="save only"
action="#{cc.attrs.controller.save()}"
update="#(.ui-message,.ui-outputlabel)">
<f:param name="onlySave" value="true"/>
</p:commandButton>
<p:commandButton value="accept button"
action="#{cc.attrs.controller.accept()}"
update="#form">
</p:commandButton>
The save button just updates only all errors and labels, so I am able to see converters errors etc, but I dont lost required styles on inputs. In this example I just lost red color of input borders.
If u re using * in labels for required fields, dont update .ui-outputlabel
I figured out a solution :
JSF page
<h:form id="form" prependId="false">
<c:if test="#{param['onlySave'] eq true}">
<c:set value="#{false}" target="#{myBean}" property="required"/>
</c:if>
<p:inputText value="#{myBean.required}"/>
<p:growl id="msgs" showDetail="true" />
<p:inputText id="data1" value="#{myBean.data1}"
required="#{myBean.required}" />
<p:inputText id="data2" value="#{myBean.data2}"
required="#{myBean.required}"/>
<p:inputText id="data3" value="#{myBean.data3}"
required="#{myBean.required}"/>
<p:commandButton value="Zapisz zmiany"
action="#{myBean.save}" />
</h:form>
Bean
#ManagedBean
#ViewScoped
public class MyBean implements Serializable{
private String data1, data2, data3;
private boolean required;
#PostConstruct
public void init(){
required = true;
}
public void save() {
System.out.println(data1+", "+data2+", "+data3);
required = false;
//FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Info","Saved"));
// FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("onlySave", "false");// FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("onlySave"));
}
// ... Getters & Setters
}
Related
I am attempting to create a dialog that will serve the purpose of both creating objects and updating them. So if I happen to click the 'new' button I will be presented a dialog containing empty fields to be filled or if I click on an edit button for an entry, that entry's data will presented in the dialog for update.
Following the example in the primefaces showcase for version 5.2, I can present the data in a read only outputText form, however when I change it to an inputText, the field remains empty. The following code is an example of what I have:
<h:form id="form">
<p:dataGrid id="guestList" var="guest" value="${guestList.guests}" columns="3" paginator="true" rows="20">
<f:facet name="header">
Guest List
</f:facet>
<p:panel>
<h:outputText value="${guest.name}" />
<br />
<h:outputText value="${guest.street}" />
<br />
<h:outputText rendered="#{guest.street2.length() gt 0}"
value="${guest.street2}" />
<h:panelGroup rendered="#{guest.street2.length() gt 0}">
<br />
</h:panelGroup>
<h:outputText value="${guest.city}, " />
<h:outputText value="${guest.state} " />
<h:outputText value="${guest.zipCode}" />
<p:commandButton update="#form:newGuestDetail" oncomplete="PF('newGuestDialog').show()" icon="ui-icon-edit" styleClass="ui-btn-inline">
<h:outputText styleClass="ui-icon ui-icon-edit" style="margin:0 auto;" />
<f:setPropertyActionListener value="#{guest}" target="#{guestList.selectedGuest}" />
</p:commandButton>
</p:panel>
</p:dataGrid>
<p:dialog header="#{guestList.hasSelected() ? 'Edit Guest' : 'New Guest'}" widgetVar="newGuestDialog" modal="true" showEffect="fade" hideEffect="fade">
<p:outputPanel id="newGuestDetail">
<h:outputText value="'#{guestList.selectedGuest.name}'"/>
<p:inputText id="guestName" value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}" pt:placeholder="Name"/>
<p:commandButton value="#{guestList.selectedGuest == null ? 'Create Guest' : 'Update Guest'}"/>
</p:outputPanel>
</p:dialog>
</h:form>
The hasSelected() method evaluates whether the selected guest is null or not, returning true if not null. The selectedGuest should be set when the commandButton is clicked so that an object is available for retrieval by the dialog, however, with tracers in the get/set for selectedGuest, I am not seeing the setter called with the above snippet. If I remove the inputText, then even though the hasSelected is still returning false, and thus the 'New Guest' is heading the dialog, the outputText is filled with a value.
I found this great post talking about the order of execution with respect to the action, action listener, etc., but don't think this quite my issue: Differences between action and actionListener.
So the ultimate question is why will my setter get called with the command button when I only have an outputText, but with an inputText, I never see it called in the log?
I appreciate the time and help anyone can provide.
Even if we fix your problem, this construct
<p:inputText value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}">
is not ever going to work. It needs to reference a model property, not an empty string.
You'd best just reuse the edit form and let the create button precreate an empty entity. This would simplify a lot in the view side. It'd be more easy if the entity has an #Id property which is only present when it's persisted in the database.
Here's a kickoff example:
<h:form id="entitiesForm">
<p:dataTable id="entitiesTable" value="#{bean.entities}" var="entity">
<p:column>#{entity.foo}</p:column>
<p:column>#{entity.bar}</p:column>
<p:column>
<p:commandButton id="edit" value="Edit"
process="#this" action="#{bean.edit(entity)}"
update=":entityDialog" oncomplete="PF('entityDialog').show()" />
<p:commandButton id="delete" value="Delete"
process="#this" action="#{bean.delete(entity)}"
update=":entitiesForm:entitiesTable" />
</p:column>
</p:dataTable>
<p:commandButton id="add" value="Add"
process="#this" action="#{bean.add}"
update=":entityDialog" oncomplete="PF('entityDialog').show()" />
</h:form>
<p:dialog id="entityDialog" widgetVar="entityDialog"
header="#{empty bean.entity.id ? 'New' : 'Edit'} entity">
<h:form id="entityForm">
<p:inputText id="foo" value="#{bean.entity.foo}" />
<p:inputText id="bar" value="#{bean.entity.bar}" />
<p:commandButton id="save" value="#{empty bean.entity.id ? 'Create' : 'Update'} entity"
process="#form" action="#{bean.save}"
update=":entitiesForm:entitiesTable" oncomplete="PF('entityDialog').hide()" />
</h:form>
</p:dialog>
With this #ViewScoped bean:
private List<Entity> entities; // +getter
private Entity entity; // +getter
#EJB
private EntityService entityService;
#PostConstruct
public void load() {
entities = entityService.list();
entity = null;
}
public void add() {
entity = new Entity();
}
public void edit(Entity entity) {
this.entity = entity;
}
public void save() {
entityService.save(entity); // if (id==null) em.persist() else em.merge()
load();
}
public void delete(Entity entity) {
entityService.delete(entity); // em.remove(em.find(type, id))
load();
}
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Keep p:dialog open when a validation error occurs after submit
I'm trying to show an updated value in confirm dialog message but I keep getting the old value as in this scenario
<h:form>
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<p:commandButton value="SUBMIT" actionListener="#{bean.submit()}">
<p:confirm header="Confirmation" message="Amount is : #{bean.object.amount} ?"/>
</p:commandButton>
<p:confirmDialog global="true">
<p:commandButton value="Yes" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
<p:commandButton value="No" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
</p:confirmDialog>
</h:panelgGroup/>
</h:form>
Bean code:
#ManagedBean(name="bean")
#ViewScoped
public class Bean implements Serializable {
private SomeClass object;
#PostConstruct
public void init(){
this.object = new SomeClass();
}
public void calculate(){
//do some colculation (not related to amount field in object)
}
public void submit(){
//submit to database
}
//getter setter
}
When I enter a value in amount, lets say 50. and update the cal component I get the updated amount in the outputtext "50". However, in the confirm button message I get amount as 0 instead 50. How can I show the updated value in the confirm message?
PS:
Primefaces-4.0
Take a look at the user guide of primefaces in the confirm dialog section, in the Non-Global mode the document mentioned:
Message facet is
useful if you need to place custom content instead of simple text.
While in the Global mode, I can't find similar sentences like that, and I've tried using the facet in Global mode and it doesn't work.So,
Do you really use this confirm dialog multiple times?
If not:
I suggest you take away the global parameter and change your code like this:
<h:form>
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<p:commandButton value="SUBMIT" actionListener="#{bean.submit()}" oncomplete="PF('confirmDlg').show()"/>
<p:confirmDialog header="Confirmation" widgetVar="confirmDlg">
<f:facet name="message">
<h:outputText value='Amount is : #{bean.object.amount} ?'/>
</f:facet>
<p:commandButton value="Yes" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
<p:commandButton value="No" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
</p:confirmDialog>
</h:panelGroup>
</h:form>
.
If so:
(You do use the confirm dialog multiple times and tired of writing several dialogs with same form but different message.)
I suggest you write a dialog on your own,and you can also change the message in the dialog from backing bean like what you did:
<h:form id="myForm">
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<ui:param name="message" value="Amount is :#{bean.object.amount}?" />
<p:commandButton value="SUBMIT" actionListener="#{bean.setMessage(message)}" action="#{bean.submit()}" update="myForm:myDialog" oncomplete="PF('myDlg').show()"/>
</h:panelGroup>
<p:dialog id='myDialog' widgetVar="myDlg" header="Confirmation" modal="true" resizable="false">
<h:panelGrid columns="3">
<h:panelGroup styleClass="ui-icon ui-icon-alert" style="float:right"/>
<h:outputText value="#{bean.message}"/>
<h:outputText/>
<h:outputText/>
<p:commandButton value="Yes" type="button" icon="ui-icon-check" oncomplete="PF('myDlg').hide()"/>
<p:commandButton value="No" type="button" icon="ui-icon-close" onclick="PF('myDlg').hide()"/>
</h:panelGrid>
</p:dialog>
</h:form>
p:confirm does not implement state saving, thus it loses its attributes' values after the first JSF lifecycle. It also evaluates EL only once at view build time.
I posted the solution in this answer.
I need to generate textboxes through a loop as follows.
<p:panel id="dataPanel" closable="true" toggleOrientation="horizontal" toggleable="true" header="Data">
<h:panelGrid id="dataPanelGrid" columns="3" cellpadding="5">
<c:forEach var="row" items="#{zoneChargeManagedBean.list}">
<p:outputLabel for="txtCharge" value="#{row[1]}"/>
<p:inputText id="txtCharge" value="#{row[2]}" converter="#{bigDecimalConverter}" onkeydown="return isNumberKey(event, this.value);" label="#{row[1]}" required="false" maxlength="45">
<f:validator validatorId="negativeNumberValidator"/>
<f:attribute name="isZeroAllowed" value="false"/>
<f:validator validatorId="bigDecimalRangeValidator"/>
<f:attribute name="minPrecision" value="1"/>
<f:attribute name="maxPrecision" value="33"/>
<f:attribute name="scale" value="2"/>
</p:inputText>
<p:message for="txtCharge" showSummary="false"/>
</c:forEach>
<p:commandButton id="btnSubmit" update="dataPanel messages" actionListener="#{zoneChargeManagedBean.insert}" icon="ui-icon-check" value="Save"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</h:panelGrid>
</p:panel>
The value of the given textbox is a type of BigDecimal from the database.
When the given command button is pressed, the values held by these textboxes should be retrieved from the corresponding JSF managed bean so that they can either be inserted or updated in the database.
It would be even better, if it is possible to retrieve the values of all of these text fields at once in some kind of collection (like java.util.List), when the given button is pressed.
<ui:repeate>, a render time tag works correctly but not <c:foreEach>, a view build time component (I can't clarify why) but in this particular case, I found <p:dataGrid> is more suitable. The XHTML has been modified accordingly as follows.
<p:panel id="dataPanel" rendered="#{zoneChargeManagedBean.renderedDataPanel}" closable="true" toggleOrientation="horizontal" toggleable="true" header="Data">
<p:dataGrid columns="3" value="#{zoneChargeManagedBean.list}" var="row" paginator="true" paginatorAlwaysVisible="false" pageLinks="10" rows="15">
<p:watermark for="txtCharge" value="Enter charge."/>
<p:tooltip for="lblCharge" value="Some message."/>
<p:column>
<p:outputLabel id="lblCharge" for="txtCharge" value="#{row[1]}"/><br/>
<p:inputText id="txtCharge" value="#{row[2]}" onkeydown="return isNumberKey(event, this.value);" converter="#{bigDecimalConverter}" label="#{row[1]}" required="false" maxlength="45">
<f:validator validatorId="negativeNumberValidator"/>
<f:attribute name="isZeroAllowed" value="false"/>
<f:validator validatorId="bigDecimalRangeValidator"/>
<f:attribute name="minPrecision" value="1"/>
<f:attribute name="maxPrecision" value="33"/>
<f:attribute name="scale" value="2"/>
</p:inputText>
<h:message for="txtCharge" showSummary="false" style="color: #F00;"/>
</p:column>
</p:dataGrid>
<p:commandButton id="btnSubmit" update="dataPanel messages" actionListener="#{zoneChargeManagedBean.insert}" icon="ui-icon-check" value="Save"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</p:panel>
The managed bean:
#Controller
#Scope("view")
public final class ZoneChargeManagedBean implements Serializable
{
#Autowired
private final transient ZoneChargeService zoneChargeService=null;
private ZoneTable selectedZone; //Getter and setter
private List<Object[]>list; //Getter and setter
private boolean renderedDataPanel; //Getter and setter
public ZoneChargeManagedBean() {}
public void ajaxListener() {
if(this.selectedZone!=null){
list=zoneChargeService.getZoneChargeList(this.selectedZone.getZoneId());
renderedDataPanel=true;
}
else {
renderedDataPanel=false;
}
}
public void insert() {
//Just do whatever is needed based on the list with new values which is retrieved when <p:commandButton> as shown in the given XHTML is clicked.
if(selectedZone!=null&&zoneChargeService.addOrUpdate(list, selectedZone)) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Message Summary", "Message"));
}
else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, "Message Summary", "Message"));
}
}
}
The service method as in the ajaxListener() method returns a list of type of an array of objects - List<Object[]>.
public List<Object[]>getZoneChargeList(Long id) {
return entityManager.createQuery("select w.weightId, w.weight, zc.charge from Weight w left join w.zoneChargeSet zc with zc.zoneTable.zoneId=:id order by w.weight").setParameter("id", id).getResultList();
}
I can't use the corresponding JPA criteria query which is intended because the with operator which doesn't seem to be supported by the JPA criteria API.
This method is invoked when an item from <p:selectOneMenu> is selected which is not covered in this question.
I have created a dynamic input field which changes depending on the item type.
<h:panelGrid columns="2" cellpadding="10">
<c:forEach items="#{tabVar.items}" var="itmVar">
<h:outputText value="#{itmVar.label}:" />
<c:if test="#{itmVar.isString}">
<p:inputText id="#{itmVar.id}" value="#{itmVar.value}" required="#{itmVar.isEditable}" disabled="#{itmVar.isEditable}" valueChangeListener="#{tabBean.processValueChange}" maxlength="100" size="75" immediate="true" onchange="form1.submit()"/>
</c:if>
<c:if test="#{itmVar.isDate}">
<p:calendar id="#{itmVar.id}" value="#{itmVar.value}" required="#{itmVar.isEditable}" disabled="#{itmVar.isEditable}" valueChangeListener="#{tabBean.processValueChange}" onSelectUpdate="form1.submit();"/>
</c:if>
<c:if test="#{itmVar.isDouble}">
<p:inputText id="#{itmVar.id}" value="#{itmVar.value}" required="#{itmVar.isEditable}" disabled="#{not itmVar.isEditable}" valueChangeListener="#{tabBean.processValueChange}" maxlength="100">
<f:validateDoubleRange minimum="#{itmVar.minDouble}" maximum="#{itmVar.maxDouble}" />
</p:inputText>
</c:if>
<c:if test="#{itmVar.isInteger}">
<p:inputText id="#{itmVar.id}" value="#{itmVar.value}" required="#{itmVar.isEditable}" disabled="#{not itmVar.isEditable}" valueChangeListener="#{tabBean.processValueChange}" maxlength="100">
<f:validateLongRange minimum="#{itmVar.minLong}" maximum="#{itmVar.maxLong}" />
</p:inputText>
</c:if>
</c:forEach>
</h:panelGrid>
Everything renders correctly, but when I change and submit the input values, then it does not get updated in the backing bean. How is this caused and how can I solve it?
#{tabBean.processValueChange} may not right. Its not possiable to use only 1 method for valueChangeListener for all value. Can u post your full code in ManagedBean ? is that on #SessionScope ? The right method for valueChangeListener may be like this:
public void saveStatus(ValueChangeEvent event) {
Integer newValue = (Integer) event.getNewValue();//this is for save Status
itmVar.setStatus(newValue);
}
If you want to save a serial of value, u have to create a serial of method :) good luck!
I'd like to change the "required" property of an InputText that is located within an ui:repeat, but I'm not able to access to the component from the ManagedBean:
<h:selectManyCheckbox id="required" value="#{test.required}"
layout="lineDirection" converter="javax.faces.Integer">
<f:ajax event="change" listener="#{test.update}" />
<f:selectItems value="#{test.selectable}"></f:selectItems>
</h:selectManyCheckbox>
<ui:repeat value="#{test.names}" var="name" id="repeat">
<h:panelGrid columns="3">
<h:outputLabel id="nameLabel">name:</h:outputLabel>
<h:inputText id="name" value="#{name}"
validator="#{test.validateName}" />
<h:message for="name"></h:message>
</h:panelGrid>
</ui:repeat>
I'm trying to use the findComponent method, but it does not work:
public void update(AjaxBehaviorEvent event) {
for(Integer i: selectable) {
UIViewRoot vr = FacesContext.getCurrentInstance().getViewRoot();
HtmlInputText input = (HtmlInputText)vr.findComponent("form:repeat:"+i+":name");
input.setRequired(required.contains(i));
}
}
The ui:repeat doesn't repeat the components in the view root, it repeats the component's output in the rendered HTML output.
There are several ways to achieve this properly. One of them is to use a value object instead and set the requireness there. E.g. a List<Item> wherein Item has the properties String name and boolean required.
<ui:repeat value="#{test.items}" var="item" id="repeat">
<h:panelGrid columns="3">
<h:outputLabel id="nameLabel">name:</h:outputLabel>
<h:inputText id="name" value="#{item.name}" required="#{item.required}" validator="#{test.validateName}" />
<h:message for="name"></h:message>
</h:panelGrid>
</ui:repeat>
There are more ways, but since the JSF version you're using and the functional requirement is unclear, it's only guessing which way is the most applicable in your case.