I want to assign a List of resources to a project and then i use selectManyCheckbox :
the problem is although I select 2 resources. it return an empty list of resources(Utilisateur) but the project is successfully added :
and then this is my xhtml file:
<p:dataTable id="dta" value="#{UtilisateurComponent.listUtilisateurs()}" var="current" rows="15" paginator="true" paginatorPosition="bottom">
<p:column>
<h:selectManyCheckbox id="selectUser" value="#{ProjetComponent.projet.utilisateurs}" >
<f:selectItem var="utilisateurs" value="#{utilisateurs.iduser}" itemLabel=""/>
<f:converter converterId="entityConverter" />
</h:selectManyCheckbox>
</p:column>
</p:dataTable>
</h:panelGrid>
<h:panelGroup>
<p:commandButton image="save" ajax="false" style="margin-right:20px;" value="#{projetmsgs['navigation.save']}" action="#{ProjetComponent.saveProjetUtilisateurs1(ProjetComponent.projet,ProjetComponent.projet.utilisateurs)}"/>
</h:panelGroup>
</p:panel>
and this is the method save in the ProjetComponent:
private Projet projet;
private Utilisateur utilisateurs;
#Autowired
private ProjetDAO projetDAO;
#Autowired
private UtilisateurDAO utilisateurDAO;
#Autowired
private ProjetService projetService;
#Transactional
public String saveProjetUtilisateurs1(Projet p, List<Utilisateur> utilisateur) {
projet = projetService.saveProjetUtilisateurs(p, utilisateur);
return "/jsf/projet/viewProjet.xhtml";
}
and this the method save in the ProjetService class called by the component ProjetCompnent:
#Transactional
public Projet saveProjetUtilisateurs(Projet projet,List<Utilisateur> ut)
{
projet.setAvancement(projet.getAvancement());
projet.setConfidentialite(projet.getConfidentialite());
projet.setDatedebut(projet.getDatedebut());
projet.setDatefineffective(projet.getDatefineffective());
projet.setDatefinprevu(projet.getDatefinprevu());
projet.setDescription(projet.getDescription());
projet.setDurreprojet(projet.getDurreprojet());
projet.setNomprojet(projet.getNomprojet());
projet.setObjectifprojet(projet.getObjectifprojet());
projet.setStatut(projet.getStatut());
projet.setUtilisateurs(ut);
projet = projetDAO.store(projet);
projetDAO.flush();
return projet;
}
and this is the Projet Entity:
#Entity
public class Projet implements Serializable {
#Id
private Integer idprojet;
#ManyToMany(mappedBy = "projets", fetch = FetchType.LAZY)
java.util.List<com.gestion.projet.domain.Utilisateur> utilisateurs;
}
If you want the Checkbox based multiple selection on Primeface Datatable, no need to use the explicit h:selectManyCheckbox.
You could do that by specifying selectionMode="multiple" attribute on first/last p:column.
See the Primefaces Showcase.
Related
I want to update a <p:outputPanel id="personName"> inside a node of a tree using PrimeFaces AJAX update. I tried my approach both with PrimeFaces <p:tree> and OmniFaces <o:tree>. In both cases the nested <p:outputPanel> is not updated. Updating the whole tree works though. I think I assigned an id to all necessary elements.
To update the <p:outputPanel id="personName"> I nested a <p:autoUpdate on="person-change-event" />. The AutoUpdateTagHandler is picking up the <p:outputPanel> but the renderer is never called. Also, the updated <p:outputPanel id="personName"> is never part of the partial view response sent back to the client.
If I add the ids personTree or oTree to the update list of the command button it works. But I specifically want to update only parts of the node to save costs. What am I doing wrong?
I created a minimal working example which I will describe:
PrimeFaces tree:
<p:card id="personTreeCard">
<f:facet name="title">Persons (PrimeFaces)</f:facet>
<p:tree id="personTree"
var="person"
value="#{personTreeModel}">
<p:treeNode>
<p:outputPanel layout="inline" id="personId">
(<h:outputText value="#{person.dbId}"/>)
</p:outputPanel>
<p:outputPanel layout="inline" id="personName" styleClass="person-#{person.state}">
<h:outputText value="#{person.name}"/>
<p:autoUpdate on="person-change-event"/>
</p:outputPanel>
</p:treeNode>
</p:tree>
</p:card>
OmniFaces tree:
<p:card id="otherPersonTreeCard">
<f:facet name="title">Persons (OmniFaces)</f:facet>
<o:tree value="#{otherPersonTreeViewModel.root}" var="person" varNode="node" id="oTree">
<o:treeNode level="0">
<ul class="person-list">
<o:treeNodeItem id="personNode">
<li class="person-list-item">
<p:outputPanel layout="inline" id="oPersonId">
(<h:outputText value="#{person.dbId}"/>)
</p:outputPanel>
<p:outputPanel layout="inline" id="oPersonName"
styleClass="person-#{person.state}">
<h:outputText value="#{person.name}"/>
<p:autoUpdate on="person-change-event"/>
</p:outputPanel>
</li>
</o:treeNodeItem>
</ul>
</o:treeNode>
</o:tree>
</p:card>
I have a simple form that selects a Person and updates the name by appending a random number to the end:
<h:form id="personForm">
<p:card id="settingsCard">
<div class="ui-fluid p-formgrid p-grid">
<div class="p-field p-col-12">
<p:selectOneMenu id="personSelectOneMenu"
converter="omnifaces.SelectItemsConverter"
value="#{personFormViewModel.selectedPerson}">
<f:selectItems value="#{personSessionModel.personList}"
itemLabel="(#{person.dbId}) #{person.name}"
itemValue="#{person}"
var="person"/>
<f:selectItem noSelectionOption="true" itemLabel="-- select person --"/>
<p:ajax/>
</p:selectOneMenu>
</div>
<div class="p-field p-col-12">
<p:commandButton value="Change person"
update="#this #obs(person-change-event) #id(personName) personSelectOneMenu messages"
action="#{personFormAction.changePersonAction}"/>
</div>
</div>
</p:card>
</h:form>
Backing Beans:
#Model
public class PersonTreeModel extends RootTreeNode implements Serializable {
private static final long serialVersionUID = 454578540550974256L;
#Inject
private PersonSessionModel personSessionModel;
#PostConstruct
void onPostConstruct() {
final List<TreeNode> personTreeNodes = personSessionModel.getPersonList()
.stream()
.map(this::createPersonNode)
.collect(Collectors.toList());
this.setChildren(personTreeNodes);
}
private TreeNode createPersonNode(final Person person) {
final DefaultTreeNode personNode = new DefaultTreeNode(person);
this.addTreeNode(person.getDbId(), personNode);
return personNode;
}
}
#Slf4j
#Named
#ApplicationScoped
public class PersonSessionModel {
#Inject
private PersonService personService;
private static final int NUMBER_OF_PERSONS = 10;
#Getter
private List<Person> personList;
#PostConstruct
private void onPostConstruct() {
log.info("Creating {} persons", NUMBER_OF_PERSONS);
this.personList = personService.createPersons(NUMBER_OF_PERSONS);
}
}
#Getter
#Setter
#ViewModel
public class PersonFormViewModel implements Serializable {
private static final long serialVersionUID = -4933603892578811138L;
private Person selectedPerson;
}
#Action
public class PersonFormAction {
private static final Random RANDOM = new Random();
#Inject
private PersonFormViewModel viewModel;
#Inject
private PersonTreeModel treeModel;
public void changePersonAction() {
final Person selectedPerson = viewModel.getSelectedPerson();
if (selectedPerson.getState().equals("alive")) {
selectedPerson.setState("dead");
} else {
selectedPerson.setState("alive");
}
selectedPerson.setName(selectedPerson.getName() + " " + RANDOM.nextInt(10));
treeModel.onPostConstruct();
}
}
#ViewModel
public class OtherPersonTreeViewModel implements Serializable {
private static final long serialVersionUID = -5150070481006078761L;
#Getter
private TreeModel<Person> root;
#Inject
private PersonSessionModel personSessionModel;
#PostConstruct
private void onPostConstruct() {
root = new ListTreeModel<>();
personSessionModel.getPersonList().forEach(root::addChild);
}
}
I recently was placed on a project to add some new functionality to an existing jsf page. Things have been going smoothly up until this point. For the last week or two I have been consulting google and other stack overflow entries in an attempt to make this function correctly.
I have datatable on my xhtml page with a number of entries, some which have a h:selectmanycheckbox in them. The table and the checkboxes are all dynamically created. I can create the checkboxes without any trouble. I can also set their initial state to checked or unchecked based on database entries. However, I cannot pull any changes from the user when the form is submitted. The values returned are always equal to the initial state, regardless of what the user has entered.
AddRemoveSkills.xhtml
<h:panelGrid id="allSkills" style=" width : 706px;">
<ui:repeat var="cat" value="#{skillsController.masterCategories}"
varStatus="status">
<h:form
rendered="#{cat.toString().equalsIgnoreCase(skillsController.mode)||skillsController.mode.equalsIgnoreCase('Show All Skills')}">
<h3 class="arSkillsHeader">
<h:outputLabel value="#{cat.toString()}"
style="font-weight:bold" />
</h3>
<h:dataTable style="margin-left:15px; margin-right:15px"
class="suggestionsTable" var="skill"
rowClasses="gray, lightgraybg"
columnClasses="null, hCol3, null, null"
value="#{skillsController.getSkillsByCategory(cat)}">
<h:column>
<h:graphicImage value="/resources/images/success.png"
style="height:20px"
rendered="#{skillsController.hasSkill(cat.toString(), skill.name.toString())}" />
</h:column>
<h:column>
<h:outputText value="#{skill.name.toString()}" />
</h:column>
<h:column>
<!-- CheckBoxProblems lie here -->
<h:selectManyCheckbox id="versions"
layout ="lineDirection"
style = "text-align: left;"
value = "#{skill.checkedVersions}">
<f:selectItems value="#{skillsController.getVersions(skill.getName(), skill.getCategoryName())}"/>
</h:selectManyCheckbox>
</h:column>
<h:column>
<h:selectOneMenu value="#{skill.proficiency}">
<f:selectItem
itemValue="#{skillsController.timeList.get(0)}"
itemLabel="Select Experience Level" />
<f:selectItems
value="#{skillsController.timeList.subList(1, skillsController.timeList.size())}" />
<f:ajax listener="#{skill.setModified(true)}"/>
<f:ajax event="click" render="#this" />
</h:selectOneMenu>
</h:column>
</h:dataTable>
<h:panelGroup layout="block" style="height:20px">
<h:commandButton value="Update Category" style="float:right; margin-right:15px;"
action="#{skillsController.updateCategorySkills(cat)}"
onclick="updatePro(this.id);">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:panelGroup>
</h:form>
</ui:repeat>
</h:panelGrid>
Skill.java
public class Skill implements Comparable<Skill> {
protected String skill;
protected String category;
private String proficiency;
private List<String> checkedVersions = new ArrayList<String>();
private boolean modified;
Logger logger = Logger.getLogger(Skill.class);
...
/**
* Gets a list of versions for this user's skill
*
* #return Returns a string list containing the versions of this skill that the user has
*/
public List<String> getCheckedVersions() {
return checkedVersions;
}
/**
* Sets a list of versions for this user's skills
*
*
* #param checkedVersions A string list of checked versions
*/
public void setCheckedVersions(List<String> checkedVersions) {
if(checkedVersions != null){
this.checkedVersions = checkedVersions;
logger.info("Inside Skill, setCheckedVersions " + checkedVersions.toString()+ "skill name is: " + this.skill );
}
}
SkillsController.java
#ManagedBean
#SessionScoped
public class SkillsController implements Serializable {
private static final long serialVersionUID = 1270888906016432185L;
#ManagedProperty(value = "#{activeUser}")
private ActiveUser user;
private TreeMap<String, Skill> allSkillMap;
private Map<String, Map<String, List<String>>> versionList;
private Map<String, Map<String, List<String>>> checkedVersionList;
public Skill getUserSkillByName(String name) {
for (Skill skill : user.getSelfEmployee().getSkills()) {
if (skill.getName().equals(name)) {
if(checkedVersionList.containsKey(skill.getCategoryName())){
if(checkedVersionList.get(skill.getCategoryName()).containsKey(skill.getName())){
skill.setCheckedVersions(checkedVersionList.get(skill.getCategoryName()).get(skill.getName()));
}
}
return skill;
}
}
return null;
}
/**
* Get Versions for Skill
*
* #param skillName
* #param categoryName
*
* #return returns a list containing all versions for this particular skill/category
*/
public List<String> getVersions(String skillName, String categoryName) {
if(versionList.containsKey(categoryName)){
if( versionList.get(categoryName).containsKey(skillName)){
return versionList.get(categoryName).get(skillName);
}
}
return null;
}
ActiveUser.java
#ManagedBean
#SessionScoped
public class ActiveUser {
private Employee selfEmployee; // the current employee object
Employee.java
#RequestScoped
public class Employee implements Comparable<Employee>, Serializable {
private static final long serialVersionUID = 4875706805440817545L;
private TreeSet<Skill> skills;
I have tried to show how all of my classes are scoped without cluttering this up with excess code. If there is anything more you would like me to add, let me know.
Thanks in advance for any help given, I am at my wit's end on this problem.
Please try to use only one form, and don't iterate through h:form. like you do here :
<ui:repeat var="cat" value="#{skillsController.masterCategories}"
varStatus="status">
<h:form
rendered="#{cat.toString().equalsIgnoreCase(skillsController.mode)||skillsController.mode.equalsIgnoreCase('Show All Skills')}">
So you can use this :
<h:form>
<ui:repeat var="cat" value="#{skillsController.masterCategories}"
varStatus="status">
<p:column>
<p:commandButton id="selectButton" update="#(form)" oncomplete="userDialog.show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{book}" target="#{CreateBookBean.selectedUser}" />
</p:commandButton>
</p:column>
</p:dataTable>
</p:outputPanel>
<p:dialog header="User Detail" modal="true" widgetVar="userDialog" width="200" height="175">
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="fname" value="First Name: " />
<h:outputText id="fname" value="#{CreateBookBean.selectedUser.fname}" />
<h:outputLabel for="lname" value="Last Name: " />
<h:outputText id="lname" value="#{CreateBookBean.selectedUser.lname}" />
<h:outputLabel for="mobileno" value="mobile no: " />
<h:outputText id="mobileno" value="#{CreateBookBean.selectedUser.mobileno}" />
</h:panelGrid>
</p:dialog>
i came across this example recently.
the datatable is properly getting updated with the values i enter. but when i want to display it in the dialog box its not displaying anything.
and i actually don understand why value="#{CreateBookBean.selectedUser.fname}" is used instead of value="#{CreateBookBean.fname}".
here is my java code
public class CreateBookBean {
private Book book = new Book();
private List<Book> books = new ArrayList<Book>();
private Book selectedUser;
public String reinit() {
book = new Book();
return null;
}
setters and getters are included here
}
Lets split this question in two parts.
First:
When you want to display updated values (e.g. with a h:outputText), you need to update this element. Updating this element means, it will fetch the current value of it's backing bean.
Do it like this:
<p:commandButton ... update="idToUpdate1, idToUpdate2, ..." >
In order to get the idToUpdate check Naming Container in JSF2/PrimeFaces.
If you have many components which need an update, I would recomment grouping them into one NamingContainer (e.g. p:outputPanel). So you only have to update the NamingContainer, and not every single component.
Second:
#CreateBookBean.selectUser.fname means: "Fetch the CreateBookBean, fetch it's property selectUser and fetch the property of selectUser called fname".
In this case you would have these class layouts:
public class CreateBookBean {
private Book selectedUser;
....
public Book getSelectedUser() {
return this.selectedUser;
}
}
public class Book {
private String fname;
....
public String getFname() {
this.fname;
}
}
#CreateBookBean.fname means: "Fetch the CreateBookBean, fetch it's property fname".
In this case you would have this class layout:
public class CreateBookBean {
private String fname;
....
public String getFname() {
return this.fname;
}
}
According to this code you posted, i guess that the CreateBookBean has a property called selectedUser (the code reveals it: target="#{CreateBookBean.selectedUser}"), and the selectUser has a property fname.
Use the Update attribute in the button your using to display the dialog box, for example, <p:commandButton update="dialogBoxId" . . ./> in order to display the items from your datatable.
In my xhtml page i have two dependant selectOneMenu, with the second one being filled in an ajax call. Here's the jsf code fragment:
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel value="Dirección:" for="direccion"/>
<p:inputText id="direccion" value="#{datosInstitucion.institucion.direccion}" required="true" label="Dirección"/>
<h:outputLabel value="Departamento:" for="departamento"/>
<p:selectOneMenu id="departamento" value="#{datosInstitucion.idDepartamento}" required="true" label="Departamento">
<f:selectItem itemLabel="Seleccione el departamento" itemValue="#{null}"/>
<c:forEach items="#{datosInstitucion.departamentos}" var="departamento">
<f:selectItem itemLabel="#{departamento.nombre}" itemValue="#{departamento.id}"/>
</c:forEach>
<f:ajax render="municipio" listener="#{datosInstitucion.cargarMunicipios()}"/>
</p:selectOneMenu>
<h:outputLabel value="Municipio:" for="municipio"/>
<p:selectOneMenu id="municipio" value="#{datosInstitucion.idMunicipio}" required="true" label="Municipio">
<f:selectItem itemLabel="Seleccione el municipio" itemValue="#{null}"/>
<c:forEach items="#{datosInstitucion.municipios}" var="municipio">
<f:selectItem itemLabel="#{municipio.nombre}" itemValue="#{municipio.id}"/>
</c:forEach>
</p:selectOneMenu>
</h:panelGrid>
This fragment of code is inside a primefaces wizard component, so when the 'next' button is pressed a validation error is caused for the second selectOneMenu even when there's a value set.
What could be causing this behavior?
Relevant backing bean code:
#ManagedBean(name = "datosInstitucion")
#ViewScoped
public class DatosInstitucion implements Serializable{
#EJB
private Instituciones instituciones;
#EJB
private Parametros parametros;
#Inject
private Mensajes mensajes;
private List<Departamento> departamentos;
private List<Municipio> municipios;
private Map<Integer, Departamento> mapaDepartamentos;
private Integer idDepartamento;
private Integer idMunicipio;
private Institucion institucion;
#PostConstruct
private void inicializar(){
this.mapaDepartamentos = new HashMap<>();
this.departamentos = parametros.consultarDepartamentos();
for(Departamento departamento : departamentos){
this.mapaDepartamentos.put(departamento.getId(), departamento);
}
this.prepararInstitucion();
}
private void prepararInstitucion(){
this.institucion = new Institucion();
this.institucion.setResponsable(new Persona());
}
public Institucion getInstitucion() {
return institucion;
}
public List<Departamento> getDepartamentos(){
return departamentos;
}
public TipoIdentificacion[] getTiposIdentificacion(){
return TipoIdentificacion.deResponsables();
}
public Integer getIdDepartamento() {
return idDepartamento;
}
public void setIdDepartamento(Integer idDepartamento) {
this.idDepartamento = idDepartamento;
}
public Integer getIdMunicipio() {
return idMunicipio;
}
public void setIdMunicipio(Integer idMunicipio) {
this.idMunicipio = idMunicipio;
}
public void cargarMunicipios(){
idMunicipio = null;
if(idDepartamento != null){
this.municipios = mapaDepartamentos.get(idDepartamento).getMunicipios();
}else{
this.municipios = Collections.emptyList();
}
}
public List<Municipio> getMunicipios() {
return municipios;
}
public void confirmar(){
this.instituciones.guardar(institucion);
this.mensajes.exito("La institución ha sido registrada en el sistema");
this.prepararInstitucion();
}
}
This is because you are using JSTL <c:foreach> with JSF. The life cycle of JSTL vs JSF matters. JSTL is executed when the view is being built, while JSF is executed when the view is being rendered. The two do not work in synch with each other. In your case, you need to use <f:selectItems> instead of <c:foreach>
Replace:
<c:forEach items="#{datosInstitucion.municipios}" var="municipio">
<f:selectItem itemLabel="#{municipio.nombre}" itemValue="#{municipio.id}"/>
</c:forEach>
with:
<f:selectItems value="#{datosInstitucion.municipios}"
var="municipio" itemLabel="#{municipio.nombre}"
itemValue="#{municipio.id}"/>
For more reading, I suggest you to read the following answer
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