Re-evaluate required expression after validation failed - primefaces

I have a form with some required fields depending on a selectOneMenu, like the following:
<p:selectOneMenu id="myList" value="#{myBean.selectedItem}">
<p:selectItems value="#{myBean.myItems}" />
<p:ajax listener="#{myBean.myList_change}"
process="myList field1 field2 field3"
update="field1 field2 field3" />
</p:selectOneMenu>
<p:inputNumber id="field1" required="true" />
<p:inputNumber id="field2" required="#{myBean.selectedItem gt 1}" />
<p:inputNumber id="field3" required="#{myBean.selectedItem gt 2}" />
The first time I push the submit button, without fill the required fields:
<p:commandButton id="mySubmit" action="#{myBean.myAction}" />
I get the validation errors, then if I change the selectOneMenu value the required expression will no longer be evaluated.
For example, if I submit the form with selectedItem equals to 3 I get all the validation errors, then I submit the form with selectedItem equals to 1 and primefaces still requires all the three fields as mandatory.
I tried to add a resetInput to the button:
<p:resetInput target=":myForm" />
Rather than the immediate="true" to the selectOneMenu, without any success.
Any idea, please?
Note: The PrimeFaces version is 6.2
PS: In the image, just the first field is required, but should required all the elements.
Following the complete minimal reproducible example:
The xhtml file (test.xhtml):
<?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>Example</title>
</h:head>
<h:body bgcolor="white">
<h:form>
<p:messages showDetail="true" />
<p:selectOneMenu id="myList" value="#{myBean.selectedItem}">
<f:selectItem itemLabel="1" itemValue="1" />
<f:selectItem itemLabel="2" itemValue="2" />
<f:selectItem itemLabel="3" itemValue="3" />
<p:ajax listener="#{myBean.myList_change}"
process="myList field1 field2 field3" update="field1 field2 field3" />
</p:selectOneMenu>
<p:inputNumber id="field1" required="true" decimalPlaces="0"
value="#{myBean.field1}" />
<p:inputNumber id="field2" required="#{myBean.selectedItem gt 1}"
decimalPlaces="0" value="#{myBean.field2}" />
<p:inputNumber id="field3" required="#{myBean.selectedItem gt 2}"
decimalPlaces="0" value="#{myBean.field3}" />
<p:commandButton actionListener="#{myBean.submit}" update="#form" />
</h:form>
</h:body>
</html>
The bean (MyBean.java):
package com.mkyong.common;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "myBean")
#SessionScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final String STRING_EMPTY = "";
private Long selectedItem;
private String field1, field2, field3;
public Long getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(final Long selectedItem) {
this.selectedItem = selectedItem;
}
public String getField1() {
return field1;
}
public void setField1(final String field1) {
this.field1 = field1;
}
public String getField2() {
return field2;
}
public void setField2(final String field2) {
this.field2 = field2;
}
public String getField3() {
return field3;
}
public void setField3(final String field3) {
this.field3 = field3;
}
public void myList_change() {
final long value = selectedItem.longValue();
if (value < 1) {
setField1(STRING_EMPTY);
}
if (value < 2) {
setField2(STRING_EMPTY);
}
if (value < 3) {
setField3(STRING_EMPTY);
}
}
public void submit() {
}
}
In the web.xml you should set the welcome-page:
<welcome-file-list>
<welcome-file>faces/test.xhtml</welcome-file>
</welcome-file-list>

This question initially was sort of strange, weird since it contained some illogical behaviour that could, like OP stated, not be solved with a p:resetInput or a resetValues="true" attribute on the p:ajax.
Compliments to #Alessandro for being responsive on the comments by initially creating a [mcve] and later on in the chat. Thanks for that, rewarding in comparison to some other people that fail to see the value of a [mcve] and being active in replying.
The first thing I did was change some illogical things in the code that might not be related
The type in the backingbean for selectedItem from a String to an int since that is what it effectively was.
Change the fields from String to int's too since they are with a p:inputNumber
Set the fields to null instead of empty String on a change of the select.
Java code:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "myBean")
#SessionScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private int selectedItem;
private Integer field1, field2, field3;
public int getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(final int selectedItem) {
this.selectedItem = selectedItem;
}
public Integer getField1() {
return field1;
}
public void setField1(final Integer field1) {
this.field1 = field1;
}
public Integer getField2() {
return field2;
}
public void setField2(final Integer field2) {
this.field2 = field2;
}
public Integer getField3() {
return field3;
}
public void setField3(final Integer field3) {
this.field3 = field3;
}
public void myList_change() {
if (selectedItem < 1) {
setField1(null);
}
if (selectedItem < 2) {
setField2(null);
}
if (selectedItem < 3) {
setField3(null);
}
}
public void submit() {
}
}
In the xhtml I
Removed the field1 field2 field3 from the process attribute since the seemed useless (submission takes place on the 'submit', no ajax submit needed).
Also removed them from the update attribute (the change of a field becoming required after a change does not need an update)
Changed the actionListener on the p:commandButton to an `action
XHTML 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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Example</title>
</h:head>
<h:body bgcolor="white">
<h:form id="myForm">
<p:messages showDetail="true" />
<p:selectOneMenu id="myList" value="#{myBean.selectedItem}">
<f:selectItem itemLabel="1" itemValue="1" />
<f:selectItem itemLabel="2" itemValue="2" />
<f:selectItem itemLabel="3" itemValue="3" />
<p:ajax listener="#{myBean.myList_change}"
process="myList"/>
</p:selectOneMenu> <br/>
<p:inputNumber id="field1" value="#{myBean.field1}" required="true" decimalPlaces="0" />
<p:inputNumber id="field2" value="#{myBean.field2}" required="#{myBean.selectedItem gt 1}" decimalPlaces="0" />
<p:inputNumber id="field3" value="#{myBean.field3}" required="#{myBean.selectedItem gt 2}" decimalPlaces="0" />
<p:commandButton value="submit" action="#{myBean.submit}" update="#form"/>
</h:form>
</h:body>
</html>
And then for me it started 'working'. In the chat, it became ovbious that OP had the fixed list of fields in the process and update attributes for a specific reason.
In the update attribute so when the select was changed from e.g. 3 to 2, the 3rd field could be cleared (set in the bean), requiring an 'upate' to make it empty.
In the process attribute so when the select was changed to e.g. 3, the 2nd field (not set/cleared in the bean) would be submitted AND updated. If it was not in the process attribute, the original value from the bean would be put back in, effectively overriding the value the user might have typed in.
But this combination was the cause of weird behaviour, since if something is processed, it is validated too (in this case related to something being required or not). Having three empty fields, setting the select to 3 and submitting all three fields will fail since 2 are empty but the '3' won't be put in the model either then. I would have suspected the resetValues to help out here too but it did not (does not for me either). But what OP effectively wanted is to conditionally update an input field. The condition for this is already in the bean and you can simply add the update of the specific field that changes there too
public void myList_change() {
if (selectedItem < 1) {
setField1(null);
}
if (selectedItem < 2) {
setField2(null);
PrimeFaces.current().ajax().update("myForm:field2");
}
if (selectedItem < 3) {
setField3(null);
PrimeFaces.current().ajax().update("myForm:field3");
}
}
There is totally no need for the field1, 2 and 3 to be in either the process or update attribute and all works as required (pun intended)

Related

Why does selectBooleanCheckbox send me to the bottom of the page on click?

I am using Primefaces, and in my xhtml file, I have two "selectBooleanCheckbox" locations, and whenever I click them they send me to the bottom of the page. I checked the tags and all I have is an id and a value.
Could there be something on the Java backend that could cause it and if so is there something I could look out for?
Here is the xhtml side of it:
<p:outputLabel for="HasRoleAdmin" value="Admin: " />
<p:selectBooleanCheckbox id="HasRoleAdmin" value="#{UserMgt.newadminrole}"/>
<h:message for="HasRoleAdmin" style="color:red"/>
<p:outputLabel for="HasRoleUser" value="User: " />
<p:selectBooleanCheckbox id="HasRoleUser" value="#{UserMgt.newuserrole}"/>
<h:message for="HasRoleUser" style="color:red"/>
On the java side....
public boolean isNewadminrole() {
return newadminrole;
}
public void setNewadminrole(boolean Newhasroleadmin) {
newadminrole = Newhasroleadmin;
}
public boolean isNewuserrole() {
return newuserrole;
}
public void setNewuserrole(boolean Newuserrole) {
newuserrole = Newuserrole;
}

Why does 'p:ajax update' fail to update a p:tree?

I want to produce the result that whenever a tree node is expanded any previously expanded sibling node is collapsed.
Below are my page and my bean. The onNodeExpanded method is invoked when a node is expanded; the System.out statements produce the expected results. However, the node upon which setExpanded(false) is executed remains expanded on the page.
I added a commandButton so that I could force an update of the tree. Pressing it results in the page properly displaying the node that was previously collapsed by the ajax event listener.
The Page:
<!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:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>PrimeFaces Tree: Ajax Update Problem</title>
</h:head>
<h:body>
<h3>PrimeFaces Tree: Ajax Update Problem</h3>
<h:form>
<p:tree id="tree" value="#{problemController.root}" var="node" dynamic="true" orientation="horizontal">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
<p:ajax event="expand" listener="#{problemController.onNodeExpanded}" update="tree" />
</p:tree>
<h:commandButton value="Update" immediate="true">
<f:ajax render="tree" />
</h:commandButton>
</h:form>
</h:body>
</html>
The Bean:
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import org.primefaces.event.NodeExpandEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
#Named
#ViewScoped
public class ProblemController implements Serializable {
private static final long serialVersionUID = 1L;
private TreeNode root;
#PostConstruct
public void init() {
root = new DefaultTreeNode("Root", null);
TreeNode node0 = new DefaultTreeNode("Node 0", root);
TreeNode node1 = new DefaultTreeNode("Node 1", root);
TreeNode node00 = new DefaultTreeNode("Node 0.0", node0);
TreeNode node01 = new DefaultTreeNode("Node 0.1", node0);
TreeNode node10 = new DefaultTreeNode("Node 1.0", node1);
node1.getChildren().add(new DefaultTreeNode("Node 1.1"));
node00.getChildren().add(new DefaultTreeNode("Node 0.0.0"));
node00.getChildren().add(new DefaultTreeNode("Node 0.0.1"));
node01.getChildren().add(new DefaultTreeNode("Node 0.1.0"));
node10.getChildren().add(new DefaultTreeNode("Node 1.0.0"));
root.getChildren().add(new DefaultTreeNode("Node 2"));
}
public TreeNode getRoot() {
return root;
}
public void onNodeExpanded(NodeExpandEvent event) {
TreeNode expandedNode = event.getTreeNode();
System.out.printf("Expanded %s\n", expandedNode);
TreeNode parent = expandedNode.getParent();
if (parent != null) {
for (TreeNode sibling : parent.getChildren()) {
if (sibling.isExpanded() && sibling != expandedNode) {
sibling.setExpanded(false);
System.out.printf("Collapsed %s\n", sibling);
}
}
}
}
}
Java 1.8 PrimeFaces 6.1 Mojarra 2.3 Weld 3.0
Update 1
I have updated the page with the code that #Kukeltje provided. Unfortunately, the siblings of expanded nodes are not being collapsed. I added a statement to the closeOthers function that logs to the console: the data ("root", or "0", or "0_1", etc.) of any node that I expand is displayed (as expected).
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>PrimeFaces Tree</title>
</h:head>
<h:body>
<h3>PrimeFaces Tree</h3>
<h:form>
<p:tree id="tree" widgetVar="treeW" value="#{testController.root}" var="node" orientation="horizontal" selectionMode="single">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
<p:ajax event="expand" listener="#{testController.onNodeExpanded}" oncomplete="closeOthers(this, PF('treeW'))"/>
</p:tree>
<h:outputScript>
//<![CDATA[
function closeOthers(current, widget) {
var dataRowkey = $.urlParam(decodeURIComponent(current.data),current.source+"_expandNode");
var selector = "li[data-rowkey='"+dataRowkey+"']";
console.log("Collapsing siblings of " + selector);
$(widget.jq).find(selector).siblings().find("span[aria-expanded='true']").siblings(".ui-tree-toggler").trigger("click");
}
$.urlParam = function (query, name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(query);
return (results !== null) ? results[1] || 0 : false;
}
//]]>
</h:outputScript>
<h:commandButton value="Update" immediate="true">
<f:ajax render="tree" />
</h:commandButton>
</h:form>
</h:body>
</html>
It is not very common to update a full component from within ajax calls inside the component itself. Due to you using dynamic="true" you see less downside effects than without using dynamic="true". The same will happen if you update a container around the p:tree. There are effectively 2 updates on the tree that sort of conflict with eachother, especially when there is some additional hiding of nodes being attempted.
What you effectively seem to be trying to achieve is to have just one node open at a time by using server side manipulation of the tree (which in itself is not wrong). This is related indeed what is attempted in https://github.com/primefaces/primefaces/issues/2277 as well but that issue is too narrowly formulated since it is not about selecting/unselecting or like you experience hiding/unhiding, but the more general issue of not being able to update the full tree component from within an ajax call in the component.
Updating things server-side so a full refresh is still supported should still be done. But instead of doing an update="tree", you can try to use the oncomplete javascript callback to close all other nodes client-side.
Adding the following javascript will do this for you:
<h:outputScript>
//<![CDATA[
function closeOthers(current, widget) {
var dataRowkey = $.urlParam(decodeURIComponent(current.data),current.source+"_expandNode");
//For a vertical tree:
//var selector = "li[data-rowkey='"+dataRowkey+"']";
//$(widget.jq).find(selector).siblings().find("span[aria-expanded='true']").siblings(".ui-tree-toggler").trigger("click");
//For a horizontal tree
var selector = "td[data-rowkey='"+dataRowkey+"']";
// The first attempt was to look for aria-expanded=true but we
// found that sometimes it would be present on a collapsed node (bug?).
// $(widget.jq).find(selector).parent().parent().parent().siblings().find("td[aria-expanded='true']").find(".ui-tree-toggler").trigger("click");
// Searching instead for the minus icon did the trick
$(widget.jq).find(selector).parent().parent().parent().siblings().find(".ui-icon-minus").trigger("click");
}
$.urlParam = function (query, name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(query);
return (results !== null) ? results[1] || 0 : false;
}
//]]>
</h:outputScript>
Then
Give your widget a widgetVar e.g. widgetVar="treeW"
add an oncomplete in the p:ajax like so oncomplete="closeOthers(this, PF('treeW'))"
REMOVE dynamic="true" OR ADD cache="false" (bug I found, then it will only work once for each node, https://github.com/primefaces/primefaces/issues/3668)
REMOVE update="tree"
So the html ends up like:
<p:tree id="tree" widgetVar="treeW" value="#{problemController.root}" var="node" orientation="horizontal">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
<p:ajax event="expand" listener="#{problemController.onNodeExpanded}" oncomplete="closeOthers(this, PF('treeW'))"/>
</p:tree>

Primefaces KeyFilter: Not working after calling "ajax update" on h:inputText

Prime faces p:keyFilter stops working when an ajax update happens on h:inputText. Please have a look at the following example.
Expected Behavior:
p:keyFilter should allow only alphabets and numbers in inputText at any point of time.
Steps to reproduce:
1) Go directly to "Project Key" field and try entering special characters.. it will not allow.. the filter works this time.
2) Now go to "Project Name" field and then click on "Project Key". This time try entering special characters. It allows to enter. The filter does not work now.
Sample xhtml:
<!DOCTYPE html>
<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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</h:head>
<h:form>
<h:outputText value="Project Name:"></h:outputText>
<h:inputText id="projectName" value="#{testBean.projectName}" >
<p:ajax event="blur" listener="#{testBean.updateKey()}" update="projectKey" process="#form"></p:ajax>
</h:inputText>
<br/>
<h:outputText value="Project Key:"></h:outputText>
<h:inputText id="projectKey" value="#{testBean.projectKey}" label="Project Key" size="29" maxlength="10">
</h:inputText>
<p:keyFilter for="projectKey" mask="alphanum" />
</h:form>
</html>
Sample Managed Bean:
import javax.faces.bean.ManagedBean;
import javax.persistence.Entity;
#ManagedBean(name="testBean")
#Entity
public class Test {
private String projectName;
private String projectKey;
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public String getProjectKey() {
return projectKey;
}
public void setProjectKey(String projectKey) {
this.projectKey = projectKey;
}
public void updateKey()
{
if(projectName.equals("Shivani"))
{
projectKey = "SK";
}
}
}
This error was reported to PrimeFaces: https://github.com/primefaces/primefaces/issues/3596
The bug was in the Jquery KeyFilter Plugin itself here: https://github.com/akzhan/jquery-keyfilter/issues/7
The patch has been applied and will be in PrimeFaces 6.3 and higher.
The PrimeFaces keyfilter is applied when the keyFilter is 'rendered'. The way it is applied can be seen in the source of the keyfilter.js.
In the PrimeFaces showcase (and documentation) you'll see two examples:
<p:inputText id="text1" value="....">
<p:keyFilter regEx="/[ABC]/i"/>
</p:inputText>
<h:outputText value="KeyFilter with mask on a h:inputText"/>
<h:inputText id="text2" value="..."/>
<p:keyFilter for="text2" mask="num" />
One where the p:keyFilter is nested and one where the for attribute is used. The latter will not be automatically reapplied after an update of the input, but the former will.
If you do need the non-nested way, make sure you update both the input and the keyfilter by either explicitly updating both, or nesting them both in e.g. a h:panelgroup id="inputAndFilter" and updating that.
<h:panelgroup id="inputAndFilter">
<h:inputText id="text2" value="..."/>
<p:keyFilter for="text2" mask="num" />
</ui:panelgroup>

Trigger notification bar from <p:ajax> event

I'm looking to trigger a notification bar on checkbox click using <p:ajax>. The notification bar would have the save option to save data in the database. The update atribute within <p:ajax> doesn't seem to work. It's been quite a research, but couldn't derive at a solution. Am I missing something here ? I'm using JSF 2.1+Primefaces 3.5. Any help would be much appreciated.
xhtml page
<p:column headerText="#{msgs.ref}" styleClass="menuHeader textAlignLeft">
<p:notificationBar widgetVar="customSaveBar" position="top" styleClass="saveBar warningBar textAlignCenter" style="height: 25px;padding-top: 0; padding-bottom: 0;" effect="none" rendered="true">
<h:outputText value="There are pending changes on the page." styleClass="warningText"/>
<h:outputText value=" "/>
<p:commandLink action="#{abcDashboardBean.abcDTOValues}"
onclick="skipPageRedirectWarning = true;showPleaseWait();"
styleClass="warningText" id="saveFromBar"
onsuccess="customSaveBar.hide()"
oncomplete="placeRemoveIcon();"
update="#form"
process="#form"
value="#{msgs.save}"/>
</p:notificationBar>
<p:selectBooleanCheckbox styleClass="margin_left_10" value="#{abcDto.refBl}"
rendered="#{!authorizationBean.userADMIN or !authorizationBean.userPM or !authorizationBean.userINDM}">
<p:ajax event="click" partialSubmit="true" update="customSaveBar"></p:ajax>
</p:selectBooleanCheckbox>
</p:column>
abcDashboardBean.java
public Map<Object, Boolean> getAbcDTOValues(){
Map<Object, Boolean> map = new LinkedHashMap<Object, Boolean>();
//fill the map with the items defaulted to unchecked
for (AbcDTO abcDTO: abcList){
map.put(abcDTO.getPpcCode(), Boolean.FALSE);
}
Abc abc1 = dataAccessEjbService.find(Abc.class, abc.getId());
saveAbcRefChanges(map, abc1);
return map;
}
public void saveAbcRefChanges(Map<Object, Boolean> map, Abc abc) {
for (Map.Entry<Object, Boolean> entry : map.entrySet()) {
if (entry.getValue().equals(true) && abc != null) {
abc.setReferenceBl(true);
} else {
abc.setReferenceBl(false);
}
}
dataAccessEjbService.update(abc);
}
AbcDTO.java
private boolean refBl;
// getters + setters

PrimeFaces <f:attribute not working correctly with p:galleria attribute

I have issue when trying to make command link from inside p:galleria component
The problem is despite the fact at run time the link value value="Show present #{present.name} #{present.presentId}" contains the correct value of the id as example value="Show present Foo 1" , when pressing the command link it sends the wrong id of the second object every time
<h:form>
<p:galleria value="#{presentBean.allPresentList}" var="present" panelWidth="500" panelHeight="313" showCaption="true">
<f:facet name="content">
<h:commandLink value="Show present #{present.name} #{present.presentId}" action="pretty:present" actionListener="#{presentBean.setPresentObj}">
<f:attribute name="present" value="#{present.presentId}"/>
</h:commandLink>
</f:facet>
</p:galleria>
</h:form>
#ManagedBean(name="presentBean")
#SessionScoped
public class PresentBean implements Serializable{
ArrayList<Present> allUserPresentList = new ArrayList<Present>();
#PostConstruct
private void usersPresent(){
PresentDao presentDao = new PresentDaoImpl();
allPresentList = (ArrayList<Present>) presentDao.findAllPresents();
}
public ArrayList<Present> getAllUserPresentList() {
return allUserPresentList;
}
public void setAllUserPresentList(ArrayList<Present> allUserPresentList) {
this.allUserPresentList = allUserPresentList;
}
private String presentId ;
public String getPresentId() {
return presentId;
}
public void setPresentId(String presentId) {
this.presentId = presentId;
}
public void setPresentObj(ActionEvent ev){
Object presentOb = ev.getComponent().getAttributes().get("present");
if(presentOb != null){
this.presentId = (String) presentOb;
}else{
presentId = null ;
}
}
}
You need to use a setPropertyActionListener instead of <f:attribute name="present" value="#{present.presentId}"/> as the f:attribute tag is only evaluated when the component is created (only once) not when the component generates html based on the iterated rows.
So you'll need to instead use:
<f:setPropertyActionListener target="#{presentBean.presentId}" value="#{present.presentId}" />
That will set the value of the presentId in your managed bean, so in your action method you can just access the presentId itself already without having to work it out.
Alternatively if you're using a later version of JSF (using Servlet 3.0 or above), then you could create a method in the managed bean which takes the presentId or even the present object as a parameter
e.g. in your managed bean:
public void myAction(Present p){
//do whatever you want with the Present object
}
and in your .xhtml:
<h:commandLink value="Show present #{present.name} #{present.presentId}" actionListener="#{presentBean.myAction(present)}">
</h:commandLink>