I have prime faces form that have set of input elements and finally button let's call it i_BTN which is not the submit button and datatable let's call it f_DT.
My logic is to fill set of elements let's is call these elements :
inpt_1 and inpt_2 not all elements and when click on i_BTN it is add new record in f_DT.
I am using partial submit in i_BTN to to that logic cause i don't to submit all fields.
Button do its task fine and new record is added in f_DT
My big deal is :
when i am add ajax in f_DT to catch rowSelect the SelectEvent object pass with null value.
with full submit SelectEvent is passed with value.
<h:form id="generalForm">
<p:inputText label="full_submit_input_one" id="inpt1"/>
<p:inputText label="full_submit_input_two" id="inpt2"/>
<h:panelGrid columns="4" id="partial_submit_Panel">
<p:inputText label="partial_submit_input_one" id="inpt3"/>
<p:inputText label="partial_submit_input_two" id="inpt4"/>
</h:panelGrid>
<p:dataTable id="itemDT" var="item" value="#{itemView.items}" selectionMode="multiple"
selection="#{itemView.selectedItems}"
rowKey="#{fee.Id}">
<p:ajax event="rowSelect"
listener="#{dtFeesView.onRowSelect}" />
<p:column headerText="Input three">
<h:outputText value="#{fee.inpt3}" />
</p:column>
<p:column headerText="Input four">
<h:outputText value="#{fee.inpt4}" />
</p:column>
</p:dataTable>
<p:commandButton value="Full Submit" actionListener="#{itemView.add}"/>
<p:commandButton value="Partial Submit" actionListener="#{itemView.insertRecord}" process=":generalForm:partial_submit_Panel"/>
#ManagedBean(name="itemView")
#ViewScoped
public class ItemView{
private ItemModel selectedItems[];
// getters and setters for selectedItems
private List<ItemModel> items;
// getters and setters for items
public void add(){
// add item to i.e database
}
public void insertRecord(){
// add itemModels to items list
}
public void onRowSelect(SelectEvent event) {
ItemModel model =(ItemModel)event.getObject();
// model is null in case of process with value :generalForm:partial_submit_Panel
//model is not null in case of process with value generalForm "submit full form"
}
}
please help.
regards.
Related
I have a problem debugged for all half day. I still could not figure it out. Basically, I use datatable expandable feature to show some extra options for each row. User could check some or none of them, then user click on update button to update database. So one row will have many options.
<f:selectItems value="#{adminBean.allTabNames}" /> is to use collect users' selected options, then managed bean will save them into database once user clicks update.
Then problem is that public void setSelectedTabsNames(List<String> selectedTabsNames) {
this.selectedTabsNames = selectedTabsNames;
} method is called several times with expected values or null values(empty list). The values are passed randomly, sometimes there are no values.
View:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form id="form1">
<p:growl id="growl" showDetail="true"/>
<p:dataTable var="user" value="#{adminBean.users}" scrollable="false"
>
<p:ajax event="rowToggle" listener="#{adminBean.onRowToggle(user.id)}" update=":form:tabView:form1:growl" />
<f:facet name="header">
All Users
</f:facet>
<p:column style="width:2%">
<p:rowToggler />
</p:column>
<p:column headerText="First Name">
<h:outputText value="#{user.firstname}" />
</p:column>
<p:column headerText="Last Name">
<h:outputText value="#{user.lastname}" />
</p:column>
<p:column headerText="Password">
<h:outputText value="#{user.password}" />
</p:column>
<p:column headerText="Active">
<h:outputText value="#{user.active}" />
</p:column>
<p:column headerText="Last Login">
<h:outputText value="#{user.timestamp}" />
</p:column>
<p:column headerText="Notes">
<h:outputText value="#{user.notes}" />
</p:column>
<p:rowExpansion>
<h:panelGrid id="display" columns="1" cellpadding="4">
<h:outputText value="Tabs: " />
<p:selectManyCheckbox id="grid" value="#{adminBean.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
</h:panelGrid>
<br/>
<p:commandButton value="Update" id="submit" actionListener="#{adminBean.updateTabsForUser(user.id)}" ajax="true" />
</p:rowExpansion>
</p:dataTable>
</h:form>
Managed Bean:
setSelectedTabsNames(List selectedTabsNames)
package org.userlogin.view;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import org.userlogin.db.entity.FopsUser;
import org.userlogin.service.UserService;
#ManagedBean
#ViewScoped
public class AdminBean implements Serializable {
private static final long serialVersionUID = -9002632063713324598L;
private List<FopsUser> users;
private List<String> selectedTabsNames;
private List<String> allTabNames;
private UserService us;
public AdminBean() {
us = new UserService();
users = us.getAllUsers();
allTabNames = us.getAllTabs();
}
public List<FopsUser> getUsers() {
return users;
}
public void setUsers(List<FopsUser> users) {
this.users = users;
}
public void setSelectedTabsNames(List<String> selectedTabsNames) {
this.selectedTabsNames = selectedTabsNames;
}
public List<String> getSelectedTabsNames() {
return selectedTabsNames;
}
public List<String> getAllTabNames() {
return allTabNames;
}
public void setAllTabNames(List<String> allTabNames) {
this.allTabNames = allTabNames;
}
public void updateTabsForUser(Long uid) {
us.updateTabsUser(selectedTabsNames);
}
public void onRowToggle(Long uid) {
//set current selected user
us.setCurrent(uid);
this.selectedTabsNames = us.getTabNamesByUserId(uid);
}
}
---------------update-------
Remove the nested 'form', but still not working. I found the the issue is not affecting the last row of data table. Suppose I have three rows in data table, the setters are called multiple times and set to null at last time when I manipulate the first two rows. But for the last row, the setter is still called multiple times. The last call sets the expected value. Now I just add
public void setSelectedOptions(List<String> selectedOptions) {
if (selectedOptions == null || selectedOptions.size() == 0) {
return;
}
this.selectedOptions = selectedOptions;
}
It is still ugly ...
------------update----------
<p:selectManyCheckbox id="grid" value="#{user.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
Should design like this: put selectedTabsNames into User object. But still not working. since I have this ajax submit button, this requests each selectedTabsNames got called with empty list passed in.
<p:rowExpansion>
<h:panelGrid id="display" columns="1" cellpadding="4">
<h:outputText value="Tabs: " />
<p:selectManyCheckbox id="grid" value="# {user.selectedTabsNames}"
layout="pageDirection" >
<f:selectItems value="#{adminBean.allTabNames}" />
</p:selectManyCheckbox>
<p:commandButton value="Update" id="submit" ajax="true" />
</h:panelGrid>
<br/>
</p:rowExpansion>
----------------update with my own solution (not graceful one, but works) -----
Every time an ajax buttom has been clicked, the whole data table is updated. That means each setSelectedItem method will be called with expected value or empty value. I don't know how to change that.
So I modify my save() method called from ajax button with following logic:
public void save(Long userId, List<String> selectedItem) {
for (User user: users) {
if (user.getId() == userId) {
//update selectedItem in db for this user.
} else {
// read selectedItems in db
// update selectedItem in user object.
}
}
}
When the ajax event is fired, all the input elements in the form are sent. That means that all the selectManyCheckbox (one for each row) are sent. That's why setSelectedTabsNames is called several times.
You have to change how you have designed your implementation. One way woud be to store the selected options in the FopsUser object, so you could do value="#{user.selectedTabsNames}":
<p:selectManyCheckbox id="grid" value="#{user.selectedTabsNames}"
layout="pageDirection" >
**<f:selectItems value="#{adminBean.allTabNames}" />**
</p:selectManyCheckbox>
This way the selected tabs for each row are stored separately.
I may be wrong, but I don't think rowToggle event is the kind of ajax event that can handle row-level parameters. Think about it this way: var="user" is a row-iteration level variable, available for each row in the datatable. The rowToggle event on the other hand is a single level tag, applicable to the entire table as one component. So there probably isn't a reliable way for the datatable to know which row you're referring to when you use
adminBean.onRowToggle(user.id), it'll just select the last row that was rendered
A more effective way to get hold of the details of the row that was toggled is using the ToggleEvent listener in the backing bean, where you don't have to pass a variable:
public void onRowToggle(ToggleEvent te){
User theSelectedUser = (User)te.getData();
int id = theSelectedUser.getId();
}
In your view, you'll now have:
<p:ajax event="rowToggle" listener="#{adminBean.onRowToggle}" update=":form:tabView:form1:growl"/>
I have a primefaces datatable. I populate it from the database. One of the fields is a boolean represented by a checkbox. I want that if I check or uncheck the checkbox, that I can save the change back to the database.
I have tried passing the current value of the row to the managed bean to save, but the new value of the checkbox isn't reflected in the current row object. How can I get the change into the current row object so I can successfully save the change to the DB?
Here is what I am doing now... I have tried to provide just what is needed. If it is too much information or too little, let me know. Thanks.
#ManagedBean(name = "itemManagerBean")
#ViewScoped
public class ItemManagerBean implements Serializable {
...
public ArrayList<Item> getAllItemsForUser() {
List list = ecf.findByPartyId(user.getPartyId());
ArrayList<Item> itemList = new ArrayList<>(list);
return (itemList);
}
...
public String saveItem(Item item){
System.out.println(item.toString());
ecf.updateRecord(item);
return (null);
}
}
//item class
public class Item {
private BigInteger itemId;
private String name;
priave boolean saleable; //database column is not null
//getters and setters
}
//facelet
<h:form>
<p:dataTable id="id_itemList"
var="item"
value="#{itemManagerBean.allItemsForUser}" >
<p:column headerText="ID">
<h:outputText value="#{item.itemId}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{item.name}" />
</p:column>
<p:column headerText="Saleable" >
<p:selectBooleanCheckbox value="#{item.saleable}" />
</p:column>
<p:column width="15" >
<p:commandButton id="id_saveRowButton" icon="ui-icon-disk"
title="Save" action="#{itemManagerBean.saveItem(item)}"/>
</p:column>
</p:dataTable>
</h:form>
You need to create a selectedItem property in ItemManagerBean and update its value when the user clicks on the commandButton:
In ItemManagerBean
private Item selectedItem;
// getter and setter
In the xhtml page
<p:column width="15" >
<p:commandButton id="id_saveRowButton" icon="ui-icon-disk"
title="Save" action="#{itemManagerBean.saveItem}">
<f:setPropertyActionListener value="#{item}" target="#{itemManagerBean.selectedItem}" />
</p:commandButton>
</p:column>
(Note that you don't need to pass item through saveItem method. Modify saveItem in the managed bean in order to make it work with selectedItem instead of accepting an input item).
Links:
example in the PrimeFaces showcase
Passing parameter to JSF action
BalusC blog
I have a data table with with two columns- Title and Action
Title is populated from a list in a managed bean and for each title in the list the datatable has a button called Confirm under Action column.
When the user clicks on the Confirm button, a dialog is displayed with additional information and another button called Submit.
If the user hits the Submit button inside that dialog a variable confirmDate is set in the backing bean, of the confirmDate is not null, I need to disable the particular Confirm button under the Action column in the main data table. Right now if I disable it, all the Confirm button is getting disabled. How do I disable only the selected confirm button. Really appreciate your help on this.
main data table
<h:panelGrid id="notificationList" width="100%">
<h:panelGroup >
<p:dataTable var="dt" value="#
{myBean.listAll}" id="titles" rowKey="#{dt.id}">
<f:facet name="header">
<h:outputText value = "Title List"/>
</f:facet>
<p:column headerText ="Title">
<h:outputText value="#{dt.title}"/>
</p:column>
<p:column headerText="Action">
<p:commandButton id="nID"
value="Confirm"
oncomplete="myDialog.show();"
process="#this"
disabled= "#{not empty dt.confirmDate}
update="#form">
<f:setPropertyActionListener value="#{dt}" target="#
{myBean.selectedTitle}"/>
</p:commandButton>
</p:column>
</p:dataTable>
</h:panelGroup>
</h:panelGrid>
Hard to say with your code, maybe all your dt objects which you retrieve via listAll are identical objects. How do you set up the list?
Anyhow this should work (simplified):
<p:dialog widgetVar="dlg">
<p:commandButton value="Submit" action="#{myBean.updateNotificationConfirmDate}" oncomplete="dlg.hide()"
update="notificationList" />
</p:dialog>
<p:dataTable id="notificationList" var="dt" value="#{myBean.tableData}">
<p:column>
<p:commandButton value="Confirm" process="#this" disabled="#{!empty dt.confirmDate}" update="#form"
oncomplete="dlg.show();">
<f:setPropertyActionListener value="#{dt}" target="#{myBean.selectedTitle}" />
</p:commandButton>
</p:column>
</p:dataTable>
And the backing bean (whatever your DT is :)):
#ManagedBean
#ViewScoped
public class MyBean {
private List<DT> tableData = new ArrayList<DT>();
private DT selectedTitle;
public MyBean() {
tableData.add(new DT(1L, "title1", null));
tableData.add(new DT(2L, "title2", null));
tableData.add(new DT(3L, "title3", null));
tableData.add(new DT(4L, "title4", null));
}
public DT getSelectedTitle() {
return selectedTitle;
}
public void setSelectedTitle(DT selectedTitle) {
this.selectedTitle = selectedTitle;
}
public List<DT> getTableData() {
return tableData;
}
public void updateNotificationConfirmDate() {
selectedTitle.setConfirmDate(Calendar.getInstance());
}
}
Im trying to implement the modification of an entity in JSF using Primefaces.
My main view, which lists the users is the following:
<p:growl id="growlEditUnit" showDetail="true" life="12000" />
<p:dialog id="dialogEditUnit" header="Edit Unit" widgetVar="editUnitDialog" showEffect="fade" hideEffect="fade" resizable="false" >
<ui:include src="editUnit.xhtml" />
</p:dialog>
<h:form id="form2">
<p:dataTable id="units" var="unit" value="#{unitController.unitsOfLoggedInUser}" >
<f:facet name="header">
Click Edit or Delete after selecting a unit to modify or remove it
</f:facet>
<p:column headerText="Code">
#{unit.unitCode}
</p:column>
<p:column headerText="Name">
#{unit.unitName}
</p:column>
<p:column headerText="Semester" >
#{unit.semester}
</p:column>
<p:column headerText="Academic Year">
#{unit.academicYear}
</p:column>
<p:column headerText="Twitter Username">
#{unit.twitterUsername}
</p:column>
<p:column headerText="Actions">
<p:commandButton id="editButton" value="Edit" action="#{unitController.setCurrent(unit)}" update=":dialogEditUnit" oncomplete"editUnitDialog.show()" />
</p:column>
</p:dataTable>
</h:form>
This view lists all the data correctly. However, when I press the current, my aim is to set the current attribute of the managed bean (code listed below) with the unit based on the button clicked. After this I try to update the edit dialog, so it will be filled with the values of that unit, and then make it visible using the oncomplete attribute. However, it seems that the managed been method setCurrent(unit) is never called when clicking the edit button. Subsequently the dialog is shown empty. Can someone help me with what am I doing wrong?
I am posting the managed bean code too.
#ManagedBean(name = "unitController")
#ViewScoped
public class UnitController implements Serializable {
private Unit current;
private List<Unit> unitsOfLoggedInUser;
#ManagedProperty(value="#{loginController.checkedUser}")
private Lecturer lecturer;
#EJB
private web.effectinet.ejb.UnitFacade ejbFacade;
#EJB
private web.effectinet.ejb.LecturerFacade lecturerFacade;
public UnitController() {
}
#PostConstruct
public void init(){
if (lecturer.getLecturerId() == null)
unitsOfLoggedInUser = null;
else
unitsOfLoggedInUser = (List<Unit>) lecturer.getUnitCollection();
}
public List<Unit> getUnitsOfLoggedInUser() {
return unitsOfLoggedInUser;
}
public void setCurrent(Unit current) {
this.current = current;
}
public Lecturer getLecturer() {
return lecturer;
}
public void setLecturer(Lecturer lecturer) {
this.lecturer = lecturer;
}
The action attribute of the commandButton is rendered without information on the value of the unit variable.
To pass the unit to the action method of your managed bean, then you need to pass the ID of unit in an <f:param> child tag of commandButton.
<p:commandButton action="#{managedBean.actionMethod}" ........>
<f:param name="unitid" value="#{unit.id}" />
</p:commandButton>
From your action method you can get the request parameter by the name from the ExternalContext and this will give you the ID of the unit that the commandButton was pressed for in your dataTable.
I have a h:datatable showing a list of rows, and the fields of each row are input fields.
I render an "Add Row" button before the table, and a "Remove Row" button on each row of the table.
The baking bean is viewScoped, and the buttons add/remove elements from the java list in the backing bean, and then return to the same view.
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
Everything works ok but one thing: the values of the input fileds are cleared. I thought that the view kept the values beacuse the bean is viewScoped.
How can I achieve adding/removing rows without triggering validations and keeping the values that were already typed by the user in the form?
My view:
<h:form>
<h:commandButton value="Añadir Fila" immediate="true" action="#{tablaController.addRowAction}" />
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" immediate="true" action="#{tablaController.removeRowAction(fila)}" />
</h:column>
</h:dataTable>
</h:form>
My backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
boolean exito = this.lista.remove(f);
return "";
}
...
}
UPDATE --> MY SOLUTION:
I write here my solution if someone is interested.
The problem is that I use immediate="true" to skip validations, but this makes to skip the update_model_values too, so that the values entered by the user in the form are lost after clicking the add/remove buttons and re-redenring the page.
As I use "JSR-303 bean validation", my solution was to skip validations using the f:validateBean to enable/disable them. Depending on the button I click, if I want the validations to execute, I enable the bean validation (for example in a "submit" button), and if I want to skip them, I disable bean validation (like in the add/remove row buttons). But anyway the update_model_values always executes, so the values are not lost.
Here's the view:
<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}">
<h:commandButton value="Añadir Fila" action="#{tablaController.addRowAction}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" action="#{tablaController.removeRowAction(fila)}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Submit" action="#{tablaController.saveData}" />
</f:validateBean>
</h:form>
The backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("fila "+i);
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
this.lista.remove(f);
return "";
}
...
public String saveData () {
...
//processes the valid data
//for example, calls to a service method to store them in a database
...
return "";
}
...
}
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
immediate="true" is the wrong tool for the job. It should be used to prioritize validation, not to enable/disable validation. The difference is rather huge as you encountered yourself.
You want to trigger validation conditionally. In case of e.g. required="true" that'd be as easy as
<h:inputText ... required="#{saveButtonPressed}" />
where #{saveButtonPressed} evaluates true when the save button is pressed. E.g. when its client ID is present in request parameter map.
In case of JSR 303 bean validation, that'd be a matter of
<f:validateBean disabled="#{not saveButtonPressed}">
<h:inputText ... />
</f:validateBean>
or with OmniFaces <o:validateBean> which allows controlling that on a per-command basis.
<h:commandButton id="add" ...>
<o:validateBean disabled="true" />
</h:commandButton>
I had exactly the same problem. In short, you can NOT use immediate for action that update data table(UIData) or facelet repeat. Short explanation:submitted values are not kept for re-display if inputs in UIData do not go through validation. Long explanation can be found here: long explanation and a related bug in Mojarra