2013-03-14 24 views
6

Wdrażam komponent złożony i znalazłem problem, którego nie znalazłem.JSF2.0 - Komponent kompozytowy z opcjonalnym wyrażeniem metody

Podałem jego atrybuty, które mogą być przekazane przez autora strony, ale nie mogłem podać atrybutu metody (wyrażenie metody do działania), które, jeśli nie zostało przekazane, komponent złożony nie użyj atrybutu method w tagu composite: implementation.

Oto mój kod:

<composite:interface> 
    <composite:attribute name="namePrompt" required="true"/> 
    <composite:attribute name="actionMethod" method-signature="java.lang.String action()" required="false"/> 
    <composite:attribute name="showComponent" default="false"/> 
</composite:interface> 

<composite:implementation> 
    <div> 
     <p:commandLink actionListener="#{cc.attrs.actionMethod}" 
         rendered="#{cc.attrs.showComponent}" 
         > 
      <h:outputText value="#{cc.attrs.namePrompt}"/>  
     </p:commandLink> 
    </div> 
</composite:implementation> 

Kiedy go za pomocą, nie określają atrybut "actionMethod". Tak:

<util:foo namePrompt="SomeName" showComponent="true"/> 

Ale pojawia się komunikat o błędzie:

javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.actionMethod}' 

Czy istnieje sposób to zrobić?

+0

można przekazać opcjonalny atrybut 'actionListener'. Co to jest przypadek użycia, jak sądzisz, co powinno się stać, gdy 'actionListener' nie zostanie rozwiązany i renderowane jest' commandLink'? – partlov

+0

Tak, komponent łącza jest renderowany, ale gdy kliknięcie odbywa się w komponencie Link, narzeka, że ​​nie zdefiniowałem metody atrybutu actionMethod. Ale to jest moja intencja, czasami nie chcę definiować metody działania dla atrybutu actionMethod. czy to możliwe? Pomyślałem, że wprowadzenie "required = false" rozwiązuje problem. –

Odpowiedz

10

Trzeba będzie utworzyć dwa p:commandLink elementy i czyni je warunkowo według definicji swojego parametru:

<p:commandLink actionListener="#{cc.attrs.actionMethod}" rendered="#{!empty cc.getValueExpression('actionMethod') and cc.attrs.showComponent}"> 
    <h:outputText value="#{cc.attrs.namePrompt}"/> 
</p:commandLink> 
<p:commandLink rendered="#{empty cc.getValueExpression('actionMethod')}"> 
    <h:outputText value="#{cc.attrs.namePrompt}"/> 
</p:commandLink> 
+0

Tak, to działa. Dziękuję za poświęcony czas i pomoc. –

3

Innym rozwiązaniem jest stworzenie własnego typu części, o sposobie działania. Przykład:

<composite:interface componentType="myButton"> 
    <composite:attribute name="namePrompt" required="true"/> 
    <composite:attribute name="actionMethod" method-signature="java.lang.String action()" required="false"/> 
    <composite:attribute name="showComponent" default="false"/> 
</composite:interface> 

<composite:implementation> 
    <div> 
     <p:commandLink actionListener="#{cc.action()}" rendered="#{cc.attrs.showComponent}"> 
      <h:outputText value="#{cc.attrs.namePrompt}"/>  
     </p:commandLink> 
    </div> 
</composite:implementation> 

A componentType musi wyglądać następująco:

@FacesComponent("myButton") 
public class MyButton extends UINamingContainer { 

    public MyButton() { 
    } 

    public String action() { 
     MethodExpression me = (MethodExpression) this.getAttributes().get("actionMethod"); 
     if (me != null) { 
      try { 
       Object result = me.invoke(FacesContext.getCurrentInstance().getELContext(),  null); 
       if (result instanceof String) { 
        return (String) result; 
       } 
      } catch (ValidatorException ve) { 
       throw ve; 
      } 
     } 
     return null; 
    } 
} 
1

Gdyby dokładnie taki sam błąd i musiał mieć opcjonalną metodę działania na moim komponentu też.

Tak więc próbowałem dodać domyślny parametr atrybutu złożonego z sygnaturą metody, wskazując metodę na odpowiedniej klasie FacesComponent i działa świetnie!

Składnik: klasa

<composite:interface componentType="myButton"> 
    <composite:attribute name="namePrompt" required="true"/> 
    <composite:attribute name="actionMethod" method-signature="java.lang.String action()" required="false" default="#{cc.dummyAction}"/> 
    <composite:attribute name="showComponent" default="false"/> 
</composite:interface> 

<composite:implementation> 
    <div> 
     <p:commandLink action="#{cc.attrs.actionMethod}" 
         rendered="#{cc.attrs.showComponent}" 
         > 
      <h:outputText value="#{cc.attrs.namePrompt}"/>  
     </p:commandLink> 
    </div> 
</composite:implementation> 

FacesComponent:

@FacesComponent("myButton") 
public class MyButton extends UINamingContainer { 

    public MyButton() { 
    } 

    public String dummyAction() { 
     return ""; 
    } 

} 
3

Zmiana metody typ zwracany podpis do java.lang.Object i dodać "null" jako wartości domyślnej.

<composite:interface> 
    <composite:attribute name="namePrompt" required="true"/> 
    <composite:attribute name="actionMethod" method-signature="java.lang.Object action()" required="false" default="null"/> 
    <composite:attribute name="showComponent" default="false"/> 
</composite:interface> 

<composite:implementation> 
    <div> 
     <p:commandLink actionListener="#{cc.attrs.actionMethod}" 
         rendered="#{cc.attrs.showComponent}" 
         > 
      <h:outputText value="#{cc.attrs.namePrompt}"/>  
     </p:commandLink> 
    </div> 
</composite:implementation> 

Bez metody:

<util:foo namePrompt="SomeName" showComponent="true"/> 

metodą:

<util:foo actionMethod="#{someBean.someMethod()}" namePrompt="SomeName" showComponent="true"/>