Reusing JSF2 View Scoped Bean on facelets templating - jsf-2

I have a common task to choose one or more 'LocalizacaoTO' before doing anything else on the page.
Currently the logic of data retrieval/process/ajax events and so on are maintained on a ViewScoped bean called "SeletorLocalizacaoMB" and I’d like to use multiple instances of the same bean on the same page.
Firstly I used composite component but when I chose a node, it were stored on the last bean on the page.
If I had 3 instances declared on TesteSeletorMB:
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceOne;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceTwo;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceThree;
}
No matter which component on page I used, instanceThree always hold the values.
Based on some research I understood that composite component is not the ideal solution for this problem.
So I changed the UI implementation and used Facelets to create a 'template' named seletor.xhtml.
<ui:composition 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:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:o="http://omnifaces.org/ui">
<p:dialog header="Busca Hierarquica"
id="#{id}ModalTree"
widgetVar="dlgSelecaoHierarquica"
showEffect="fade"
hideEffect="fade"
closeOnEscape="true"
modal="#{bloqueiaModal}"
height="400px"
width="500px">
<h:panelGrid columns="2">
<p:commandButton id="#{id}btnSelecao"
value="Selecionar e Voltar"
action="#{mb['selecionarLocalHierarquico']}"
update="#(.#{id}-auto-complete)"
oncomplete="bloqueiaAutoMulti();"/>
<p:commandButton value="Voltar"
type="button"
onclick="PF('dlgSelecaoHierarquica').hide();" />
</h:panelGrid>
<p:scrollPanel style="width:100%;height:350;" mode="native">
<p:tree id="#{id}Tree"
style="width:100%;height:100%;"
styleClass="estilo-arvore"
value="#{mb.arvoreHierarquica}"
var="local"
selectionMode="multiple"
dynamic="true"
animate="true">
<p:ajax event="select" listener="#{mb['onNodeSelect']}" update="#this"/>
<p:treeNode >
<h:outputText value="#{local.cdClasseLocal}: #{local.cdLocalizacao} #{local.niveis}" />
</p:treeNode>
</p:tree>
</p:scrollPanel>
</p:dialog>
</ui:composition>
Test page using <ui:include>
<f:subview id="seletorAlpha">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorAlpha}" />
<ui:param name="id" value="alpha" />
</ui:include>
</f:subview>
<f:subview id="seletorBravo">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorBravo}" />
<ui:param name="id" value="bravo" />
</ui:include>
</f:subview>
Test Bean holding multiple instances:
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorAlpha;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorBravo;
}
CDI Bean used on 'seletor.xhtml'
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class SeletorLocalizacaoMB implements Serializable {
private List<LocalizacaoTO> locaisHierarquicosSelecionados;
private TreeNode arvoreHierarquica;
//PostConstruct, Ajax events and things :)
}
In my example, I want that TesteSeletorMB variables (seletorAlpha and seletorBravo) hold different values on their lists. Is it possible?
I tried to change SeletorLocalizacaoMB scoped to #Dependent but it didn't work neither. Here is where the things got confused. Reading CDI API, the first state says:
Beans declared with scope #Dependent behave differently to beans with other >built-in scope types. When a bean is declared to have scope #Dependent:
No injected instance of the bean is ever shared between multiple injection >points.
It should't hold the same instance, right?!
Environment
WebSphere Application Server 8.5.5.2
Apache MyFaces 2.0.2
PrimeFaces 5.0
OmniFaces 1.7
I can provide additional data if necessary. I didn't paste all 'SeletorLocalizacaoMB' code because it has many dependencies and I had the feeling that the problem is not related to how the class handles actions.

Related

Passing and using parameters between JSF includes

I've been trying to understand JSF templating and include attributes and passing parameters between components. In Mastering JavaServer Faces 2.2 by Anghel Leonard, I came across the following example of passing parameters, which I don't fully understand.
Given this bean:
#Named
#ViewScoped
public class TemplatesBean implements Serializable {
private String msgTopDefault="";
private String msgBottomDefault="";
private String msgCenterDefault="No center content ... press the below button!";
public void centerAction(){
this.msgCenterDefault="This is default content";
}
// Getters and setters
}
Parameters are passed to contentDefault.xhtml with:
<ui:insert name="content">
<ui:include src="/template/default/contentDefault.xhtml">
<ui:param name="templatesBeanName" value="#{templatesBean}"/>
<ui:param name="contentPropertyName" value="msgCenterDefault"/>
</ui:include>
</ui:insert>
Then, within contentDefault.xhtml the parameters are used as follows:
<ui:composition>
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName['centerAction']()}"/>
</h:form>
</ui:composition>
I've never used the square-bracket syntax before, but if a reference to templatesBean is being passed in, why not just use that to access the properties or invoke action methods? For example, the following code works for me too and seems simpler:
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName.centerAction()}"/>
</h:form>
Recognising that the example in the book may be a contrived example to illustrate a point, are there use cases where the other syntax is appropriate?
I do not know or own the book, so I cannot investigate that way what they want to illustrate, but I can sort of deduce that by looking at the full example you posted, not just the part about the centerAction.
If you look at
<ui:insert name="content">
<ui:include src="/template/default/contentDefault.xhtml">
<ui:param name="templatesBeanName" value="#{templatesBean}"/>
<ui:param name="contentPropertyName" value="msgCenterDefault"/>
</ui:include>
</ui:insert>
you'll see that 2 params are passesd on, templatesBeanName and contentPropertyName
In
<ui:composition>
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName['centerAction']()}"/>
</h:form>
</ui:composition>
from which you just pointed to the line with action="#{templatesBeanName['centerAction']()}", a dynamic bean with a static value in suqare brackets made into a method by adding () as a postfix, you'll see another line of code above it
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
What effectively is done here is to have a dynamic bean AND a dynamic property name being used.
So my conclusion is that with this example what they are trying to illustrate is that you are able to pass on a dynamic bean, and on that bean use either both static or dynamic methods and properties(static properties and dynamic methods not being in the example)

#SessionScoped bean instantiated over and over [duplicate]

This question already has an answer here:
#SessionScoped bean looses scope and gets recreated all the time, fields become null
(1 answer)
Closed 8 years ago.
Using PrimeFaces 5.10, JSF 2, and Wildfly, I am trying to get my xhtml page to interact with a single instance of a #SessionScoped bean with a PF poll component. Each time the poll calls the bean method, a new instance of the bean is created. I've tried #ViewScoped and #SessionScoped with no change in behavior. I've noticed other similar questions, but have not seen any with a solution I have been able to implement.
I know the println's are not a reliable way to show order of method calls, but i'm using them to merely demonstrate which methods are being called and it appears that the init() method gets called over and over, even though I have #PostConstruct, so it's new instantiations. I'm even printing out "this" and it's showing different hashes each time it prints.
It never gets through the if statement in refreshTweets() because the stopPolling field never gets set to false in the right context.
I've run into this problem before and have been able to work around it rather than solve it. If anyone has any ideas as to what I am doing wrong, please let me know.
Below is the relevant xhtml code:
<p:layoutUnit id="center" position="center" styleClass="dataBox">
<h:form id="TwitterFeed">
<p:panelGrid columns="2">
<p:outputLabel value="Twitter topic to query: " />
<p:inputText value="#{dataBean.tweetTopic}"/>
<p:outputLabel value="Number of Twitter Results: " />
<p:inputText value="#{dataBean.tweetCount}" />
<p:commandButton value="Submit" action="#{dataBean.toggleRenderTweets}" update="tweets"/>
<p:commandButton value="Polling" action="#{dataBean.togglePolling}" update="tweets"/>
</p:panelGrid>
<p:panel visible="#{dataBean.renderTweets}" id="tweets">
<p:panelGrid columns="1">
<p:dataTable id="twitterTable" value="#{dataBean.tweetList}" var="tweetStatus">
<p:columns value="#{dataBean.tweetColumns}" var="column" columnIndexVar="colIndex">
<f:facet name="header">
<h:outputText value="#{column.header}"/>
</f:facet>
<h:outputText value="#{tweetStatus[column.property]}"/>
</p:columns>
</p:dataTable>
<p:poll interval="10" listener="#{dataBean.refreshTweets}" update="twitterTable" widgetVar="tweetPoll" id="tweetPoll" autoStart="true"/>
</p:panelGrid>
</p:panel>
</h:form>
</p:layoutUnit>
The relevant bean code is below:
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.annotation.PostConstruct;
import java.io.Serializable;
#SessionScoped
#ManagedBean
public class DataBean implements Serializable {
private List<TwitterStatusModel> tweetList;
private boolean renderTweets;
private boolean stopPolling;
#PostConstruct
public void init() {
<<initialize fields>>
stopPolling = true;
System.out.println(this + " init()");
}
private void getTweets() {
<<this method sets the List above tweetList>>
}
public void refreshTweets() {
if (!stopPolling) {
<<Method never passes the if statement because stopPolling is set to true in init()
}
public void togglePolling() {
stopPolling = !(stopPolling);
System.out.println(this + "Toggling polling - now " + stopPolling);
}
You should use the correct imports of #SessionScoped etc.
With a #ManagedBean you need the javax.faces.bean.* ones not the javax.enterprise.context ones or javax.faces.view
See also Why are there different bean management annotations

How to invoke JSF backing bean method from link/non-faces-request

The use case is calling a method on a JSF 2.x Backing Bean directly from a hyperlink (Non-Faces-Request). What is the best way to do this?
I imagine to do something like this:
The Link:
http://localhost/show.xhtml?id=30&backingbeanname=loaddata&method=load
The Backing Bean:
#Named (value = "loaddata")
public class DataLoader {
public void load(int id){ ... }
}
Use <f:viewParam> in the target view to set GET parameters as bean properties and use <f:event type="preRenderView"> to invoke an action on them.
In show.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" required="true" />
<f:event type="preRenderView" listener="#{bean.load}" />
</f:metadata>
<h:message for="id" />
In managed bean:
private Integer id;
private Data data;
public void load() {
data = service.find(id);
}
Note that in the above example the URL http://localhost/show.xhtml?id=30 is sufficient. You can always set more parameters as bean properties and have one "God" bean which delegates everything, but that's after all likely clumsy.
Also note that you can just attach a Converter to the <f:viewParam> (like as you could do in <h:inputText>). The load() method is then most likely entirely superfluous.
<f:metadata>
<f:viewParam name="id" value="#{bean.data}"
converter="dataConverter" converterMessage="Bad request. Unknown data."
required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:message for="id" />
See also:
Communication in JSF 2 - Processing GET request parameters
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

Performance issue while setting and getting parameter in jsf bean

i m using JSF2.0 and i m making one dataTable in that datatable i m getting the value from managed bean.And in managed bean in post construct annoted method i m calling my web service from another file.
Following is code for that
<h:dataTable
value="#{bean1.getList}" var="c" styleClass="order-table"
headerClass="order-table-header" width="100%"
rowClasses="order-table-odd-row,order-table-even-row" rows="8"
columnClasses="first,second">
<h:column>
<f:facet name="header">
<h:selectBooleanCheckbox></h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox value="#{c.id}"></h:selectBooleanCheckbox>
</h:column>
<h:column>
<!-- <f:facet name="header"/> -->
<h:outputLabel value="From: "></h:outputLabel>
<h:outputLabel value="#{c.from}"></h:outputLabel>
<br></br>
<!-- -->
<h:outputLabel value="Sub: "></h:outputLabel>
<h:outputLabel value="#{c.sub}"/>
<h:commandLink immediate="true" action="#{bean2.doRead}" value="Read" id="Read"></h:commandLink>
</h:column>
<!-- Footer Setting -->
<f:facet name="footer">
</f:facet>
</h:dataTable>
My Bean1 class
#PostConstruct
public void prepareList(){
{
web service call
}
public List<InboxBean> getemailList(){
return list;
}
Now when i m clicking on commandlink which has id Read at that time my bean1 post construct taged property also called. That i dont want to perform. So,how to get out from this problem and i also want to set the subject value in bean2 setProperty. Thanks in advance
That can happen if the bean is put in request scope. Every single HTTP request will then reconstruct the bean. Put the bean in view or session scope instead.
E.g. in the view scope:
#ManagedBean
#ViewScoped
public class Bean {}
A view scoped bean lives as long as you're interacting with the same view by returning null or void in action methods.
Or in the session scope:
#ManagedBean
#SessionScoped
public class Bean {}
A session scoped bean lives as long as the established browser session. That is, from the very first HTTP request involving the bean until the client closes the entire browser instance or when the session expires on the server side (which defaults to 30 minutes).
For your particular case, a view scoped bean is most likely the best choice.
See also:
How to choose the right bean scope?

How to save a list/map/set in JSF with h:inputText + managed bean

What I'm trying to achieve is very similar to the one posted in the following link.
How to save an array in JSF with ui:repeat + h:inputText + managed bean?
I'm particularly fascinated with the answer provided by Arjan Tijms in the link above however what I want to achieve is slightly different. Consider the following code snippets.
The bean
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
#RequestScoped
#Named
public class MyBean {
List<String> choices;
public List<String> getChoices() {
return choices;
}
#PostConstruct
public void initChoices() {
choices= new ArrayList<String>();
}
public String save() {
// should save all the choices into some repository
return "";
}
}
and the facelet page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
</h:body>
</html>
The thing is, this will work if we have some initial data in the list at the beginning. What about situations where the initial list will be empty?
The ideal solution which I'm looking for is to have 1 h:inputText for each choice and when save button is clicked, all choices in each h:inputText is then added to the choices list. I've searched high and low but can't seem to find any hints on how this can be done.
If JSF 2 really doesn't support this, I guess I'll have to use the ugly way with just one h:inputText and use a converter to convert to and from a list but I'm still hoping that an ideal solution can be found.
Hopefully someone from stackoverflow can shed a light in the right direction for me.
Just add an "add" button which adds a new String to the list.
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:inputText value="#{myBean.newChoice}" />
<h:commandButton value="Add" action="#{myBean.add}" />
<h:commandButton value="Save" action="#{myBean.save}" />
with
private String newChoice;
public void add() {
choices.add(newChoice);
newChoice = null;
}
// ...
Note that this only works if bean is put in view scope. A request scoped one would be constructed on every request and hereby recreate the list everytime.

Resources