1 2 3 Previous Next 31 Replies Latest reply on Aug 9, 2007 4:44 AM by zerg-spirit Go to original post
      • 15. Re: Evaluation of action attibute in s:link
        wise_guybg

        Thank you for the reply Gavin. I'm sorry that I have reopened the issue so many times but no one from the community understood what I have written at first place and no one commented.

        This is the first time that someone actually wrote to respond to my question. I wouldn't really open it as a feature request at first place but this was the only way to get an answer. You can draw your conclusions from that fact.

        I don't have your understanding of the inner-workings and this is why I'm asking for help. Sure I can drill into it but I thought someone in the community can give me a hint if I'm doing something wrong.

        Nether you, neither anyone else has done so for now. In JIRA you have noted:

        This cannot be implemented, and I'm really bored with this discussion. You have a workaround now, so please stop reopening this issue. Thanks.


        The workaround is easy. I knew about it at the time I saw the problem. I had to use it because there was no one to help. Anyways, how can you have a workaround of a feature request :D This is ridiculous.

        Finally to the question:
        <s:link value="#{localeProvider.getDisplayString(sel.value)}"
         action="#{localeSelector.selectLanguage(sel.value)}"
         rendered="#{not localeSelector.locale.toString().equals(sel.value)}"/>
        


        Otherwise how on earth can the EL expression (which is evaluated during the invoke phase of the second request) possibly know about the JSF page variable (which is only defined during the render phase of the first request)??


        Well:

        #{sel.label} -> can be evaluated
        #{localeProvider.getDisplayString(sel.value)} -> can be evaluated
        #{not localeSelector.locale.toString().equals(sel.value)} -> can be evaluated

        My question is:

        action="#{localeSelector.selectLanguage(sel.value)}"

        How can sel.value be evaluated and the MethodBinding be constructed the Seam-way with a literal string?

        PS OK, to stop irritating people on the staff I'll not post to JIRA about this issue anymore. I'll only comment in the forum. Wit teh nubz. If finally you decide that this makes sense to be reopened, whatever, you'll do it, not me. If no one pays attention to my post here, I'll be a bit disappointed but I'll make it through :) Peace

        • 16. Re: Evaluation of action attibute in s:link
          wise_guybg

          Does anyone know where one can comment on Facelets?

          A forum that is working. I tried they site but couldn't find something updated.

          I am not sure that the Seam team should be distracted anymore with this issue.

          • 17. Re: Evaluation of action attibute in s:link
            gavin.king

             

            #{sel.label} -> can be evaluated


            No it can not! How the hell is an arbitrary page variable going to be available when the method expression is evaluated on the faces request?? It's a whole different request!

            Now, Seam is actually pretty cool, and *if* "sel" is a variable that iterates a DataModel that exists in PAGE or CONVERSATION scope and is the value of a UIData, then Seam *can* evaluate #{sel.label} on the postback.

            So, like I said above, you can solve your problem simply by sticking the stuff you are iterating in a page or conversation scope datamodel. (Like I said above.)




            • 18. Re: Evaluation of action attibute in s:link
              wise_guybg

              Hi, Gavin, thanks for the response. I should have taken in account the time zone difference long ago and write my posts only at night so that someone can see them in the US at a normal time.

              I think you're not talking in the same scope as I do so there is a little misunderstanding.

              #{sel.label} - can be evaluted because this is all happening inside ui:repeat and sel is an item from the collection returned by localeSelector.supportedLocales Please refer to initial post if something is left out uncommented. I cannot repost the hole thread here.

              action="#{localeSelector.selectLanguage(sel.value)}"

              I do not want sel.value evaluated on post back. But this is what Seam does with a MethodBinding. I want sel.value to be evaluated in the first request so that on postback Seam will have to evaluated the valid code:
              action="#{localeSelector.selectLanguage('de')}" //for example


              PS I can be wrong in not spending enough time on the manuals. You can be wrong on not spending enough time on my question.

              I have written my question for the 5th time probably. I'll get bored too, eventually :)

              • 19. Re: Evaluation of action attibute in s:link
                gavin.king

                 

                #{sel.label} - can be evaluted because this is all happening inside ui:repeat and sel is an item from the collection returned by localeSelector.supportedLocales


                No it is not, this is the source of your whole misunderstanding.

                It is a method binding. It is never evaluated while the page is being rendered.

                I do not want sel.value evaluated on post back.


                Sorry, thats what a method binding is. This is basic JSF behavior.

                • 20. Re: Evaluation of action attibute in s:link
                  wise_guybg

                  I think there is something wrong. Maybe I'm using the wrong terms. I don't know!?

                  #{sel.label} is evaluated and it is displayed on my page. No action, no nothing. Only text on the page. Example... I can iterate with ui:repeat and display the supported locales. It is not a method binding.

                  A MethodBinding in my view is what is used with the action attribute. It is encoded in the URL and executed on click for example. It is not evaluated as the page is rendered.

                  Please, tell me if these two statements are wrong.

                  Now what I want is to be able to have a variable in the method binding that will be evaluated when the page is rendered. My question is if JBoss EL can implement this feature.

                  • 21. Re: Evaluation of action attibute in s:link
                    wise_guybg

                    Just to get rid of background noise:
                    - my nick has no meaning
                    - i have done my homework (i agree that many people don't do it)
                    - i'm new in this forum but that does not mean a thing about me

                    I think that so far no response was actually targeted towards my little question and this is really frustrating. This thread should have never gotten so big. All this fluff makes my question irrelevant. At least for spending some time on the forum I managed to reply to other users' questions and I hope I helped them at least a bit.

                    • 22. Re: Evaluation of action attibute in s:link
                      dmitriy.lapko

                      It was so long conversation... I just want to check, did I understood your problem correctly.

                      So, do you mean that you would like to be able to dynamically generate the contents of the "action" attribute?

                      So, instead of writing a lot of times:

                      <s:link action="#{someBean.doSomeWork('value1')}" .../>
                      <s:link action="#{someBean.doSomeWork('value2')} ..."/>
                      ...
                      <s:link action="#{someBean.doSomeWork('valueN')} ..."/>
                      

                      you would like to be able to write:

                      <cycle name="some form of cycle which iterates by all possible values like 'value1', 'value2'...">
                      
                      <s:link action="#{someBean.doSomeWork(valueToEvaluate)}" .../>
                      
                      </cycle>
                      


                      which should be transformed into previous form during rendering of the page.

                      Am I right? I just also had such dreams about EL and Seam before...

                      And to have special marks to show Seam that we need evaluate valueToEvaluate on rendering phase...



                      • 23. Re: Evaluation of action attibute in s:link
                        wise_guybg

                        Exactly, thank you... I guess my explanation was a bit confusing, I don't know.

                        As of now, I think of making some modifications to the way Seam works with action's MethodBinding value so that it's inner parts are scanned for variables . Then they could be evaluated at the rendering stage. If I succeed I will post the code here for comments or post it directly to jira.

                        I think that the following syntax:
                        <s:link action="#{someBean.doSomeWork(#{valueToEvaluate})}" .../>

                        makes sense because action is a MethodBinding. It won't be evaluated at rendering stage. The path for valueToEvaluate is clear.

                        I have posted the same question in Facelets' forum:
                        http://www.nabble.com/RepeatTag-variable-cannot-be-used-with-MethodBinding-tf4147933.html

                        I did not received any help from the Seam team so I guess it is up to me now to drill into the problem. I am sure that there are other people that will pop into it. Someone on the internet commented that what I'm trying to do is simply impossible at the moment. My guess is that JBoss EL is a good ground for making some changes. Not sure though if it's worth the trouble anymore :D

                        • 24. Re: Evaluation of action attibute in s:link
                          dmitriy.lapko

                          But why should we stop on such a simple solution? Let's evolve this idea (dynamic EL construction) till the whole madness?

                          Why only parameter value should be dynamic? What about bean name or action name? If action value used only on invoke application phase, and on rendering phase it is converted to MethodBinding object for validation (I'm not sure it is true)?

                          For example:

                          <s:link action="#{#{beanNameToEvaluate}.#{methodNameToEvaluate}(#{valueToEvaluate)})}" .../>


                          Looks ugly, eha?

                          But sometimes I thought about it - because of my humble knowledge of problems with it, as I can see the result of such construction only as a GET paramet in URL of the link.

                          So, may be it just possible to allow next code:

                          <s:link dynaAction="#{beanNameToEvaluate}.#{methodNameToEvaluate}(#{valueToEvaluate)})" .../>


                          like additional attribute for tag s:link which will try to evaluate the code before considering it's contents as method name during page rendering phase?

                          Wouldn't it be convenient?

                          Again, in another words,

                          <s:link action="#{someBean.doSomeAction('value1')}" ... />

                          may be convenient to write as

                          <s:link dynaAction="someBean.doSomeAction('value1')" ... />

                          or

                          <s:link dynaAction="#{'someBean.doSomeAction(\'value1\')'}" ... />

                          which looks more real...

                          It will work the same way but with pre-evaluation of given expression.

                          For JSP tags it can be something like this:

                          package org.jboss.seam.ui.tag;
                          
                          import javax.el.ELContext;
                          import javax.el.ELException;
                          import javax.el.ValueExpression;
                          import javax.faces.FacesException;
                          import javax.faces.component.ActionSource;
                          import javax.faces.component.UIComponent;
                          import javax.faces.context.FacesContext;
                          import javax.faces.el.MethodBinding;
                          
                          @SuppressWarnings("deprecation")
                          public class DynaLinkTag extends LinkTag {
                          
                           private String dynaAction;
                          
                           protected void setProperties(UIComponent component) {
                           super.setProperties(component);
                           setDynaActionProperty(getFacesContext(), component, getDynaAction());
                           }
                          
                           public static void setDynaActionProperty(FacesContext context, UIComponent component, String dynaAction) {
                           if (dynaAction != null) {
                           if (!(component instanceof ActionSource)) {
                           throw new IllegalArgumentException("Component " + component.getClientId(context) + " is no ActionSource");
                           }
                           if (isValueReference(dynaAction)) {
                           ValueExpression vb = component.getValueExpression(dynaAction);
                           ELContext elContext = FacesContext.getCurrentInstance().getELContext();
                           String actionValue = null;
                           try {
                           actionValue = (String) vb.getValue(elContext);
                           } catch (ELException ele) {
                           throw new FacesException(ele);
                           }
                           MethodBinding mb = context.getApplication().createMethodBinding(actionValue, null);
                           ((ActionSource) component).setAction(mb);
                           } else {
                           component.getAttributes().put("outcome", dynaAction);
                           }
                           }
                           }
                          
                           public String getDynaAction() {
                           return this.dynaAction;
                           }
                          
                           public void setDynaAction(String dynaAction) {
                           this.dynaAction = dynaAction;
                           }
                          }
                          
                          


                          For Facelets it needs changes in Facelets code, I think, it is not so obvious as for JSP...

                          What do you think?

                          • 25. Re: Evaluation of action attibute in s:link
                            gavin.king

                            yew!

                            Folks, you can already solve this usecase with f:param. I definitely don't prefer double-interpolation.

                            • 26. Re: Evaluation of action attibute in s:link
                              dmitriy.lapko

                              Do you mean:

                              instead of trying to do:

                              <s:link action="#{someBean.someMethod(someValue)}" .../>


                              to use:

                              <s:link action="#{someBean.someMethod}">
                              <f:param name="nameForMapping" value="#{someValue}"/>
                              </s:link>
                              

                              ?

                              And in someMethod implementation just read this value and call what you need?

                              (Just to finish this conversation)



                              By the way, I managed to implement idea with double-interpolation, so now I can write:

                              <s:link dynaAction="#{'itemBrowseList'}.#{'browseAll'}">#{messages['submenu.browse.all']}</s:link>


                              or

                              <s:link dynaAction="itemBrowseList.browseAll">#{messages['submenu.browse.all']}</s:link>


                              or

                              <s:link dynaAction="#{'itemBrowseList.browseAll'}">#{messages['submenu.browse.all']}</s:link>


                              and it works like

                              <s:link action="#{itemBrowseList.browseAll}">#{messages['submenu.browse.all']}</s:link>



                              It was a nasty hack into Facelets, just to check this idea, I don't think I will use it in production :)


                              But for history:

                              I made changes in 2 classes in jsf-facelets.jar:

                              added to class com.sun.facelets.tag.TagAttribute method

                              public MethodExpression getMethodPreEvaluationExpression(FaceletContext ctx, Class type,
                               Class[] paramTypes) {
                               try {
                               ExpressionFactory f = ctx.getExpressionFactory();
                              
                               ValueExpression valueExpression = this.getValueExpression(ctx, type);
                              
                               return new TagMethodExpression(this, f.createMethodExpression(ctx,
                               "#{"+(String)valueExpression.getValue(ctx)+"}", type, paramTypes));
                               } catch (Exception e) {
                               throw new TagAttributeException(this, e);
                               }
                               }


                              and 2 internal classes into com.sun.facelets.tag.jsf.ActionSourceRule:

                              final static class DynaActionMapper extends Metadata {
                              
                               private final TagAttribute attr;
                              
                               public DynaActionMapper(TagAttribute attr) {
                               this.attr = attr;
                               }
                              
                               public void applyMetadata(FaceletContext ctx, Object instance) {
                               ((ActionSource) instance).setAction(new LegacyMethodBinding(
                               this.attr.getMethodPreEvaluationExpression(ctx, String.class,
                               ActionSourceRule.ACTION_SIG)));
                               }
                               }
                              
                               final static class DynaActionMapper2 extends Metadata {
                              
                               private final TagAttribute attr;
                              
                               public DynaActionMapper2(TagAttribute attr) {
                               this.attr = attr;
                               }
                              
                               public void applyMetadata(FaceletContext ctx, Object instance) {
                               ((ActionSource2) instance).setActionExpression(this.attr
                               .getMethodPreEvaluationExpression(ctx, String.class,
                               ActionSourceRule.ACTION_SIG));
                               }
                              
                               }
                              


                              also changed its method public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta) for support of dynaAction attribute:
                               if ("dynaAction".equals(name)) {
                               if (elSupport && meta.isTargetInstanceOf(ActionSource2.class)) {
                               return new DynaActionMapper2(attribute);
                               } else {
                               return new DynaActionMapper(attribute);
                               }
                               }




                              It's crazy, yeh?

                              • 27. Re: Evaluation of action attibute in s:link
                                wise_guybg

                                When I think of it, I might be more willing to accept Gavin's suggestion. From the beginning I was not so sure if this should be made available. I wanted to discuss it with the folks but somehow the thread headed somewhere else.

                                I think this issue will be discussed and eventually syntax will change in some way. It's not ready for a solution right now, or I simply don't see it. JBoss EL will make modifications, I just hope they will make it to a JSR.

                                Thank you, dmitriy for sharing the code. I will look at it when I have more time. You have definitely saved me a lot of work.

                                • 28. Re: Evaluation of action attibute in s:link
                                  wise_guybg

                                  I submitted a request in JIRA to add this in the reference manual as a limitation in the expression language enhancements. Here is a link:
                                  http://jira.jboss.org/jira/browse/JBSEAM-1733

                                  I think this is the most appropriate thing to do for now...

                                  • 29. Re: Evaluation of action attibute in s:link
                                    dmitriy.lapko

                                    I'm not sure it is a problem of Seam. It is a limitation of JSF EL. You cannot construct JSF EL dynamically - that is what you would like to have. You cannot have nasted EL constructions.

                                    I just cannot understand, how would you like to fix this limitation - it will break the logic of EL, if you can use JSF page variable to construct expression. For me the problem is in specific logic you would like to have only for action attribute - don't you want this feature for ALL EL expressions?

                                    For example:

                                     <s:link value="#{curLocale.label}" action="#{localeSelector.selectLanguage(curLocale.value)}"/>
                                    


                                    If you would like to have the feature you posted in JIRA, then the parser of EL should try to check, is localeSelector also a page variable.

                                    Or in case there is curLocale component in the session scope, what should be done?

                                    Seam doesn't provide it's own parser of expressions, it uses standard but almost everewhere (that is cool :)).

                                    As for me, nested EL can be another powerful feature, which can help new developers to avoid such mistakes - they will be able to construct expressions dynamically with respect to current context, like:

                                     <s:link value="#{curLocale.label}" action="#{localeSelector.selectLanguage(#{curLocale.value})}"/>
                                    


                                    But may be it would just make the code more complicated. The decision with <f:param is more clear, you should just to know it and not to try to do what we did with you.

                                    Hope, this topic is closed :)