JSF viewscope values not getting displayed in the view properly - jsf

I have a managed bean under ViewScope. It has an instance variable inside it.
MetaData object has a inputItem object List.
#ManagedBean
#ViewScoped
public class ConBean implements Serializable {
private MetaData metadata;
#PostConstruct
#SuppressWarnings("unchecked")
public void init() throws IOException {
this.metadata = new MetaData ();
}
public void proc(){
List<InputItem> inputs= new ArrayList<InputItem>();
inputs.add(***** code to populate the inputItem List);
//after populating, inputs added to the metadata
metadata.setInputs(inputs);
}
//getters & setters
}
in my JSF , input list is populated inside a UI repeat.
<div id="inputplaceholder">
<ui:repeat value="#{conBean.metaData.inputs}" var="content">
</ui:repeat>
</div>
the div inputplaceholder is periodically updated using a richfaces poll.
<a4j:poll id="poll" interval="12000" action="#{conBean.proc}"
execute="#form" render="inputplaceholder"/>
The problem that I have is even though inputItems are set to the metaData object correctly inside the proc() method, when the view is rendered/partially updated, it doesn't get highlighted in the UI. so partial update takes no effect. I tried moving
this.metadata = new MetaData ();
inside the proc method but had no luck.
any ideas and help is highly appreciated.
thanks ...

Did the partial render really take place? This is impossible. There is namely no JSF component with the ID inputplaceholder. You assigned it to a plain HTML <div> element. Replace it by a fullworthy JSF component:
<h:panelGroup layout="block" id="inputplaceholder">
Also, since you used a relative ID in the render attribute, it will only scan for components in the same parent naming container component. The <ui:repeat> is such one, however the component with the desired ID is placed outside it. You'd like to use an absolute ID instead. Assuming that it's inside a <h:form> with a fixed ID:
<h:form id="myform">
<h:panelGroup layout="block" id="inputplaceholder">
...
then you should be referencing it in the render attribute as follows
render=":myform:inputplaceholder"

Related

Dynamically instantiate composite components on page, on clicking CommandButton

Following on from the response by the legendary BalusC to this post:
How to programmatically or dynamically create a composite component in JSF 2
Had I sufficient points I would attach a comment to that post -- but I don't have sufficient points .
Problem as follows.
I'm trying to set up a commandButton which adds a JSF composite component dynamically to an xhtml file. With the intention that clicking it multiple times will put multiple instances of the component on the page.
So I have a button on an XHTML file:
<h:commandButton action="#{assessingController.addQuestion}" value="Add a Question"></h:commandButton>
Which calls a method on AssessingController:
public void addQuestion() {
UIComponent parent = null;
includeCompositeComponent(parent, "http://xmlns.jcp.org/jsf/composite/components", "questionComposite", "someId");
}
UIComponent parent = null; -- because it has to be instantiated or referenced somehow, before being passed into includeCompositeComponent . But as noted below - making it null might be causing the null pointer exception, (so what should I do instead?)
includeCompositeComponent method is as per the JSF 2.2 method referred to by BalusC in the above post:
public void includeCompositeComponent(UIComponent parent, String taglibURI, String tagName, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent composite = context.getApplication().getViewHandler()
.getViewDeclarationLanguage(context, context.getViewRoot().getViewId())
.createComponent(context, taglibURI, tagName, null);
composite.setId(id);
parent.getChildren().add(composite);
}
When I click on the commandButton, logs as follows:
javax.faces.el.EvaluationException: java.lang.NullPointerException
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315) ...
Caused by: java.lang.NullPointerException
at controllers.AssessingController.includeCompositeComponent(AssessingController.java:123)
AssessingController.java:123 is this line:
parent.getChildren().add(composite);
Composite is not null (checked that).
So, obviously perhaps, - parent is null and that's where the problem is.
So how can I better reference UIComponent parent to begin with?
Do I need to make it refer to something on the xhtml file? I'm presuming it needs some kind of a placeholder which will serve as the parent(?). Right now all there is on the xhtml page is the commandButton.
Thank you all.
The parent is supposed to represent the component where you'd like to include the composite component in.
Imagine that you ultimately want to end up with this plain XHTML representation:
<h:panelGroup id="questions">
<your:questionComposite />
</h:panelGroup>
You should then supply exactly that <h:panelGroup> component as parent.
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<h:panelGroup id="questions" />
public void addQuestion() {
UIComponent parent = context.getViewRoot().findComponent("questions");
// ...
}
Or, by passing the concrete component itself:
<h:form>
<h:commandButton ... action="#{bean.addQuestion(questions)}" />
</h:form>
<h:panelGroup id="questions" binding="#{questions}" />
public void addQuestion(UIComponent parent) {
// ...
}
Unrelated to the concrete problem: there's a thinking/design mistake here. You should rather use an <ui:repeat><your:compositeComponent> and then feed from a #ViewScoped bean to the <ui:repeat> a dynamically sized list of entities representing the composite's model value.
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<ui:repeat value="#{bean.questions}" var="question">
<your:questionComposite value="#{question}" />
</ui:repeat>
private List<Question> questions;
public void addQuestion() {
questions.add(new Question());
}
Anytime you need to deal with raw UIComponent instances in a backing bean, take a pause and carefully research or ask if you're really doing things the right way. Perhaps it belongs in a backing component instead, or could just be done with pure XHTML.
See also:
How to dynamically add JSF components
How does the 'binding' attribute work in JSF? When and how should it be used?

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>

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

Getting same instance of `componentType` in composite component on every use

Hi Have this Wierd Issue in which I am using a Composite Component which I wrote and I get values from the previous use of the backing bean of the CC (the componentType bean)
I don't know how to describe this better than just show the code.
I'll try to be brief about it and cut the redundant parts:
This is the Composite Component definition:
<cc:interface componentType="dynamicFieldGroupList">
<cc:attribute name="coupletClass" />
<cc:attribute name="form" default="#form"/>
<cc:attribute name="list" type="java.util.List" required="true"/>
<cc:attribute name="fieldNames" type="java.util.List" required="true" />
</cc:interface>
<cc:implementation>
<h:dataTable value="#{cc.model}" var="currLine">
<h:column>
<h:outputText id="inner_control_component" value="Inner Look at currLine:#{currLine}"/>
</h:column>
</h:dataTable>
</cc:implementation>
The CC bean defintion:
#FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
#SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements
NamingContainer
{
private transient DataModel model;
#Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
{
model = new ListDataModel(getList());
}
return model;
}
private List<Map<String, String>> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
}
And the use code:
<ui:repeat var="group" value="#{currentContact.detailGroups}">
<h:panelGroup rendered="#{not empty group.values}">
<h:outputText id="controlMsg" value=" list:#{group.values}" /><br/><br/>
<utils:fieldTypeGroupList list="#{group.values}"
fieldNames="#{group.fields}" coupletClass="utils" />
</h:panelGroup>
</ui:repeat>
The text of id controlMsg displays the correct values in #{group.values} while the control output inside the component of id inner_control_component shows the values from the previous use.
The values are correct the first time...
I guess it's a fundemental error in use of a CC bean, otherwise it could be a bug with MyFaces 2.1 (Which I'm using)
The explanation for this behaviour is simple: there's only one component definied in the view. So there's also only one backing component with one model. Since the model is lazily loaded on first get, the same model is been reused in every iteration of a parent iterating component.
The <ui:repeat> doesn't run during view build time (as JSTL does), but during view render time. So there are physically not as many components in the view as items which are iterated by <ui:repeat>. If you were using <c:forEach> (or any other iteration tag which runs during view build time), then the composite component would have behaved as you'd expect.
You would like to change the way how the datamodel is kept in the backing component. You would like to preserve a separate datamodel for each iteration of a parent iterating component. One of the ways is to replace the model property as follows:
private Map<String, DataModel> models = new HashMap<String, DataModel>();
public DataModel getModel() {
DataModel model = models.get(getClientId());
if (model == null) {
model = models.put(getClientId(), new ListDataModel(getList()));
}
return model;
}
See also:
What's the view build time?
The problem described here is an old known isse in JSF, hidden by the usage of composite components. It is so important and so difficult, that instead answer here I create a detailed answer in a blog entry for this one: JSF component state per row for datatables
To keep this answer short, I'll say to you it is not a bug in MyFaces 2.1. Please use 2.1.1, because that is a quick bug fix version of 2.1.0. In JSF 2.1 there is a new property for h:dataTable called rowStatePreserved, and this scenario is just one case where "this little baby" becomes useful. Just replace ui:repeat with h:dataTable and add rowStatePreserved="true". That will do the trick. If you need to manipulate the model (add or remove rows) you can use tomahawk t:dataTable and t:dataList, but you will have to take an snapshot version for now. Note this is new stuff not available in any different JSF framework an the moment (JUN 2011).
If you need more info, keep tuned with MyFaces Team on Twitter or ask to the experts on MyFaces Users and Dev Mailing Lists.

JSF: How to bind many of h:selectBooleanCheckbox?

I have a problem to bind list of h:selectBooleanCheckbox to my bean.
Anybody helps ?
This is not working:
<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</ui:repeat>
public class CartBean extends BaseBean {
public List<Product> getProductsList() {...}
private HtmlSelectBooleanCheckbox[] checkboxes;
public HtmlSelectBooleanCheckbox[] getCheckboxes() {
return checkboxes;
}
public void setCheckboxes(HtmlSelectBooleanCheckbox[] checkboxes) {
this.checkboxes = checkboxes;
}
}
I get error:
javax.faces.FacesException: javax.el.PropertyNotFoundException: /WEB-INF/flows/main/cart.xhtml #26,97 binding="#{cartBean.checkboxes[i.index]}": Target Unreachable, 'checkboxes' returned null
I solved my problem. I used code like below and get what i want (thanks to BalusC blog - http://balusc.blogspot.com/2006/06/using-datatables.html#SelectMultipleRows):
<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>
public class CartBean extends BaseBean {
private Map<Integer, Boolean> selectedIds = new HashMap<Integer, Boolean>();
public Map<Integer, Boolean> getSelectedIds() {
return selectedIds;
}
}
Your concrete problem is caused because the binding attribute is evaluated during view build time, that moment when the XHTML source code is turned into a JSF UI component tree, while the <ui:repeat> runs during view render time, that moment when the JSF UI component tree needs to produce HTML.
In other words, the #{i.index} is only available during view render time and evaluates as null during view build time. In effects, you're doing a binding="#{cartBean.checkboxes[null]}"
There's another conceptual mistake here: you seem to expect that the <ui:repeat> produces physically multiple <h:selectBooleanCheckbox> components. This is untrue. There's physically only one <h:selectBooleanCheckbox> which is reused multiple times to produce HTML based on the currently iterated variable. Actually, binding="#{cartBean.checkbox}" was been sufficient. However, collecting the values is a story apart. I won't go in detail, but you can find several hints in this answer: Validate order of items inside ui:repeat.
In order to achieve the (apparent) concrete functional requirement of generating physically multiple <h:selectBooleanCheckbox> components and binding each to a separate array item, you should be using an iteration component which runs during view build time instead of view render time. That's the JSTL <c:forEach>:
<c:forEach items="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</c:forEach>
But, after all, using binding on a bean property should be avoided as much as possible. Use instead exactly that attribute which you ultimately need: the value attribute. This way you don't need to do a HtmlSelectBooleanCheckbox#getValue() everytime. You already figured the right solution with a Map<Integer, Boolean> selectedIds:
<ui:repeat value="#{cartBean.productsList}" var="cartProduct">
<h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?
I don't know if you can bind elements stored in an array. But in your code, the problem is that your HtmlSelectBooleanCheckbox[] is null. So maybe change your Java code to:
public HtmlSelectBooleanCheckbox[] getCheckboxes() {
if (checkboxes == null) {
checkboxes = new HtmlSelectBooleanCheckbox[getProductsList().size()];
}
return checkboxes;
}
but I am really not sure if it will work... Maybe the solution is to not bind your HtmlSelectBooleanCheckbox elements in the Java code. Why do you need to bind them?

Resources