I can't pass the param after clicking the h:commandLink - jsf

I'm trying to create a quizz with data from a db but I'm a bit lost.
I have 3 tables :
Quizz
Questions (ManyToOne: Quizz)
Answers (ManyToOne: Questions)
So I wrote this code to display each question with its answers:
<p>Questions</p>
<ui:repeat value="#{questionBean.fetchQuestionsFromQuizz(quizzBean.fetchQuizz(quizzBean.quizzId))}" var="i" varStatus="current">
<p>#{i.question}</p>
<h:selectOneRadio value="#{i.selectedAnswerId}">
<f:selectItems value="#{answerBean.fetchAnswersFromQuestion(i)}" var="item"
itemLabel="#{item.answer}" itemValue="#{item.id}" />
</h:selectOneRadio>
</ui:repeat>
I'm getting the "quizzBean.quizzId" through a GET param.
The value of h:selectOneRadio is the selectedAnswerId property in my Question entity, so I'm trying to bind it with the selected answer by the user.
So I'm trying to pass the quizz id in the submit button to check them in the bean(#RequestScoped), but the quizz id is null once clicking on the submit button...
Here's the button:
<h:commandLink value="Submit" action="#{questionBean.checkTheAnswers()}">
<f:setPropertyActionListener target="#{questionBean.fromQuizzId}" value="#{quizzBean.quizzId}" />
</h:commandLink>
And here's the method (a simple print):
public void checkTheAnswers(){
System.out.println("FROMQUIZZID : " + fromQuizzId);
}
So do you have any idea on why the quizzId is null?

You have a requestScoped managed bean and you pass the quizzId using the http GET method, in this case you shoud initialize the quizzId filed with the value from the GET method using the #PostConstruct init method of the managedbean.
#PostConstruct
public void init() {
try {
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String, String> params = facesContext.getExternalContext().getRequestParameterMap();
if (params.containsKey("quizzId") {
quizzId= params.get("quizzId");
....

Related

Passing Values from page to other page JSF

I am beginner in java server faces (JSF), I need to pass the content of text input to second page to display it, the same applies for the second page: I want to pass radio buttons values to a third page. I searched and tried a lot without success.
For example I tried
<h:commandButton value="Next" action="#{myBean.execute(input_id.value)}"/>
Execute method is:
public void execute(String value) {
// ...
try{
FacesContext.getCurrentInstance().getExternalContext().dispatch("/Quizy.xhtml?faces-redirect=true");
}
catch(Exception e){
System.out.println("err");
}
}
Any suggestions?
Here are 4 other ways to pass a parameter value from JSF page to other page JSF :
1- Method expression (JSF 2.0)
2- f:param
3- f:attribute
4- f:setPropertyActionListener
1. Method expression
Since JSF 2.0, you are allow to pass parameter value in the method expression like this #{bean.method(param)}.
JSF page
<h:commandButton action="#{user.editAction(delete)}" />
ManagedBean
#ManagedBean(name="user")
#SessionScoped
public class UserBean{
public String editAction(String id) {
//id = "delete"
}
}
2- f:param
Pass parameter value via f:param tag and get it back via request parameter in backing bean.
JSF page
<h:commandButton action="#{user.editAction}">
<f:param name="action" value="delete" />
</h:commandButton>
ManagedBean
#ManagedBean(name="user")
#SessionScoped
public class UserBean{
public String editAction() {
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String action = params.get("action");
//...
}
}
3. f:atribute
Pass parameter value via f:atribute tag and get it back via action listener in backing bean.
JSF page
<h:commandButton action="#{user.editAction}" actionListener="#{user.attrListener}">
<f:attribute name="action" value="delete" />
</h:commandButton>
ManagedBean
#ManagedBean(name="user")
#SessionScoped
public class UserBean{
String action;
//action listener event
public void attrListener(ActionEvent event){
action = (String)event.getComponent().getAttributes().get("action");
}
public String editAction() {
//...
}
}
4. f:setPropertyActionListener
Pass parameter value via f:setPropertyActionListener tag, it will set the value directly into your backing bean property.
JSF page
<h:commandButton action="#{user.editAction}" >
<f:setPropertyActionListener target="#{user.action}" value="delete" />
</h:commandButton>
ManagedBean
#ManagedBean(name="user")
#SessionScoped
public class UserBean{
public String action;
public void setAction(String action) {
this.action = action;
}
public String editAction() {
//now action property contains "delete"
}
}
There are several ways for doing this, but here is one of them.
You will need to save the inputText value into a property of your bean and both your h:inputText and your h:commanButton should be in the same h:form element
Here is a sample code
In your view
<h:form>
...
<h:inputText value={myBean.someValue} />
....
<h:commandButton value="Next" action="#{myBean.execute()}"/>
</h:form>
Your managed bean should be at least session scoped if you want your property (someValue) to be available in different pages. The content of the managed bean should look like this also:
private String someValue;
// Getter and setter for `someValue`
public String execute() {
// ...
return "/Quizy.xhtml?faces-redirect=true";
}
In the second page if you want to retrieve that value, just use #{myBean.someValue}
to have this done, you just need to set the Value of Your component here inputText or radioButton to a Property of your Managed bean or Cdi bean called on the page of course you won't forget to have getter and setter method for ur property in ur bean. Finally be sure that the scope of Ur bean allow it to be alive (with all its properties' value) across the session. Then, from ur end page you may call ur Managed bean or Cdi bean proprety as value of page components

Values of h:inputText inside ui:repeat are not processed

I want to process this form (valueChangueListener is not valid in real case).
This is the back bean:
public class TestBean extends PrivateBaseBean implements Serializable {
private List<String> strings;
#PostConstruct
public void init() {
strings = new ArrayList<String>();
strings.add("");
strings.add("");
strings.add("");
}
public void saveAction(ActionEvent event) {
StringBuilder textToShowInMessage = new StringBuilder();
for (String string : strings) {
textToShowInMessage.append(string);
textToShowInMessage.append("; ");
}
FacesMessage msg = new FacesMessage(super.getBundle().getString(
textToShowInMessage.toString()), "");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
getters... setters...
An the view:
....
<h:form>
<ui:repeat var="string" value="#{testBean.strings}">
<h:inputText value="#{string}" />
<br />
</ui:repeat>
<p:commandButton value="#{msg.save}"
actionListener="#{testBean.saveAction}" icon="ui-icon-disk"
update="#form" />
</h:form>
...
When the form is processed in the back bean string list always is blank.
How to process form intput's inside iteration, without any value changue listener?
There are some screenshots:
The same problem occurs with action or actionListener on
Your problem is not connected with PrimeFaces <p:commandButton>'s behaviour, but rather with a scoping problem that is implicilty created when using the <ui:repeat> tag.
First of all, let's depart from your example. Basically, you've got
<ui:repeat value="#{bean.strings}" var="s">
<h:inputText value="#{s}"/>
</ui:repeat>
with the backing List<String> strings.
The culprit is here: value="#{s}". The exported by <ui:repeat> variable s is visible only within its loop and it is not bound to any managed bean's property, but instead only to a local variable. Put it differently, s is not bound/equal to bean.strings[index] as one would expect and has no knowledge, as we see, where it originated from. So basically, you're off with a unilateral relationship: value from the bean is printed in your input properly, but the reverse is not happening.
The workarounds
Workaround #1: wrapper classes / model objects
The situation can be overcome by using a wrapper object for your class. In case of a string it could be a 'simple mutable string', like below:
public class MString {
private String string;//getter+setter+constructor
}
In this case the iteration will be working as predicted:
<ui:repeat value="#{bean.mstrings}" var="ms">
<h:inputText value="#{ms.string}"/>
</ui:repeat>
with the backing List<MString> mstrings.
Note that if you have your model class, like User, and will change its properties within <ui:repeat> the class itself will be effectively a wrapper, so that the properties will be set appropriately.
Workaround #2: chained property access
Another workaround consists of accessing an element of your collection directly from within a <h:inputText> tag. This way, any such property will be set by accessing the bean, then collection, then setting the property at the desired index. Excessively long, but that's how it is. As to the how question, <ui:repeat> provides for an exported current iteration status variable, varStatus, that will be used to access the array/collection in the managed bean.
In this case the iteration will also be working as predicted:
<ui:repeat value="#{bean.strings}" var="s" varStatus="status">
<h:inputText value="#{bean.strings[status.index]}"/>
</ui:repeat>
with the ordinary backing List<String> strings.
My workaround solution take the value directly from the page:
<ui:repeat id="repeat" value="#{bean.strings}" var="s" varStatus="status">
<h:inputText id="x" value="#{s.field}"/>
<h:commandLink style="margin: .5em 0" styleClass="commandLink" actionListener="#{bean.save(status.index)}" value="#{bundle.Send}"/>
</ui:repeat>
The save method:
public void save(String rowid) {
String jsParam = Util.getJsParam("repeat:" + rowid + ":x");
System.out.println("jsParam: " + jsParam); //persist...
}
The getJsParam method:
public static String getJsParam(String paramName) {
javax.faces.context.FacesContext jsf = javax.faces.context.FacesContext.getCurrentInstance();
Map<String, String> requestParameterMap = jsf.getExternalContext().getRequestParameterMap();
String paramValue = requestParameterMap.get(paramName);
if (paramValue != null) {
paramValue = paramValue.trim();
if (paramValue.length() == 0) {
paramValue = null;
}
}
return paramValue;
}

primefaces uiViewRoot find component inside <p:dataTable >

I am using primefaces 3.2.
I've got the following situation:
<h:form id="someForm">
..
<p:dataTable id="someDataTable" value="#{BackingBean.list}" var="element" ..>
<p:column>
<p:calendar id="someCalendar" value=#{element.date} ../>
<p:message id="someCalendarMessage" for=":someForm:someDataTable:someCalendar"/>
<p:column>
</p:dataTable>
..
</h:form>
The "someDataTable" is updated dynamically and then all the data are submitted to the server side. In the backing bean I want to send message for calendar "someCalendar" if the entered date doesn't satisfy some condition. I try to find the component using this code:
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(facesContext.getViewRoot().findComponent(":someForm:someDataTable:" + "i" + ":someCalendar").getClientId(), new FacesMessage(FacesMessage.SEVERITY_ERROR, Utils.getResourceBundleString("dictionary", "error") + ":", Utils.getResourceBundleString("dictionary", "some_message")));
return;
Where i is the index of the "element" in the dataTable which the same as index in the list located in the BackingBean.
The problem is that I get NullPointerException since the facesContext.getViewRoot().findComponent(..) method cannot find the component, although I checked the generated id of the calendar in the view and it is
:someForm:someDataTable:0:someCalendar for the first element and it should be :someForm:someDataTable:1:someCalendar for the next element etc.
Why the facesContext.getViewRoot().findComponent(..) method cannot find the component inside the ? The is updated dynamically and maybe the server side doesn't get the updated component tree after submission is done?
Thanks in advance.
This is because the p:dataTable is a repeated component and during view build time there is only one calendar in the view root. It has the id someForm:someDataTable:someCalendar.
Only during view render time the table rows are created and the row-dependent ids generated.
You should use JSF build-in validation facilities to check your dates:
in the view:
<p:calendar id="someCalendar" value=#{element.date}
validator="#{BackinBean.validateDate}"/>
<p:message id="someCalendarMessage" for="someCalendar"/>
(someCalendar in the for attribute is sufficient)
and in the backing bean:
public void validateDate(
FacesContext context,
UIComponent component,
Object value) throws ValidatorException {
if (/* date is not valid */) {
throw new ValidatorException(
new FacesMessage("Date is not valid"));
}
}
The FacesMessage from the validation method will automatically be displayed in the correct table row.

h:commandButton inside h:dataTable [duplicate]

This question already has answers here:
How can I pass selected row to commandLink inside dataTable or ui:repeat?
(4 answers)
Closed 7 years ago.
I am using a JSF data table. One of the columns in the table is a Command button.
When this button is clicked I need to pass few parameters (like a value of the selected row) using the Expression language. This paramaters need to be passed to the JSF managed bean which can execute methods on them.
I have used the following snippet of code but the value i am getting on the JSF bean is always null.
<h:column>
<f:facet name="header">
<h:outputText value="Follow"/>
</f:facet>
<h:commandButton id="FollwDoc" action="#{usermanager.followDoctor}" value="Follow" />
<h:inputHidden id="id1" value="#{doc.doctorid}" />
</h:column>
Bean Method:
public void followDoctor() {
FacesContext context = FacesContext.getCurrentInstance();
Map requestMap = context.getExternalContext().getRequestParameterMap();
String value = (String)requestMap.get("id1");
System.out.println("Doctor Added to patient List"+ value);
}
How can I pass values to the JSF managed bean with a commandbutton?
Use DataModel#getRowData() to obtain the current row in action method.
#ManagedBean
#ViewScoped
public class Usermanager {
private List<Doctor> doctors;
private DataModel<Doctor> doctorModel;
#PostConstruct
public void init() {
doctors = getItSomehow();
doctorModel = new ListDataModel<Doctor>(doctors);
}
public void followDoctor() {
Doctor selectedDoctor = doctorModel.getRowData();
// ...
}
// ...
}
Use it in the datatable instead.
<h:dataTable value="#{usermanager.doctorModel}" var="doc">
And get rid of that h:inputHidden next to the h:commandButton in the view.
An -less elegant- alternative is to use f:setPropertyActionListener.
public class Usermanager {
private Long doctorId;
public void followDoctor() {
Doctor selectedDoctor = getItSomehowBy(doctorId);
// ...
}
// ...
}
With the following button:
<h:commandButton action="#{usermanager.followDoctor}" value="Follow">
<f:setPropertyActionListener target="#{usermanager.doctorId}" value="#{doc.doctorId}" />
</h:commandButton>
Related:
The benefits and pitfalls of #ViewScoped - Contains CRUD example using DataModel<E>.

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