Primefaces Datatable + Row Expansion with updating component - jsf

I have a datatable that has a collection of objects that is initialized on page load. It is not lazy loaded.
In this datatable row, I have a row expansion object that I wish to "toggle" depending on a boolean value for the object in that row (inputSwitch tag in Primefaces). Once that is toggled, I update the DOM and render the sub collection using the "rendered" attribute for the rowExpansion (which I suspect might be the problem, because I think that requires a DOM refresh)
However, whenever I hit the first inputSwitch (the main toggle), it reloads the entire collection and wipes out the changes that have been made.
<p:dataTable
id="myTable"
var="row"
reflow="true"
expandedRow="true"
filteredValue="#{mybean.filteredAllObjects}"
value="#{mybean.allObjects}">
<p:column>
<p:inputSwitch value="#{row.boolSelected}">
<p:ajax update=":myform:myTable"/>
</p:inputSwitch>
</p:column>
<p:rowExpansion rendered="#{row.boolSelected}">
<ui:repeat value="#{row.subsetCollection}" var="subsetRow">
<p:inputSwitch value="#{subsetRow.boolSelected}"/>
</ui:repeat>
</p:rowExpansion>
</p:dataTable>
How can I essentially keep the state of the collection on the client side without the need to re-render the collection (and thus eliminating all changes)?
Edit
Backing bean (simplified - it's really this simplistic). When the ajax call is made in the front end, the getter for the collection is called (breakpoint confirms this). Also see a POST is happening, so a call to the server is made:
#Component
#ViewScoped
public class MyBean implements Serializable
{
private static final long serialVersionUID = 1L;
private List<MyObject> allObjects;
private List<MyObject> filteredAllObjects;
public MyBean(#Value("#{param['id']}") String selectedId)
{
init();
}
private void init()
{
allObjects = ... // call to get objects from DB
}
// Setters & Getters
}

Related

How to hold values in a CDI conversion scope?

I try to add a object to a LinkedList in a #ConversationScoped backing bean.
#Named
#ConversationScoped
public class CategoryController implements Serializable{
...
private List<Category> selectedCategories = new LinkedList<Category>();
...
#PostConstruct
public void initNewMember() {
conversation.begin();
newCategory = new Category();
loadExistingCategories();
}
...
}
I want to send an ajax request with new objects (of type category). They should simply be added to the linked list.
this.selectedCategories.add(newParentCategory);
With the ajax render attribute <f:ajax render="allSelectedCategories"/> I immediately render the output text to render the object list.
<h:outputText id="allSelectedCategories" value="#{categoryController.selectedCategories}" />
And yes, the object I clicked is displayed, but the previously clicked objects are gone.
The values do not serialize/persist in memory during my "conversation". What do I need to do to make that conversion scope temporarily persist the values of the ajax calls?
I really want to get used to CDI and abandon the ManagedBean path for this project (e.g. #ViewScoped), despite the fact that it works like a charm.
Also, I cannot reproduce the following tutorial on CDI Conversation Scope. I simply cannot debug into the initConversation by adding
<f:event listener="#{categoryController.initConversation}"
type="preRenderView"></f:event>

How to get a lazily loaded List of p:dataGrid back in the associated JSF managed bean?

I have a lazily loaded <p:dataGrid>. The corresponding XHTML code is as under.
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean}" var="row" columns="3" rows="9" pageLinks="10" paginator="true" lazy="true">
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}" converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:inputText id="txtCharge" value="#{row.charge}" converter="#{bigDecimalGeneralConverter}"/>
</p:column>
<p:ajax event="page"/>
</p:dataGrid>
<p:commandButton id="btnSubmit" update="dataPanel" actionListener="#{testManagedBean.insert}" value="Save" icon="ui-icon-check"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</p:panel>
The associated JSF managed bean looks like as show below.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
setRowCount(zoneChargeService.rowCount(7L).intValue());
return zoneChargeService.getZoneChargeList(7L, first, pageSize);
}
public void insert() {
System.out.println("insert() called.");
}
}
The data grid displays a group of <p:inputText>s that looks something like the following.
A user can modify values held by <p:inputText> as can be seen in the snap shot. The modified values are to be stored into the database, when the given <p:commandButton> (save) immediately below the data grid is pressed.
The associated action listener insert() is invoked, when this <p:commandButton> is pressed but how to get these modified values in that action listener so that they can be sent to the database in question?
This can be done avoiding lazy loading as shown in this answer. This is the exact same scenario but with lazy loading.
How to get the list, List<ZoneChargeUtils> with new / modified values in <p:inputText>, when the given <p:commandButton> is clicked?
The utility class ZoneChargeUtils though completely unnecessary.
public final class ZoneChargeUtils implements Serializable
{
private Long weightId;
private BigDecimal weight;
private BigDecimal charge;
private static final long serialVersionUID = 1L;
//Getters and setters + constructor(s).
}
This is not a persistent entity / POJO. It is used to execute queries with constructor expressions in JPA
The solution to this problem involves keeping two buffers in your #ViewScoped managed bean, one for the whole set of the changed values and other one for the current view values. Moreover, you'll need to call a listener method everytime you switch the page to send your current values to the managed bean:
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean}" var="row" columns="3"
rows="9" pageLinks="10" paginator="true" lazy="true">
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}"
converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:inputText id="txtCharge" value="#{row.charge}"
converter="#{bigDecimalGeneralConverter}"/>
</p:column>
<p:ajax event="page" listener="#{testManagedBean.pageChanged}"/>
</p:dataGrid>
<p:commandButton id="btnSubmit" update="dataPanel"
action="#{testManagedBean.insert}" value="Save" icon="ui-icon-check"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</p:panel>
I made couple of changes here. One is adding a listener method to the ajax event for the page changing. The other one is replacing actionListener by action in your p:commandButton. action is the most convenient way to go when performing business actions like yours.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
private Map<Integer, ZoneChargeUtils> bufferedZones = new HashMap<Integer, ZoneChargeUtils>();
private List<ZoneChargeUtils> currentZones = new ArrayList<ZoneChargeUtils>();
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
currentZones.clear();
setRowCount(zoneChargeService.rowCount(7L).intValue());
List loadedZones = zoneChargeService.getZoneChargeList(7L, first, pageSize);
for (ZoneChargeUtils zone : loadedZones){
if (bufferedZones.containsKey(zone.getId())){
//The zone has been loaded before in the view. Load the buffered value
//Otherwise, you'll lose it'll be overwritten with DB value when lazy loading
currentZones.add(bufferedZones.get(zone.getId()));
}else{
currentZones.add(zone);
}
}
return currentZones;
}
public void pageChanged(){
//The user has changed the page. Update bufferedZones with the possible new values
for (ZoneChargeUtils zone : currentZones){
bufferedZones.put(zone.getId(), zone);
}
}
//Looks for modified values in the CURRENT page before updating them.
//If value isn't there, return the one passed in the param
private ZoneChargeUtils lookUpInCurrent(ZoneChargeUtils zone){
for (ZoneChargeUtils z : currentZones){
if (zone.getId() == z.getId()){
return z;
}
}
return zone;
}
//Persist the values. Look in the general buffer, keeping in mind it has been updated in the last page change.
//Because of that, we have to look also in the current buffer for changes made in the current page.
public void insert() {
for (ZoneChargeUtils zone : bufferedZones.values()){
zoneChargeService.updateZone(lookUpInCurrent(zone));
}
}
}
For the managed bean, you're interested in keeping two values: the changes happened in the current page and the changes for the whole set of loaded pages. I use a List for the first one and a Map for the second, supposing you already have an Id defined for your ZoneChargeUtils. Steps are following:
When user loads the first page (or any page) the loadData method is called for the current value set. In order of returning the persisted values directly, you check them against the whole buffer. If the value has been loaded before, use the buffered value. Otherwise, present the persisted one.
When user changes the page, update the whole buffer with the current one. That way you are able to keep the modified values.
When user saves the changes, go to the whole buffer (the Map) and iterate over its values. Make an update for each one of the loaded entities.
The associated action listener insert() is invoked, when this
is pressed but how to get these modified values in
that action listener so that they can be sent to the database in
question?
Store the reference of changed 'entities' in a HashMap<Integer, ZoneChargeUtils >. Then execute those changes in insert(), by iterating through that HashMap. You need an ajax value change listener for the <p:inputText> to listen to the changes, and in order to modify/update the state storing HashMap.
It's slightly different that the solution proposed by Xtreme Biker, but the idea is same : Store the state-change in Map.
hy all,
First: i m not ok for do #ManagedBean and #ViewScoped in Class TestManagedBean where this Class extend LazyDataModel
the solution is:
public final class lazyZoneChargeUtils extends LazyDataModel<ZoneChargeUtils> implements Serializable{
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
currentZones.clear();
setRowCount(zoneChargeService.rowCount(7L).intValue());
List loadedZones = zoneChargeService.getZoneChargeList(7L, first, pageSize);
for (ZoneChargeUtils zone : loadedZones){
if (bufferedZones.containsKey(zone.getId())){
//The zone has been loaded before in the view. Load the buffered value
currentZones.add(bufferedZones.get(zone.getId()));
}else{
currentZones.add(zone);
}
}
return currentZones;
}
}
and :
#ManagedBean
#ViewScoped
public class TestManagedBean {
//all variable
private LazyDataModel<ZoneChargeUtils> listZoneChargeUtils;
#PostConstruct
public void init() {
//init listZoneChargeUtils
this.listZoneChargeUtils = new lazyZoneChargeUtils();
}
public void onEdit(RowEditEvent event) {
ZoneChargeUtils var = (ZoneChargeUtils) event.getObject();
//do your code and save object in DataBase
}
public void onCancel(RowEditEvent event) {
ZoneChargeUtils var = (ZoneChargeUtils) event.getObject();
FacesMessage msg = new FacesMessage("Message : ", var.getName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
/**
* #return the listZoneChargeUtils
*
* #author asghaier
*
* Created on 12/mag/2014
*/
public LazyDataModel<ZoneChargeUtils> getListZoneChargeUtils() {
return listZoneChargeUtils;
}
/**
* #param listZoneChargeUtils the listZoneChargeUtils to set
*
* #author asghaier
*
* Created on 12/mag/2014
*/
public void setListZoneChargeUtils(LazyDataModel<ZoneChargeUtils> listZoneChargeUtils) {
this.listZoneChargeUtils = listZoneChargeUtils;
}
//all getter and setter
}
and now in your page do this:
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean.listZoneChargeUtils}" var="row" columns="3" rows="9" pageLinks="10" paginator="true" lazy="true" editable="true">
<p:ajax event="rowEdit" listener="#{testManagedBean.onEdit}" />
<p:ajax event="rowEditCancel" listener="#{testManagedBean.onCancel}" />
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}" converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.charge}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{row.charge}" style="width:100%" converter="#{bigDecimalGeneralConverter}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column >
<p:rowEditor />
</p:column>
</p:dataGrid>
this is in general haw you must do, ( i dont have see good all code).
resume:
1- do class extends LazyDataModel<...> and dont put any #ManagedBean or #ViewScoped
2- do class #ManagedBeanand and #ViewScoped and in the class creat variable in type
LazyDataModel<...> listData, implement getter and setter for this variabile, and init the variable listData in methode init() where is #PostConstruct
3- add editable="true" to your dataTable
4- in the class creat in step 2 add method onCancel & onEdit , in the methode onEdit do your code Java and save the object in database.
5- all is ok :)
In this case, the following approach using the getWrappedData() method of LazyDataModel<T> works as expected.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
setRowCount(zoneChargeService.rowCount(7L).intValue());
return zoneChargeService.getZoneChargeList(7L, first, pageSize);
}
public void insert() {
//Returns the lazily loaded list with the modified values completely appropriate to the page size.
//Do whatever you want to do with the lazily loaded list now.
List<ZoneChargeUtils> zoneChargeUtils = (List<ZoneChargeUtils>) getWrappedData();
for(ZoneChargeUtils utils:zoneChargeUtils) {
System.out.println(utils.getWeightId()+" : "+utils.getWeight()+" : "+utils.getCharge());
}
}
}
The getWrappedData() method returns the list with modified values in <p:inputText> according to the page size defined, hence, eliminating the need of extraneous code to get the associated lazily loaded list back in the listener method.

Session scoped beans and #PostConstruct in JSF

A quite simple and straight-forward question.
I have a session scoped managed bean as follows (demonstrating a PrimeFaces range slider).
#ManagedBean
#SessionScoped
public final class RangeSliderBean implements Serializable
{
private static final long serialVersionUID = 1L;
private static final byte scale=2;
private BigDecimal maxPrice;
private BigDecimal minPrice;
public RangeSliderBean()
{
maxPrice=new BigDecimal(100).setScale(scale, RoundingMode.HALF_UP);
minPrice=new BigDecimal(5).setScale(scale, RoundingMode.HALF_UP);
}
#PostConstruct
private void init()
{
}
//Mutators and accessors
}
The given two fields in the above session scoped managed bean are bound to an XHTML page.
<h:form id="rangeForm" prependId="true">
<p:panel header="Shop by Price">
<h:panelGrid id="rangeSliderPanelGrid" columns="1" style="margin-bottom:10px">
<h:outputText id="displayRange" value="Min : #{rangeSliderBean.minPrice.toPlainString()} Max : #{rangeSliderBean.maxPrice.toPlainString()}"/>
<p:slider for="txtMinPrice, txtMaxPrice"
minValue="#{rangeSliderBean.minPrice}"
maxValue="#{rangeSliderBean.maxPrice}"
display="displayRange"
style="width:170px"
range="true" displayTemplate="Min : {min} Max : {max}"/>
</h:panelGrid>
<h:inputHidden id="txtMinPrice" value="#{rangeSliderBean.minPrice}" converter="#{bigDecimalConverter}"/>
<h:inputHidden id="txtMaxPrice" value="#{rangeSliderBean.maxPrice}" converter="#{bigDecimalConverter}"/>
<p:commandButton value="Submit"/> <!--Update/process is temporarily omitted.-->
</p:panel>
</h:form>
If these fields are initialized in the method annotated by #PostConstruct i.e init(), in this case (instead of initializing them in the constructor as shown in the snippet), their specified values are not set unless and until a user logs in (unless a session is created).
How can they be initialized in the constructor then, just a little confusion? (I know that the constructor is called before the method annotated by #PostConstruct is invoked).
How can they be initialized in the constructor then, just a little
confusion? (I know that the constructor is called before the method
annotated by #PostConstruct is invoked).
Use the #PostConstruct's init method only to initialize fields which are being injected (i.e Ejbs). If you don't have any injections and dependencies, init method becomes pretty useless. The bean's constructor is used to initialize bean's own properties. In your example, you don't have any injection, so you can safely remove that #PostConstruct's init method.
If these fields are initialized in the method annotated by
#PostConstruct i.e init(), in this case (instead of initializing them
in the constructor as shown in the snippet), their specified values
are not set unless and until a user logs in (unless a session is
created).
It's the normal behavior, there is no reason to emphasize on the not, because a #SessionScoped bean is created and initialized only when a new session is created.
For more info check the link, the question has already been answered : Why use #PostConstruct?

Single page applications with ajax [duplicate]

This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between

datatables under tree structure in jsf core/ primefaces

I am stuck in a rather weird situation.
I have a requirement in which i need a tree structure to define a list of elements. And when we click on any of those elements in a tree. it should expand the section below it to show 2 side by side datatables which are linked to that element.
I can use JSF 2.0 core or even primefaces 3.1.
Is it possible ??
Could anyone please help ... any suggestions would be appreciated.
Updated
My model is something like :
class Shop{
boolean isoperational;
String name;
List<Item> items;
List<boolean> itempresent;
List<Employee> employees;
}
I need the name of the shop on the tree node along with the isoperational checkbox;
And when we click on that node it should open 2 datatables.
One containing the List of items along with itempresent checkbox.
Other containing the List of employees.
Thanks
Edited per your response (if i understand you correctly). Note that this is written from head so some attribute names might differ. The point is to set an active collection from your treetable depending on which row is clicked. An ID is set via the actionListener, then the action sets mycontroller.activeCollection to the list you want to show. Then the datatable is rerendered via normal post or ajax with values depending on which row you clicked.
Markup
<p:treeTable value="#{myController.treenode}" var="item">
<p:column>
<h:commandLink action="#{myController.setActiveShop}" value="set">
<f:setPropertyActionListener target="#{myController.shipName}" value="#{item.shop.name}"/>
</h:commandButton>
</p:column>
</p:treeTable>
<p:dataTable value="#{myController.activeShop.items" rendered="#{!empty myController.activeShop}" var="item">
<p:column>#{item.name}</p:column>
</p:datatable>
<p:dataTable value="#{myController.activeShop.employees" rendered="#{!empty myController.activeShop}" var="item">
<p:column>#{item.name}</p:column>
</p:datatable>
Controller
#ManagedBean
#ViewScoped // Or #SessionScoped... something that can cache lists, not sure how this would be done with requestscope
public class MyController{
private List<Shop> shopList; // Set this from a datasource. Or use only shopTree below to store your shops..
private Shop activeShop;
private String shopName;
private TreeNode shopTree; // Generate this from shopList
// insert getters and setters
private setActiveShop(){
for(Shop s : shipList)
if(s.getName().equals(shopName)
activeShop = s;
}
}

Resources