How to dynamically add new row to p:dataTable without validating the form? - forms

I'm developing a form for adding/editing product prices with JSF and PrimeFaces. A single product can have multiple prices depending on volume which is shown in a <p:dataTable>.
The backing bean:
#ManagedBean
#ViewScoped
public class ProductBean {
protected Product product;
protected List<ProductPrice> productPrices;
public void addNewPrice() {
ProductPrice productPrice = new ProductPrice();
productPrice.setPrice(new BigDecimal(0));
this.productPrices.add(productPrice);
}
// ...
}
The Facelet page:
<h:form id="productForm">
<p:inputText value="#{productBean.product.name}" required="true">
<f:ajax event="blur" render="nameMessage" />
</p:inputText>
<p:message id="nameMessage" for="name" />
<p:dataTable id="pricesList" ...>
</p:dataTable>
<p:commandButton value="Add another price" update="pricesList" action="#{productBean.addNewPrice()}" />
<p:commandButton value="Submit" action="#{productBean.submit}" />
</h:form>
The first button "Add another price" does, what it is supposed to do: Adding a new row to "pricesList". But only if form is valid (form is invalid, if product-name is not set).
My problem is, that I am having two commandButtons for the form, but I don't know how to get my wished functionallity without a commandButton. I tried a lot of ways: Changing the "Add another price" to a standard <p:button> with ajax-functionality; doesn't work because of buttons' outcome. I tried "type=button" for this button, but in this case simply nothing happens.
Are there any suggestions have to achieve my wished functionality? It is not necessary to have a button solving my problem.

The <p:commandButton> submits and processes by default the entire form. This will indeed validate all input fields. You can control this with the process attribute which thus defaults to #form. In your particular case, you could just use #this so that only the command button's own action is invoked.
<p:commandButton value="Add another price" process="#this" update="pricesList" action="#{productBean.addNewPrice()}" />

what's wrong with using p:commandButton to add rows dynamically?
If i undersatnd your question right, you obviously need a request to your managed bean in order to add your new row information into your datatable list. you could always go for p:commandLink if you are not comfortable with p:commandButton. and for editing the row data you could use p:rowEditor with p:datatable.
check out the showcase example for datatable row editing
hope this helps :)

Related

Ignore custom validation, but not the required="true" depending on button pressed

I am using JSF and I want to validate a form.
In the form is a text field that is validated by required="true" and a validator method.
<h:inputText
required="true" requiredMessage="Please enter a topic"
validator="#{eventController.validateTopic}" />
To submit the form I have two buttons. When clicking on the first, it should be only validate if the field is empty. By the second one the custom validation should be additionally invoked.
Is this possible?
First turn that validation method into a true Validator implementation.
#FacesValidator("topicValidator")
public TopicValidator implements Validator {}
Then you can use it in a <f:validator> which supports disabled attribute.
<h:inputText ...>
<f:validator validatorId="topicValidator" disabled="..." />
</h:inputText>
To let it check if a certain button is pressed, just check the presence of its client ID in the request parameter map.
<h:inputText ...>
<f:validator validatorId="topicValidator" disabled="#{empty param[secondButton.clientId]}" />
</h:inputText>
...
<h:commandButton binding="#{secondButton}" ... />
Note: do absolutely not bind it to a bean property! The above code is as-is. You should only guarantee that the EL variable #{secondButton} is unique in the current view and not shared by another component or even a managed bean.
See also:
How to let validation depend on the pressed button?
How does the 'binding' attribute work in JSF? When and how should it be used?

Is it possible to define a form for a single row in a panelgrid?

Is it somehow possible to have a form for a single row in a panelGrid? If I just put the specific columns in a form-Tag they are (of course) rendered in one single column of my parent panelGrid.
Is there a possibility to solve this problem? It does not matter if a solution use the jsf-tag or the primefaces-tag
I am using Mojarra 2.1.26 and Primefaces 4.0
use partial process/update.
if your requirement is to send only data in specific row (and not sending other http parameters, even if they are not processed) add partialSubmit feature:
<h:form>
<p:panelGrid id="grid">
<p:row id="row1">
<p:column>
<p:inputText value="#{someBean.someProperty}"/>
</p:column>
<p:column>
<p:inputText value="#{someBean.anotherProperty}"/>
</p:column>
</p:row>
<!-- other rows -->
</p:panelGrid>
<p:commandButton action="#{someBean.someAction}" process="#this row1"
update="grid" partialSubmit="true" value="submit"/>
</h:form>
this behave the same (almost) as having a form just for row1.
note that you have to update grid because p:panelgrid renders its child components on its own.
however your desired behavior (exactly) is not possible using plain html either.

Tapestry 5 custom component in form - access during validation

A have problem with accessing my custom components (which are used as parts of the form).
Here is the story:
I have dynamic form which have few modes of work. Each mode can be selected and loaded into form body with AJAX. It looks like that (template):
<t:form t:id = "form">
<p class= "calcModeTitle">
${message:modeLabel}: <select t:id="modeSelect"
t:type="select"
t:model="modesModel"
t:value="selectedMode"
t:blankOption="NEVER"
t:encoder="modeEncoder"
t:zone = "modeZone"
/>
</p>
<div class="horizontal_tab">
<t:errors/>
</div>
<t:zone t:id="modeZone" id="modeZone" t:update="show">
<t:if test="showCompany">
<t:delegate to="block:companyBlock" />
</t:if>
<t:if test="showPersonal">
<t:delegate to="block:personalBlock" />
</t:if>
<t:if test="showMulti">
<t:delegate to="block:multiBlock" />
</t:if>
</t:zone>
<t:block id="companyBlock">
<t:modes.CompanyMode t:id="company"/>
</t:block>
<t:block id="personalBlock">
<t:modes.PersonalMode t:id="personal" />
</t:block>
<t:block id="multiBlock">
<t:modes.MultiMode t:id="multi" />
</t:block>
<div class="horizontal_tab">
<input type="submit" value="${message:submit_label}" class="submitButton thickBtn"/>
</div>
</t:form>
AJAX works pretty well and form changes accordingly the "modeSelect" state. But i run into problem when submitting the form. I have in class definition hooks for components placed as:
//----form elements
#Component(id = "form")
private Form form;
#InjectComponent
private CompanyMode company;
#InjectComponent
private PersonalMode personal;
#InjectComponent
private MultiMode multi;
where *Mode classes are my own components, containing form elements and input components. I planned to get access to them during validation, and check values supplied by user with form, but when I am trying to reach anything from them I've got nullPointerException - it seems that component are not initialized in my class definition of form. On the other hand form component is injected properly (I am able to write some error for example). I am a bit lost now. How to properly inject my components to class page containing the form?
Dynamic forms in tapestry are a bit complicated. Tapestry passes a t:formdata request parameter which contains the serialized form entities. This is then used serverside in the POST to re-hydrate initial form state. This must be kept up-to-date with what the client sees.
If you want to add dynamic content to a form via ajax, you will need to use the FormInjector. You might want to take a look at the source code for the AjaxFormLoop to see an example.
If you want to render hidden form fragments and make them visible based on clientside logic, you can use the FormFragment
From tapestry guide:
A block does not normally render; any component or contents you put
inside a block will not ordinarily be rendered. However, by injecting
the block you have precise control over when and if the content
renders.
Try to use here either "t:if" or "t:delegate".
Something like this:
<t:zone t:id="modeZone" id="modeZone" t:update="show">
<t:delegate to="myBlock" />
</t:zone>
<t:block t:id="companyBlock">
<t:modes.CompanyMode t:id="company"/>
</t:block>
<t:block t:id="personalBlock">
<t:modes.PersonalMode t:id="personal" />
</t:block>
<t:block t:id="multiBlock">
<t:modes.MultiMode t:id="multi" />
</t:block>
java:
#Inject
private Block companyBlock, personalBlock, multiBlock;
public Block getMyBlock(){
if (getShowCompany()) return companyBlock;
if (getShowPersonal()) return personalBlock;
return multiBlock;
}

Execute other form field value in JSF ajax

Consider the following JSF 2.x markup:
<h:form id="form1">
<h:inputText id="input" value="#{testBacking.input}"/>
</h:form>
<h:form id="form2">
<h:commandButton value="go" action="#{testBacking.go()}">
<f:ajax execute="#all" render="output"/>
</h:commandButton>
<h:outputText id="output" value="#{testBacking.input}"/>
</h:form>
The action method as follows:
public void go() {
System.out.println("go() is called");
System.out.println("input: "+ input);
}
The input value does not submitted to the server upon clicking the button.
Are there any ways to submit the input value to the server (while keeping the input in a different form)?
If you can only submit fields from the same form, then what is the different between the following two?
<f:ajax execute="#all" render="output"/>
<f:ajax execute="#form" render="output"/>
A quick search of jsf execute=#all vs execute=#form yields some results:
JSF: Execute values of multiple forms
What is <f:ajax execute="#all"> really supposed to do? It POSTs only the enclosing form
In essence, the JSF processing works ok but HTML only sends the form that contains the ajax (I suspect HTML specifies a separate request for each form).

JSF2.0: variable list of custom component

Is there any way of using JSF2.0 in connection with variable lists of components? For example, lets say I have list o people that I would like to edit. They are presented on the page as list of components PersonEditor, which allow changing person data. Each editor is associated with single Person element. In order for this to work I need to perform following steps:
On initial request:
Get list of people
For each person create PersonEditor and associate it with Person object.
Fill editor's data.
On user action:
When user changes values and presses Save, data is processed by backing bean.
I can either fill editor with data from list of people or bind it to the backing bean, but not at the same time, so I am stuck.
I tried
people.xhtml
<ui:render value="#{bean.people}" var="person">
<example:personEditor person="#{person}"/>
</ui:render>
where personEditor.xhtml:
a) proper association with person object, but no connection to backing bean
<h:form>
<h:outputText value="#{cc.attr.person.name}"/>
<h:commandButton name="Save" actionListener="editorBean.save">
<f:ajax execute="#form" render="#form"/>
</h:commandButton>
</h:form>
b) no association with person object, but there is connection to backing bean - there is no way to pass that person to the backing bean
<h:form>
<h:outputText value="#{editorBean.name}"/>
<h:commandButton name="Save" actionListener="editorBean.save">
<f:ajax execute="#form" render="#form"/>
</h:commandButton>
</h:form>
If I had each editor on separate page, I could pass the person id as url parameter (either using f:param or f:attribute) and initialize it accordingly.
Is there any solution to this problem?
Hm, wondering why nobody answered this so far... Check this out:
http://balusc.blogspot.com/2006/06/communication-in-jsf.html
So your code would look something like this:
<h:form>
<h:outputText value="#{cc.attr.person.name}"/>
<h:commandButton name="Save" actionListener="#{editorBean.save}">
<f:ajax execute="#form" render="#form"/>
<f:setPropertyActionListener target="#{editorBean.editedPersonId}" value="#{cc.attr.person.id}" />
</h:commandButton>
</h:form>
and upon calling editorBean.save the attribute will contain the id of the person edited (or you could pass the person object itself).