0

かなり普通のケース:

拡張と折りたたみの2つの状態を持つ「ポートレット」複合コンポーネントがあります。ポートレットは展開された状態で開始されますが、ユーザーはそれらをクリックして折りたたむことができます。この状態はセッションに保存する必要があります。これにより、ユーザーがページを更新するか、新しいページに移動すると、ポートレットは展開/折りたたみされているかどうかを記憶します。

これが問題の核心です。ページに複数回挿入できるこのような状態保存をコンポーネントに実際にどのように実装しますか?

いくつかの背景/アイデア:

1つのポートレットに状態保存を実装するには、セッションスコープのBeanを使用することで簡単に実現できます。また、固定数のセッションスコープBeanを作成するか、1つのBeanに異なるプロパティを宣言することで、固定数のポートレットをサポートできます。しかし、なぜそれらのアプローチが悪いのかについても言及したくありません。

これについての私の最初のアイデアは、すべてのポートレットの状態を保持するために、単一のセッションBeanの下にマップ(またはいくつかのオブジェクト構造)を作成することでした。ただし、JSFからこのデータを直接参照することはできません(JSFもそれらを更新するため)。マップ内の正しい値をフェッチ/更新するために特定のゲッター/セッターを作成することを検討しましたが、ゲッターとセッターの実行中に識別データがないため、それは不可能です。

ただし、状態をセッションBeanに保存する必要があることはおそらく明らかです。f:ajaxフォームを投稿し、送信されたデータを使用して特別なメソッドを実行することで、状態の保存を非常に簡単に行うことができlistenerます。コンポーネントの複数のインスタンスをサポートするために、リクエストスコープのBean(の複数のインスタンス)を使用して、各展開/折りたたみを処理できます。ただし、ポートレットとその状態を識別するデータを実際に投稿するには、最初にレンダリング時にフォームフィールドにデータを挿入する必要があります。

では、レンダリング時に各ポートレットに適切なデータを実際に提供するにはどうすればよいでしょうか(実際には、この場合はブール値/列挙型を指定しますが、より多くのデータを処理する必要がある場合を考えてみてください)。

のようだ:

  • h:inputHiddenまたh:inputText、value-attribute(を指す)以外の初期値の設定はサポートされていません#{portletBean.portletState}
  • 利用可能な識別情報がないため、作成時に正しい初期値でリクエストBeanを自動ロードできません。

もう一度、何かが足りないように感じます...ポインタ?

答えの少なくとも1つは、UIComponent複合コンポーネントではなく使用することだと思いますが、生のHTML要素がたくさん含まれているため、これを複合コンポーネントとして保持したいと思います。

アップデート:

  • ビュースコープのBeanを使用することを提案する、かなり類似した質問があります。ただし、これはここでは実行可能ではないと思います。
4

3 に答える 3

0

以前に解決したハックを使用して、JSからBeanメソッドを呼び出しました

空の非表示のフォームを作成し、そのフォーム内でh:commandButtonf:ajax呼び出しlistenerます。

展開/折りたたみイベントを起動するための別のボタンを作成しました。そのボタンからjavascriptメソッドを開始します。これは、展開/折りたたみをアニメーション化すると同時に、フォーム内の非表示のボタンをクリックします。必要なすべてのデータは、listener属性を使用して送信されます。リスナーは、コンポーネントのクライアントIDによって識別される状態のマップをチェック/更新するセッションBeanをターゲットにします。

これは非常に単純です、なぜ私がそれを早く気づかなかったのか疑問に思います...

ただし、それでも完全にはほど遠いため、リクエストスコープのBeanをデフォルト値で開始して、ストレージ/トランスポートフォームとして使用する方法については説明していません。

于 2010-09-28T17:31:20.437 に答える
0

私はこれのためにいくつかの可能なハックを手に入れました。ここに投稿しますが、これらが実際に進むべき道ではないと思います。

javascriptを使用して、レンダリング直後に適切なデータでフォームフィールドを設定します。

window.addEvent('domready', function() {
    var portletState = '#{portletBean.getPortletState(cc.attrs.clientId)}';
    // find the field and set the data...
});

ひどいハッキーを感じます。私はこのルートを取りたくありません。

コンポーネントの属性マップを使用してデータを保持します。

<cc:interface>
    <cc:attribute name="portletState" default="#{portletBean.getPortletState(cc.attrs.clientId)}" />
</cc:interface>

コードからアクセスします。

public void stateChangedCallback(String clientId) {
    UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId);
    String state = (String) component.getAttributes().get("portletState");
}

また、気分が悪い。また、それが機能するかどうかもわかりません(実際にデフォルト属性でELを使用できますか)。

コンポーネントの属性マップを使用して、コンポーネントを呼び出すときにデータを提供することにより、データを保持します。

<portlet:portlet id="specificPortlet">
    <f:attribute name="portletState" value="#{portletBean.getPortletState(component.clientId)}" />
</portlet:portlet>

繰り返しますが、非常に不器用で、コードを複製します。

于 2010-09-28T12:53:21.843 に答える
0

これはtaglibsを使用して行うことができ、パラメータをタグに渡すことができます。

taglibに以下を追加します。

<tag>
    <tag-name>date</tag-name>
    <source>components/date.xhtml</source>
</tag>

次に、components/date.xhtmlの内容を示します。

<ui:composition name="date_template">
    <h:panelGrid id="#{id}Panel" columns="1" border="0" cellpadding="0" cellspacing="0">
        <rich:calendar immediate="true" id="#{id}" popup="true" datePattern="dd.MM.yyyy"
                        enableManualInput="true" showApplyButton="true" cellWidth="12px" cellHeight="11px" style="width:100px"
                        value="#{dateForm.date}" required="#{required}" readonly="#{readonly}" validator="#{dateForm.validateDate}">
            <a4j:support event="onchanged" reRender="#{id}Panel,#{reRenderDate}"/>
            <ui:insert />
        </rich:calendar>

        <rich:message for="#{id}" errorClass="error" />
    </h:panelGrid>
</ui:composition>

そして、あなたはこれを次のように使用します:

<adse:date id="dateTransfert" required="true"
           dateForm="#{dossierBean.dateTransfert}"
           readonly="false" reRenderDate="montantAncien,montantNouveau,montantEmolument">
     <a4j:support event="oninputblur" reRender="dateTransfertPanel,montantAncien,montantNouveau,montantEmolument"/>
</adse:date>

この場合、dateFormが渡され、これはオブジェクトであり、taglibではそのオブジェクトのプロパティ(dateForm.date)を使用します。また、XHTMLに他の要素を含めるために使用できる<ui:insert/>にも注意してください。

したがって、各ポートレットのコンテキストを渡すことができます。getPortletState()メソッドを定義するスーパークラスとしてportletBeanを使用することで、この標準を作成することもできます。

于 2010-09-28T13:18:25.613 に答える