Bean method reading null property from xhtml - jsf

I have read a lot of posts at Stackoverflow but I didn't succeed in implementing the belowmentioned problem from my side.
the problem is: I need to type some text in <p:inputTextarea> and when clicking on button I need to get this value in the bean method.
I.e.:
<p:inputTextarea binding="#{input}"/>
<p:commandButton action="#{pessoaMB.adicionarContato(input.value)}" immediate="true"/>
with the bean method:
public void adicionarContato(String value) {
System.out.println(value);
}
The code I'm using gives me a null value.
I'm using #ViewScoped and cannot change this.

First of all, a side note: it is a bad practice to work with JSF components, you should work with model instead. I.e. don't use binding="#{input}", but stick to value="#{bean.text}".
Second, I doubt that immediate="true" is used appropriately in your setup. When used in a UICommand component like <h:commandButton> it will cause to skip JSF lifecycle for components with immediate="false" (or omitted, as it's the default), thus their value won't be set at all. Still, JSF will still preset submittedValue behind the scenes before the action method is executed.
Also, I strongly recommend to read BalusC's blog post Debug JSF lifecycle, as it is more than enlightening on the topic.
As to the solution, I'd suggest to deal with value binding with the bean, as presented in the first comment. With this approach you won't need action method parameter at all. Moreover, rethink your use of immediate attribute. If you think it's correct then you've got two choices: (1) use immediate="true" on <p:inputTextarea> or (2) switch to action="#{bean.action(input.submittedValue)}".

I would've done this :
<h:form>
<p:inputText value="#{pessoaMB.input}"/>
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>
input would be here a pessoaMB property with a getter and setter (an IDE can autogenerate it).
private String input;
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
As for the adicionarContato method, it would be like this :
public void adicionarContato() {
System.out.println(input);
}

You should create a new class, i.e:
public class MyFields(){
String input1;
String input2; //and so on...
//getters and setters
}
Then, in pessoaMB create a property:
private MyFields inputFields; //getter and setter
Finally, in your xhtml file:
<h:form>
<p:inputText value="#{pessoaMB.inputFields.input1}"/>
<p:inputText value="#{pessoaMB.inputFields.input2}"/>
<!-- add more inputText components... -->
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>

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?

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

h:selectBooleanCheckbox is not passing the result to a Map

I want to pass check boxes to a backing CDI-Bean. The postTest.values are just a List of Longs.
<h:form>
<h:dataTable value="#{postTest.values}" var="val">
<h:column>
<h:outputLabel value="#{val}"/>
</h:column>
<h:column>
<h:selectBooleanCheckbox value="#{postTest.checked[val]}"/>
</h:column>
</h:dataTable>
<h:commandButton action="#{postTest.process}"/>
</h:form>
The action method should print out the checked values. But it is just empty.
#Named
#RequestScoped
public class PostTest {
List<Long> values;
Map<Long, Boolean> checked;
...
public String process() {
logger.info(this.toString() + "Processing");
for (Long l : checked.keySet()) {
logger.info(this.toString() + "\t" + l + ". checked: " + checked.get(l));
}
return "index2";
}
...
}
When I add logging to the getChecked() method, I can see, that it is just retrieved once per column and its content isn't changed at all.
The problem seem to be related to the point that the postTest.values is not initialized when the form passes the values. Because if I initialize the postTest.values in the constructor (or a #PostConstruct) the checked items are passed correctly.
Why do I need to initialize the postTest.values at all after the POST request is executed?
Is there a way to prevent that?
Or do I have another option? E.g. make sure that the postTest.values are initialized properly not using the constructor nor the #PostConstruct, cause I want to pass values to it before initialization (I tried listeners, but they don't seem to solve that).
Thanks!
Tim
You can also use Myfaces CODI #ViewAccessScoped annotation if you don't want to play with #ConversationScoped and the start() and end() methods. it is a CDI extension that is kind of equivalent to #ViewScoped of JSF managed bean. I did not check the implementation of this annotation but I see many developers tell that it is even better than #ViewScoped annotation.
Just download Myfaces CODI and drop it in your classpath and use the annotation.

custom validation and component reset

EDIT: I have this snippet of code:
<h:inputText id="email_id" value="#{CreateUserManager.email}"
styleClass="#{CreateUserManager.emailPrimariaValid ? '' : 'inputErrorClass'}">
<f:validator validatorId="EmailValidator" />
<a4j:support event="onblur" reRender="email_id, messages" oncomplete="setAnchor();"
status="status4divCoverAll" ajaxSingle="true" />
</h:inputText>
This is the managed session bean:
public class CreateUserManager {
...
protected boolean emailPrimariaValid;
public CreateUserManager() {
...
this.emailPrimariaValid = true;
}
public boolean isEmailPrimariaValid() {
FacesContext context = FacesContext.getCurrentInstance();
UIInput input = (UIInput)context.getViewRoot().findComponent(":createUser:email_id");
return input.isValid();
}
public void setEmailPrimariaValid(boolean emailPrimariaValid) {
this.emailPrimariaValid = emailPrimariaValid;
}
}
Keep in mind that I remove this bean from session if I come from another page (url), so the bean execute the constructor again.
The problem: I write an invalid email and it sets correctly the class to inputErrorClass, but if I go to another page (so the input component is still invalid) and then come back to the first one, the class remains to inputErrorClass.
Are you by any chance using Seam? It has some good functionality for styling input elements when there are errors.
In Seam 2, you can use the <s:decorate> tag: http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/controls.html#d0e28688
In Seam 3, you can use UIInputContainer and a composite component: http://jerryorr.blogspot.com/2011/10/replacement-for-sdecorate-in-seam-3.html
If you aren't using Seam... well, you can look at the Seam source code to see what they did!
One of the many approaches :
http://mkblog.exadel.com/2011/05/how-to-hightlight-a-field-in-jsf-when-validation-fails/

JSF commandButton with immediate="true"

I have a situation where there is a selectOneMenu that has a value bound to a backing bean.
I need to have a button that doesn't update model values (that is why it has immediate="true" property).
That button's action method changes the value the selectOneMenu is bound to, but when the page is redisplayed the original value is displayed (the one that was submitted) and not the one set in the action method.
Any ideas why that is happening?
If I didn't explain the problem good enough please let me know.
EDIT:
As requested here is the source code in question:
page code:
<h:selectOneMenu id="selectedPerson"
binding="#{bindings.selectPersonComponent}"
value="#{bean.selectedPerson}">
<s:selectItems var="op" value="#{bean.allPersons}"
label="#{op.osoba.ime} #{op.osoba.prezime}"
noSelectionLabel="#{messages.selectAPerson}">
</s:selectItems>
<f:converter converterId="unmanagedEntityConverter" />
</h:selectOneMenu>
...
<a4j:commandButton action="#{bean.createNew}" value="#{messages.createNew}"
immediate="true" reRender="panelImovine">
</a4j:commandButton>
java code:
private Person selectedPerson;
public String createNew() {
log.debug("New created...");
selectedPerson = null;
bindings.getSelectPersonComponent().setSubmittedValue(null); //SOLUTION
return "";
}
The solution is in the lined marked SOLUTION :)
As it frequently happens a few moments after posting this question I have found an answer:
The cause of the problem is in detail explained here: ClearInputComponents
The problem is (as explained) that model values haven't been updated so the submitted inputs are still in component.submittedValue field and that field is displayed if not empty. It is emptied normally after model has been updated.
The first solution didn't work in my case because there is other important state in the view that mustn't get lost. But the second solution worked great:
component.setSubmittedValue(null);
And that was all that was needed: it is a little extra work because components must be bound to some bean, but not that bad.
To follow up a bit, I don't think you need to bind the component to a bean. You can just grab the component from the FacesContext instance via the UIViewRoot, if you know the component's client ID.
It would go a little something like this:
Foo component = (Foo)FacesContext.getCurrentInstance().getViewRoot().getComponent(clientId);
Where Foo is the class of the component you are using and clientId is the client ID of the component in the "formId:elementId" format that JSF uses.
For me, this has worked:
#ManagedBean(name = "bean")
#ViewScoped
public class Bean {
private SelectOneMenu component;
public SelectOneMenu getComponent() {
return selectComponent;
}
public void setComponent(SelectOneMenu component) {
this.Component = component;
}
public void resetComponent() {
component.resetValue();
}
...
}
<h:selectOneRadio value="#{bean.value}" id = "idRadio" required="true" requiredMessage = "Required Message" binding="#{bean.component}" >
<f:selectItem itemLabel="Value 1" itemValue="value1"/>
<f:selectItem itemLabel="Value 2" itemValue="value2" />
</h:selectOneRadio>
<primefaces:commandButton action="#{bean.resetComponent}" value="Erase" update="idRadio" immediate="true"/>
...
Thanks.

Resources