I have a simple form in JSF and I want to add the bean associated with this form in an ArrayList.
Here my form :
<h:form styleClass="form-horizontal">
<div class="row bottom-offset-20">
<div class="col-sm-4">
<div>
<h:outputLabel for="pseudo">pseudo</h:outputLabel>
</div>
<div>
<h:inputText id="pseudo" styleClass="form-control input-lg" value="${storyController.story.author}"/>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h:commandButton action="#{storyController.save}" styleClass="btn btn-primary btn-lg" value="send.story.button"/>
</div>
</div>
</h:form>
My controller :
#Named
#RequestScoped
public class StoryController implements Serializable {
private DefaultStoryService defaultStoryService;
#Inject
private Story story;
#Inject
public StoryController(DefaultStoryService defaultStoryService) {
this.defaultStoryService = defaultStoryService;
}
public String save() {
defaultStoryService.save(story);
return "index.xhtml";
}
public void setStory(Story story) {
this.story = story;
}
public Story getStory() {
return story;
}
}
The service :
#Named
#RequestScoped
public class DefaultStoryService {
#Inject
StoryMock mock;
public void save(Story story) {
mock.addStory(story);
}
}
The ArrayList:
#Named
#SessionScoped
public class StoryMock implements Serializable {
private List<Story> stories;
#PostConstruct
public void setupData() {
stories = new ArrayList<>();
}
public List<Story> getStories() {
return stories;
}
public void setStories(List<Story> stories) {
this.stories = stories;
}
public void addStory(Story story) {
stories.add(story);
}
}
And the story bean:
#Model
public class Story implements Serializable {
private Long id;
private String author;
}
My problem is that when a create a new story and save it, all the stories in the list are updated with the new values.
In my debugger, at the first call :
first call
And the second call :
second call
It's like the request scope does not work.
I don't get why the bean is not just add to the list, but it replace all the bean added before.
Please create and assign the Story object in a postconstruct method in controller and do not use #Inject to inject it.
Related
i am using a selectMultiMenu from bootsFaces, the initial values are showed perfectly, but after rendered, with the new values the combo doesnt open, if I check the source code in my browser it shows that the bean loeaded the values correctly. It only happens with this bootsFaces's element, the rest of my project with jsf render with no problems with ajax.
Any clue? Thanks!
<h:form id="form-Principal">
<h:panelGroup id="panel-Principal" layout="block" >
<div class="col-md-12">
<div class="col-md-1">
<label for="servicio" class="control-label">Servicio:</label>
</div>
<div class="col-md-2">
<h:selectOneMenu disabled="#{empty testops.ambiente}" id="servicio" class="combobox form-control" value="#{testops.servicio}" >
<f:selectItem itemValue="" itemLabel="Seleccione..."/>
<f:selectItems value="#{testops.listServicios}" />
<f:ajax event="change" listener="#{testops.obtenerOperaciones}" render="cboperacion" execute="#this"></f:ajax>
</h:selectOneMenu>
<h:message for="servicio" class="error"/>
</div>
<div class="col-md-1">
<label for="operacion" class="control-label">Operación:</label>
</div>
<div class="col-md-2">
<b:selectMultiMenu id="cboperacion" value="#{testops.operacion}" nonSelectedText="Seleccione...">
<f:selectItems value="#{testops.operaciones}"/>
</b:selectMultiMenu>
</div>
<div class="col-md-1">
</div>
<div class="col-md-1">
<f:ajax render=":salida form-Principal:panel-Principal" execute="#form" onevent="loading">
<h:commandLink class="btn btn-danger boton_rojo pull-right" value="Ejecutar" action="#{testops.ejecutarOperaciones()}"></h:commandLink>
</f:ajax>
</div>
</div>
</h:panelGroup>
</h:form>enter code here
Onload:
After rendering, it has diffent values, but combo is not display.
I've tried to reproduce your bug without success. Or rather: the code works as intended. The <b:selectMultMenu> is updated with the new values.
[meta] I know this isn't an answer (yet)... I just chose the answer because it's the only way to include source code. [/meta]
So I suggest you
copy me example code below into your project and see if it works
or you send me a "reproducer", i.e. a tiny but complete project showing the problem. For instance, you could upload a Maven project to GitHub. Please reduce the reproduces as much as possible. For instance, I need to be able to run it without configuring a database.
Here's the sourcecode I used to reproduce your bug:
As a basis, I used our showcase.
I copied your JSF code snippet into the empty.xhtml.
I created a JSF bean as follows:
package de.beyondjava.jsf.sample.carshop;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Testops {
private String ambiente = "que";
private List<String> listServicios = new ArrayList<>();
private String operacion;
private List<String> operaciones = new ArrayList<>();
private String servicio;
{
listServicios.add("Servicio 1");
listServicios.add("Servicio 2");
shuffleOperaciones();
}
public void ejecutarOperaciones(Object o) {
}
public String getAmbiente() {
return ambiente;
}
public List<String> getListServicios() {
return listServicios;
}
public String getOperacion() {
return operacion;
}
public List<String> getOperaciones() {
return operaciones;
}
public String getServicio() {
return servicio;
}
public void obtenerOperaciones(Object o) {
shuffleOperaciones();
}
public void setAmbiente(String ambiente) {
this.ambiente = ambiente;
}
public void setListServicios(List<String> listServicios) {
this.listServicios = listServicios;
}
public void setOperacion(String operacion) {
this.operacion = operacion;
}
public void setOperaciones(List<String> operaciones) {
this.operaciones = operaciones;
}
public void setServicio(String servicio) {
this.servicio = servicio;
}
private void shuffleOperaciones() {
operaciones = new ArrayList<>();
for (int i = 0; i < 4; i++) {
operaciones.add("opción " + Math.ceil(Math.random()*1000));
}
}
}
When I chose one of the options of the first combobox, the <b:selectMultiMenu> is updated with the new (random) values.
Basically , in the input.xhtml there is a form which takes a username and password and if they are equal to a specific value(doesn't matter the value) the program should print a message in the browser, but this doesn't happen. To make sure of the problem i added 2 lines of "System.out.println(...)" where i print the value of the property and what i found out is that the properties are still null even after i submit. So after i click send in the console is written "null null". Any help is appreciated!
This is the UserBean class (backing bean)
package bean;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class UserBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String password;
private String output_message;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String go(){
output_message = "";
if(name == null && password == null){
output_message += "Both fields cannot be empty!";
}else if(name == "name" && password == "pass"){
output_message += "Success!";
}else{
output_message += "Data is wrong!";
}
System.out.println(name);
System.out.println(password);
return output_message;
}
public String getOutput_message() {
return output_message;
}
public void setOutput_message(String output_message) {
this.output_message = output_message;
}
public String ret(String r){
return r;
}
}
This is the input.xhtml file, that contains the form that will submit the data to the bean. (Ignore the url to template.xhtml, it's just a parent template that has a header and a footer other than the mid-content that input.xhtml defines)
<!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:cc="http://java.sun.com/jsf/composite/myComponent">
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<style type="text/css">
#form1{
position: absolute;
top: 20%;
left:40%;
border: 1px solid black;
background-color: orange;
}
td{
padding-top:10px;
}
input[type="text"]{
backgorund-color:blue;
}
</style>
<form id="form1" method="post">
<table columns="2">
<tr>
<td><span>Emri:</span></td>
<td><input type="text" id="emri" value="#{userBean.name}"/></td>
</tr>
<tr>
<td><span>Password:</span></td>
<td><input type="password" id="pass" value="#{userBean.password}"/></td>
</tr>
<tr>
<td colspan="2" align="center"><button type="submit" onclick="#{userBean.go()}">Send</button></td>
</tr>
</table>
</form>
<p>#{user.output_message}</p>
</ui:define>
</ui:composition>
</html>
The problem caused by the button html tag. Don't use HTML buttons or anchors if you want to use the JSF mechanism. Instead use (button/link) components to submit the page. Define the navigation rules ot the userBean.go should pass back the next page name.
I just solved this. the problem was with the input tag, the value attribute does not represent the value written in the textbox is just some kind of a default value or somekind of a pre-value. Anyway instead of input and form tags i used and which worked out fine
h is a namespace with url xmlns:h="http://xmlns.jcp.org/jsf/html"
I've got a bit of a problem. Basically I have a page with a form containing an input text field, a search button and a ui:repeat structure that displays the results of the search using more input text fields and a couple of other buttons (the idea is to list all search hits and allow the user to edit them directly from the same page). Now, the search and the display part works well - it does what it's supposed to. However, when I try to click on one of the buttons that are displayed in the ui:repeat section, the action isn't invoked.
When I press the search button (Pretraga in code) a function is called in the Kupac bean which then gets the results from the database and places them into a list and finally redirects back to the same page (from my understanding this will load the page again) and lists the results using the ui:repeat component. But as I said, when I press the other buttons (Izmeni and Glavna in code) they do nothing. Kupac bean is #RequestScoped and I already tried changing it to #ViewScoped, however this only made it worse by having the search not work as well (i.e. it will display nothing).
Here's the JSF page 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://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Pregled kupaca</title>
</h:head>
<h:body>
<h3 align="center">Pregled kupaca</h3>
<h:form>
<table align="center">
<tr>
<td align="center" colspan="2"><h:link outcome="pocetna.xhtml">Pocetna</h:link></td>
</tr>
<tr>
<td>Firma</td>
<td><h:inputText value="#{kupac.naziv_firme}"/></td>
</tr>
<tr>
<td align="center" colspan="2">
<h:commandButton action="#{kupac.listKupci()}" value="Pretraga">
</h:commandButton>
</td>
</tr>
</table>
<br/>
<ui:repeat value="#{kupac.zeljeni_kupci}" var="kupac">
<table align="center" border="1">
<tr>
<td>Ime i prezime</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli ime i prezime!"
value="#{kupac.ime_prezime}"/></td>
</tr>
<tr>
<td>Adresa</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli adresu!"
value="#{kupac.adresa}"/></td>
</tr>
<tr>
<td>Naziv firme</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli naziv firme!"
value="#{kupac.naziv_firme}"/></td>
</tr>
<tr>
<td>Adresa firme</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli adresu firme!"
value="#{kupac.adresa_firme}"/></td>
</tr>
<tr>
<td>Br. telefona</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli broj telefona!"
value="#{kupac.br_tel}"/></td>
</tr>
<tr>
<td>
<h:commandButton value="Izmeni" action="#{kupac.izmenaKupca()}"/>
</td>
<td><h:commandButton action="#{kupac.test()}" value="Glavna"/></td>
</tr>
</table>
<br/><br/>
</ui:repeat>
</h:form>
</h:body>
</html>
and here's the full bean code in Java:
package beans;
import exceptions.DBException;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ViewScoped;
import util.Database;
#ManagedBean
#RequestScoped
public class Kupac implements Serializable {
private int id_kupac;
private String ime_prezime;
private String adresa;
private String naziv_firme;
private String adresa_firme;
private String br_tel;
private List<Kupac> svi_kupci;
private List<Kupac> zeljeni_kupci;
public void init() {
listKupci();
}
public void poruka() {
System.out.println("ID "+id_kupac);
}
public String test() {
return "pocetna";
}
public String izmenaKupca() throws DBException {
Kupac kupac = new Kupac();
Database db = Database.getInstance();
kupac.setId_kupac(id_kupac);
kupac.setIme_prezime(ime_prezime);
kupac.setAdresa(adresa);
kupac.setNaziv_firme(naziv_firme);
kupac.setAdresa_firme(adresa_firme);
kupac.setBr_tel(br_tel);
try {
db.updateKupac(kupac);
} catch (DBException ex) {
return "error";
}
return "pregled_kupaca";
}
public String unosKupca() throws DBException {
Kupac kupac = new Kupac();
Database db = Database.getInstance();
kupac.setIme_prezime(ime_prezime);
kupac.setAdresa(adresa);
kupac.setNaziv_firme(naziv_firme);
kupac.setAdresa_firme(adresa_firme);
kupac.setBr_tel(br_tel);
try {
db.insertKupac(kupac);
} catch (DBException ex) {
return "error";
}
return "pocetna";
}
public String listKupci() {
Database db = Database.getInstance();
zeljeni_kupci = new LinkedList<Kupac>();
try {
svi_kupci = db.listKupci();
for (Kupac k : svi_kupci) {
if (k.naziv_firme.equals(naziv_firme) || "".equals(naziv_firme)) {
zeljeni_kupci.add(k);
}
}
} catch (DBException ex) {
return "error";
}
return "pregled_kupaca";
}
public List<Kupac> getZeljeni_kupci() {
return zeljeni_kupci;
}
public void setZeljeni_kupci(List<Kupac> zeljeni_kupci) {
this.zeljeni_kupci = zeljeni_kupci;
}
public List<Kupac> getSvi_kupci() {
return svi_kupci;
}
public void setSvi_kupci(List<Kupac> svi_kupci) {
this.svi_kupci = svi_kupci;
}
public int getId_kupac() {
return id_kupac;
}
public void setId_kupac(int id_kupac) {
this.id_kupac = id_kupac;
}
public String getIme_prezime() {
return ime_prezime;
}
public void setIme_prezime(String ime_prezime) {
this.ime_prezime = ime_prezime;
}
public String getAdresa() {
return adresa;
}
public void setAdresa(String adresa) {
this.adresa = adresa;
}
public String getNaziv_firme() {
return naziv_firme;
}
public void setNaziv_firme(String naziv_firme) {
this.naziv_firme = naziv_firme;
}
public String getAdresa_firme() {
return adresa_firme;
}
public void setAdresa_firme(String adresa_firme) {
this.adresa_firme = adresa_firme;
}
public String getBr_tel() {
return br_tel;
}
public void setBr_tel(String br_tel) {
this.br_tel = br_tel;
}
/**
* Creates a new instance of Kupac
*/
public Kupac() {
}
}
I'm using JSF 2.2 on a GlassFish 4.0 server using Netbeans 7 IDE.
Sorry for the long post and the fact that this question has now been asked several times, but I haven't managed to fix it for 2 hrs now and would appreciate any help. Cheers!
I want to display menu in JSF template. Every user of my application has different menu and the menu is stored in database. Here is my code,
MenuBean.java
public List<Menuitem> getUserMenu() {
List<Menuitem> menuitems = (List<Menuitem>) em.createQuery("_____________").setParameter("_______", _______).getResultList();
return menuitems;
}
pageTemplate.xhtml
<div class="container">
<div id="navigation">
<ul>
<ui:repeat var="_item" value="#{menuitemBean.userMenu}">
<li><h:outputLink value="#{_item.url}">
<h:outputText value="#{_item.name}" />
</h:outputLink></li>
</ui:repeat>
</ul>
</div>
<div id="content">
<h1>
<ui:insert name="header" />
</h1>
<h2>
<ui:insert name="subheader" />
</h2>
<ui:insert name="main" />
</div>
</div>
Problem is each time I navigate to a new page (.xhtml file) which is using the same template (pageTemplate.xhtml) the menu is loading all over again.
How can I load the menu only once per user.
If the menu is dependent on the user, it would be better to create a bean with a scope session that will store the content of this menu.
This way, once the menu is initialized the first time, it will not be re-initialized. Your code will look like that:
public class MySessionBean ... {
private List<Menuitem> menuItems = null;
public List<Menuitem> getUserMenu() {
if (menuItems == null) {
// Initialize the menu items.
menuItems = ...;
}
return menuitems;
}
Note that you can also initialize the menuItems objects in the constructor, or in a post-construct method (i.e. a method called just after the bean is instantiated).
An important thing also : do not put database access code in your beans (your em.createQuery(...)). Move that on service / DAO layers, and let the bean call the service to retrieve the information needed to build the menu items.
You should NOT put logic accessing the database in a getter method, because they are often called more than once in the same request.
To load your menu once for each user, put the property in a #SessionScoped backing bean and then initialize it in a #PostConstruct annotated method:
#SessionScoped
public SomeBean {
private List<Menuitem> menuItems;
#PostConstruct
public void init() {
menuItems = (List<Menuitem>) em.createQuery("_____________")
.setParameter("_______", _______).getResultList();
}
// getter and setter for menuItems
}
As the bean is in the session scope, it will exist as one instance for each user session in your application.
Note that I assumed you are using JSF 2, because you tagged the question as java-ee-6.
I wrote a simple JSF form. The problem is that there is a bug that I can't find. When I open the main page and enter the username and password the page must redirect me to the next page but this is not happening. Can you help me to find my mistake?
This is the main login JSF page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:h="http://java.sun.com/jsf/html">
<head>
<title>Login</title>
<link rel="stylesheet" type="text/css" href="resources/css/style.css" />
<script src="resources/js/cufon-yui.js" type="text/javascript"></script>
<script src="resources/js/ChunkFive_400.font.js" type="text/javascript"></script>
<script type="text/javascript">
Cufon.replace('h1',{ textShadow: '1px 1px #fff'});
Cufon.replace('h2',{ textShadow: '1px 1px #fff'});
Cufon.replace('h3',{ textShadow: '0px 1px #000'});
Cufon.replace('.back');
</script>
</head>
<body>
<div class="wrapper">
<div class="content">
<div id="form_wrapper" class="form_wrapper">
<form class="login active">
<h3><center><img src="resources/images/title.png"/></center></h3>
<div>
<label>Username:</label>
<h:inputText value="#{loginController.user}"/>
<span class="error">This is an error</span>
</div>
<div>
<label>Password:</label>
<h:inputSecret value="#{loginController.password}"/>
<span class="error">This is an error</span>
</div>
<div class="bottom">
<h:commandButton label="Login" value="Login" action="#{loginController.user_compare}"/>
<div class="clear"></div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
This is the managed bean
/** Bean for checking users and passwords.
If the user enters the correct username and password
the user will be redirected to main.xhtml
If not the page will refresh. */
package com.dx.sr_57;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named("loginController")
#SessionScoped
public class user_check implements Serializable {
private String user;
private String password;
public user_check(){
}
public user_check(String user, String password){
super();
this.user = user;
this.password = password;
}
/** get the content of the variables from the JSF Login page */
public String setUser(String newValue) {
user = newValue;
return user;
}
public String getUser(){
return user;
}
public String setPassword(String newValue) {
password = newValue;
return password;
}
public String getPassword(){
return password;
}
public String user_compare() {
return "success";
}
}
You need to use a <h:form> component in order to get JSF inputs and commands to work.
So, replace
<form class="login active">
...
</form>
by
<h:form styleClass="login active">
...
</h:form>
You also need to fix your setters to be fullworthy setters, otherwise you might face a PropertyNotFoundException.
So, replace
public String setUser(String newValue) {
user = newValue;
return user;
}
public String setPassword(String newValue) {
password = newValue;
return password;
}
by
public void setUser(String newValue) {
user = newValue;
}
public void setPassword(String newValue) {
password = newValue;
}
Unrelated to the concrete problem, the HTML <center> tag is deprecated since 1998 and invalid in XHTML strict. Remove it. You need to set CSS text-align: center on the <img> instead.