I'm new to JSF 2.0 and am trying to output a message to my page. I want to have a form that accepts some input, does some processing, and displays some output. Seems pretty simple right? However, I don't want to define a property in my backing bean to display the output via:
<h:outputText value="#{bean.property}" />
That approach seems very messy to me; I would need a member variable for every status message I want to display. I also don't want to bind the output display to a form variable as in:
<h:inputText id="someId" />
<h:message for="someId" />
because there is no corresponding form variable for my status result. Setting a message and using the global messages:
<h:messages globalOnly="true" />
doesn't work well either because I might need to update multiple elements on the page (not lump all my status messages into the same div).
Coming from Spring MVC, one can set arbitrary properties on the ModelAndView object that is passed to the View, and then access those properties from within the view. Is there a corresponding way of doing this in JSF?
Thank you.
In order to make arbitrary variables easily available to the view, you could define a Map in e.g. request scope by putting the following in faces-config.xml:
<managed-bean>
<description>Request scoped map for general usage</description>
<managed-bean-name>map</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
You can inject this map in your backing bean, or programmatically request it, and then put something in it. E.g.:
#ManagedBean
public class GeneralMapBacking {
#ManagedProperty("#{map}")
private Map<Object, Object> map;
public void onPreRenderView() {
map.put("foo", "bar");
}
public void setMap(Map<Object, Object> map) {
this.map = map;
}
}
You can reference this map via EL on your Facelet, e.g.:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<f:event listener="#{generalMapBacking.onPreRenderView}" type="preRenderView" />
#{map.foo}
</h:body>
</html>
Not sure I understand the question. I am also unfamiliar with Spring MVC and that example passed me by I must say.
However I think it basically sounds like you want to either construct the output serverside or use another component.
For example use a single <h:outputText>and use it with a getter that returns concatenated data.
Or perhaps you should use a <h:dataTable> to display your data?
Or maybe you want to output using some other component. It sounds like you just want a box with text and for that I myself would use the concatenated outputText.
For good looking output you might want to look into primefaces, richfaces or icefaces. I prefer primefaces myself and maybe this would look nice:
http://www.primefaces.org/showcase-labs/ui/dataListUnordered.jsf
Related
Sorry, really really basic question...
I've got a list of 'messageboard threads' that I display on a page. I want to be able to click on one of them and redirect to a page which displays the details for that thread. I'm struggling despite googling it for a while...
(I'm using PrimeFaces by the way)
Here's the relevant code from my 'list' page:
<p:commandLink value="#{thread.title}" action="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</p:commandLink>
(it's in an h:form element)
This is part of my named bean (other methods work fine)
...
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
...
public String showThread() {
System.out.println("id is " + getThreadId());
return "messageboard/list";
}
...
As you can see my method isn't implemented yet, but it's not even being called. Please can someone tell me why?
I tried with an h:link too by the way, same (or similar) problem.
Thanks!
UPDATE - Solved
Thanks to the help below, here is my solution (I've renamed 'messageboard' to 'discussion').
The link is generated using this code
value: what to display on the page, in my case the title of my discussion
outcome: refers to edit.xhtml, the faces file I want to go to
...and the [request] param is going to be called 'threadId' and has a value of the id attribute in my 'thread' object.
In the edit.xhtml page, I've got this
<f:metadata>
<f:viewParam name="threadId" value="#{viewDiscussionBean.threadId}" />
<f:event type="preRenderView" listener="#{viewDiscussionBean.loadDiscussion}" />
</f:metadata>
Note that 'threadId' is the same as the param name in the first page, and it is bound to my viewDiscussionBean's threadId property.
Then once the params are all set on my bean, I call the loadDiscussion method of my viewDiscussionBean. Since it now has the threadId property, it's able to do this (see below)
My viewDiscussionBean has the following managed property (I think the viewParam tag sets this, rather than the other way around).
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
private Discussion thread;
So once that's set, this method is able to run (because it now has an ID)
public String loadDiscussion() {
thread = mbDao.find(threadId);
return "edit";
}
This just uses a DAO (using Hibernate) to look up the discussion thread with that ID, and set it in the bean. And then...
In my edit.xhtml page, I can access values in the discussion thread using things like
<h:outputText value="#{viewDiscussionBean.thread.message}" />
Voila! Thanks.
There are many possible caused for an UICommand action not being invoked. You can find them all here: commandButton/commandLink/ajax action/listener method not invoked or input value not updated Among others a missing form, a nested form, or a conversion/validation error elsewhere in the form, being in a datatable whose datamodel is not properly preserved, etcetera.
As to your particular functional requirement, better is to use a <h:link>. A command link issues a POST request which does in your particular case not end up with a bookmarkable URL with the thread ID in the URL. A <h:link> creates a fullworthy link which is bookmarkable and searchbot-indexable.
E.g.
<h:link value="#{thread.title}" outcome="messageboard/list">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
This doesn't require a form nor an action method. You only need to move that #ManagedProperty to the bean associated with messageboard/list, or maybe replace it by <f:viewParam> in the messageboard/list view which allows for finer-grained validation/conversion.
See also:
Communication in JSF2 - Processing GET request parameters
When should I use h:outputLink instead of h:commandLink?
ViewParam vs #ManagedProperty(value = "#{param.id}")
Your best bet it probably to go with BalusC's answer and use <h:link>. However, I have some thoughts about the behavior you're seeing.
Primefaces <p:commandLink> (like <p:commandButton>) uses ajax by default. Therefore, there won't be any actual navigation resulting from returning an outcome from your action. This could make it look like your action isn't being invoked. Try adding ajax=false to your <p:commandLink>.
When using <h:link>, navigation is resolved when the link is rendered rather than when it's clicked. Modifying your example:
<h:link value="#{thread.title}" outcome="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
showThread() will be called (I think) when the view containing the link is being rendered. If you're not checking at the right time, this may also make it look like the method is being called.
In both cases, this doesn't explain why you wouldn't see the message to System.out at all, but I know I've tried that thinking it was fail-safe and still not seen the output, which all depends on your container, configuration, how you launched it, etc.
This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 6 years ago.
Up until now, I have always been using JSP to display pages. When a user request for a page such as "Add Item", I will load all Item Category in an Array List and display them as options in select box like this:
<select name="category>
<%
ArrayList<Category> categories = (ArrayList<Category>) request.getAttribute("categories");
for (Category c : data) {
%>
<option value="<%= c.getId() %>"><%= c.getName() %></option>
<%
}
%>
</select>
From the book "JavaServer Faces 2.0, The Complete Reference", I learnt that: "JSF enforces clean Model-View-Controller separation by disallowing the inclusion of Java code in markup pages". Hence, I'd be very grateful if someone could show me how I can handle the above task using JSF since I cannot use Java code as I have always done anymore.
Best regards,
James Tran
JSF 2.0 uses Facelets as the templating method, which in a nutshell is XHTML with some additional elements.
While technically you can perform method calls from Facelets, in general the idea is to access a JavaBean with proper geter/setter methods to perform your data moving. You can accomplish this as the below segment of code shows:
<h:selectOneMenu value="#{backingBean.selectedCategory}">
<f:selectItems value="#{backingBean.categoryList}"/>
</h:selectOneMenu>
On the bean side of things, you want to expose a bean to JSF using either faces-config (which is largely discouraged) or a mechanism such as CDI or the Managed Bean infrastructure. I highly recommend you look into using SEAM if you go the CDI route, as it will unify the (currently really strangely disparate) Managed Bean and CDI frameworks, so you can use JSF scopes in CDI, and have CDI beans available in JSF scopes.
#ManagedBean(name="backingBean")
#ViewScoped
public class MyJavaBackingBean {
#ManagedProperty("#{param.categories}")
protected List<String> categoryList
public void setSelectedCategory(String value) {
this.selectedCategory = value;
}
public String getSelectedCategory() {
return this.property;
}
...
}
You can also make the getters do lazy initialization of your values (for pulling categoryList from a database for example), and use some other JSF annotations to do various initialization tasks.
You can also code action methods which return a String representing the JSF action (this gets coded into your faces-context.xml file) to take after returning. Phase listeners on the backing bean can also be called at various stages of page rendering, validation and submission, getting you very fine grained control.
categoryList in the above example is not limited to basic types of course, and <f:selectItems> also has some syntax for writing out the textual version of your select items, so you can make some quite complex expressions to display each item in a friendly way.
Create a bean and make it known with e.g. #Named so you can refer to it from your JSF script. Then give that bean a method returning the data you want to show, and invoke that method from your JSF script in a location where that data is expected e.g. a loop construct.
Store the data you want to display in a Java list, and expose that list as a property of a backing bean. The use the appropriate JSF tag to display that property.
In JSF 2.0 you can include the tag h:selectOneMenu in which you get the value where you store the item value selected. The value in f:selectItems could be a collection of any object the most of times SelectItem in this object your declare value object and the label to display.
<h:selectOneMenu value="#{backingBean.selectedvalue}">
<f:selectItems value="#{backingBean.List}"/> </h:selectOneMenu>
if you required values and labels of another object in you must declare
<h:selectOneMenu value="#{backingBean.selectedvalue}">
<f:selectItems value="#{backingBean.ListCar}" var="car" itemLabel="#{car.model}" itemValue="#{car.modelId}"/>
</h:selectOneMenu>
My codes are bellow,
JSF :
<h:selectBooleanCheckbox id="bundleAdded" value="#{accountAdjustmentBean.bundleAdded}"
required="true" onchange="if(this.checked != bundleAdded) {
alert('Click works')}
else { alert('Not worked!') }"/>
<h:message styleClass="errors" for="bundleAdded"/>
My backing bean :
public class AccountAdjustmentsBean extends BaseBean {
private boolean bundleAdded;
// public setters, getters and other stuffs
}
face-config.xml :
<managed-bean>
<description>
Backing bean used do account adjustments
</description>
<managed-bean-name>accountAdjustmentBean</managed-bean-name>
<managed-bean-class>beyondm.bi.customercare.view.bean.AccountAdjustmentsBean</managed-bean-class>
<!-- NOTE!: proper behaviour of this bean relies on being created for each request -->
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>serviceLocator</property-name>
// propagates.......
When I checked the box, there is no alert. Where is the problem? I can't figure out it. Can anyone point out it?
Thanks!
You're expecting the bundleAdded property to be magically present as a JavaScript variable in the onclick function scope. This is not true. Java/JSF and JavaScript does not run in the same environment. You should see Java/JSF more as a HTML/CSS/JS code generator. Java/JSF runs in webserver, generates HTML/CSS/JS and sends it to webbrowser. HTML/CSS/JS runs in the webbrowser.
You need to let Java/JSF print the bundleAdded property value using EL.
onclick="if(this.checked != #{accountAdjustmentBean.bundleAdded}) ..."
This condition is invalid: if(this.checked != bundleAdded) I think you just need to do:
if(this.checked)
If you are trying to see if the value (bundleAdded) has actually been set then you shouldn't use Javascript to do it as this is only on the client side (unless of course you use Ajax but looking at your example I can't see why you would want to).
I do not know JSF but IMHO it should be
if(this.checked && this.value=='bundleAdded'){alert('Worked');}else{alert('failed');}
I have a facelet component for displaying rss content:
rssFeedReader.xhtml
<h:outputText
binding="#{rssReaderBean.text}"
value="#{url}">
<f:attribute
name="url"
value="#{url}" />
</h:outputText>
<ui:repeat
value="#{rssReaderBean.rss}"
var="rss">
<ice:panelGroup>
<ice:outputLabel
value="#{rss['publishDate']} - "
rendered="#{not empty rss['publishDate']}">
</ice:outputLabel>
<a
href="#{rss['link']}"
target="_blank">#{rss['title']}</a>
</ice:panelGroup>
<ice:panelGroup>
<ice:outputLabel>#{rss['description']}</ice:outputLabel>
</ice:panelGroup>
<hr />
</ui:repeat>
and I include it where I need it like:
<myLib:rssFeedReader url="http://rss.news.yahoo.com/rss/topstories"></myLib:rssFeedReader >
If I include it with different urls, multiple times on my page, I do not understand why it displays multiple times the same FIRST url rss feed insted of taking each url separately.
To be able to read the specified url in my bean I bind it to the h:outputText from my facelet. Code from RssReaderBean bean:
private HtmlOutputText text;
public HtmlOutputText getText() {
return text;
}
public void setText(final HtmlOutputText text) {
this.text = text;
}
and the method which takes the url and returns the list:
public List<Rss> getRss() {
try {
final URL u = new URL((String) text.getAttributes().get("url"));
///read the rss feed and prepare the result, this code works good so its not required here
}
Can you see the problem...?
Thanks.
UPDATE: The bean has Request scope specified in faces-config.xml. If I print out the value of the text url it shows the LATEST url but all the content is taken from FIRST...
so basically for:
<gra:rssFeedReader url="http://blog.test.com/feed/rss/"></gra:rssFeedReader>
<gra:rssFeedReader url="http://rss.news.yahoo.com/rss/topstories"></gra:rssFeedReader>
it prints out the content of blog.test.com but text value when the page is rendered will show empty for first and yahoo url from second one...
The problem is caused because you're binding the <h:outputText> of the tag file to a single bean property. So, everytime you add another <myLib:rssFeedReader> tag, it will override the binding with the last added tag in the view. Finally, when #{rssReaderBean.rss} is been evaluated during rendering the view, it has only the last one at it hands.
There are several ways to solve this. The cleanest way is to create a fullworthy custom UIComponent wherein you specify the URL as an attribtue. The attribute is supposed to be specific to the component, not to a single bean property. An alternative is to use a Map<String, HtmlOutputText> property instead, this is however going to be clumsy.
Or if you're running a Servlet 3.0 / EL 2.2 capable container or replace the standard EL implementation by one which accepts method arguments, such as JBoss EL, then you could pass the URL as argument instead. E.g. #{rssReaderBean.rss(url)}. For installation/configuration detail, see this answer.
I'm getting deeper into JSF 2.0 at the moment and lacking a bit of understanding about the "transport" of managed bean properties from one view to the other. I searched a bit but haven't found a really good example, so if anyone could point me to a tutorial or explain the things a little bit I'd really grateful.
So here is my scenario:
I'm developing a small playground calendar application. The first view select.xhtml contains the calendar selector, where the user can pick a specific date:
<html>
...
<h:form>
<!-- Calendar selector from primefaces -->
<p:calendar value="#{calendarSelect.date}" mode="inline" navigator="true" />
<p:commandButton value="Show entries for date" action="day" />
...
My corresponding backing bean looks like this:
#ManagedBean(name="calendarSelect")
#RequestScoped
public class CalendarSelectComponent {
private Date date = null;
... // Getters and setters
Now when I submit the form from select.xhtml I'm forwarded to day.xhtml
<html>
...
<h:form>
The current day ist:
<h:outputText value="#{calendarEdit.date}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
The backing bean now looks like this:
#ManagedBean(name="calendarEdit")
#ViewScoped
public class CalendarEditComponent implements Serializable {
private Date date = null;
private CalendarEntryBean currentEntry = null;
private List<CalendarEntryBean> allEntries = null;
....
I am now trying to solve the problem: How do I transfer the date parameter from the selector to the editor?
I've tried a number of options, one was this:
<p:commandButton value="Show entries for date" action="day" />
<f:setPropertyActionListener target="#{calendarEdit.date}" value="#{calendarSelect.date}" />
</p:commandButton>
A debugger shows, that indeed, the date property of the calendarEdit is populated with the value from calendarSelect, but since day.xhtml is a new view, a new CalendarEditComponent backing bean is being created and not the one I've populated with the date from the selector in the select view.
I've read that one solution would be to create a SessionScoped backing bean that does retain all it's values. But this is not the way I think it's supposed to work, because I don't really need the information in the session, I simply want it to "travel" from A to B. Another downside with the session based approach is that I can only use one selector and one editor per session - which I think isn't acceptible if you think of multi window browsing and so on.
I really don't think I'm the first one encountering such a scenario and I'm sure that JSF provides an elegant solution for this but I haven't been able to find that solution.
So once again, if anyone knows how to approach this - I'm listening! ;-)
The <f:setPropertyActionListener> is executed during invoke action phase of the form submit. So it expects that the value is still there at that point. But since your select bean is request scoped, it isn't there during form submit anymore. You want instead to pass a request parameter which get inlined in the output during render response. You can do this with <f:param>.
<p:commandButton value="Show entries for date" action="day" />
<f:param name="date" value="#{calendarSelect.dateAsString}" />
</p:commandButton>
It'll be available as request parameter (note that it only understands Strings, due to the nature of HTTP). You could let JSF set request parameters as managed properties, but since your edit bean is view scoped, this isn't possible with #ManagedProperty. You've got to gather it yourself by ExternalContext.
String dateAsString = externalContext.getRequestParameterMap().get("date");
True, that's clumsy. I would just have used the same bean and view for this and toggle visibility of select/edit forms by rendered attribute. The edit view is after all not directly openable/bookmarkable by a simple GET, isn't it? ;)