1

私は次の構造を持っています

<h:form>
<!-- some elements -->
<p:accordionPanel id="outer" multiple="true" var="node" dynamic="false" value="#{model.nodes}">
    <p:tab id="outerId">
        <p:accordionPanel id="inner" multiple="true" dynamic="false" var="child" value="#{node.children}">
            <p:tab id="innerId">
              <!-- iterated components -->
            </p:tab>
        </p:accordionPanel>
    </p:tab>
</p:accordionPanel>
</h:form>

次に、内部タブ内および階層全体の外部から ajax ポストバック & 再レンダリングで使用しようとしました:

<f:ajax event="click" render="@form" execute="@form" />

また

<p:ajax process="@form" partialSubmit="false" update="@form" />

問題は、アクティブ インデックスが外側のアコーディオンに対してのみ永続化され、子アコーディオンに対しては永続化されないことでした (ただし、POST データを見ると、子アコーディオンのアクティブ インデックスも送信されます)。私は何か間違ったことをしていますか、それともこれがすぐに使えると期待すべきではありませんか?

何がうまくいくでしょうか

一方、たとえばモデルとすべてのノードにフィールドを提供することで、アクティブなインデックスを手動で管理できることを知っています。これにより、このデータが永続化されます。(テストはしませんでしたが、多くのpf投稿/ページを掘り下げた後、それが私が期待するものです)

<p:accordionPanel activeIndex="#{model.activeIndex}"...
       <p:accordionPanel activeIndex="#{node.activeIndex}"...

この2番目のアプローチが唯一の回避策であることを誰かが確認できますか? または、最初のケースで何か間違ったことをしていますか?

プライムフェイス3.4.2

Glassfish スタック3.1.2.2

更新 05.04.2013

後者のアプローチも機能しません。ajax POST では node.activeIndex が値を受け取るため""(ルート アクティブ インデックスのみが正しく設定されます)

データ シナリオ (POST データの詳細)

  1. ページをロードします。
  2. 最初の 2 つの外側のタブを開きます。
  3. 2 番目の外側のタブから最初の 2 つの内側のタブを開きます。
  4. ページ内の要素をクリックします
  5. 投稿データ
    javax.faces.partial.ajax=true
    javax.faces.source=j_idt106:j_idt271:1:j_idt121:j_idt110:0:j_idt113:featureRepeater:11:featureCheckboxP
    javax.faces.partial.execute=gridDetailPage
    javax.faces.partial.render=gridDetailPage
    javax.faces.behavior.event=valueChange
    javax.faces.partial.event=変更
    gridDetailPage=グリッド詳細ページ
    j_idt106:j_idt271:1:j_idt121:j_idt110_active=0,1 // 内部の開いているタブ
    j_idt106:j_idt271_active=0,1 // 外側の開いているタブ
    javax.faces.ViewState=4232962649695633063:-8633977119414123467
  1. レンダリングされたページには、最初の 2 つの外側のタブがあり、2 番目の外側のタブから 1 番目の内側のタブのみが開いています (間違っています)。
  2. 次の POST は、現在の (間違った) 構成のみを POST しています。
javax.faces.partial.ajax=true
javax.faces.source=j_idt106:j_idt271:1:j_idt121:j_idt110:0:j_idt113:featureRepeater:0:featureCheckboxP
javax.faces.partial.execute=gridDetailPage
javax.faces.partial.render=gridDetailPage
javax.faces.behavior.event=valueChange
javax.faces.partial.event=変更
gridDetailPage=グリッド詳細ページ
j_idt106:j_idt271:1:j_idt121:j_idt110_active=0 // 内部の開いているタブ
j_idt106:j_idt271_active=0,1 // 外側の開いているタブ
javax.faces.ViewState=4232962649695633063:-8633977119414123467
4

1 に答える 1

2

andybaによって提案されたソリューション:

「activeIndex 値が確実に伝播されるようにするには、accordionPanel をくすぐる必要があります。トップレベルの accordionPanel<p:ajax/>内に空の p:ajax タグ ( )を追加するだけでこれを実行できます。」

残念ながら、それはうまくいきませんでした (outer、inner、両方の + with & without activeIndex のすべての組み合わせを試しました)。

しかし、これは

  • サーバー側ではインデックスに興味がないので、activeIndex を設定する必要はありません):

  • 外側:

    <p:ajax event="tabChange"/>
    

    (これは基本的に、ソリューションの制限された形式です

  • 私が追加した内側のアコーディオンで:

    <p:ajax event="tabChange" process="@this" update="@form"/>
    

    私の場合、内部タブのステータスを変更するには、フォーム全体の再レンダリングのみが必要であることを意味します

残念ながら、複雑なページ構造のため、これにより見苦しいちらつきが追加されます。タブチェンジでajaxなしで解決できることを望んでいました。

プライムフェイスフォーラムにもあります

更新 20130510

最後に、私は自分のソリューションを醸造することになりました。あれは:

同じ数のアコーディオンを同じ順序で表示するという制約があるため、アコーディオンが開いている場合は 1、閉じている場合は 0 を含む文字列にステータスを保存できます。したがって、解決策は次のとおりです。

var CONTAINER_SELECTOR = 'selector of container containing all accordions';

// called whenever we click on an accordion (see assignment in init)
var saveAccordionsState = function () {
  var state = '';
  $(CONTAINER_SELECTOR + ' .ui-accordion-header').each(function (i, el) {
      // for every accordion put a 0 or 1 in the state string
      state += ($(el).hasClass('ui-state-active') ? '1' : '0');
  });
  // put the state string in an input that will be submitted to the server
  $('#accordionState').val(state); 
};

// this method is called right after accordions are rendered
var init = function () {
    // retrieve the saved state
    var state = $('#accordionState').val();

    // get reference to all accordions
    var $accordions = $('.ui-accordion-header');

    // turn jquery effects off for quick restoration (otherwise we'll have glitches
    $.fx.off = true;

    if (state === '' || $accordions.length !== state.length) { // if no state defined 
        // open all accordions by simulating a click on them
        $('.ui-accordion-header').not('.ui-state-active').trigger('click');
    } else { // otherwise
        for (var i = state.length - 1; i >= 0; --i) {
            var $accordion = $($accordions[i]);
            var c = state[i];
            // for every accordion that is in the opposite state
            if ((c === '1' && !$accordion.hasClass('ui-state-active')) ||
                (c === '0' && $accordion.hasClass('ui-state-active'))) {
                $accordion.trigger('click'); // simulate a click on its header to toggle it
            }
        }
    }
    // turn effects back on
    $.fx.off = false;
    // save the state
    saveAccordionsState();
    // assign the save state method to every accordion header click
    $('.ui-accordion-header', $featureTable).click(saveAccordionsState);
};

xhtml は次のようになります。

<h:form>
    <p:accordionPanel ... >
        <p:tab ... >
            <h:panelGroup ... >
                <p:accordionPanel ... >
                    <p:tab ... >
                        <h:panelGroup ... />
                    </p:tab>
                </p:accordionPanel>
            </h:panelGroup>
        </p:tab>
    </p:accordionPanel>
    <h:inputHidden id="accordionState" value="#{bean.accordionState}"/>
    <script type="text/javascript">
        init();
    </script>
</h:form>
于 2013-04-05T10:42:36.547 に答える