Failing to populate Select element using RequestScoped bean? [duplicate] - jsf

This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
(2 answers)
Closed 5 years ago.
I've been struggling with a task that seemed to be very simple, but somehow I can't see a way to solve it without using some pretty hacky code - which I really want to avoid.
The problem itself has been reduced to a very simple task: I have a project with a single page containing a form, where I have to type a non-empty username and use a select element (h:selectOneMenu) to choose one "user group" for this user. This is submitted to a RequestScoped bean that I have (this is also the only bean I have in the project). Only validation rule (to simplify my explanation) is: the "username" field cannot be empty.
Here's my page's code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:head></h:head>
<h:body>
<f:metadata>
<f:event listener="#{userManagementBean.initializeGroupsList()}" type="preRenderView" />
</f:metadata>
<h:form>
<h:inputText id="fieldUsername" value="#{userManagementBean.user.username}" p:placeholder="Username" required="true" />
<h:message for="fieldUsername"/>
<h:selectOneMenu id="fieldGroup" value="#{userManagementBean.usergroup_id}">
<f:selectItem itemValue="#{null}" itemLabel="Please, select a group" />
<f:selectItems value="#{userManagementBean.groupsList}" var="curGroup" itemLabel="#{curGroup.groupName}" itemValue="#{curGroup.id}" />
</h:selectOneMenu>
<h:message for="fieldGroup"/>
<h:commandButton action="#{userManagementBean.submitValues()}" value="Submit data" />
</h:form>
</h:body>
</html>
And here's the bean's code, which initializes a list containing the elements of the select box:
import java.io.Serializable;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
....
#RequestScoped
#Named
public class UserManagementBean implements Serializable {
// PRIVATE FIELDS
private User user = new User();
private List<UserGroup> groupsList;
private Integer usergroup_id;
// BEAN'S PUBLIC METHODS
public void initializeGroupsList() {
groupsList = loadAllGroupsFromDatabase();
System.out.print(String.format("%d groups have been loaded\n", groupsList.size()));
}
// Getters, setters and database-loading code has been ommited
...
}
Question is: when/how should I initialize the list of user groups, which is used to populate the select element on the page?
First I tried to use an <f:event> element which calls initializeGroupsList() on the "preRenderView" event (as in the code I've wrote above). Everything is populated fine, but if I select a user group and do not type any username, the select element returns an error message after the form is submitted ("Validation Error: Value is not valid"), while it should not give me any validation errors, as the user has selected a valid user group.
Secondly, I have tried replacing the <f:event> by a <f:viewAction> which calls initializeGroupsList(). When I open the page for the first time, everything works fine. But when I submit the form without a username, the page is reloaded, showing me the validation error, and the select element is not populated with any user groups at all (the initializeGroupsList() isn't called at all when there are validation errors in this case).
Currently I'm solving this issue by removing both the <f:event> and <f:viewAction> elements, and annotationg initializeGroupsList() with #PostConstruct. Problem is: if I do so, I won't be abble to access any of the URL's query string parameters through the use of <f:viewParam> inside the initializeGroupsList(), which is something I want to be able to do in this page in a near future.
How should I call initializeGroupsList() then, to avoid these errors described in both the first and second cases, while allowing me to access URL's query string parameters inside initializeGroupsList()?
Thanks in advance.

Keep using #PostConstruct to initialize initializeGroupsList().
About the view params you could use #Param ( http://showcase.omnifaces.org/cdi/Param ) from ominifaces, which will inject them for you without the need to use view action or view event.

Related

Render XHTML Content with parameter carried by URL [duplicate]

I am trying to pass parameter between two pages.my User.xhtml page has ui:repeat which displays user.I have access to the user Id as well. I want to click on the user and go to their details page. I have userDetails.xhtml which is blank at the moment.
I have a Bean as well.
Currently I am using h:link to navigate one page to another. And it works.
My mission is : Click on the user and get their details.
Please help, I am pretty new in JSF
Thanks
You can try using <f:param>:
<ui:repeat value="#{userBean.users}" var="u">
...
<h:link outcome="userDetails" value="Details">
<f:param name="userID" value="#{u.id}" />
</h:link>
...
</ui:repeat>
then you can get the id like this:
#ManagedBean
#RequestScoped
public class UserDetailsBean {
#ManagedProperty(value = "#{param.userID}")
private String userID;
// Getters and Setters
}

h:link with includeViewParams=true does not always include viewparams

For some reason,the does not always append the view parameters to the produced link. I can't figure out why. If I change the outcome to another similar link,then it is processed correctly.
Can anyone point me to some requirement that could not be fulfilled? I didn't find anything relevant in the docs.
I am trying to set up 4 views backed by a single bean. Those views all contains the same view parameters, but only one of them process them. All view use the same template.
So i have in all views
<f:metadata>
<f:viewParam name="param1"
value="#{bean.param1}"/>
<f:viewParam name="param2"
value="#{bean.param2}"/>
</f:metadata>
<ui:composition template="/onpage/template.xhtml">
// ...
And in one of them, i included a <f:viewAction>
In the template I have some links
<h:link outcome="#{bean.outcome1}"
value="Go to view1"/>
<h:link outcome="#{bean.outcome2}"
value="Go to view2"/>
and in the bean:
private String param1; // And get/setters
private String param2; // and get/setters
public String getOutcome1() {
return "/my/path.jsf?some=param&includeViewParams=true";
}
public String getOutcome2() {
return "/my/path2.jsf?some=param2&includeViewParams=true";
}
With this setup, some of the links point to "/my/path.jsf?param1=value1&param2=value2" as expected, while others point to "/my/path2.jsf?some=param2" for no apparent reason, and without any information in the log.
All this running on glassfish 4/JSF 2.2/primefaces 4.
THanks
Answer part of the OP comments:
What happened is that I mixed XML namespace domains. The pages using xmlns:f="java.sun.com/jsf/core were working correctly, while those using xmlns:f="xmlns.jcp.org/jsf/core were not. See The metadata component needs to be nested within a f:metadata tag. Suggestion: enclose the necessary components within <f:metadata> for more details.
Note: JSF 2.2 schemas use the xmlns:f="xmlns.jcp.org/jsf/core namespace.

lose view page parameter

i have page my.xhtml:
<f:metadata>
<f:viewParam name="id"/>
</f:metadata>
...
<h:form>
Current id is: "#{id}"
<h:commandButton action="#{bean.doSomething}" value="Do some logic..">
<f:param name="id" value="#{id}"/>
</h:commandButton>
</h:form>
and Bean.java:
#ManagedBean
#ViewScoped
public class Bean {
....
public void doSomething(){
//do some logick, don't use id parameter
}
}
When I get to page first time with id=10 I can see on page Current id is: "10"..
When I click on button page is reload and I can see on page Current id is: "10". again.
But when I click on button third time I can see on page Current id is: ""., i lose id parameter and I don't understand why?
I know I can do this with save parameter value in bean
(by add to f:viewParam:
<f:metadata>
<f:viewParam name="id" value="#{bean.value}/>
</f:metadata>
), but can I do this without save parameter value in bean?
h:button works with f:param but h:commandButton does not. In this case, your best is to bind the view parameter to a bean property as you explain the last. The #ViewScoped bean will retain its state as long as you call void action methods.
You could also pass it as a parameter to the action method (there are several ways to do that), but this doesn't make sense for a method which has nothing to do with that value.
See also:
Passing parameters to action methods in JSF
Communication in JSF

f:param does not work with p:commandLink or h:commandLink on query string

f:param works great with h:link, but not with p:commandLink or h:commandLink.
For example, I have two pages test_first.xhtml and test_second.xhtml, and a backing java bean TestBean.java.
I start running test_first.xhtml.
If I click link1, which is a h:link, the page will redirect to test_second.xhtml. With the help of f:param, the address bar of the browser will show .../test_second.xhtml?id=1. On that page, testBean.userId gets printed.
If I click link2 or link3, the page redirects to test_second.xhtml. However, the address bar only shows .../test_second.xhtml, there is NO ?id=#! And testBean.userId does not get printed on that page.
How can I make commandLink work with f:param? Sometimes I want the link not to redirect to another page but to call some methods of bean depending on the data.
test_first.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form>
<h:link value="link1" outcome="test_second" >
<f:param name="id" value="1"/>
</h:link>
<br/><br/>
<h:commandLink value="link2" action="test_second?faces-redirect=true" >
<f:param name="id" value="2" />
</h:commandLink>
<br/><br/>
<p:commandLink value="link3" action="test_second?faces-redirect=true">
<f:param name="id" value="3" />
</p:commandLink>
<br/><br/>
</h:form>
</h:body>
</html>
test_second.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:viewParam name="id" value="#{testBean.userId}" />
</f:metadata>
<h:head/>
<h:body>
<h:form>
This is the second page.
<h:outputText value="Selected id is #{testBean.userId}" />
<h:commandButton value="Print page id" action="#{testBean.print()}" />
</h:form>
</h:body>
</html>
TestBean.java
#ManagedBean
#SessionScoped
public class TestBean implements Serializable{
private Integer userId;
public void print() {
System.out.println(userId);
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
You misinterpreted the meaning of those two tags, namely <h:link> and <h:commandLink>, therefore, you also misinterpreted the meaning of <f:param> attached to either of the two. In anycase it is worthwhile to always read the documentation before asking the questions to get more insight.
<h:link> renders an HTML "a" anchor element. The value of the component is rendered as the anchor text and the outcome of the component is used to determine the target URL rendered in the "href" attribute. Any child UIParameter components are appended to the String to be output as the value of the "href" attribute as query parameters before rendering...
<h:commandLink> render an HTML "a" anchor element that acts like a form submit button* when clicked ... if the disabled attribute is not present, or its value is false. It renders "#" as the value of the "href" attribute, renders the current value of the component as the link text if it is specified and *renders JavaScript that is functionally equivalent to the following as the value of the "onclick" attribute:
document.forms['CLIENT_ID']['hiddenFieldName'].value='CLIENT_ID';
document.forms['CLIENT_ID']['PARAM1_NAME'].value='PARAM1_VALUE';
document.forms['CLIENT_ID']['PARAM2_NAME'].value='PARAM2_VALUE'; return false;
document.forms['CLIENT_ID'].submit()"
where hiddenFieldName is as described above, CLIENT_ID is the clientId of the UICommand component, PARAM_NAME and PARAM_VALUE are the names and values, respectively, of any nested UIParameter children.
In other words, within <h:link> tag nested <f:param> will end up as a query parameter of the generated URL, while within <h:commandLink> tag nested <f:param> will end up as a request parameter with a given value.
While the first one is clear, the second one deserves a better elaboration. To understand what it does, consider that if we abstract away from the details <h:commandLink> sends a POST request and attaches all nested <f:param> tags as request parameters. But it is up to you how you will handle them, as navigation is entirely in your hands.
So, the first option is to set a hardcoded action attribute, which use case is dubious, like in action="second-page", in which way you didn't pass any query parameter at all. What will be done is POSTing to the same view and forwarding to the second without undertaking any action. Quite a dumb action.
The second option is to specify an action method, like in action="#{bean.action}". In this case you must handle navigation in the provided action method, i.e. return null/void from the method for a postback, or return a navigation case outcome as a string to make a forward to the specified view. As for the request parameters that you passed with <f:param> they will be available with standard JSF means like #ManagedProperty("#{param.name}") on a request-scoped bean, or by calling ExternalContext#getRequestParameterMap() in any-scoped bean, for example, in action method, like in String param = externalContext.getRequestParameterMap().get("name"). So now you have your parameter in action method that you're free to use how you like, just adhere to a set of rules that exist for URLs.
Two things left worth mentioning. Remember that request parameters passed with calling the command link will be available only within that same request, as you might expect it to survive a faces-redirect=true that basically fires another request. The other option is to specify includeviewparams=true to pass through the paramaters of the current view, if that's desired, as mentioned in the other answer.
You could do it by concatenating the parameters with & directly at the action attribute:
<p:commandLink value="link3" action="test_second?faces-redirect=true&id=3"/>
Update 1
You might also consider to add &includeViewParams=true. This way view parameters of your target navigation will be included automatically.

use multiple form instances jsf 2.0

my jsf appication is designed so that by clicking on a menuitem the corresponding page is displayed in a newly created tab. the pages displayed on tabs have their own form element & backing bean.
normally this works pretty well, but could not find a way how to solve the situation when multiple instances of the same form is used concurrently, eg. more 'add new employee' tabs are opened at the same time.
i try to use a #SessionScoped managed bean with a Map containing instances of the form data (currently only one string for simplicity) like this:
#ManagedBean(name="employeeBean")
#SessionScoped
public class EmployeeBean extends BaseManagedBean implements Serializable{
private Map<String, String> fields = new HashMap<String, String>();
private String formId;
public void newForm(){
this.formId=RandomStringUtils.randomAlphabetic(10);
logger.debug("newForm: formId: " + formId);
this.fields.put(formId, new String());
}
//... etc
}
when i click on a menuitem, a new random formId is generated and new form data holder is added to the fields map.
the jsf page is this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.prime.com.tr/ui">
<div class="dataContainer clearfix">
<h:form id = "#{employeeBean.formId}">
<h:inputText id="empField1" value="#{employeeBean.fields[employeeBean.formId]}" />
<p:commandLink action="#{employeeBean.action}" value="Action" id="actionLink">
</p:commandLink>
</h:form>
</div>
</html>
the last opened tab instance works perfectly but the old ones do not. if the commandLink is pressed on older tabs the right form is submitted and the getFormId method is called once in the restore view phase, but nothing else is called in my EmployeeBean.
if i use fixed formId not the random #{employeebean.formId} then always the first opened tab's data is submitted. (multiple forms with same id on the page).
i suppose something is wrong with my component tree.
i am using Primefaces's TabView component (based on jquery) and i add new tabs to the tab component in a jquery javascript function.
Can anyone tell me what i am doing wrong? or suggest a better way to solve problem? what is the right approach to handle situtations like this?
thanks a lot in advance
Do you need here a session scoped bean? E.g. do you want to reach bean-content from other pages? If not, than maybe you could simply make your EmployeeBean request scoped. Than you don't need a map inside your employeeBean, and you valuebindings could also be more simple...

Resources