3
votes

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.

2

2 Answers

3
votes

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:

1
votes

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.