Dynamic adding text fields in JSF [duplicate] - jsf-2

This question already has answers here:
How to dynamically add JSF components
(3 answers)
Closed 7 years ago.
I have a screen with inputText, beside it there's a (+) button, when the user should press that button the form should add another extra inputText beside it (or below, whatever)
Here's the code:
<table>
<tr>
<td>
<p:inputText value="#{controller.x}" />
<img src="../images/ico_plus.png" />
</td>
</tr>
</table>
in Controller.java:
private String x;
public String getX(){return x}
public void setX(String val){x = val}
I need the page to be populated with multiple fields and the controller to have all the fields values' fetched

This question was answered more than one time, basically you need to keep a List for all fields in the bean, and you remove or add to this List with your buttons. Note this is important to be in ViewScoped or SessionScoped ortherwise your List will be reset at every actions.
View :
<h:form>
<h:dataTable id="tblFields" value="#{bean.fields}" var="field">
<h:column>
<h:inputText value="#{field.value}" />
</h:column>
<h:column>
<h:commandButton value="Remove">
<f:ajax listener="#{bean.onButtonRemoveFieldClick(field)}" immediate="true" render="#form" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Add">
<f:ajax listener="#{bean.onButtonAddFieldClick}" execute="#form" render="tblFields" />
</h:commandButton>
</h:form>
Helper class :
public class Field implements Serializable
{
private String m_sName;
public void setName(String p_sName)
{
m_sName = p_sName;
}
public String getName()
{
return m_sName;
}
}
Bean :
#ManagedBean
#ViewScoped
public class Bean implements Serializable
{
private List<Field> m_lFields;
public Bean()
{
m_lFields = new ArrayList();
m_lFields.add(new Field());
}
public void setFields(List<Field> p_lFields)
{
m_lFields = p_lFields;
}
public List<Field> getFields()
{
return m_lFields;
}
public void onButtonRemoveFieldClick(final Field p_oField)
{
m_lFields.remove(p_oField);
}
public void onButtonAddFieldClick(AjaxBehaviorEvent p_oEvent)
{
m_lFields.add(new Field());
}
}

Related

Parameters always return null in JSF [duplicate]

This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 6 years ago.
I am trying to make a login page. I keep the members in different .txt files. But "person", "fileName" and "pageName" variables always return null. I tried everything but can't get it work. Here is my managed bean.
package hw;
import java.io.IOException;
import javax.faces.bean.ManagedBean;
#ManagedBean(name="choose")
public class Choose{
private String person=new String();
private String email;
private String password;
public String pageName,fileName,fileName2;
private boolean ifExists;
FileDatabase fileDatabase = new FileDatabase();
//getters and setters
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//chooses which file to read to check if the member exists
//according to the selectMenu value and set the returning page name.
//doesnt enter any of the if blocks.
public String chooseFile() {
if(person.equals("1")){
fileName="admins.txt";
pageName="admin-page";
}
else if(person.equals("2")){
fileName="instructors.txt";
pageName="instructor-page";
}
else if(person.equals("3")){
fileName="assistants.txt";
pageName="assistant-page";
}
else if(person.equals("4")){
fileName="students.txt";
pageName="student-page";
System.out.println("Filename:"+fileName);
System.out.println("Pagename:"+pageName);
}
return fileName;
}
//gets the fileName and checks the member but fileName is always null,
//person and pageName as well.
public String login() throws IOException {
fileName2=chooseFile();
System.out.println("Person:"+person);
System.out.println("Filename2:"+fileName2);
System.out.println("Pagename:"+pageName);
ifExists = fileDatabase.ifExistsMember(fileName2, email, password);
if(ifExists)
return(pageName);
else
return("index");
}
public String register() throws IOException{
return("index");
}
}
Here is the body part of the index.xhtml:
<h:body>
<h1 class="title">Welcome!</h1>
<fieldset>
<h:form>
<h3>Which one are you?</h3>
<h:selectOneMenu value="#{choose.person}">
<f:selectItem itemValue="1" itemLabel="Admin" />
<f:selectItem itemValue="2" itemLabel="Instructor" />
<f:selectItem itemValue="3" itemLabel="Assistant" />
<f:selectItem itemValue="4" itemLabel="Student" />
</h:selectOneMenu>
</h:form>
</fieldset>
<fieldset>
<h:form>
Email<br/><h:inputText value="#{choose.email}"/><br/>
Password<br/><h:inputSecret value="#{choose.password}"/><br/><br/>
<h:commandButton value="Login" action="#{choose.login}" />
<h:commandButton value="Register" action="#{choose.register}" />
</h:form>
</fieldset>
</h:body>
Your problem is easy to solve.
Just move your <h:selectOneMenu> to the other form
<h:body>
<h1 class="title">Welcome!</h1>
<h:form>
<fieldset>
<h3>Which one are you?</h3>
<h:selectOneMenu value="#{choose.person}">
<f:selectItem itemValue="1" itemLabel="Admin" />
<f:selectItem itemValue="2" itemLabel="Instructor" />
<f:selectItem itemValue="3" itemLabel="Assistant" />
<f:selectItem itemValue="4" itemLabel="Student" />
</h:selectOneMenu>
</fieldset>
<fieldset>
Email<br/><h:inputText value="#{choose.email}"/><br/>
Password<br/><h:inputSecret value="#{choose.password}"/><br/><br/>
<h:commandButton value="Login" action="#{choose.login}" />
<h:commandButton value="Register" action="#{choose.register}" />
</fieldset>
</h:form>
</h:body>

Passing parameters to a bean method from a datatable within a view/page in JSF 2.0

I have a page with a datatable that populates from a list. The list has many ids, which I need to pass to a bean method and perform a database operation.I am using a commandButton's rendered attribute to make a call to the bean method (findInfo()). I need to pass the ids (myBean.testList.id) one at a time from the list to this bean method so that I get the boolean back. First of, I am not sure how to pass the id (to the findInfo method in my bean), secondly if I use tag, I end up sending just a single ID. Could anyone please suggest me a solution. I tried doing it with the codes as below.
My Bean
#ManagedBean(name="myBean")
public class MyBean(){
public boolean findInfo(Integer indId){
boolean var = dataProvider.isIdPresent(indId); // database operation
if (var)
return true;
else
return false;
}
}
xhtml page
<h:dataTable value="#{myBean.testList}" var="t" >
<h:column>
<f:facet name="header">
<h:outputText value="Actions" />
</f:facet>
<h:commandButton value = "Add"
action = "#{someBean.loadReport}"
rendered = "#{myBean.findInfo() == false}"/>
<h:commandButton value = "View"
action = "#{someBean.loadReport}"
rendered = "#{myBean.findInfo() == true}"/>
</h:column>
<h:column>
...
</h:column>
</h:dataTable>
UPDATE:
I tried to follow the answer that BalusC's explained (that kolossus posted), I end up passing the id as null in f:param. Any suggestions. My updated code:
<h:dataTable value="#{myBean.testList}" var="t" >
<h:column>
<f:facet name="header">
<h:outputText value="Actions" />
</f:facet>
<h:commandButton value = "Add"
action = "#{someBean.loadReport}"
rendered = "#{myBean.findInfo() == false}">
<f:param name="id" value="#{t.id}" />
</h:commandButton>
<h:commandButton value = "View"
action = "#{someBean.loadReport}"
rendered = "#{myBean.findInfo() == true}">
<f:param name="id" value="#{t.id}" />
</h:commandButton>
</h:column>
<h:column>
...
</h:column>
My Updated Bean
#ManagedBean(name="myBean")
#RequestScoped
public class MyBean(){
#ManagedProperty("#{param.id}")
private Integer indId;
public boolean findInfo(){
boolean var = dataProvider.isIndIdPresent(indId);
if (var)
return true;
else
return false;
}
}
Also, I think I cannot use f:ViewParam as I am calling the bean from the data table within the same view.
First of all, you should declare your bean as #ViewScoped. Then, you can keep your findInfo method as following:
#ManagedBean(name="myBean")
#ViewScoped
public class MyBean(){
private List testList;
public boolean findInfo(Integer indId){ ... }
// Getters and Setters
}
The following snippet should do the job:
<h:dataTable value="#{myBean.testList}" var="t" >
<h:column>
<h:commandButton value="Add" action="#{someBean.loadReport}"
rendered="#{not myBean.findInfo(t.id)}" />
<h:commandButton value="View" action="#{someBean.loadReport}"
rendered="#{myBean.findInfo(t.id)}" />
</h:column>
</h:dataTable>
UPDATE: Since you're not using EL 2.2, you may need process the boolean value for each row before rendering the table. Wrapping the objects in the testList inside a dummy object containing a boolean value should do the job :). Something like this:
#ManagedBean(name="myBean")
#ViewScoped
public class MyBean(){
private List<DummyObject> testList;
#PostConstruct
public boolean prepareTestList(){
// Initiate test list
List<AnObject> oriList = ....;
// Process oriList to create a testList
this.testList = new LinkedList();
for (AnObject o : oriList) {
DummyObject do = new DummyObject();
do.setObject(o);
do.setIdPresent(findInfo(o.getId()));
this.testList.add(do);
}
}
public boolean findInfo(Integer indId) { ... }
public class DummyObject {
private boolean idPresent;
private AnObject object;
// Getters and Setters
}
// Getters and Setters
}
Then your rendered attribute should look like this:
<h:commandButton value="View" action="#{someBean.loadReport}"
rendered="#{t.idPresent}" />

command button works on second click and accordion first tab content is empty

I Have an accordion panel with a list of students and I have set dynamic="true", In a tabs of accordion panel, I have command button which invokes the method in backing bean.
here the content of first tab is empty and rest all is fine. To correct this ,I have set dynamic="false" now the content of tab is appearing but command button click doesnot invoke the method of backing bean on first click. Iam not sure what is happening.. Im using prime faces 3.4 and jsf2
<p:accordionPanel value="#{testBean.students}" var="stud" dynamic="true" activeIndex="#{systemManagedBean.formBean.id}">
<p:tab title="#{stud.name}" id="studId">
<p:commandButton process="#this" value="edit" icon="ui-icon-pencil" styleClass="btn-primary" style="margin-left:734px;" action="#{testBean.edit}">
<f:setPropertyActionListener target="#{testBean.stydent}" value="#{stud}"></f:setPropertyActionListener>
</p:commandButton>
I have tried proceess=#form did not make any change..
The following code is working:
The xhtml:
<h:form>
<p:accordionPanel value="#{so15320248.students}" var="student">
<p:tab title="#{student.name}">
<p:commandButton icon="ui-icon-pencil" value="Edit" actionListener="#{so15320248.edit(student)}"/>
</p:tab>
</p:accordionPanel>
</h:form>
The managed bean:
#ManagedBean(name = "so15320248")
#ViewScoped
public class SO15320248 implements Serializable {
private static final long serialVersionUID = -2285963068688871710L;
private List<Student> students;
#PostConstruct
public void init() {
students = new ArrayList<Student>();
students.add(new Student("Student 1"));
students.add(new Student("Student 2"));
}
public void edit(Student student) {
System.out.println("===========================");
System.out.println(student.getName());
System.out.println("===========================");
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}

Multiple instances of a composite component in a view?

I read many similar questions, but I cannot figure out how to solve my problem:
I wrote a composite component backed by a view-scoped, self-contained managed bean.
The component consists of an autocomplete textbox with a button that opens a dialog. The user can select an item either by name (autocomplete) or selecting a node in a tree (dialog).
The backing bean implements all the stuff needed (data access, tree-logics etc) and should expose the selected item (as a POJO).
Now I have 2 problems:
Due to the complexity of the tree management, selectedObj property is accessed by a getter and a setter that do some stuff in the bean: they are not simply accessing a class field. Now I'm passing the entire bean as an attribute. How can I just make the bean's selectedObj the "value" attribute of my composite component?
How can I use multiple instance of my component in the same view?
Here is an example of the component:
<cc:interface>
<cc:attribute name="bean" type="com.yankee.OUTreeBean" required="true"/>
<cc:attribute name="listener" method-signature="void listener()"/>
</cc:interface>
<cc:implementation>
<p:dialog id="#{cc.id}_dialog" widgetVar="_dlg" header="Select OU" modal="true" dynamic="true" >
<p:toolbar>
<!-- some buttons to refresh, expand, collapse etc. -->
</p:toolbar>
<p:tree id="#{cc.id}_tree" value="#{cc.attrs.bean.root}" var="node"
selectionMode="single"
selection="#{cc.attrs.bean.selectedNode}">
<p:ajax event="select" update="#form" listener="#{cc.attrs.listener}" oncomplete="if (!args.validationFailed) _dlg.hide()" />
<p:treeNode>
<h:outputText value="#{node.OU_NAME}" />
</p:treeNode>
</p:tree>
</p:dialog>
<p:autoComplete id="#{cc.id}_inner" value="#{cc.attrs.bean.selectedObj}" completeMethod="#{cc.attrs.bean.completeObj}"
var="obj" itemLabel="#{obj.OU_NAME}" itemValue="#{obj}"
forceSelection="true"
converter="ouConverter"
multiple="false"
minQueryLength="2">
<p:ajax event="itemSelect" listener="#{cc.attrs.listener}" update="#form"/>
</p:autoComplete>
<div style="float: right">
<p:commandButton id="bSearch" icon="ui-icon-search" onclick="_dlg.show()"/>
</div>
</cc:implementation>
The backing bean of the COMPONENT:
#ManagedBean
#ViewScoped
public class OUTreeBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<OU> data; // Data as plain list
protected TreeNode root; // root node of data as a tree
protected TreeNode selectedNode;
#PostConstruct
private void init() throws SQLException {
refreshData();
}
public OU getSelectedObj() {
if (selectedNode == null) {
return null;
}
return ((OU) selectedNode.getData());
}
public void setSelectedObj(OU ou) {
// Find the right tree node and do whatever needed
}
public TreeNode selectedNode getSelectedNode() {
// Blah blah
}
public void setSelectedNode(TreeNode selectedNode) {
// Blah blah
}
public List<OU> completeObj(String namePattern) {
// Autocomplete handler
}
public void refreshData() {
// Blah blah
}
// etc...
}
The using page excerpt:
<ism:selectOUTree id="cbSelectOu" bean="#{myBean.ouFilterBean}" listener="#{myBean.onOUChange}"/>
The backing bean of the PAGE:
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty("#{oUTreeBean}")
private OUTreeBean ouFilterBean;
public void onOUChange() throws SQLException {
// Blah blah
}
}
I had the same problem few days ago. Just like you I used ManagedBean as an object that should do the job. After some time I figured out that I should just create FacesComponent. I'm new in JSF so it wasn't that easy to find the solution but it solved all my problems. This is how does it work:
view.xhtml
<h:body>
<cc:interface componentType="playerComponent">
<cc:attribute name="playerId" required="true"/>
</cc:interface>
<cc:implementation>
<c:set var="inplaceId" value="inplace-#{cc.attrs.playerId}" />
<c:set var="outputId" value="output-#{cc.attrs.playerId}" />
<h:form id="form-#{cc.attrs.playerId}">
<p:inplace editor="false" widgetVar="#{inplaceId}">
<h:inputText value="#{cc.player.name}" id="outputId"/>
<p:commandButton onclick="#{inplaceId}.save()" action="#{cc.save}" update="#{outputId}" value="save" />
<p:commandButton onclick="#{inplaceId}.cancel()" update="#{outputId}" value="cancel" />
</p:inplace>
</h:form>
</cc:implementation>
</h:body>
PlayerComponent.java
#FacesComponent("playerComponent")
public class PlayerComponent extends UINamingContainer {
private Player player;
private void init() {
Object idObj = getAttributes().get("playerId");
if (idObj != null) {
// create player object
}
}
public void save() {
// save player object
}
public Player getPlayer() {
if (player == null) {
init();
}
return player
}
}
Player.java (entity)
public class Player {
private name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As I wrote I'm new in JSF and probably player object should be created in different way (using #PostConstruct on in constructor?) but this work.

jsf2 template component with parameter

I have a jsf template page. In this template i would like to use component with parameter. Actually i would like to iterate over collection. This collection should be determined by parameters from particular page. Parameter name is selectedMenu. How can i use this in my bean?
<div id="notes">
selectedMenu: #{selectedMenu}
<h:form>
<h:inputHidden value="#{notatkaController.searchForm.kategoria}">
<f:param value="#{selectedMenu}" />
</h:inputHidden>
<ui:repeat value="#{notatkaController.items}" var="item" varStatus="iter">
<f:param value="#{selectedMenu}" />
<p class="q-title"><strong><h:outputText value="#{item.ntaData}" /></strong></p>
<p class="answer"><h:outputText value="#{item.ntaDane}" escape="false" /></p>
</ui:repeat>
<span>Moje notatki</span>
<textarea>Tu wpisz treść swojej notatki</textarea>
<span>[+] dodaj notatkę</span>
</h:form>
</div>
My bean:
#ManagedBean(name = "notatkaController")
#ViewScoped
public class NotatkaController extends AbstractController<Notatka> implements Serializable {
#EJB
private pl.alfaprojekt.model.session.NotatkaFacade ejbFacade;
private NotatkaSearchForm searchForm;
public DataModel getItems() {
if (items == null)
items = getPagination().createPageDataModel();
return items;
}
public PaginationHelper getPagination() {
if (pagination == null) {
if (paginationSize == null)
paginationSize = 10;
pagination = new PaginationHelper(paginationSize) {
#Override
public int getItemsCount() {
return getFacade().countByParam(getSearchForm());
}
#Override
public DataModel createPageDataModel() {
if (rapId == null)
return new ListDataModel(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
else {
Long uzyId = SessionUtil.getUser().getUzyId();
return new ListDataModel(convertToRaportWierszList(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}), uzyId));
}
}
};
}
return pagination;
}
}
I am not sure I understood the question but the question I answer is this:
I want to dynamically display something. I want to tell it what to display when the page gets accessed.
View:
You could then use the following:
<f:event listener="#{myBean.myMethod}" type="preRenderView" />
Bean:
public void myMethod(ComponentSystemEvent event){
//your logic here
}
With parameter:
<f:metadata>
<f:event listener="#{myBean.myMethod}" type="preRenderView" id="fevent"/>
<f:attribute name="myParam" value="#{mySecondBean.param)" />
</f:metadata>
And
public void myMethod(ComponentSystemEvent event){
String id = (String) event.getComponent().getAttributes().get("myParam");
}

Resources