Using Apache MyFaces JSF 2.0.
XHTML code:
<h:form id="searchUser" prependId="false">
<h:selectManyListbox value="#{listManyBean.listUser}" id="userList" size="10">
<f:selectItems value="#{listManyBean.selListUser}"/>
</h:selectManyListbox>
<h:commandButton id="clickGo" value="#{bundle.btn_login}"
type="submit"
action="#{listManyBean.submitList}"/>
<input type="button" value="Add" onclick="addUserToList();" />
</h:form>
Script to add to the list:
function addUserToList(){
var UserListBox = document.getElementById('UserList');
var UserNum = document.getElementById('UserNumber').value.toUpperCase();
var UserOption = new Option(UserNum,UserNum);
UserListBox.options[UserListBox.options.length] = UserOption;
}
Bean:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.model.SelectItem;
#ManagedBean
#RequestScoped
public class ListManyBean {
private List<String> listUser;
private List<SelectItem> selListUser;
public List<SelectItem> getSelListUser() {
return selListUser;
}
public List<String> getListUser() {
return listUser;
}
public void setListUser(List<String> listUser) {
this.listUser = listUser;
}
public void submitList() {
System.out.println("User List Value***" + this.listUser);
System.out.println("User ListPan***++"+selListUser);
}
}
I am getting null always, irrespective of adding one or more than one record.
Please let me know what is going wrong here.
You're adding new items using JS instead of using JSF. This way JSF won't know anything about the new items. This information is in no way been submitted to the server side.
Replace your wrong JS approach by a sane JSF approach:
<h:form>
<h:selectManyListbox value="#{bean.selectedUsers}" size="10">
<f:selectItems value="#{bean.availableUsers}" />
</h:selectManyListbox>
<h:commandButton value="submit" action="#{bean.submit}" />
<h:inputText value="#{bean.user}" />
<h:commandButton value="Add" action="#{bean.add}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
and
#ManagedBean
#ViewScoped
public class Bean {
private List<String> selectedUsers;
private List<String> availableUsers = new ArrayList<String>();
private String user;
public void add() {
availableUsers.add(user);
user = null;
}
public void submit() {
System.out.println("Selected users: " + selectedUsers);
System.out.println("Available users: " + availableUsers);
}
// ...
}
Related
I have two dropdowns: One is implemented using a selectOneMenu component and the other is implemented with selectCheckboxMenu.
When selecting an option in the selectOneMenu, the option values of the selectCheckboxMenu are updated depending of what option was selected in the selectOneMenu.
The following scenario happens:
I select an option of the selectOneMenu, the selectCheckboxMenu gets populated
I select/check some options of the selectCheckboxMenu
I select another option of the selectOneMenu, the selectCheckboxMenu gets populated with other values
I select some of the new values
I select the option in step 1 of the selectOneMenu
The values I selected in step 2 are no longer selected
I believe this is because the list value bound to the selectCheckboxMenu is getting reset by the setter method.
What I would like is for the state of the selectCheckboxMenu to be globally saved. What would be the best strategy for doing this?
EDIT:
Here's the relevant code that duplicates the previous behavior:
Bean:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
#ManagedBean
#ViewScoped
public class BackingBean {
private List<Parent> parents = new ArrayList<>();
private List<Child> children = new ArrayList<>();
private List<Child> selectedChildren = new ArrayList<>();
private Parent selectedParent = new Parent();
#Inject
FamilyService service;
#PostConstruct
public void init(){
parents = service.findParents();
}
public void parentChanged(){
children = new ArrayList<>();
if(getSelectedParent() == null){
return;
}
children = service.findChildrenByParent(getSelectedParent());
}
public void selectedSonChanged(){
System.out.println(selectedChildren.size());
}
public List<Parent> getParents() {
return parents;
}
public void setParents(List<Parent> parents) {
this.parents = parents;
}
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
public List<Child> getSelectedChildren() {
return selectedChildren;
}
public void setSelectedChildren(List<Child> selectedChildren) {
this.selectedChildren = selectedChildren;
}
public Parent getSelectedParent() {
return selectedParent;
}
public void setSelectedParent(Parent selectedParent) {
this.selectedParent = selectedParent;
}
}
XHTML:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form id="selectOne">
<p:messages autoUpdate="true" />
<h:outputLabel for="parents" value="Parents:" />
<p:selectOneMenu converter="#{parentConverter}" id="parents" value="#{backingBean.selectedParent}">
<p:ajax update="children" listener="#{backingBean.parentChanged}" />
<f:selectItem noSelectionOption="true" value="#{null}" itemLabel="None" />
<f:selectItems value="#{backingBean.parents}" var="p" itemLabel="#{p.name}" itemValue="#{p}" />
</p:selectOneMenu>
<h:outputLabel for="children" value="Children:" />
<p:selectCheckboxMenu converter="#{childConverter}" id="children"
value="#{backingBean.selectedChildren}"
label="Children" filter="true" filterMatchMode="startsWith">
<p:ajax update="display" listener="#{backingBean.selectedSonChanged}" />
<f:selectItems value="#{backingBean.children}" var="c" itemLabel="#{c.name}" itemValue="#{c}" />
</p:selectCheckboxMenu>
<p:outputPanel id="display">
<p:dataList value="#{backingBean.selectedChildren}" var="sn" emptyMessage="No children selected">
#{sn.name}
</p:dataList>
</p:outputPanel>
<p:commandButton value="Submit" update="display, selectOne" />
</h:form>
</h:body>
</html>
The complete project is here: https://github.com/cenobyte321/jsfsamples/tree/master/selectcheckboxmenu
You can find a video of the interaction mentioned previously here:
https://github.com/cenobyte321/jsfsamples/blob/master/selectcheckboxmenu/example1.mp4?raw=true
As you can see when choosing another "Parent" and then selecting their children the previous children list gets substituted. How can I properly modify this behavior so the previously selected elements get persisted and shown as checked in the selectCheckboxMenu?
EDIT 2:
One solution I found was introducing another variable which will hold the global values and will be modified in the listener method "selectedSonChanged". Here's the relevant code:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
#ManagedBean
#ViewScoped
public class BackingBean {
private List<Parent> parents = new ArrayList<>();
private List<Child> children = new ArrayList<>();
private List<Child> selectedChildren = new ArrayList<>();
private List<Child> globalSelectedChildren = new ArrayList<>();
private Parent selectedParent = new Parent();
#Inject
FamilyService service;
#PostConstruct
public void init(){
parents = service.findParents();
}
public void parentChanged(){
children = new ArrayList<>();
if(getSelectedParent() == null){
return;
}
children = service.findChildrenByParent(getSelectedParent());
selectedChildren = globalSelectedChildren.stream().filter(c -> c.getParent().equals(selectedParent)).collect(Collectors.toList());
System.out.println(selectedChildren.size());
}
public void selectedSonChanged(){
System.out.println(selectedChildren.size());
globalSelectedChildren = globalSelectedChildren.stream().filter(c -> !c.getParent().equals(selectedParent)).collect(Collectors.toList());
globalSelectedChildren.addAll(selectedChildren);
}
public List<Parent> getParents() {
return parents;
}
public void setParents(List<Parent> parents) {
this.parents = parents;
}
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
public List<Child> getSelectedChildren() {
return selectedChildren;
}
public void setSelectedChildren(List<Child> selectedChildren) {
this.selectedChildren = selectedChildren;
}
public Parent getSelectedParent() {
return selectedParent;
}
public void setSelectedParent(Parent selectedParent) {
this.selectedParent = selectedParent;
}
public List<Child> getGlobalSelectedChildren() {
return globalSelectedChildren;
}
public void setGlobalSelectedChildren(List<Child> globalSelectedChildren) {
this.globalSelectedChildren = globalSelectedChildren;
}
}
XHTML:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form id="selectOne">
<p:messages autoUpdate="true" />
<h:outputLabel for="parents" value="Parents:" />
<p:selectOneMenu converter="#{parentConverter}" id="parents" value="#{backingBean.selectedParent}">
<p:ajax update="children" listener="#{backingBean.parentChanged}" />
<f:selectItem noSelectionOption="true" value="#{null}" itemLabel="None" />
<f:selectItems value="#{backingBean.parents}" var="p" itemLabel="#{p.name}" itemValue="#{p}" />
</p:selectOneMenu>
<h:outputLabel for="children" value="Children:" />
<p:selectCheckboxMenu converter="#{childConverter}" id="children"
value="#{backingBean.selectedChildren}"
label="Children" filter="true" filterMatchMode="startsWith">
<p:ajax update="display" listener="#{backingBean.selectedSonChanged}" />
<f:selectItems value="#{backingBean.children}" var="c" itemLabel="#{c.name}" itemValue="#{c}" />
</p:selectCheckboxMenu>
<p:outputPanel id="display">
<p:dataList value="#{backingBean.globalSelectedChildren}" var="sn" emptyMessage="No children selected">
#{sn.name}
</p:dataList>
</p:outputPanel>
<p:commandButton value="Submit" update="display, selectOne" />
</h:form>
</h:body>
</html>
Here's the branch with this solution: https://github.com/cenobyte321/jsfsamples/tree/solution-1/selectcheckboxmenu
How can dynamically show or hide a panel ?
With the given example below, when I click btn-1 then panel-2 shows and panel-1 hides. But when I click btn-2 nothing happens.
ManagedBean
#ManagedBean
#ViewScoped
public class SampleController implements Serializable {
private Boolean showPanel;
public void button1() {
showPanel = Boolean.FALSE;
}
public void button2() {
showPanel = Boolean.TRUE;
}
public Boolean showPanel1(){
return showPanel;
}
public Boolean showPanel2(){
return ! showPanel;
}
}
XHTML
<h:form id="form">
<h:panelGroup id="container-panel-1">
<h:panelGroup id="panel-1" rendered="#{sampleController.showPanel1()}">
<p:commandButton id="btn-1"
actionListener="#{sampleController.button1}"
update=":form:container-panel-1, :form:container-panel-2" />
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="container-panel-2">
<h:panelGroup id="panel-2" rendered="#{sampleController.showPanel2()}">
<p:commandButton id="btn-2"
actionListener="#{sampleController.button2}"
update=":form:container-panel-1, :form:container-panel-2" />
</h:panelGroup>
</h:panelGroup>
</h:form>
I hope you can help me with this.
Thank you,
Bell
This code is works:
View:
<h:form id="form">
<h:panelGroup id="container-panel-1">
<h:panelGroup id="panel-1" rendered="#{sampleController.showPanel1()}">
<p:commandButton id="btn-1" value="btn1"
actionListener="#{sampleController.button1}"
update=":form:container-panel-1, :form:container-panel-2" />
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="container-panel-2">
<h:panelGroup id="panel-2" rendered="#{sampleController.showPanel2()}">
<p:commandButton id="btn-2" value="btn2"
actionListener="#{sampleController.button2}"
update=":form:container-panel-1, :form:container-panel-2" />
</h:panelGroup>
</h:panelGroup>
</h:form>
Bean:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class SampleController implements Serializable {
private boolean showPanel;
public void button1() {
showPanel = false;
}
public void button2() {
showPanel = true;
}
public boolean showPanel1(){
return showPanel;
}
public boolean showPanel2(){
return ! showPanel;
}
}
I have using primefaces in my project. I need to create and delete field dynamically on my project. Here I am going to attached my code please find it
my xhtml page is
<ui:composition 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:panelGrid border="0" columns="3" cellpadding="4" columnClasses="control-label">
<h:panelGrid columns="3" cellpadding="4" >
<h:outputText value="Individual Email"/>
<div>
<h:dataTable value="#{utilBean.attachments}" var="attachmentBean" binding="#{utilBean.data}" id="attachments">
<h:column>
<h:inputText id="attachment" value="#{attachmentBean.emailAddress}" binding="#{utilBean.attachment}"/>
</h:column>
<h:column>
<h:commandButton id="delete" value="Delete" immediate="true" actionListener="#{utilBean.deleteAddress}"/>
</h:column>
</h:dataTable>
<h:commandButton id="add" value="Add Email Address" immediate="true" actionListener="#{utilBean.addAddress}" />
</div>
<br/>
</h:panelGrid>
</h:panelGrid>
</ui:composition>
My Bean Is:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIData;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean
#SessionScoped
public class UtilBean{
private UIData data=null;
private UIInput attachment = null;
private List<AttachmentBean> attachments = new ArrayList<AttachmentBean>();
public void addAddress(ActionEvent event){
attachments.add(new AttachmentBean());
this.updateAddresses();
FacesContext.getCurrentInstance().renderResponse();
System.out.println("adress size:" + attachments.size());
}
public void deleteAddress(ActionEvent event){
int index = data.getRowIndex();
this.updateAddresses();
this.getAttachments().remove(index);
FacesContext.getCurrentInstance().renderResponse();
}
public void updateAddresses(){
System.out.println("adress sizedfdfdfdf:" + attachments.size());
#SuppressWarnings("unchecked")
List<AttachmentBean> list = (ArrayList<AttachmentBean>)data.getValue();
for(int i =0;i<data.getRowCount();i++){
data.setRowIndex(i);
list.get(i).setEmailAddress((String)getAttachment().getSubmittedValue());
}
data.setRowIndex(0);
}
public UIData getData() {
return data;
}
public void setData(UIData data) {
this.data = data;
}
public UIInput getAttachment() {
return attachment;
}
public void setAttachment(UIInput attachment) {
this.attachment = attachment;
}
public List<AttachmentBean> getAttachments() {
return attachments;
}
public void setAttachments(List<AttachmentBean> attachments) {
this.attachments = attachments;
}
}
And the Attachment Class is
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
#ManagedBean
#SessionScoped
public class AttachmentBean implements Serializable {
private static final long serialVersionUID = 1L;
private String emailAddress;
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public AttachmentBean() {
super();
}
}
I am not able to add textBox by clicking the add button. Please help. Thanks in advance.
You need to put the whole in a <h:form>. See also commandButton/commandLink/ajax action/listener method not invoked or input value not updated.
Another major mistake is here:
<h:dataTable ... binding="#{utilBean.data}">
...
<h:inputText ... binding="#{utilBean.attachment}"/>
Remove those binding attributes. UI components are request scoped and yet you're binding them to a session scoped bean. This would fail hard if you open the same page in multiple browser windows in the same session. See also How does the 'binding' attribute work in JSF? When and how should it be used?.
That said, the #ManagedBean #SessionScoped on AttachmentBean is completely unnecessary. Get rid of those annotations. The #SessionScoped on UtilBean is also rather strange. The #ViewScoped is much better at its place here. See also How to choose the right bean scope?
Form field rendering is depending on selected item in selectOneMenu.
Page:
<h:body>
<f:view>
<h:form>
<h:panelGrid>
<p:inputText value="#{user.username}"/>
<p:selectOneMenu value="#{user.moreInputs}"
required="true">
<p:ajax event="change"
update="moreInputGrid"/>
<f:selectItem itemLabel="" itemValue=""/>
<f:selectItems value="#{user.selectItems}"/>
</p:selectOneMenu>
</h:panelGrid>
<h:panelGrid id="moreInputGrid">
<p:inputText rendered="#{user.renderMoreInputs}"
value="#{user.name}"/>
</h:panelGrid>
<p:commandButton action="#{user.register}"
value="Register user"/>
</h:form>
</f:view>
</h:body>
Backing bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;
#ManagedBean
#ViewScoped
public class User {
private String username;
private MoreInputs moreInputs;
private String name;
public enum MoreInputs {
YES,
NO
}
public boolean isRenderMoreInputs() {
return (moreInputs == MoreInputs.YES);
}
public SelectItem[] getSelectItems() {
SelectItem[] items = new SelectItem[2];
items[0] = new SelectItem(
MoreInputs.YES,
"yes");
items[1] = new SelectItem(
MoreInputs.NO,
"no");
return items;
}
public String register() {
return null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public MoreInputs getMoreInputs() {
return moreInputs;
}
public void setMoreInputs(MoreInputs moreInputs) {
this.moreInputs = moreInputs;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Issue arrises if the client does page refresh after choosing an item causing form fields to render. Such form fields will not be rendered on page refresh, although they should. Plus, if client then tries to submit form, validation is skipped for those hidden fields and form is successfully processed.
Am I doing something wrong? Is there an elegant solution?
I'm trying to merge an existing shop to a new client in jsf but it isn't successful. The program consists basically off a backing bean controller,an ejb and the jsf page (register) I have been able to populate the shoplist in a comboBox UI. here is the code.
register.xhtml:
clientcontroller.client.fname is a SFSB.
Property already persisted but trying to be merged.
A shop from a list (shopcontroller.shopList)
<h:form>
<h:panelGrid columns="3" >
<h:outputText value="Select From.
Available Shops :" />
<h:selectOneMenu value="#.
{shopController.shop}" >
<f:selectItems var="s" value="#.
{shopController.shopList}" />
</h:selectOneMenu>
<h:commandButton value="register".
action="#{clientcontroller.Register(s)}" />
</h:panelGrid>
</h:form>
backing bean class:
ManagedBean(name="clientcontroller")
#RequestScoped
public class clientController {
#EJB ClientEJB clientEJB;
private Client clt = new Client();
private Shop shp = new Shop();
private String clientfname;
//getters and setters
public String Register(Shop shp){
this.shp = shp;
clientEJB.register(clt, shp);
return "";
}
EJB class:
#Stateful
#LocalBean
public class ClientEJB {
#PersistenceContext
EntityManager em;
public void addClient(Client clt){
em.persist(clt);
}
public void register(Client c ,Shop s){
c.getShopList().add(s);
s.setAvailability("false");
s.setClientid(c);
em.merge(s);
em.merge(c);
}
}
Adjust your code as follows:
XHTML:
<h:commandButton value="register" action="#{clientcontroller.Register}" />
ManagedBean
public String Register(){
clientEJB.register(clt, shp);
return "";
}
See Also:
JSF 2 dropdown box example