I'm wondering which of those two code snippets is more efficient.
First one
In userSearch.xhtml :
<rich:dataTable
var="user"
value="#{userSearchResultList}"
rendered="#{not empty userSearchResultList}">
...
</rich:dataTable>
In UserSearchAction.java :
#Produces #RequestScoped
#Named("userSearchResultList")
public List<User> getResultList() {
return resultList;
}
Second one
In userSearch.xhtml :
<rich:dataTable
var="user"
value="#{userSearchAction.resultList}"
rendered="#{not empty userSearchAction.resultList}">
...
</rich:dataTable>
In UserSearchAction.java :
public List<User> getResultList() {
return resultList;
}
In both solutions, my resultList variable is filled by a method UserSearchAction.search().
I'm using JBoss 7.0.2.Final and RichFaces 4.1.0.Final.
More generally, I wanted to know if it's better to write producers than to call sub-properties of some classes in JSF files.
That depends on how your producer scopes what is being produced. If it's dependent scoped (meaning you don't have a scope on it, nor on the containing class) it ends up being the same, possibly less depending what it is you are having to do inside that method.
In your example it should be more efficient because that producer method should only be called once (per request).
Related
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>
On the Dashboard each User can see some Basic Stats. Lets take for example the "last login" Date. (But there are many more stats / values / settings to display)
The XHTML Files looks simplidfied like this:
<h:outputText value="statisticController.lastLoginDate()" />
The Bean itself uses #Inject to get the Session and therefore the current user:
#Named
#RequestScoped
public StatisticController{
#Inject
private mySessionBean mySession;
#PostConstruct
private void init(){
//load stats for mySession.currentUser;
}
}
Now, i want to generate a List where for example a certain role can view the values for ALL users. Therefore i can't use the Session Inject anymore, because the StatisticController now needs to be generated for multiple Users.
Having regular Classes this would not be a big problem - add the userEntity to the constructor. What is the "best practice" to solve this in JSF?
If i modify the StatisticController to something like this:
#Named
#RequestScoped
public StatisticController{
public void init(User user){
//load stats for user;
}
}
i would need to call init(user) manually of course. How can this be achieved from within a Iteration in the XHTML file?
I could refactor it so the valueLoading happens in the actual getter method, and iterate like this:
<ui:repeat var="user" value="#{userDataService.getAllUsers()}">
<h:outputText value="statisticController.lastLoginDate(user)" />
...
</ui:repeat>
But then i would need to load "every" value seperate, which is bad.
So a way like this would be "better":
<ui:repeat var="user" value="#{userDataService.getAllUsers()}">
statisticController.init(user);
<h:outputText value="statisticController.lastLoginDate()" />
...
</ui:repeat>
However this doesnt look very comfortable either. Further more doing things like this, will move nearly "all" Backend Stuff into the Render Response Phase, which is feeling wrong.
Any Ideas / Tipps how to solve this in a way that's not feeling "like a workaround"?
Create a new model wrapping those models.
public class UserStatistics {
private User user;
private Statistics statistics;
// ...
}
So that you can just use e.g.
public class UserStatisticsBacking {
private List<UserStatistics> list;
#EJB
private UserService userService;
#EJB
private StatisticsService statisticsService;
#PostConstruct
public void init() {
list = new ArrayList<UserStatistics>();
for (User user : userService.list()) {
list.add(new UserStatistics(user, statisticsService.get(user)));
}
}
// ...
}
(better would be to perform it in a new UserStatisticsService though)
with
<ui:repeat value="#{userStatisticsBacking.list}" var="userStatistics">
<h:outputText value="#{userStatistics.user.name}" />
<h:outputText value="#{userStatistics.statistics.lastLoginDate}" />
...
</ui:repeat>
An alternative to using a wrapped model proposed by BalusC is to store two separate lists with model data. With this approach you don't need to introduce modifications.
Following this route you'll be iterating over one list with <ui:repeat> and, ensuring equality of sizes of both lists, get second list element by index, which in turn is available via varStatus attribute that exports the iteration status variable.
<ui:param name="stats" value="#{bean.stats}/>
<ui:repeat value="#{bean.users}" var="user" varStatus="status">
<h:outputText value="#{user}/>
<h:outputText value="#{stats[status.index]}/>
</ui:include>
Population of lists may be done beforehand in PostConstruct method:
private List<User> users;
private List<Statistic> stats;
#PostConstruct
public void init() {
users = userService.list();
stats = statService.list();
}
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.
Hi Have this Wierd Issue in which I am using a Composite Component which I wrote and I get values from the previous use of the backing bean of the CC (the componentType bean)
I don't know how to describe this better than just show the code.
I'll try to be brief about it and cut the redundant parts:
This is the Composite Component definition:
<cc:interface componentType="dynamicFieldGroupList">
<cc:attribute name="coupletClass" />
<cc:attribute name="form" default="#form"/>
<cc:attribute name="list" type="java.util.List" required="true"/>
<cc:attribute name="fieldNames" type="java.util.List" required="true" />
</cc:interface>
<cc:implementation>
<h:dataTable value="#{cc.model}" var="currLine">
<h:column>
<h:outputText id="inner_control_component" value="Inner Look at currLine:#{currLine}"/>
</h:column>
</h:dataTable>
</cc:implementation>
The CC bean defintion:
#FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
#SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements
NamingContainer
{
private transient DataModel model;
#Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
{
model = new ListDataModel(getList());
}
return model;
}
private List<Map<String, String>> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
}
And the use code:
<ui:repeat var="group" value="#{currentContact.detailGroups}">
<h:panelGroup rendered="#{not empty group.values}">
<h:outputText id="controlMsg" value=" list:#{group.values}" /><br/><br/>
<utils:fieldTypeGroupList list="#{group.values}"
fieldNames="#{group.fields}" coupletClass="utils" />
</h:panelGroup>
</ui:repeat>
The text of id controlMsg displays the correct values in #{group.values} while the control output inside the component of id inner_control_component shows the values from the previous use.
The values are correct the first time...
I guess it's a fundemental error in use of a CC bean, otherwise it could be a bug with MyFaces 2.1 (Which I'm using)
The explanation for this behaviour is simple: there's only one component definied in the view. So there's also only one backing component with one model. Since the model is lazily loaded on first get, the same model is been reused in every iteration of a parent iterating component.
The <ui:repeat> doesn't run during view build time (as JSTL does), but during view render time. So there are physically not as many components in the view as items which are iterated by <ui:repeat>. If you were using <c:forEach> (or any other iteration tag which runs during view build time), then the composite component would have behaved as you'd expect.
You would like to change the way how the datamodel is kept in the backing component. You would like to preserve a separate datamodel for each iteration of a parent iterating component. One of the ways is to replace the model property as follows:
private Map<String, DataModel> models = new HashMap<String, DataModel>();
public DataModel getModel() {
DataModel model = models.get(getClientId());
if (model == null) {
model = models.put(getClientId(), new ListDataModel(getList()));
}
return model;
}
See also:
What's the view build time?
The problem described here is an old known isse in JSF, hidden by the usage of composite components. It is so important and so difficult, that instead answer here I create a detailed answer in a blog entry for this one: JSF component state per row for datatables
To keep this answer short, I'll say to you it is not a bug in MyFaces 2.1. Please use 2.1.1, because that is a quick bug fix version of 2.1.0. In JSF 2.1 there is a new property for h:dataTable called rowStatePreserved, and this scenario is just one case where "this little baby" becomes useful. Just replace ui:repeat with h:dataTable and add rowStatePreserved="true". That will do the trick. If you need to manipulate the model (add or remove rows) you can use tomahawk t:dataTable and t:dataList, but you will have to take an snapshot version for now. Note this is new stuff not available in any different JSF framework an the moment (JUN 2011).
If you need more info, keep tuned with MyFaces Team on Twitter or ask to the experts on MyFaces Users and Dev Mailing Lists.
I have a problem to bind list of h:selectBooleanCheckbox to my bean.
Anybody helps ?
This is not working:
<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</ui:repeat>
public class CartBean extends BaseBean {
public List<Product> getProductsList() {...}
private HtmlSelectBooleanCheckbox[] checkboxes;
public HtmlSelectBooleanCheckbox[] getCheckboxes() {
return checkboxes;
}
public void setCheckboxes(HtmlSelectBooleanCheckbox[] checkboxes) {
this.checkboxes = checkboxes;
}
}
I get error:
javax.faces.FacesException: javax.el.PropertyNotFoundException: /WEB-INF/flows/main/cart.xhtml #26,97 binding="#{cartBean.checkboxes[i.index]}": Target Unreachable, 'checkboxes' returned null
I solved my problem. I used code like below and get what i want (thanks to BalusC blog - http://balusc.blogspot.com/2006/06/using-datatables.html#SelectMultipleRows):
<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>
public class CartBean extends BaseBean {
private Map<Integer, Boolean> selectedIds = new HashMap<Integer, Boolean>();
public Map<Integer, Boolean> getSelectedIds() {
return selectedIds;
}
}
Your concrete problem is caused because the binding attribute is evaluated during view build time, that moment when the XHTML source code is turned into a JSF UI component tree, while the <ui:repeat> runs during view render time, that moment when the JSF UI component tree needs to produce HTML.
In other words, the #{i.index} is only available during view render time and evaluates as null during view build time. In effects, you're doing a binding="#{cartBean.checkboxes[null]}"
There's another conceptual mistake here: you seem to expect that the <ui:repeat> produces physically multiple <h:selectBooleanCheckbox> components. This is untrue. There's physically only one <h:selectBooleanCheckbox> which is reused multiple times to produce HTML based on the currently iterated variable. Actually, binding="#{cartBean.checkbox}" was been sufficient. However, collecting the values is a story apart. I won't go in detail, but you can find several hints in this answer: Validate order of items inside ui:repeat.
In order to achieve the (apparent) concrete functional requirement of generating physically multiple <h:selectBooleanCheckbox> components and binding each to a separate array item, you should be using an iteration component which runs during view build time instead of view render time. That's the JSTL <c:forEach>:
<c:forEach items="#{cartBean.productsList}" var="cartProduct" varStatus="i">
<h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</c:forEach>
But, after all, using binding on a bean property should be avoided as much as possible. Use instead exactly that attribute which you ultimately need: the value attribute. This way you don't need to do a HtmlSelectBooleanCheckbox#getValue() everytime. You already figured the right solution with a Map<Integer, Boolean> selectedIds:
<ui:repeat value="#{cartBean.productsList}" var="cartProduct">
<h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>
See also:
JSTL in JSF2 Facelets... makes sense?
I don't know if you can bind elements stored in an array. But in your code, the problem is that your HtmlSelectBooleanCheckbox[] is null. So maybe change your Java code to:
public HtmlSelectBooleanCheckbox[] getCheckboxes() {
if (checkboxes == null) {
checkboxes = new HtmlSelectBooleanCheckbox[getProductsList().size()];
}
return checkboxes;
}
but I am really not sure if it will work... Maybe the solution is to not bind your HtmlSelectBooleanCheckbox elements in the Java code. Why do you need to bind them?