-
1. Re: How to invoke a method in a facelet tag
gjeudy Apr 8, 2008 7:29 PM (in response to haefti)I'm not sure what else you may be doing in your code, I encourage you to get facelets source and run in debug mode to see what is going on exactly.
From what I can guess from the partial stacktrace you provided it could be that facelets/JSF is looking to resolve a property (value expression) instead of a method expression. Therefore it might be looking at getEditPicture property instead of the method you are expecting.
I have tried the method you explained using this:
Facelets fits JSF like a glove
and it worked fine for me. Alternatively you can look into inserting your button with an anonymous insert (see end of article to know how). This approach lets you insert virtually any facelet fragment inside your custom component at the defined position. (I usually prefer this method over the
backingBean[action]
approach).
-
2. Re: How to invoke a method in a facelet tag
haefti Apr 9, 2008 1:09 AM (in response to haefti)First of all thanks for the answer.
From what I can guess from the partial stacktrace you provided it could be that facelets/JSF is looking to resolve a property (value expression) instead of a method expression. Therefore it might be looking at getEditPicture property instead of the method you are expecting.That's exactly what I mean. Seam does not call the method editPicture() but looks for a getter.
I have tried the method you explained using this:
Facelets fits JSF like a gloveI know the link but if I look here it seems to me that there is nothing different from my code.
Alternatively you can look into inserting your button with an anonymous insert (see end of article to know how). This approach lets you insert virtually any facelet fragment inside your custom component at the defined position. (I usually prefer this method over thebackingBean[action]
approach).That's where it gets interesting for me. ;)
What do you mean by anonymous insert? Is it explained in the IBM article or in the facelets documentation? Is there a code example too?Sorry for my stupid questions but I don't how to get the stuff running with own tags and don't know what you mean by the anonymous insert either.
Thanks for the help!
-
3. Re: How to invoke a method in a facelet tag
haefti Apr 9, 2008 1:03 PM (in response to haefti)Hi!
Just to let you know how I
fixed
it.The problem occured due to working (!) code which was commented out (!!!).
To make it clear here the not working code:
<cs:listButtons assetManager="#{pictureManager}" editAction="editPicture" /> <!-- <h:commandButton type="submit" action="#{pictureManager.editPicture}" value="Edit" /> -->
Working code:
<cs:listButtons assetManager="#{pictureManager}" editAction="editPicture" /> <h:commandButton type="submit" action="#{pictureManager.editPicture}" value="Edit" />
Normally I would say this is something for a JIRA task but I don't know exactly if such kind of behaviour may be intended.
Actually I can't see any reason why code which is commented out has to be parsed at all but interpreting working code as buggy can't be the solution.Maybe someone can tell me if this is really a bug and if it is a problem of Seam or facelets in general.
Thanks!
-
4. Re: How to invoke a method in a facelet tag
przemjaskier Apr 9, 2008 1:57 PM (in response to haefti)Yeah, invocation of commented out components surprised me one day too.
Solution is to add
<context-param> <param-name>facelets.SKIP_COMMENTS</param-name> <param-value>true</param-value> </context-param>
to web.xml. It will skip any
<!-- -->
content. -
5. Re: How to invoke a method in a facelet tag
haefti Apr 9, 2008 3:05 PM (in response to haefti)
Solution is to add<context-param> <param-name>facelets.SKIP_COMMENTS</param-name> <param-value>true</param-value> </context-param>
to web.xml. It will skip any<!-- -->
content.Thanks!
Interestingly the documentation says that the default value should be true which is not the case in my Seam project.
-
6. Re: How to invoke a method in a facelet tag
gjeudy Apr 9, 2008 4:13 PM (in response to haefti)Yes the anonymous insert approach is explained in the last part of the IBM article. It can be useful when you re-use a custom component but you don't know what actions will be on the button and moreover what type of button it could be or even how many buttons you wish to place inside your custom component.
-
7. Re: How to invoke a method in a facelet tag
parkylin May 13, 2008 11:53 AM (in response to haefti)Hi everybody,
I used the solution
Facelets fits JSF like a glove
.
It works fine for me, but i have one question.
I notice that with that solution the outcome works fine if and only if I put thebackingBean[action]
parameter in my navigation rule.
Have you another solution? If I let the 'normal' navigation rule, my outcome success is never found...
Thanks
-
8. Re: How to invoke a method in a facelet tag
koelec Aug 29, 2009 4:34 PM (in response to haefti)
parkylin parkylin wrote on May 13, 2008 11:53:
Hi everybody,
I used the solutionFacelets fits JSF like a glove
.
It works fine for me, but i have one question.
I notice that with that solution the outcome works fine if and only if I put thebackingBean[action]
parameter in my navigation rule.
Have you another solution? If I let the 'normal' navigation rule, my outcome success is never found...
ThanksI faced the same problem. It seams Seam uses the template action param value defined in the tag lib component to match against navigation from-action param. To circumvent the problem I came up with the following solution to share with you. Also see Max Katz blog about creating a reuseable confirmation dialog :
http://www.nofluffjuststuff.com/blog/max_katz/2008/11/richfaces_confirmation_dialog_3<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="http://richfaces.org/a4j" xmlns:hvkl="http://prorail.nl/hvkl" xmlns:rich="http://richfaces.org/rich" template="layout/template.xhtml"> <ui:define name="body"> <h:form> <a4j:jsFunction name="ok" action="#{userBean.save}" /> <a4j:jsFunction name="cancel" action="#{userBean.cancel}" /> <hvkl:confirm confirmId="confirm1" label="Saved" OKButtonValue="OK" cancelButtonValue="Annuleer" okFunction="ok()" cancelFunction="cancel()"/> <hvkl:confirm confirmId="confirm2" label="Saved2" OKButtonValue="OK" cancelButtonValue="Annuleer" okFunction="ok()" cancelFunction=""/> </h:form> </ui:define> </ui:composition>
The trick is to pass the name of the javascript functions to invoke when the OK or Cancel button is clicked. These functions are defined in the calling code and can be separate or shared between multiple confirmation dialogs. Now we can setup different navigation rules on the actions defined in the calling code.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:component xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" xmlns:f="http://java.sun.com/jsf/core" xmlns:hvkl="http://prorail.nl/hvkl" xmlns:ui="http://java.sun.com/jsf/facelets"> <a4j:commandButton value="#{label}" onclick="#{rich:component(hvkl:concat(confirmId,'confirmation'))}.show();return false" /> <rich:modalPanel id="#{confirmId}confirmation" width="250" height="150"> <f:facet name="header">Confirmation</f:facet> <h:panelGrid> <h:panelGrid columns="2"> <h:graphicImage value="/alert.png" /> <h:outputText value="Are you sure?" style="FONT-SIZE: large;" /> </h:panelGrid> <h:panelGroup> <rich:spacer height="20px" /> <input type="button" value="#{OKButtonValue}" onclick="#{rich:component(hvkl:concat(confirmId,'confirmation'))}.hide(); #{okFunction};return false;" /> <input type="button" value="#{cancelButtonValue}" onclick="#{rich:component(hvkl:concat(confirmId,'confirmation'))}.hide();#{cancelFunction};return false;" /> </h:panelGroup> </h:panelGrid> </rich:modalPanel> </ui:component>
The tag component definition uses the String concat function defined in a custom taglib as described in the post at the head of this thread.
-
9. Re: How to invoke a method in a facelet tag
detailleo Feb 10, 2010 8:41 PM (in response to haefti)Hi!
I try to build a composite component, defining a facelet tag. Basically, the component have to show a button, with some text and an image :
In my taglib file, I declare the so called myButton component :
<tag> <tag-name>myButton</tag-name> <source>myButton.xhtml</source> </tag>
and write it's definition into the myButton.xhtml file :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jstl/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" xmlns:s="http://jboss.com/products/seam/taglib"> <!-- parameters --> <!-- componentName : a seam component name --> <!-- methodName : method name I want to invoke --> <ui:composition> <span id="myButton_#{componentName}"> <h:graphicImage value="/img/#{methodName}.png" styleClass="textmiddle" /> <h:commandLink value="#{bundle[methodName]}" action="${componentName[methodName]}" /> </span> </ui:composition> </html>
I would like that the h:commandLink bellow
<h:commandLink value="#{bundle[methodName]}" action="#{componentName[methodName]}" />
invokes the methodName method (first parameter of my facelet tag) of a Seam component called componentName (second parameter of my facelet tag).
Here is the way I use my tag, in my
client
page (mapped into the fuji namespace) :<fuji:myButton componentName="portFolioManager" methodName="save" />
This is intended to invoke the save method of the portFolioManager Seam component
The application starts correctly, the page loads successfuly but, when I click to the link, the following exception is thrown :
javax.el.MethodNotFoundException: /WEB-INF/facelets/tags/myButton.xhtml @27,47 action="${componentName[methodName]}": Method not found: portFolioManager.save() com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:72) javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) javax.faces.component.UICommand.broadcast(UICommand.java:387) org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:324) org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:299) org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:256) org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:469) com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82) com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) javax.faces.webapp.FacesServlet.service(FacesServlet.java:265) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178) org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290) org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388) org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515) org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
The save method obviously exists in the portFolioManager Java interface, but is seem's that it can't be found.
Here are the first lines of the Java class that implement the Seam component :
@Local(IAbstractManager.class) @Stateful @Scope(SESSION) @Name(value = "portFolioManager") public class PortfolioManager extends AbstractManager<Portfolio> { ...
You can see the @Name(value = "portFolioManager") annotation that define the Seam component name (the one that is passed in the componentName facelet parameter)
The save method is actually implemented in the super class AbstractManager, that implements a Java interface AbstractManager (in which save is declared).
I know that the EL expression
backingBean[method]
works and allow to pass action with plain JSF backing bean. But why doesn't it work with a Seam component ?
Am I missing something ?
Please help. I'm trying hard to solve this problem for hours now, reading documentation, browsing forums and source codes etc...
Being unable to do such a thing breaks the DRY principle in my pages, one thing that would make me completely crazy.
Octave