I have an h:inputText element and an h:message for it:
<h:form id="cancelForm">
<h:inputText id="days" />
<h:message for="days" />
</h:form>
So when I open the page, JSF renders a "span" element for the error message. This is ok.
When I press submit the application goes to java and validates the fields:
// Some code
if (error) {
FacesContext.getCurrentInstance().addMessage("days", new FacesMessage("Error message"));
return error();
}
But after this JSF does not render the "span" for h:message.
Why?
days is just the simple ID for the inputText component. For the addMessage call you need the full ID (the client ID).
You can obtain the client ID by looking at the rendered HTML source code, or if all parent naming containers on your Facelet have IDs, guess it. It's typically all the parent IDs concatenated with : as a separator.
To always get the 100% correct ID, bind the inputComponent to your backing bean and in the code fragment you show above query it for its ID.
Finally, one word of advice: typically the kind of error checking and adding faces messages is done via a Validator and/or Converter. Doing this in a backing bean should not be your first approach.
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.
My web application has two search pages - search1.jsf and search2.jsf - which share the same bean which in turn calls a result page - result.jsf.
So both search pages have a commandButton
<h:commandButton value="Commit" action="#{search.commit}" />
The "search" bean then processes the search and forwards to the result page using
target = "result?faces-redirect=true";
Now the result.jsf doesn't know which search page has been used. How can I pass the calling page so that the called page is able to render a link back to the calling page?
Using the browser back button (or Javascript code) to go back in the history has the disadvantage that the user, after browsing through the results, only would go back one page in the results instead of going 'up' to the search parameter form.
Options I see so far are:
pass the caller page name through the chain to the result page, using <f:param> or action="#{search.commit(name_of_calling_page)}
put all 'search parameter' forms in one JSF page and conditionally switch the content
Or is there a JSF functions which returns the name of the calling JSF page?
You're redirecting to the result page which suggests that you're using a session scoped bean to hold the results (a request/view scoped simply doesn't survive redirects). Ignoring the fact that this is a poor/odd approach, you could just store the search type in that bean as well?
Anyway, easiest and cleanest is to use a single master view with a single master view scoped bean and conditionally display search1.xhtml, search2.xhtml and results.xhtml using <ui:include> in the master view.
search.xhtml
<ui:fragment rendered="#{empty search.results}">
<ui:include src="/WEB-INF/search#{search.type}.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{not empty search.results}">
<ui:include src="/WEB-INF/results.xhtml" />
</ui:fragment>
As long as you return void or null in action methods, the same view scoped bean will be retained on every subsequent (and non-redirected!) request. If you intend to make it a GET instead of POST (so that it's bookmarkable and back-button-navigable such as Google), then you should actually change the forms and view parameters to make it GET instead of POST.
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? ;)
I'm somewhat confused about the lifecycle of ManagedBeans of type "request".
In this example i'm using one request bean "userBean" to fill this page and one request bean "userEditBean" to fill the following edit page.
<h:form>
<h:panelGrid border="1" columns="2">
<h:outputText value="Name" />
<h:outputText value="#{userBean.user.name}" />
...
</h:panelGrid>
<h:commandButton value="Edit" action="edit" actionListener="#{userEditBean.init}">
<f:attribute name="user" value="#{userBean.user}"/>
</h:commandButton>
</h:form>
When i press the Edit button a userEditBean is created but the attribute map resolves "user" to null.
Does this mean that the attribute EL is resolved after the userBean has already been destroyed? How can i pass values from incoming beans to outgoing beans?
You're setting the attribute value with an expression, not a static value. Whenever you request the value, the expression will be re-evaluated again. The userBean.user apparently isn't present in the subsequent request. You need to ensure that it is there (in other words, the constructor of the userBean should ensure that the user is been created and set.
There are however alternatives. One of the best is to use Tomahawk's <t:saveState> for that. Add it somewhere in the page:
<t:saveState value="#{userBean.user}" />
That said, I agree with Bozho that the whole approach is a bit strange, but that's another story. You may however get lot of useful ideas out either of the following articles: Communication in JSF and/or Using Datatables. Good luck.
request scope means the bean lives during one request. And you fill your edit page (1st request), and send the edited user (2nd request).
In addition to that, <f:attribute> sets tha attributes in the parent component, not in the request. So in your code the attributes will be found in the button.getAttributes() (if you have bound your button).
Furthermore, it is strange to have an actionListener method named init. Since you don't need the event, you can set the action to be the method which will do the editing operation, and make that method return the navigation-rule you want.