JSF - Null values from parameters - FacesContext - jsf

I'm trying to get na few parameters (now it's two, but on the other xhtml probably I'll need more).
On page index.html I have a link, to page Threads.xhtml, with parameters user_id and section_id:
<h:dataTable value="#{Sections.sections}" var="Section">
<h:column>
<h:form>
<h:link value="#{Section.section_label}" outcome="Threads">
<f:param name="user_id" value="#{LoginIn.user_id}"/>
<f:param name="section_id" value="#{Section.section_id}"/>
</h:link>
</h:form>
</h:column>
</h:dataTable>
When I click into on of the links, it goes to for ex.:
Project/faces/Threads.xhtml?user_id=5&section_id=2
So it's good :).
Now, on page Threads.xhtml I have a link (one link, not dataTable, as on index.xhtml - to create new section), to page NewThread.xhtml, with parameters user_id and section_id:
<h:form>
<h:link value="#{msg.create_new_thread}" outcome="NewThread">
<f:param name="user_id" value="#{param.user_id}"/>
<f:param name="section_id" value="#{param.section_id}"/>
</h:link>
</h:form>
When I click into on of the links, it goes to, for ex..:
Project/faces/NewThread.xhtml?user_id=5&section_id=2
So it's also nice :).
Now, I check on NewThread.xhtml page values of user_id and section_id, by:
<h:outputText value="User_id: #{param.user_id}"/><br/>
<h:outputText value="Section_id: #{param.section_id}"/><br/>
And I see on page values:
User_id: 5
Section_id: 2
So ok :). But now, when I'm trying to get these values in Java code NewThread.java, they returns only null:
FacesContext facesContext = FacesContext.getCurrentInstance();
String user_id = (String) facesContext.getExternalContext().getRequestParameterMap().get("user_id");
String section_id= (String) facesContext.getExternalContext().getRequestParameterMap().get("section_id");
//For test:
System.out.println("User_id: " + user_id);
System.out.println("Section_id: " + section_id);
And in console i've got:
User_id: null
Section_id: null
I've also try toString() method, but it didn't help.
Going back to the index.xhtml, when I click on the link to one of the section, ex. second section (by any user, ex. user_id=5), it goes to Threads.xhtml:
Project/faces/Threads.xhtml?user_id=5&section_id=2
And on Threads.xhtml I've got list of Threads of second section (but this part of xhtml code is irrelevant):
<h:dataTable value="#{Threads.threads}" var="Thread">
<h:column>
<h:link value="#{Thread.thread_label}" outcome="Threads">
<f:param name="thread_id" value="#{Thread.thread_id}"/>
</h:link>
</h:column>
</h:dataTable>
And on Java code of Threads.java, I've got:
FacesContext facesContext = FacesContext.getCurrentInstance();
String section_id = (String) facesContext.getExternalContext().getRequestParameterMap().get("section_id");
System.out.println("Section_id: " + section_id);
And in console i've got:
Section_id: 2
So WTF? Once it works, but another time it won't.
EDIT:
Sorry, I forgot. I access into NewThread.java, by commandButton in NewThread.xhtml:
<h:commandButton value="#{msg.add_thread}" action="#{NewThread.AddThread}"/>
and it calls AddThread method in NewThread.java; and in try (of try-catch) of AddThread method, there I'm trying to get parameters.
I've also already add into faces-config.xml:
<managed-bean>
<managed-bean-name>Threads</managed-bean-name>
<managed-bean-class>forum.Threads</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>NewThread</managed-bean-name>
<managed-bean-class>forum.NewThread</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

When you click an h:commandButton, a new request is made. The problem is that the parameters are not being passed to this request.
So, if you want your request scoped bean NewThread to get the data from the request parameters, you have to include the parameters in the request made from the h:commandButton too. Try this:
<h:commandButton value="#{msg.add_thread}" action="#{NewThread.AddThread}">
<f:param name="user_id" value="#{param.user_id}"/>
<f:param name="section_id" value="#{param.section_id}"/>
</h:commandButton>
As you are using JSF 2, you may find useful to use f:metadata with f:viewParam together with the includeViewParameters=true trick for navigating between pages, check out these questions:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Handling view parameters in JSF after post

As elias says, when you click on the command button there's a new request (a post) and this won't include the get parameters from the previous request.
An alternative solution is using the mentioned view parameters in combination with the o:form component from OmniFaces, that has an attribute that automatically retains all view parameters as GET parameters:
<o:form includeViewParams="true">
This has the additional advantage that users keep to see those parameters in the URL, so if they copy it or refresh the page by hitting enter in the address bar of their browser, things keep working as expected.

Related

Auto calculated fields

I've the following form:
<h:form>
<h:inputText size="2" value="#{orderMB.quantity}" />
<h:outputLabel value=" #{orderMB.totalPriceOneItem} €" />
<h:commandButton value="submit" />
</h:form>
And I've the following method in a session scoped managed bean:
public void setQuantity(int quantity) {
this.quantity = quantity;
setTotalPriceOneItem(quantity* item.getItem().getPrice().doubleValue());
}
I would like to auto-update the total price result on every key press of the input field. How can I achieve this without pressing the submit button?
Your code isn't doing that anywhere. It's missing a <f:ajax>.
<h:inputText size="2" value="#{orderMB.quantity}">
<f:ajax event="keyup" render="total" />
</h:inputText>
<h:outputText id="total" value="#{orderMB.totalPriceOneItem} €" />
The event attribute can be set to any HTML DOM event on which JSF must submit the form by ajax, such as click, keyup, blur, focus, etc. The render attribute can be set to any JSF client ID which needs to be updated when the ajax submit finishes. In this case it's referring the ID of the component showing total price.
Note that I replaced the wrong <h:outputLabel> by <h:outputText>. Also noted should be that a setter isn't exactly the right place to perform business logic (a getter also not!). Better revert that setter method to a true setter and add an ajax listener method:
<f:ajax event="keyup" listener="#{orderMB.updateTotalPriceOneItem}" render="total" />
public void updateTotalPriceOneItem() {
totalPriceOneItem = quantity * item.getItem().getPrice().doubleValue();
}
In case when it still doesn't work, then verify if you have a <h:head> in the template instead of a <head>. If still in vain, work through commandButton/commandLink/ajax action/listener method not invoked or input value not updated.
That said, I strongly recommend to take a pause and work through a sane JSF 2.x book. The above is usually already covered in the 1st chapter.

jsf datatable why commandLink clientid resolved before update model values phase

I have a datatable that iterates over a list, lets call it myList. I populate this myList based on some request parameters. Inside the datatable there are commandLinks. If i put a dummy entry into myList during apply request values phase, i can click on the first commandLink, and it works as it should (it is executed during invoke application phase, and by then the correct entries are in myList). If i dont do it, or i click on the second or later commandLink, nothing happens. So im guessing the clientId of the command button is resolved during apply request phase, even thought it is only used during the invoke application phase, which results in the broken commandLinks.
something like this:
<h:selectManyCheckbox styleClass="hidden"
value="#{cc.attrs.selectionList.selected}"
converter="#{cc.attrs.converter}" >
<f:selectItems value="#{cc.attrs.selectionList.all}"
var="item" itemValue="#{item}" itemLabel="" />
</h:selectManyCheckbox>
<h:dataTable value="#{cc.attrs.selectionList.selectedTest}" var="item">
<h:column>
<h:commandLink value="deselect" action="#{cc.attrs.selectionList.deSelect(item)}">
<f:ajax execute=":#{component.parent.parent.parent.clientId}"
render=":#{component.parent.parent.parent.clientId}" />
</h:commandLink>
</h:column>
</h:dataTable>
and the model:
public List<E> getSelected()
{
return myList;
}
public List<E> getSelectedTest()
{
if(FacesContext.getCurrentInstance().getCurrentPhaseId().equals(PhaseId.RESTORE_VIEW) && getSelectedList().isEmpty())
{
return Collections.singletonList(myList.get(0));
}
else if(FacesContext.getCurrentInstance().getCurrentPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES) && getSelectedList().isEmpty())
{
return Collections.nCopies(2, myList.get(0));
}
else if(FacesContext.getCurrentInstance().getCurrentPhaseId().equals(PhaseId.PROCESS_VALIDATIONS) && getSelectedList().isEmpty())
{
return Collections.nCopies(3, myList.get(0));
}
else if(FacesContext.getCurrentInstance().getCurrentPhaseId().equals(PhaseId.UPDATE_MODEL_VALUES) && getSelectedList().isEmpty())
{
return Collections.nCopies(4, myList.get(0));
}
return myList;
}
public void deSelect(E item)
{
myList.remove(item);
}
with this example, the top two commandLinks of the datatable works.
My question is why is this behaviour, and is there any way around without filling myList with dummy entries? I do not want to use any (viewscoped) backing bean to store the data.
During apply request values phase, JSF needs to iterate over the model in order to find the clicked command link. If the model changes incompatibly during the HTTP request wherein the form submit is processed (the postback) as compared to the initial HTTP request wherein the table with the command links is shown, then JSF may not be able to find the clicked command link and thus never queue the desired action, or the object representing the "current row" is not the same as the enduser intented.
If your bean is request scoped, then it should be written in such way that it initializes selectedTest in the constructor or #PostConstruct method based on some request parameter. At least, you should absolutely not perform business logic in getters.
You can pass the parameters necessary for reconstructing the selectedTest as <f:param> in the command link.
<h:commandLink ...>
<f:param name="some" value="#{bean.some}" />
</h:commandLink>
And prepare the model as follows:
#ManagedProperty
private String some;
#PostConstruct
public void init(){
selectedTest = populateItBasedOn(some);
}
// Don't change standard getters/setters!
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4
I managed to get my way around by binding the selectManyCheckbox itself to my componentBindings HashMap, and using that for the dataTable (with immediate="true" on the selectManyCheckbox):
<h:selectManyCheckbox immediate="true" styleClass="hidden"
binding="#{componentBindings[cc.attrs.selectionList]}"
value="#{cc.attrs.selectionList.selected}"
converter="#{cc.attrs.converter}" >
<f:selectItems value="#{cc.attrs.selectionList.all}" var="item"
itemValue="#{item}" itemLabel="" />
</h:selectManyCheckbox>
<h:dataTable value="#{componentBindings[cc.attrs.selectionList].value}" var="item">
<h:column>
<h:commandLink value="deselect" action="#{cc.attrs.selectionList.deSelect(item)}">
<f:ajax execute=":#{component.parent.parent.parent.clientId}"
render=":#{component.parent.parent.parent.clientId}" />
</h:commandLink>
</h:column>
</h:dataTable>
in faces-config.xml:
<managed-bean>
<description>Holder of all component bindings.</description>
<managed-bean-name>componentBindings</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Pass param via h:link using bean with the same view scope( has a value of null and thus will not be added to the URL)

I have one bean with view scope and want pass parametr between two different pages and on first page before this link I have <p:selectOneMenu/> where I choose test which id should be pass as GET param
<p:selectOneMenu value="#{addQuestion.test}" id="tests"
converter="#{testConverter}" required="true" requiredMessage="Please, choose test">
<f:selectItem itemLabel="--Select a test--" itemValue="" />
<f:selectItems value="#{addQuestion.testList}" var="testItem"
itemValue="#{testItem}" itemLabel="#{testItem.testName}" />
<p:ajax process="#this"
listener="#{addQuestion.getQuestionsBySubject()}"
update="addingQuestionsTable, testId" />
</p:selectOneMenu>
<h:link value="Add new question" outcome="addQuestion">
<f:param id="testId" name="testId" value="#{addQuestion.test.testIdentifer.testId}"/>
</h:link>
//in second page
<f:metadata>
<f:viewParam name="testId"
value="#{addQuestion.test.testIdentifer.testId}"
converter="#{testConverter}" required="true" requiredMessage="Invalid page access. Please use a link from within the system."/>
</f:metadata>
And bean
#ManagedBean(name = "addQuestion")
#ViewScoped
public class AddQuestion implements Serializable {
private Test test;
//get
//set
}
But when I try to get value on second page I nothing to get in expression #{addQuestion.test.testIdentifer.testId}" And also in development mode I get
has a value of null and thus will not be added to the URL.
My #{testConverter} is managed bean in view scope.
How I can pass testId in one bean with view scope and why I get this error?
The <f:xxx> tags like <f:param> doesn't generate any HTML and thus have nothing to update in the HTML DOM tree on ajax request. The <h:xxx> components are the ones which generate HTML and are updatable in the HTML DOM tree on ajax request. You need to update the <h:link> component instead of the <f:param> tag. So, move that id from <f:param> to <h:link>.
<h:link id="testId" value="Add new question" outcome="addQuestion">
<f:param name="testId" value="#{addQuestion.test.testIdentifer.testId}"/>
</h:link>

How to pass parameter from a RequestScoped to a ViewScoped bean

I have a simple form where you can input a String. When submitting the form, the user is redirected to another page that echos the user input. The first page is using a RequestScoped bean whereas the second page is using a ViewScoped bean.
First Page:
<h:form>
Type a String: <h:inputText value="#{requestScopedBean.property}"></h:inputText>
<h:commandButton value="To View" action="#{requestScopedBean.toViewScopedBean}">
<f:setPropertyActionListener target="#{viewScopedBean.property}" value="#{requestScopedBean.property}" />
<f:ajax execute="#form" />
</h:commandButton>
</h:form>
Second Page:
This is the property passed by the requestScoped bean: <h:outputText value="#{viewScopedBean.property}"></h:outputText><br/>
This is the property created in the PostConstruct: <h:outputText value="#{viewScopedBean.otherProperty}"></h:outputText>
I understand why it does not work. When the form is submitted, the viewScopedBean.property is set to the correct value but then we switch to another view, so a new ViewScopedBean is created. That's why the value from the request is lost.
How do you pass the parameter from page one to page two without changing the scope of the bean?
Alternatively you could put the string on the request map when triggering the requestScopedBean action
public String toViewScopedBean(String string){
Map<String,Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
requestMap.put("StringKey", string);
return "toViewScopedBean";
}
and then retrieve the value from the valueScopedBean
public String getProperty(){
Map<String, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
return (String) requestMap.get("StringKey");
}

open detail view with request parameter

I created a simple master/detail using myfaces and richfaces. By clicking a h:commandLink in the rich:dataTable the user is able to open the detail view and edit the entity.
Now I want to create a URL that allows the user to open the detail view directly. Normally I would to this by creating an URL like /detail.jsp?id=12 - how can I achieve that with JSF?
You can construct the URL using parameters on a link control:
<h:outputLink value="reqscope.faces">
<f:param name="id" value="#{row.id}" />
<h:outputText value="link" />
</h:outputLink>
On the target page, you can read the id from the parameter map, either directly using the expression language or via a managed bean.
View:
<f:view>
id= <h:outputText value="#{param['id']}" />
<br />
id= <h:outputText value="#{lookupBean.id}" />
</f:view>
Bean:
public class LookupBean implements Serializable {
public String getId() {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext extContext = context.getExternalContext();
Map<String, String> params = extContext.getRequestParameterMap();
return params.get("id");
}
}
faces-config.xml declaration:
<managed-bean>
<managed-bean-name>lookupBean</managed-bean-name>
<managed-bean-class>reqscope.LookupBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
I use an a4j:commandlink to first pass the id of the entity I want to show details for to the detail view bean. And then I simply use document.location to navigate to the view.
<a4j:commandLink action="#{detailviewBean.setDetailID(entity.someid)}" value="#{entity.someid}" oncomplete="document.location='/app/detailview.seam'"/>
If you are using JSF 1.2, you can use f:setPropertyActionListener:
<h:commandLink action="#{reqscope.faces}">
<h:outputText value="link"/>
<f:setPropertyActionListener
value="#{id}"
target="#{lookupBean.id}"/>
</h:commandLink>
Executing Methods From LinkButton Parameters

Resources