Doubts about how to combine CDI beans: SessionScoped and RequestScoped - java

My goal is to present a jsf page that has Create, Retrieve and Update features.
I decided to create different CDI beans and different composite components for each of this operations and then put it all together in the page.
So far so good, but i just finished and i discovered a really confusing bug, and i don't know how to fix it:
The CDI bean tool that does the CREATE operation is a #RequestScoped bean, so the input fields clean them selves after the request.(See the image bellow)
I have no problem at all with it(Just that warning i cant get rid off), it works fine.
The next gadget i created is a data table that can also edit the data. To do it i needed to use a #SessionScopped CDI bean.(See image below)
Here comes the problem:
When the page is rendered the #SessionScoped bean caches the data in the session, but when new data is inserted, using the #RequestScoped bean,the data goes to the data base but the datatable does not display the new entered values, because are not in the session.
So what should i do?
Here i will show you the two beans:
THE CREATE BEAN
#Named("subjectControllerCreate")
#RequestScoped
public class SubjectControllerCreate implements Serializable {
private Subject currentSubject;
#EJB
private SubjectFacade ejbFacade;
//INITIALIZATION
public SubjectControllerCreate() {
currentSubject = new Subject();
}
//CREATE
public String create() {
try {
currentSubject.setCreationDate(new Date());
getSubjectFacade().create(currentSubject);//Adds the current subject to the database!
JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("SubjectCreated"));
return "";//Can perform a redirect here if we want
//}
//return null;
} catch (Exception e) {
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
return null;
}
}
THE UPDATE BEAN
#Named("subjectControllerUpdate")
#SessionScoped
public class SubjectControllerUpdate implements Serializable {
//Using DataModel<Subject> instead of List<Subject> is necessary in order to be able to get the current row.
private DataModel<Subject> subjects;
#EJB
private SubjectFacade ejbFacade;
//INITIALIZATION
#PostConstruct
public void init() {
subjects = new ListDataModel<Subject>(getSubjectFacade().findAll());
}
//RETRIEVE
public DataModel<Subject> retrieve() {
return subjects;
}
//UPDATE
public void update() {
getSubjectFacade().edit(subjects.getRowData());
}
//HELP METHODS
//RETURN THE FACADE FOR DATA MANIPULATION(Best practice)
private SubjectFacade getSubjectFacade() {
return ejbFacade;
}
//GETTERS AND SETTERS
public DataModel<Subject> getSubjects() {
return subjects;
}
public void setSubjects(DataModel<Subject> subjects) {
this.subjects = subjects;
}
}
Is it maybe possible to make the data table send some ajax request when detects that the Create dialog closes, to get the rest of the newly entered data?
If yes how could i do it?
This is the markup for my datatable:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<p:dataTable id="allSubjects" var="subject" value="#{subjectControllerUpdate.subjects}" paginator="true" rows="7" >
<p:ajax event="rowEdit" listener="#{subjectControllerUpdate.update()}"/>
<p:column headerText="Name" sortBy="#{subject.name}" style="width:200px" >
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.name}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.name}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{subject.description}" headerText="Description">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.description}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.description}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{subject.credits}" headerText="Credits" style="width:50px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.credits}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.credits}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Options" style="width:50px">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
</html>
Ill appreciate your help

Can't you just inject the #SessionScoped bean into the #RequestScoped bean and when create is clicked, call a method refresh in the #SessionScoped bean?

Related

Property [marca] not found on type [com.example.bean.CarBean]]

first of all, I am writing this because I am desperate. The thing is I was doing a simple Spring Boot CRUD with Primefaces. I used a bean called "carBean" to access the data in the index.xhtml file. Until there everything ok, things started to turn weird from now on. I tried to use a simple inputText to bind a text given in the UI to a property in the bean.
But I was constantly getting error 500, telling me that the property "marca" was not found in the bean, and I have checked 10000 times and everything is OK in there. So I started testing, and eventually I figured out that, the property that was working fine "carBean.cars" if I change the name to whatever I change (and obviously the methods liked to the property), It stop working. Is like the only property that works has to be named "cars". What I am missing here? Is driving me crazy, I promise this was my last resource. Thanks in advance .
carBean
package com.example.bean;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import com.example.controller.CarController;
import com.example.dto.CarDTO;
import lombok.Data;
#Data
#Named("carBean")
#Scope(value = "session")
public class CarBean implements Serializable {
private static final long serialVersionUID = -8338541378806874723L;
#Autowired
CarController carController;
private List<CarDTO> cars;
private Integer id;
private String marca;
private String modelo;
private String precio;
private String bastidor;
private String potencia;
public String getMarca() {
return marca;
}
public void setMarca(String marca) {
this.marca = marca;
}
public List<CarDTO> getCars() {
cars = carController.getAllCars();
return cars;
}
public void delete(CarDTO car) {
carController.deleteCar(car.id);
cars = carController.getAllCars();
}
public void add() {
CarDTO newCar = new CarDTO();
newCar.marca = this.marca;
newCar.modelo = this.modelo;
newCar.precio = this.precio;
newCar.bastidor = this.bastidor;
newCar.potencia = this.potencia;
carController.create(newCar);
}
public String redirect() {
return "index.xhtml?faces-redirect=true";
}
}
index.xhtml
<!DOCTYPE xhtml 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:rich="http://richfaces.org/rich"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<h3> REGISTRO DE COCHES </h3>
<h:form id = "tabla">
<div class="card">
<p:dataTable var="car" value="#{carBean.cars}">
<p:column sortBy="#{car.marca}" headerText="Marca">
<h:outputText value="#{car.marca}" />
</p:column>
<p:column sortBy="#{car.modelo}" headerText="Modelo">
<h:outputText value="#{car.modelo}" />
</p:column>
<p:column sortBy="#{car.precio}" headerText="Precio">
<h:outputText value="#{car.precio}" />
</p:column>
<p:column sortBy="#{car.bastidor}" headerText="Bastidor">
<h:outputText value="#{car.bastidor}" />
</p:column>
<p:column sortBy="#{car.potencia}" headerText="Potencia">
<h:outputText value="#{car.potencia}" />
</p:column>
<p:column>
<p:commandButton type="submit" value="Eliminar" actionListener="#{carBean.delete(car)}"
update=":tabla" />
<p:commandButton type="button" value="Editar"/>
</p:column>
</p:dataTable>
<p:commandButton value="Nuevo Coche" type="submit" oncomplete="PF('createModal').show();"/>
</div>
</h:form>
<p:dialog header="Agregar" widgetVar="createModal" id="createModal">
<h:form id="createDialog">
<p:panel header="Detalles del coche">
<h:panelGrid columns="1">
<h:outputLabel value="Marca:"/>
<h:inputText id="marca" value="#{carBean.marca}" required="true"> </h:inputText>
<h:outputLabel value="Modelo"/>
<h:inputText id="modelo"> </h:inputText>
<h:outputLabel value="Precio"/>
<h:inputText id="precio"> </h:inputText>
<h:outputLabel value="Bastidor"/>
<h:inputText id="bastidor"> </h:inputText>
<h:outputLabel value="Potencia"/>
<h:inputText id="potencia"> </h:inputText>
</h:panelGrid>
</p:panel>
</h:form>
</p:dialog>
</h:head>
</html>
Why I cannot used other property that isn´t called "cars"?
Don't mess Lombok #Data autogenerated getters and setters with the one you've declared in the Bean.
You have used a getter as a method, which is not a good thing to do because it can be called multiple times, see: Why JSF calls getters multiple times
public List<CarDTO> getCars() {
cars = carController.getAllCars(); // remove business logic from getter
return cars;
}
Better initialize your private List<CarDTO> cars variable in a method annotated with #PostContruct
#PostConstruct
public void init() {
cars = carController.getAllCars();
}
For more check this example: PrimeFaces DataTable CRUD

Primefaces In cell editing data table event.getNewValue() sends the old value to the bean

I am trying to use the feature of prime faces which allows user to edit the cell data in the table itself.I have followed this link to achieve it:
Primefaces showcase
When I say edit a cell in the table, new values which are entered are not sent to the bean.It still shows the old values only.
My code JSF:
<h:form id="testform">
<p:growl id="messages" showDetail="true" />
<p:outputPanel id="testContainer" deferred="true">
<p:remoteCommand name="oncompleteCellEdit" update="cars messages" />
<p:dataTable id="cars" var="car" value="#{articlesbean.LMatpilotaccess1}" editable="true" editMode="cell" widgetVar="carsTable" update=":cars">
<f:facet name="header">
Matériel du pilotage et accessoires
</f:facet>
<p:ajax event="cellEdit" listener="#{articlesbean.onCellEdit}" oncomplete="oncompleteCellEdit()" update=":testform:messages" />
<p:column headerText="Serie" style="width:25%">
<p:cellEditor >
<f:facet name="output"><h:outputText value="#{car.serie}" /></f:facet>
<f:facet name="input"><p:inputText id="modelInput16" value="#{car.serie}" style="width:96%"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Cap" style="width:25%">
<p:cellEditor >
<f:facet name="output"><h:outputText value="#{car.cap}" /></f:facet>
<f:facet name="input"><p:inputText id="modelInput15" value="#{car.cap}" style="width:96%"/></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</p:outputPanel>
</h:form>
My code bean
#ManagedBean(name="articlesbean")
#ViewScoped
public class ArticlesBean implements Serializable{
#Inject
private ArticlesDAO articleDAO;
private Matpilotaccess1 matpilotaccess1;
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println("/////"+(event.getNewValue());
System.out.println("/////"+(event.getOldValue());
FacesContext context = FacesContext.getCurrentInstance();
Matpilotaccess1 mpltiacc = context.getApplication().evaluateExpressionGet(context, "#{mpltiacc}", Matpilotaccess1.class);
articleDAO.Updatetable(mpltiacc);
}
/////////Getters and Setters
}
and as result of
System.out.println("/////"+(event.getNewValue());
System.out.println("/////"+(event.getOldValue());
i got in both case the old value!!!
Could anyone let me know how I can get the new values???I am using Jboss 7 and primefaces4 Thanks
You need to annotate your bean with #SessionScoped annotation.

primefaces tabview onChange not fired

i wish to display 2 different datatables in each tab of the tabview of primefaces 3.2.
there datatables will fetch data based on the 'type' variable set in the onChange event. but my problem is that the onChange event does not fire at all.
pls check my tabview code to check why this is happening:
<h:form id="frm">
<p:tabView activeIndex="#{equityBean.activeIndex}">
<p:ajax event="tabChange" listener="#{equityBean.onChange}" update=":frm"/>
<p:tab title="NSE" binding="#{equityBean.tbn}">
<p:dataTable binding="#{equityBean.dt}" value="#{equityBean.scripList}" var="scrip">
<f:facet name="header">
Scrip Symbol
</f:facet>
<h:outputText value="#{scrip.scripSymbol}"/>
<f:facet name="header">
Company Name
</f:facet>
<h:outputText value="#{scrip.companyName}"/>
<f:facet name="header">
Volume
</f:facet>
<h:outputText value="#{scrip.totalTradedVolume}"/>
</p:dataTable>
</p:tab>
<p:tab title="BSE" binding="#{equityBean.tb}">
</p:tab>
</p:tabView>
</h:form>
bean:
public void onChange(TabChangeEvent event) {
type=event.getTab().getTitle();
}
edited:
bean code to get datatable value:
public List<MasterScrip> getScripList() {
scripList=new ArrayList<MasterScrip> ();
scripList=getScripByVolumeType(type);
return scripList;
}
private java.util.List<service.MasterScrip> getScripByVolumeType(java.lang.String type) {
service.StatelessWebService port = service.getStatelessWebServicePort();
return port.getScripByVolumeType(type);
}
edited : jpa query
public Collection<MasterScrip> getScripByVolumeType(String type)
{
Collection sm=null;
sm=em.createQuery("select m from MasterScrip m where m.type = :type order by m.totalTradedVolume").setParameter("type", type).setMaxResults(2).getResultList(); // retuens no records
return sm;
}
records are returned but not displayed..
why does this happen? where am i wrong?
Your mistake is here.
listener="#{equityBean.onChange(event)}"
The event object does not exist in EL scope. Remove the argument. You don't need to specify it at all. JSF will supply the necessary action listener argument itself.
listener="#{equityBean.onChange}"
The same is true for all other listener and actionListener attributes. Only in action attribute of UICommand components you can specify custom arguments (which should be passed with real values, not with some random and non-existent variable name).

Passing parameter from PrimeFaces datatable to managed bean

I have a primefaces datatable:
<p:dataTable id="idCrawledDataTable"
var="crawledData"
value="#{crawlerCorpusTreatmentBean.crawledDataModel}"
rowKey="#{crawledData.id}"
rows="10"
scrollable="true"
scrollHeight="300"
selection="#{crawlerCorpusTreatmentBean.crawledData}"
style="width: 850px;">
<f:facet name="header">
RadioButton Based Selection
</f:facet>
<p:column selectionMode="single"
style="width: 12px;"/>
<p:column headerText="id"
style="width: 20px;">
#{crawledData.id}
</p:column>
<p:column headerText="Sritis"
style="40px;">
#{crawledData.domain}
</p:column>
<p:column headerText="URL"
style="width: 450px;">
#{crawledData.url}
</p:column>
</p:dataTable>
It is all filled with values after action method is called. Datatable has radio button selection. When I select one of the radio button and click the command button, I go to some method in which I call my bean, but all values from datatable that my bean has is null.
Showcases shows only how to display data in modal window, I can not find any information on how to pass parameters to managed bean. Maybe someone could help me with this?
Works just for me. Perhaps your data loading logic is wrong (e.g. you're doing it inside a getter method) or the equals() method of the object behind rowKey is broken.
Here's a self-containing kickoff example so that you can at least nail down your own mistake:
<h:form>
<p:dataTable value="#{bean.items}" var="item" selection="#{bean.item}" rowKey="#{item.id}">
<p:column selectionMode="single" />
<p:column headerText="id">#{item.id}</p:column>
<p:column headerText="value">#{item.value}</p:column>
</p:dataTable>
<p:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<Item> items;
private Item item;
#PostConstruct
public void init() {
items = new ArrayList<>();
items.add(new Item(1L, "one"));
items.add(new Item(2L, "two"));
items.add(new Item(3L, "three"));
}
public void submit() {
System.out.println(item);
}
public List<Item> getItems() {
return items;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}
where Item has just Long id and String value properties.

Why this table In-Cell editor, doesnt work?

I am trying to figure out, how the primefaces in-cell editor works.
For some reason, it does not work. I just see it activating and also i can type, but the values do not change. What is missing?
<?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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<p:dataTable id="allSubjects" var="subject" value="#{subjectControllerUpdate.retrieve()}" paginator="true" rows="7" >
<p:column headerText="Name" sortBy="#{subject.name}" style="width:200px" >
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.name}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.name}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{subject.description}" headerText="Description">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.description}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.description}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{subject.credits}" headerText="Credits" style="width:50px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{subject.credits}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{subject.credits}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Options" style="width:50px">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
</html>
This is the managed bean
package controllers;
import crudfacades.SubjectFacade;
import entities.Subject;
import java.io.Serializable;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named("subjectControllerUpdate")
#SessionScoped
public class SubjectControllerUpdate implements Serializable {
private List<Subject> subjects;
private Subject currentSubject;
#EJB
private SubjectFacade ejbFacade;
//INITIALIZATION
public SubjectControllerUpdate() {
currentSubject = new Subject();
}
//RETRIEVE
public List<Subject> retrieve() {
return getSubjectFacade().findAll();
}
//UPDATE
//HELP METHODS
//RETURN THE FACADE FOR DATA MANIPULATION(Best practice)
private SubjectFacade getSubjectFacade() {
return ejbFacade;
}
//GETTERS AND SETTERS
public Subject getCurrentSubject() {
return currentSubject;
}
public void setCurrentSubject(Subject currentSubject) {
this.currentSubject = currentSubject;
}
public List<Subject> getSubjects() {
return subjects;
}
public void setSubjects(List<Subject> subjects) {
this.subjects = subjects;
}
}
but when i click comfirm, the value in the UI is not changed
You've bound the value of the <p:dataTable> to retrieve() instead of getSubjects(). So every single getter call will get the values straight from the DB instead of the model.
and i see no changes in the database
You are not saving anything in the DB.
Fix your controller as follows:
#Named
#SessionScoped
public class SubjectControllerUpdate implements Serializable {
private DataModel<Subject> subjects;
#EJB
private SubjectFacade ejbFacade;
#PostConstruct
public void init() {
subjects = new ListDataModel<Subject>(ejbFacade.findAll());
}
public void save() {
ejbFacade.save(subjects.getRowData());
}
public List<Subject> getSubjects() {
return subjects;
}
}
with
<h:form>
<p:dataTable value="#{subjectControllerUpdate.subjects}" ...>
        <p:ajax event="rowEdit" listener="#{subjectControllerUpdate.save}" />
...
</p:dataTable>
</h:form>
Using DataModel<Subject> instead of List<Subject> is necessary in order to be able to get the current row.

Categories

Resources