primefaces commandButton not set input field value in ui:repeat - jsf

I have list in view scoped bean. The #{repeatController.add} a new object to the list. It call the h:commandButton and the p:commandButton also.
My problem is, when I have a new line, typing into the "repeatName" field something, after press h:commandButton or p:commandButton, they have different working.
The h:commandButton push the new field value to the bean and it appeared after refresh the form and the new line also.
The p:commandButton not push the new field value to the bean. After refresh the form the new line appeared, but the previously typed content of the "repeatName" field is empty.
I think the h:commandButton working fine, the p:commandButton is not working fine.
The "noRepeatName" field value always set with h:commandButton and p:commandButton.
Steps and result with h:commandButton:
push the button (create new line) more times.
type to the "noRepeatName" field
type to the the first "repeatName" field
push the button
Result: after refresh, previously typed content of the field appeared.
Steps and result with p:commandButton:
push the button (create new line) more times.
type to the "noRepeatName" field
type to the the first "repeatName" field
push the button
Result: after refresh, previously typed content of the "noRepeatName" field appeared, but the first "repeatName" is empty.
Do I miss something?
Why doesn't set the value of the first "repeatName" filed to the bean like with h:commandButton?
I use primefaces 6.2.10, jsf 2.2.18 (oracle) and spring boot 2.0.6.
JSF code
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form id="repeatForm">
<h:commandButton value="plus" id="addJsf">
<f:ajax event="click" immediate="true" render="repeatForm" execute="repeatForm"
listener="#{repeatController.add}"/>
</h:commandButton>
<p:commandButton icon="fa fa-plus" actionListener="#{repeatController.add}" immediate="true" id="add"
process="repeatForm" update="repeatForm"/><br/>
<p:inputText value="#{repeatData.name}" id="noRepeatName">
<f:validateLength minimum="30"/>
</p:inputText><br/>
<ui:repeat value="#{repeatData.products}" var="product" varStatus="productStatus">
First: #{productStatus.first}"; Last: #{productStatus.last}; Index: #{productStatus.index}<br/>
<p:inputText value="#{product.name}" id="repeatName">
<f:validateLength minimum="20"/>
</p:inputText><br/>
</ui:repeat>
</h:form>
</h:body>
</html>
Java bean
#Named
#Scope("view)
public class RepeatData {
private List<Product> products = new ArrayList<>();
private String name;
public List<Product> getProducts() {
return products;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Product
public class Product {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Controller
#Named
#Scope("request")
public class RepeatController {
#Autowired
private RepeatData repeatData;
public void add() {
repeatData.getProducts().add(new Product());
}
}

Related

How to reuse Primefaces datatable with different data in different browser tabs?

My application has a query param in the url which is used to render different data using the same xhtml (all dynamic content) in a datatable.
Scope of the bean is session scope, the datatable renders all data, and has lots of input elements which open different dialogs.
If I open another browser tab sending a different query param, the datatable renders perfectly, however if I go back to the first tab, all commandlinks won't invoke the actions and the whole application will start to act very erratically.
According to my research this is because I changed the data in the datatable, I tried naming it with dynamic ids, dynamic widget names, but nothing seems to work.
<f:metadata>
<f:viewParam name="param" value="#{moduleBean.param}"/>
<f:viewAction action="#{moduleBean.setup}" />
</f:metadata>
<c:set var="module" value="#{moduleBean.param}" />
<p:dataTable id="#{module}-dataTable" value="#{moduleBean.model[module]}" var="data">
<p:commandLink action="#{moduleBean.openModuleDetails}" update=":#{module}-searchDialog" oncomplete="PF('#{module}-searchWidget').show();">
<f:param name="module" value="#{module}" />
<f:param name="dataRow" value="#{data.dbKey}" />
</p:commandLink>
</p:dataTable>
#Named
#javax.faces.view.ViewScoped
public class ModuleBean implements Serializable {
private String param;
public void setup() throws IOException {
this.model.put(this.param, new LazyDataModel(this.param));
}
public Map<String, LazyDataModel> getModel() {
return model;
}
}
This builds all the expected html with all correct ids in each tab, however JSF is still not processing the action inside the commandlink. Needless to say, if I stick to only one browser tab everything works perfectly.
Sometimes it starts working after clicking twice in the link, but going back and forth between the browser tabs will eventually always crash it.
Adding an action listener to the commandlink didnt fix it either.
Any suggestions on how to make JSF treat the same datatable as different entities on the same page but with different parameters ?
Without knowing more about the underlying bean - if you place your moduleBean in #SessionScoped this would be the expected behavior. The session (and session scoped beans) are shared between browser tabs. So you cannot rely on the underlying values from two different tabs.
Try changing to #RequestScoped/#ViewScoped for the backing values of the table data.
Here is a complete solution that works, note that this uses PrimeFaces 6.2, Apache Commons and Lombok;
#Data
#Named
#ViewScoped
public class TableTestBackingBean implements Serializable {
private int param;
#Inject
private PersonsBean personsBean;
public void onClicked() {
System.out.println("Clicked fine!");
}
public List<Person> getPersons() {
return personsBean.getPersons()[param];
}
}
#Data
#ApplicationScoped
public class PersonsBean {
#Data
#AllArgsConstructor
public class Person {
private String firstName;
private String lastName;
private int age;
}
private List<Person> persons[];
#PostConstruct void init() {
persons = new List[4];
for (int j = 0; j < 4; j++) {
persons[j] = new ArrayList<>();
for (int i = 0; i < 30; i++) {
final String firstName =
RandomStringUtils.randomAlphanumeric(10);
final String lastName =
RandomStringUtils.randomAlphanumeric(10);
final int age = RandomUtils.nextInt(0, 120);
persons[j].add(new Person(firstName, lastName, age));
}
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">
<f:metadata>
<f:viewParam name="param" value="#{tableTestBackingBean.param}"/>
</f:metadata>
<h:head>
<title>Test</title>
</h:head>
<h:body>
<p:dataTable value="#{tableTestBackingBean.persons}" var="t">
<p:column headerText="First Name"><h:outputText value="#{t.firstName}" /></p:column>
<p:column headerText="Last Name"><h:outputText value="#{t.lastName}" /></p:column>
<p:column headerText="Age"><h:outputText value="#{t.age}" /></p:column>
</p:dataTable>
<h:form>
<p:commandButton action="#{tableTestBackingBean.onClicked}" value="Click Me!" />
</h:form>
</h:body>
</html>
This uses an application scoped bean for the table data, keeping it completely static. This works without a hitch and the table renders the data differently based on the parameter passed in param.

How do you update the page size of a PrimeFaces datatable dynamically?

I am trying to update the page size of a PrimeFaces datatable dynamically, after the datatable is displayed on the page but I can't seem to be able to do that. I am using a lazy loaded datatable if that matters... putting an EL expression in the rows attribute and doing a table refresh does not work and causes the paginator to return no data.
Any ideas if this is a bug and how to fix it?
Thanks
You need not refresh or update the datatable. Use EL expression in rowsPerPageTemplate attribute of <p:dataTable> and after loading datatable just change the rows number.
<p:dataTable value="#{managedBean.users}" var="user" lazy="true" paginator="true" rows="10" rowsPerPageTemplate="10,25 #{fn:length(managedBean.users)}">
And include this xmlns:fn="http://java.sun.com/jsp/jstl/functions" in page.
What exactly are you trying to do? This works for me (Mojarra 2.1.26, PrimeFaces 3.5):
#ManagedBean
#ViewScoped
public class Bean {
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
private List<Item> items;
public Bean() {
Item item1 = new Item("item1");
Item item2 = new Item("item2");
items = Arrays.asList(item1, item2);
}
public List<Item> getItems() {
return items;
}
private int tableSize = 1;
public int getTableSize() {
return tableSize;
}
public void actionSwitchSize() {
tableSize = tableSize == 1 ? 2 : 1;
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<h:form>
<p:dataTable id="table" var="item" value="#{bean.items}"
rows="#{bean.tableSize}" paginator="true">
<p:column>
#{item.name}
</p:column>
</p:dataTable>
<p:commandButton value="switch size" action="#{bean.actionSwitchSize}"
update="table" />
</h:form>
</h:body>
</html>

Insert primefaces dataTable rows based on p:inputText fields

I would like a sugestion how implement this case. (using jsf 2.0 and primefaces 3.5)
Have about 10 primefaces inputTexts
Have one primefaces dataTable
Have an entity named Contact with 10 properties like (name,description,etc...)
How the best way to add rows in dataTable after typing in the inputTexts and clicking on button. ? (I cant persist data on DB. Only add the typed new data in the dataTable new row)
thanks,
so here's what you'd do (10 times) to get your result :
Start with specifying whichever entity bean you desire, we'll stay generic here to make this useful for as many good souls :
package pack;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class Entity {
private String entityProperty ;
public String getEntityProperty() {
return entityProperty;
}
public void setEntityProperty(String entityProperty) {
this.entityProperty = entityProperty;
}
public Entity(String e) {
this.entityProperty = e ;
}
}
You'll have then to use this Entity in a bean (which I called Bean). We do that to fill a list which the dataTable we'll iterate to create its rows. Here's the bean :
package pack ;
import java.util.ArrayList;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class Bean {
private String property ;
private ArrayList<Entity> list ;
public ArrayList<Entity> getList() {
return list;
}
public void setList(ArrayList<Entity> list) {
this.list = list;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
public Bean() {
list = new ArrayList<Entity>();
}
public void showInDataTable(){
list.add(new Entity(property));
}
}
Lastly, we come to the presentation page, a tour on primefaces site usually gives you an idea about what to use and how :
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>StackOverflow</title>
</h:head>
<h:body>
<h:form>
<p:inputText value="#{bean.property}" />
<p:commandButton value="show in dataTable" action="#{bean.showInDataTable}" update="dataTable"/>
<p:dataTable id="dataTable" value="#{bean.list}" var="o">
<p:column>
<h:outputText value="#{o.entityProperty}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
So you adapt this to your needs, it should flow nicely once you determine which properties your Entity equivalent must handle (that's to say, in your case, 9 more properties for the bean and for the entity and an adjusted constructor for those).
Best of luck.
Try following
Make List of Contact class as table value.
In the actionListener method of commandButton, create new Contact class and set it's property with appropriate inputText.
Append that newly created object to List
In commandButton : process inputTexts, update Datatable
Which will not required to store intermediate result into database

JSF Ajax not rendering until a page refresh [duplicate]

This question already has an answer here:
Ajax update/render does not work on a component which has rendered attribute
(1 answer)
Closed 7 years ago.
Here is my view:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Welcome</title>
</h:head>
<h:body>
<h:form prependId="false" id="myForm">
<h3>Please enter your name and password.</h3>
Name: <h:inputText id="name" value="#{user.name}"/>
Password: <h:inputSecret id="password" value="#{user.password}"/>
<h:commandButton value="Login">
<f:ajax execute="name password" render="greeting"/>
</h:commandButton>
<h:outputText id="greeting" value="Welcome + #{user.name}" rendered="#{user.nameRendered()}"/>
</h:form>
</h:body>
</html>
Any my User.java :
#Named
#SessionScoped
public class User implements Serializable {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean nameRendered() {
return this.name != null;
}
}
So when I type something in Name field and click submit, I expect to see outputText with id"greeting" because, user.nameRendered() should return true.
However, I will need to refresh the page after I submit name to see it. Why might be the reason? Why does it require a page refresh? How can I do it without a page refresh?
You can't refresh components that are not rendered in the JSF tree, you need to encalsulate the output inside a component that will always exists :
<h:panelGroup id="greeting">
<h:outputText value="Welcome + #{user.name}" rendered="#{user.nameRendered()}"/>
</h:panelGroup>
More info :
Why do I need to nest a component with rendered some in another component

How to add a message to a specific component from JSF backing bean

I have an h:inputText and an h:message connected to it:
<h:inputText id="myText" value="#{myController.myText}" />
<a4j:outputPanel>
<h:message for="myText" .../>
</a4j:outputPanel>
I want to send a message to it from java, in a manner like:
FacesContext.getCurrentInstance().addMessage(arg0, arg1);
which is sent to h:messages, but to a specific id in a specific form.
How can I do this? (Without implementing validation bean or validation method - meaning without throwing validation exception).
You need to provide the so called client id, which you'll find on UIComponent.
The following is a quick example of how to use this.
Consider the following bean:
#ManagedBean
#RequestScoped
public class ComponentMsgBean {
private UIComponent component;
public UIComponent getComponent() {
return component;
}
public void setComponent(UIComponent component) {
this.component = component;
}
public String doAction() {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(component.getClientId(), new FacesMessage("Test msg"));
return "";
}
}
being used on the following Facelet:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<h:form>
<h:outputText id="test" value="test component" binding="#{componentMsgBean.component}"/>
<h:message for="test"/>
<h:commandButton value="click me" action="#{componentMsgBean.doAction}" />
</h:form>
</h:body>
</html>
This will add a Faces message with content "Test msg" for the outputText component used in the example.
Another way to do that is: give an ID to the form, like "form1", then, when add the message, the clientId is "form1:test".

Resources