How to access object methods using dataTable in JSF? - jsf

I'm working with LastFM api, let's say I have a class called Artist which I call in this dataTable:
<h:dataTable var="artist" value="#{personEAO.topArtists}" >
<h:column>Artist : #{artist.name} </h:column>
</h:dataTable>
Artit have a field which refers to his picture :
artist.getImageURL(ImageSize.LARGE)
Which works fine, but how do I call this method in my jsf page using dataTable ?

I searched around for Javadocs, but I couldn't find them anywhere. The answer depends on what kind of constant ImageSize.LARGE is.
If ImageSize is an enum, just do:
<h:graphicImage value="#{artist.getImageURL('LARGE')}" />
But if it isn't and is thus a public static constant, then one of the ways is to wrap it in some helper bean which returns exactly that:
<h:graphicImage value="#{artist.getImageURL(someHelperBean.ImageSize_LARGE)}" />
I of course assume that your environment supports EL 2.2.

Related

jsf methods expression valuechanged event don't work or work different in inputtext and selectOneMenu

i'm new with jsf technology and use of managed bean.
I'm reading the Java Platform, Enterprise Edition The Java EE Tutorial release 7 but it seems to be not clear, i have different problem how in example below :
<h:selectOneMenu value="#{user.age}" onchange="submit()" valueChangeListener="#{user.ageChanged}">
<f:selectItems value="#{user.ages}" />
<f:converter converterId="javax.faces.Integer"/>
</h:selectOneMenu>
<h:inputText id="name" value="#{user.name}" required="true" validator="#{user.validateName}" valueChangeListener="#{user.nameChanged}" onchange ="submit()" />
the first one do the job, but the second not it displays:
'managedBean.User' does not have the property nameChanged.
but ageChanged is not a property but the first example do the job
but i'm using method expression to refers method nameChanged that it's present on the bean user,
i'm confusing, too with use or not of the bracket on methods expression:
valueChangeListener="#{user.nameChanged}" or valueChangeListener="#{user.nameChanged()}" what is the properly way to use methods expression?
i say this cause in another example having method with no parameters, the two approaches had different behave, first the same error about property missing, the second Apparently worked.
any help? a speak about method expressions it's appreciated to. thank you.

Setting f:setPropertyActionListener value with a f:param value

I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.

commandLink with ui:repeat in composite component

I am trying to use links in a composite component, my links are in a simple array and do not belong to any managed bean.
<composite:interface>
<composite:attribute name="links" required="true" />
</composite:interface>
<composite:implementation>
<ui:param name="linksSplit" value="#{fn:split(cc.attrs.links, ',')}" />
<ui:repeat var="link" value="#{linksSplit}" >
<h:commandLink value="#{option}" action="#{link}" />
</ui:repeat>
</composite:implementation>
I am getting the following error :
Identity '#{link}' does not reference a MethodExpression instance, returned type: java.lang.String
We are supposed to use String or bean methods in EL expression but I don't understand why we cannot evaluate a parameter which is a String (link in my case).
If I put a real String referenced in my faces-config, it works
<h:commandLink value="#{option}" action="#navigate" />
If you have an explanation or a workaround to get my link working, it would be great
When specifying an EL expression in <h:commandLink action>, it's interpreted as a method expression returning a String (or void if you don't want to navigate). See also the tag documentation:
Name action
Type javax.el.MethodExpression
(signature must match java.lang.Object action())
Description MethodExpression representing the application action to invoke when this component is activated by the user. The expression must evaluate to a public method that takes no parameters, and returns an Object (the toString() of which is called to derive the logical outcome) which is passed to the NavigationHandler for this application.
Given the fact that you seem to want pure page-to-page navigation links, you're actually going in the wrong direction as to using <h:commandLink> for that. You should instead be using <h:link> for that. It generates SEO-friendly and bookmarkable GET links instead of a piece of JavaScript which submits a parent POST form.
<ui:repeat var="link" value="#{linksSplit}" >
<h:link value="#{option}" outcome="#{link}" />
</ui:repeat>
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Note that this all has nothing to do with composite components. You'd have had exactly the same problem when using this in a normal page.

How get row index of <ace:dataTable> in every row?

In searching I found that we can do something with rowStateVar or rowIndex attributes of <ace:datatable>, but how?
I tried using <h:outputText value="#{myDataTableVar.rowIndex}"> but it shows an error message that myDataTableVar has no property rowIndex.
For a component library independent way, just use UIData#getRowIndex() as every component library specific datatable extends from this base component.
In the below example, x: can be anything: standard JSF h:, ICEfaces ice: or ace:, PrimeFaces p:, RichFaces rich:, etc.
<x:dataTable binding="#{table}" ...>
<x:column>#{table.rowIndex}</x:column>
</x:dataTable>
Note: the binding="#{table}" is as-is! You don't need to bind it to some managed bean property.
I found the solution <ace:datatable id='tbl' rowIndexVar="row"> and then just print like that <h:outputtext value="#{row}">Very simple
First, set varStatus:
<ice:dataTable varStatus="status">
An then, inside that dataTable, use:
#{status.index}

JSF. Convert value for h:commandLink display

I am passing Status object to h:commandLink value. So it is displayed on the page. The problem is, displayed string is
packages.entity.Status#db2674c8.
I created converter for Status with annotation
#FacesConverter(forClass = Status.class, value = "statusConverter")
but it doesn't work. I tried to explicitly set it:
<h:commandLink value="#{result.status}" action="/view">
<f:converter converterId="statusConverter" />
</h:commandLink>
Then I got an error: /search-form.xhtml #57,58 <f:converter> Parent not an instance of ValueHolder: javax.faces.component.html.HtmlCommandLink#53e387f3
which is quite true, h:commandLink is not ValueHolder. Is there some way to convert value for h:commandLink?
Interesting, I'd intuitively expect it to work here, but the UICommand does indeed not extend UIOutput (while the UIInput does). It's maybe worth an enhancement request to JSF boys.
You can go around this issue by displaying it using <h:outputText>.
<h:commandLink action="/view">
<h:outputText value="#{result.status}">
<f:converter converterId="statusConverter" />
</h:outputText>
</h:commandLink>
Or just without explicit <f:converter> since you already have a forClass=Status.class
<h:commandLink action="/view">
<h:outputText value="#{result.status}" />
</h:commandLink>
Converters can not be attached to command components (h:commandLink, h:commandButton)
You could create a composite component or use a method in your backing bean for that.
As you pointed out an h:commandLink is not a ValueHolder so it does not support a converter. The value attribute actually dictates the text that is displayed.
Converters are used to convert a value that is an Object into a String for representation in html and then on the flip side to convert that String back into an instance of an object.
In your example I'm guessing that result.status is an object which you'd like to convert to a string? If so you may just need to reference an actual String attribute of the object, like:
<h:commandLink value="#{result.status.statusMessage}" action="/view" />

Resources