0

アプリケーションに次のカスタム コンポーネントを実装しました。

@FacesComponent ("org.app.component.hintBubble")
public class TutorialHintBubbleComponent extends UIComponentBase implements Serializable {

private static final long serialVersionUID = -8124906197708898894L;

public static final String COMPONENT_TYPE = "org.app.component.hintBubble";

@Override
public String getFamily() {
    return COMPONENT_TYPE;
}

@Override
public boolean isTransient() {
    return false;
}

@Override
public void encodeBegin(FacesContext context) throws IOException {
    setId("hintBubble");

    TutorialHintBubble value = (TutorialHintBubble) this.getValueExpression("value").getValue(context.getELContext());
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement("div", this);
        writer.writeAttribute("style", value.getCss().getBodyCss(), null);
        writer.writeAttribute("class", "hint-bubble", null);

        if ( value.getPointer().getLocation() != HintBubblePoinerLocation.NONE ) {
            writer.startElement("div", this);
                writer.writeAttribute("style", value.getCss().getPointerCss(), null);
                writer.writeAttribute("class", "hint-bubble-pointer", null);
            writer.endElement("div");

            if ( value.getBorder().getThicknessInPixels() > 0 ) {
                writer.startElement("div", this);
                    writer.writeAttribute("style", value.getCss().getPointerBorderCss(), null);
                    writer.writeAttribute("class", "hint-bubble-pointer-border", null);
                writer.endElement("div");
            }
        }



        writer.startElement("div", this);
            writer.writeAttribute("class", "hint-bubble-inner-html-container", null);
            writer.write(value.getInnerHtml());
        writer.endElement("div");

        if ( value.isShowConfirmButton() ) {
            writer.startElement("div", this);
            writer.writeAttribute("class", "hint-bubble-btn-container", null);

            UICommandLink commandLink = new UICommandLink();
            getChildren().add(commandLink);
            commandLink.setParent(this);

            commandLink.setValue(value.getButtonCaption());
            commandLink.setStyleClass("hint-bubble-btn");
            commandLink.setId("okButton");

            ValueExpression actionListenerExpression = getValueExpression("actionListener");

            if ( actionListenerExpression != null ) {
                commandLink.addActionListener(
                    (ActionListener) actionListenerExpression.getValue(context.getELContext())
                );
            }
        }
    }


@Override
public void encodeEnd(FacesContext context) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    TutorialHintBubble value = (TutorialHintBubble) this.getValueExpression("value").getValue(context.getELContext());
    if ( value.isShowConfirmButton() ) {
        writer.endElement("div");
    }

    writer.endElement("div");
}

}

ご覧のとおり、このコンポーネントの子として UICommandLink が追加されています。このコマンド リンクに添付されているのは ActionListener です。ActionListener は、パラメーターとして HintBubble コンポーネントに渡された式から評価されます。デバッグは、アクション リスナーが正しく評価され、UICommandLink に追加されたことを示しています。

xhtml のコード:

<h:form id="tutorialForm">
<a4j:outputPanel id="tutorialContainer" layout="block" >
    <a4j:repeat value="#{tutorialBean.hintBubbles}" var="hintBubble">
        <gg:hintBubble value="#{hintBubble}" actionListener="#{tutorialManager}" />
    </a4j:repeat>
</a4j:outputPanel>
</h:form>

すべてが Web ページに正しくレンダリングされますが、ボタンをクリックするとアクションが実行されません。(サーバーにajaxリクエストが送られますが)

私の質問は:

動作させるには、どのメソッドで UICommandLink をコンポーネントの子に追加する必要がありますか? (UICommandLink は richfaces からのものであることに注意してください。つまり、org.richfaces.component.UICommandLink です)

4

1 に答える 1

0

私はついにこれを機能させることができました。問題の JSF コンポーネントには、Component、Renderer、ComponentHandler の 3 つのクラスが必要です。

子 UICommandLink は、作成されたコンポーネントのメソッドの ComponentHandler で HintBubbleComponent に追加する必要があります。

public class HintBubbleHandler extends ComponentHandler {

public HintBubbleHandler(ComponentConfig config) {
    super(config);
}

@Override
public void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) {
    HintBubbleComponent hintBubbleComponent = (HintBubbleComponent) c;

    UICommandLink commandLink = new UICommandLink();
    hintBubbleComponent.getChildren().add(commandLink);
    commandLink.setParent(hintBubbleComponent);
    commandLink.setId("okButton");      
}

}

そのおかげで、アクションを実行したコンポーネントを探すコールバックによってツリーが訪問されたときに、UICommandLink がコンポーネント ツリーに存在します。

actionListener は、レンダラーの decode() メソッドで UICommandLink に設定する必要があります。

@Override
public void decode(FacesContext context, UIComponent component) {
    super.decode(context, component);

    UICommandLink commandLink = (UICommandLink) component.getChildren().get(0);

    MethodExpression actionListener =  ((HintBubbleComponent) component).getActionListener();

    if ( actionListener != null ) {
        commandLink.setActionExpression(actionListener);
    }

}   

アクションが呼び出されると、すべてが機能するようになりました。

于 2013-10-11T13:43:23.967 に答える