5 Replies Latest reply on Jul 20, 2006 3:49 AM by Ulf Niesar

    Facelets: Parameters to custom tags

    Marcus Schmidke Newbie

      Hello,

      I am using MyFaces / Facelets / Seam.

      Can I inject the attributes of a custom tag into my bean?

      I've written a custom tag with tag file:

      <tag>
       <tag-name>kontoname</tag-name>
       <source>kontoname.xhtml</source>
      </tag>
      


      kontoname.xhtml:
      <ui:component xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:t="http://myfaces.apache.org/tomahawk"
       >
      
       <ui:repeat value="#{liste.angezeigteSpalten}" var="spalte">
       <td class="auftragszelle">
       <h:outputText value="#{kontoname.wert}" />
       </td>
       </ui:repeat>
       <td class="auftragszelle">
       ?
       </td>
      </ui:component>
      


      I'm calling this tag with arguments:
      <le:kontoname konto="#{kontozeile_iter}" liste="#{leistungsschein.kontozeilen}" />
      


      The Tag is using a Java bean:
      @SuppressWarnings("serial")
      @Scope(ScopeType.APPLICATION)
      @Name("kontoname")
      public class Kontoname implements Serializable{
      
       private @In(required=false) Kontowrapper konto;
       private @In(required=false) Anzeigespalte spalte;
      
       public String getWert() {
       if (spalte==null) return "Keine Spalte angegeben";
       if (konto==null) return "Kein Konto angegeben";
       return spalte.getWertInObjekt(konto);
       }
      
      }
      


      Unfortunately, this does not work. Accessing the "liste" argument from within the tag file is no problem, but accessing the "konto" argument from within the JavaBean isn't possible.

      Can I do anything to get the parameter injected?

      Thank you!!

      Regards,

      Marcus.

        • 1. Re: Facelets: Parameters to custom tags
          Ulf Niesar Newbie

          Hi Marcus,

          I'm not sure if I correctly understand what you try to do. But let's give it a try...

          In

          <le:kontoname konto="#{kontozeile_iter}" liste="#{leistungsschein.kontozeilen}" />
          you are actually passing kind of a reference of your data (kontoname_iter) to your custom tag. In kontoname.xhtml you are then accessing "kontozeile_iter" using the name "konto".

          If you also want to use "konto" aka "kontoname_iter" in the bean, you need to make "kontozeile_iter" available for the bean, too.

          It's hard to guess where "kontozeile_iter" is coming from in your code, but looking at the name it sounds like you are iterating through a list of - let's say - "Kontozeile" instances. I further guess a variable like "Kontozeile kontoname_iter" is supposed to be the currently selected element of the list.

          If that is the case, you may want to take a look at Seam's @DataModel/@DataModelSelection. It is used in the hotel booking example, see
          http://docs.jboss.com/seam/latest/reference/en/html/tutorial.html#booking . If you take a look at HotelSearchAction.java, you will find @DataModel and @DataModelSelection.

          In main.xhtml (you will find it in the booking example which comes with Seam) you can see how this is used to display a list of hotels.

          Now, if you want to pass your user's selection to another Bean, you can access it from there by using a getter method.

          In the booking example Bean HotelSearchingAction is annotated with @Name("hotelSearch"):
          @Name("hotelSearch") // !!!
          @Scope(ScopeType.SESSION)
          public class HotelSearchingAction implements HotelSearching {
           ...
           @DataModel
           private List<Hotel> hotels;
           @DataModelSelection
           private Hotel selectedHotel;
           ...
           public Hotel getSelectedHotel() { // that's the way to access the user selection
           return selectedHotel;
           }
          

          If you want to access the user selection from another Bean, this could be done like this:
          @In
          private HotelSearching hotelSearch // from the @Name annotation in HotelSearchingAction.java
          [...]
          // later in your code:
          Hotel selectedHotelFromOtherBean = hotelSearch.getSelectedHotel()/;
          // now do something useful with selectedHotelFromOtherBean
          

          Is this more or less what you try to do?

          • 2. Re: Facelets: Parameters to custom tags
            Marcus Schmidke Newbie

            Hi niesar,

            no ... unfortunately not exactly what I want. Perhaps I showed a little too few context of the calling page, sorry.

            I want to have a reusable component "kontoname.xhtml" which can be embedded to any other page. This reusable component needs two parameters, konto and liste.

            Then I have one calling page which wants to make use of this reusable component. It iterates over some objects:

            <t:dataList var="kontozeile_iter" value="#{leistungsschein.kontozeilen.gefilterteListe}">
             <tr>
             <ui:include src="/komponenten/kontoname.xhtml">
             <ui:param name="konto" value="#{kontozeile_iter}" />
             <ui:param name="liste" value="#{leistungsschein.kontozeilen}" />
             </ui:include>
             </tr>
            </t:dataList>
            


            (You see I also tried the "ui:param" syntax, but no success.)

            The dataList iterates over something named leistungsschein.kontozeilen.gefilterteListe. This works fine. The current iteration is saved in the variable kontozeile_iter. This works fine. Then the component is called with the two paramers konto (which is actually kontozeile_iter, but inside a reusable method, you don't want to worry about the actual parameter's name) and liste. This even works fine since I can access both parameters, for example using outputText elements.

            So the "konto" parameter is somewhere where it can be accessed via EL. But it can't be accessed via injection. So where is it stored?


            Once again my reusable component:
            <ui:component xmlns:ui="http://java.sun.com/jsf/facelets"
             xmlns:h="http://java.sun.com/jsf/html"
             xmlns:f="http://java.sun.com/jsf/core"
             xmlns:t="http://myfaces.apache.org/tomahawk"
             >
            
             <td class="auftragszelle">
             <!-- The following is absolutely perfect! -->
             <h:outputText value="#{konto.name}"></h:outputText>
             </td>
             <ui:repeat value="#{liste.angezeigteSpalten}" var="spalte">
             <td class="auftragszelle">
             <h:outputText value="#{kontoname.wert}" />
             </td>
             </ui:repeat>
            </ui:component>
            


            • 3. Re: Facelets: Parameters to custom tags
              Ulf Niesar Newbie

              OK, next try ;)

              Let me see if I understand your problem now...

              <t:dataList var="kontozeile_iter" value="#{leistungsschein.kontozeilen.gefilterteListe}">
               <tr>
               <ui:include src="/komponenten/kontoname.xhtml">
               <ui:param name="konto" value="#{kontozeile_iter}" />
               <ui:param name="liste" value="#{leistungsschein.kontozeilen}" />
               </ui:include>
               </tr>
              </t:dataList>
              
              You are basically iterating through #{leistungsschein.kontozeilen.gefilterteListe} and you say kontoname.xhtml is doing what you are expecting, is that right?

              You know, what I don't catch yet is what you want to do now with "konto" aka "kontozeile_Iter". In kontoname.xhtml you are able to access it as "konto". In the code snipplet above, you can use it with name "kontozeile_iter". And after you are leaving <t:dataList> "kontozeile_iter" is undefined (and makes no sense any more since that was the iterator for the table rows - but the table is complete now). Do you need the last "kontozeile_iter" to know which was the last displayed line or something like that?

              • 4. Re: Facelets: Parameters to custom tags
                Marcus Schmidke Newbie

                Yes ... and no ... :-)

                Nearly everything you wrote is correct. Only one problem: kontozeile.xhtml is only doing part of what I want.

                Remember the first "outputText" element in the kontozeile. It works perfect. But it's only there for debugging purposes. I was wondering: is there a local variable named konto inside of kontozeile? outputText proves: there is. As I excpected.

                But what I really want is not this first outputText. The second one is it. The call to method getWert() of the corresponding Seam Bean (named kontoname, class Kontoname - look at my very first posting). I try to inject that obviously existing variable named "konto" into that bean. But it doesn't arrive there.

                In other words: the variable does exist, but it is uninjectable. Why????

                Thank you very much for your patience so far!

                Marcus.

                • 5. Re: Facelets: Parameters to custom tags
                  Ulf Niesar Newbie

                  Hmmm,

                  still not sure if I really understand your problem exactly.

                  However, I don't think it's possible to inject a temporary variable, which is created by JSF, into an arbitrary bean.

                  But can't you do it the "usual" way?

                  Let's keep the class name I invented before for a moment, namely "Kontozeile" for "kontozeile_iter" aka "konto" within kontoname.xhtml.

                  if class Kontozeile has this method "public String getWert()" you showed in your first post, there should be no need to inject "konto" or "kontozeile_iter" anywhere. In that case you should be able to invoke that method with "#{konto.wert}" in kontoname.xhtml.

                  ... or this way?

                  again: "kontozeile_iter"/"konto" is of Class Kontozeile

                  public class Kontozeile {
                  private Kontoname kontoname;
                  ...
                  //don't forget getters (and setters if required) for JSF


                  public class Kontoname {
                  
                  public String getWert() {
                   return "this is what I really need";
                  }


                  If you can do it like that, you can access it with #{konto.kontoname.wert} within kontoname.xhtml.

                  Is that no option for you?