How to send data to a faces-flow? - jsf-2.2

My use case: the user choose a questionnaire in a form. When the form is submitted, a faces-flow is started to display the questions of the questionnaire.
To send the questionnaire to the flow, in the bean of the flow I inject the CDI bean of the page which contains the form.
I wonder if there are other ways to send the questionnaire to the flow. If there are several ways, what's the best one?

You can pass parameters via the form and get them in the initializer method called at the initialization of your flow.
Form (just replace the inputHidden parameter with whatever you're using to select your questionnaire)
<h:form id="myForm" prependId="false">
<h:commandLink value="Enter myFlow" action="my-flow"/>
<h:inputHidden id="parameter" name="parameter" value="8"/>
</h:form>
Flow
#Produces #FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "my-flow";
flowBuilder.id("", flowId);
flowBuilder.initializer("#{myFlowBean.startFlow()}");
...
}
Backing bean
#Named
#FlowScoped("my-flow")
public class MyFlowBean implements Serializable {
public void startFlow() {
String parameter = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("parameter");
//now do sthg with the parameter, such as fetching the questionnaire
....
}
}
See this answer for more details

Addition to "thomas.g"s helpful answer:
I had the same problem, but could not fix it with the hiddenInput approach. Despite the prependId="false" attribute my id and name of the hidden input field got changed by the primefaces p:dataTable element I used. The issue could be fixed with the f:param elemtent inside the h:commandLink element:
<h:commandLink value="Enter myFlow" action="my-flow" >
<f:param name="parameter" value="8"/>
</h:commandLink>
I hope this might be helpfull to someone with a similar problem.

This can be done in the flow xml file using the initializer tag
<initializer>
#{myFlowBean.startFlow()}
</initializer>
to call the your initialize method in the flow scoped bean

Related

h:inputText value is always null after AJAX event

I use ajax to enable an input text if a certain value of a selectonemenu is selected. Like this:
<a4j:outputPanel id="panelFilial">
<h:selectOneMenu id="perfil" tabindex="5"
value="#{actionCadastrarCotacaoDadosCarga.idProduto}"
label="#{msg.selecione}" style="width: 145px;"
required="false">
<f:selectItems value="#{actionCadastrarCotacaoDadosCarga.listProdutos}"></f:selectItems>
<a4j:support ajaxSingle="true" event="onchange"
action="#{actionCadastrarCotacaoDadosCarga.direcionarEnableOutros}"
onclick="javascript:Richfaces.showModalPanel('progressWaitModalPanel');
atualizarImagem();"
reRender="panelOutros" />
</h:selectOneMenu>
</a4j:outputPanel>
Here's my backing bean method:
public void direcionarEnableOutros() {
if (this.idProduto.equals(ID_PRODUTO_OUTROS)) {
this.enableOutros = false;
this.descricaoProduto = new String();
} else {
this.enableOutros = true;
}
}
When I submit my form, the value of the input text is always null. Am I missing something here?
Here's the input text:
<a4j:outputPanel id="panelOutros">
<h:inputText id="outros" tabindex="6" required="false"
maxlength="50"
value="#{actionCadastrarCotacaoDadosCarga.descricaoProduto}"
disabled="#{!actionCadastrarCotacaoDadosCarga.habilitarCampoOutros}">
</h:inputText>
</a4j:outputPanel>
Assuming you are using Seam, the problem must be the event scope. Change it to conversation scope.
Event Scope
The event (request) context. Spans a server request, from restore view
to render response.
Conversation Scope
The conversation context. Spans multiple requests from the same
browser window, demarcated by #Begin and #End methods. A conversation
context is propagated by any faces request, or by any request that
specifies a conversation id as a request parameter. The conversation
context is not available during the restore view phase.
In JSF 2.x you can make use of #ViewScoped to makee your bean alive while the user interacts with the same view e.g. ajax requests. In JSF 1.x, there's no #ViewScoped, so you had to store and remove the data from view state or even session scope manually. Still, since you're using RichFaces, you can make use of #KeepAlive annotation, which works very similar to #ViewScoped from JSF 2.
Just do this:
#KeepAlive
public class ActionCadastrarCotacaoDadosCarga {
//bean definition here...
}
And make sure the beans is configured in request scope:
<managed-bean-name>actionCadastrarCotacaoDadosCarga</managed-bean-name>
<managed-bean-class>location.of.your.bean.ActionCadastrarCotacaoDadosCarga</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<!-- ^-IMPORTANT-^ -->
</managed-bean>

Calling a method using JSF2 + ajax

I've seen a lot of examples online of code where a method is called with a "f:ajax" tag but the name of the method gets shortened in the tag when the method name starts with "get". I haven't been able to find the reason for this. Below is an example of what I mean.
For instance, in the xhtml file "sayWelcome" is called:
...
<h:commandButton value="Welcome Me">
<f:ajax execute="name" render="output" />
</h:commandButton>
<h:outputText id="output" value="#{helloBean.sayWelcome}" />
...
but the method in the bean is called "getSayWelcome":
public String getSayWelcome(){
return name;
}
Why does the "get" get dropped from the method name in the "f:ajax" tag?
The JavaBeansSpecification defines the naming convention for the properties adding the get and set before the functions that acts as properties, see this article for more info.
The expression language that use JSF also complains the JavaBeans properties name convention you can check this in this article, refer to the Referring to Object Properties Using Value Expressions section.
So in conclusion when the EL (Expression language) finds a sentence as <h:outputText id="output" value="#{helloBean.sayWelcome}" /> it will try to call a getter or the setter function for the sayWelcome property, it depends if it need to assign the value (setter) or get the value (getter).

View scope reset fields to default after performing an action

First of all, my beans are managed by spring not by JSF and I am using custom view scope as described in this article. So if the behavior is weird for regular JSF2 and might be related to Spring, please tell me.
Bean:
public class DepartmentBean {
private DefaultTreeModel model;
public void preRender(ComponentSystemEvent event) throws Exception {
if (model == null) {
model = myService.buildModel();
}
}
public String clear() {
// resetting stuff
return "pretty:";
}
}
View:
<h:form>
<ice:panelGroup styleClass="crud-links">
<h:commandLink value="Delete" action="#{department.deleteDepartment}" />
</ice:panelGroup>
</h:form>
<h:form>
<ice:panelGroup>
<ice:tree id="tree" value="#{department.model}" var="item" hideRootNode="false" hideNavigation="false" imageDir="./xmlhttp/css/xp/css-images/">
<ice:treeNode>
<f:facet name="content">
<ice:panelGroup style="display: inline">
<ice:commandLink value="#{item.userObject.text}"></ice:commandLink>
</ice:panelGroup>
</f:facet>
</ice:treeNode>
</ice:tree>
</ice:panelGroup>
</h:form>
When page is loaded for first time the model object is populated with data, but when clicking delete button I notice that after clearing preRender() method is executed and the model (which was populated before clearing becomes null, and gets populated again, although I am in same page, and it should maintain the value)
Does the code have a problem that leads to such behavior, or this is the normal behavior?
If the problem maybe related to Spring or the custom view scope or the IceFaces, please advise.
UPDATE- REQUIREMENT:
I want to initialize the tree model on construction of the page, and while i am still on the page the tree model doesn't gets initialized again until i do that programatically .
oh my mistake, initialization should be inside #PostConstruct.

JSF2 Composite component link using ajax

Here is my (simplified) issue :
I've got a page that is using 2 composite components of mine :
- CCSelection
- CCDisplay
In CCSelection, I have a list of values, each one has got a h:commandLink onto.
When clicking on a link, the CCDiaplay component is refreshed using the selected value.
To do this, CCSelection exposes a method attribute that is directly linked on each h:commandLink. The value is given to the method using f:attribute.
In the page backing bean, I've got a method (that is given to CCSelection as an attribute), that sets a member.
CCDisplay gets this value though an cc:attribute via the pages's member's getter.
It works !
Now, I want to ajaxize this behaviour.
I tryed to put an f:ajax for each h:commandLink in CCSelection... but if I put #form or #all in the render attribute, nothing is rendered (but the setter methods are called). If I put the id of the UIComponent (of the Page) to render, I get a nullpointerexception saying that a property is not defined for NamingContainer in CCDisplay. Quite strange because I didn't change anything inside CCDisplay !
I think the solution is to put the f:ajax not inside CCSelection but in Page.
So there may be 2 ways to achieve this :
- CCSelection raises an event f:ajax can manage... but how ?
- Using cc:clientBehaviour for CCSelection. But is it possible to target more that 1 component (I've got many h:commandLink, but I want only 1 event).
- Other ways ?
Here is a pseudo code
page.xhtml
<myComp:ccSelection actionMethod="#{pageBean.select}"
render="#{clientIDHelper.clientId['display']}" />
<h:panelGroup id="diplay" binding="#{clientIDHelper.bindings['display']}">
<myComp:ccDisplay value="#{pageBean.value}" />
</h:panelGroup>
To recover the full clientid of the panel containing the ccDiaplay composite component, I use a clientIDMap technic described here.
PageBean.java
private String _value;
public String getValue() { return _value; }
public void setValue(String value) [ _value = value; }
public void select(String value) {
setValue(value);
}
ccSelection.xhtml
<cc:interface>
<cc:attribute method-signature="void selectAction(String)"
name="actionMethod" />
<cc:attribute name="render" />
</cc:interface>
<cc:implementation>
<t:dataTable value="#{cc.values}"
var="val"
...
>
<h:column>
<t:commandLink actionListener="#{cc.selectionValueListener}"
<f:ajax render="#{cc.attrs.render}" />
<f:attribute name="value"
value="#{val}" />
</t:commandLink>
</h:column>
</t:dataTable>
</cc:implementation>
ccSelection.java
public void selectionValueListener() {
// recover the attribute value
String value = event.getComponent().getAttributes().get("value");
// call the callback method of the page
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression method = (MethodExpression) this.getAttributes().get("actionMethod");
if (method != null)
method.invoke(context.getELContext(), new Object[] {value});
}
I don't think ccDisplay is interressting.
So, if I don't put the f:ajax tag, it works.
When I put the f:ajax with the render pointing to the clientId passed in param, I get an error while loading the page.
If I change the render for #form or #all, the pageBean.select method is called, but ccDisplay is not refreshed.
I think i see a little error in page.xhtml.
See when you created the component cc:display you said:
<cc:attribute method-signature="void selectAction(String)" name="actionMethod" />
That means that a parameter is needed.
But when you call it in page.xhtml you do this:
<myComp:ccSelection actionMethod="#{pageBean.select}"...
And its backing bean method is:
public void select(String value) {
setValue(value);
}
As you see the backing bean is correct, but when you call the component in the page, there is no parameter being passed to the bean, and at the end the value is never set.
I think that might be one of the reasons.
To fix it i think you should pass the value some how:
<myComp:ccSelection actionMethod="#{pageBean.select(???Selected value
???)}"...
OK. It is solved... but I don't like it very much.
You'll think I'm a fool : I solved the problem by removing the <![CDATA surrounding my scripts !
I've already found some issue using CDATA. I don't know if this is a MyFaces bug or something I do the wrong way like putting many h:outputScript blocks with CDATA in composite components but with CDATA, I get errors or not working. Just removing it, it works !

JSF 2.0,partially rendered form field input value not updated in the bean

I have an Edit product form which is pre-populated with values from DB . User can change one or more values and post the form back. One input field called t:inputFileUpload is rendered only after an ajax request ,if the user opts to change product image.During the final postback of the edit form through a save button,the bean is not updated with the value of t:inputFileUpload field.The relevant portion of the form is below:
<h:form>
<tr>
<td>Product Image*:</td>
<td>
<h:graphicImage url="#{addItem.prodFileName}" width="100" height="100"/>
<br /><h:commandLink value="change image" >
<f:ajax render="uploadimage" execute="#this" listener="#{addItem.ChangeImage}"/>
</h:commandLink>
</td>
</tr>
<tr >
<td>
<h:panelGroup id="uploadimage">
<t:inputFileUpload rendered="#{addItem.editImgChange}" label="editImage" value="#{addItem.uploadedFile}" />
<h:messages for="prodimage"/>
<h:inputHidden id="hiddeneditimgchange" value="#{addItem.editImgChange}" />
</h:panelGroup>
</td>
</tr>
<h:commandButton value="save" action="#{addItem.EditItem}" />
</h:form>
The AddItem bean is request scoped and the relevant part of its code is :
#ManagedBean
public class AddItem extends AbstractBean{
boolean editImgChange;
private UploadedFile uploadedFile;
//..
//getters and setters
public void ChangeImage(){
this.editImgChange=true;
}
public String EditItem() {
//some logic
}
}
I have read a few similar questions some of whose answers were to make the bean viewscoped.I have tried making the bean ViewScoped ,but it breaks my initial logic of prepopulating the form values. Since i am happy with RequestScoped , I have saved the state of the editImgChange flag ,if its turning off is affecting the updation of the t:inputFileUpload . When i looked at the bean properties all is fine ,the flag is true , but the uploadedFile property is null.
As per the comments, you used <h:inputHidden value="#{addItem.editImgChange}" /> to save the state. This is not going to work. The rendered attribute is evaluated during apply request values phase, while that hidden value is made available during update model values phase which is thus too late.
Since you're already using Tomahawk, use <t:saveState value="#{addItem.editImgChange}" /> instead. Or, just fix the problem which you encountered when making the bean view scoped. I don't forsee why that would be a problem. Perhaps you're using #PostConstruct and expecting that it's invoked on every request. You should then use <f:event type="preRenderView"> instead.

Resources