为什么嵌套的动态手风琴面板在@form rerender上丢失了activeIndex信息?

时间:2013-04-04 07:31:33

标签: ajax jsf primefaces accordion

我有以下结构

<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回发中使用&amp;从内部选项卡和内部选项卡中重新渲染来自整个层级的外部:

<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}"...

任何人都可以确认第二种方法是唯一的方法吗?或者我在第一种情况下做错了什么?

Primefaces 3.4.2

Glassfish堆栈 3.1.2.2

更新05.04.2013

后一种方法也不起作用。因为在ajax POST node.activeIndex接收值""(并且只正确设置了根活动索引)

数据方案(POST数据详情)

  1. 加载页面。
  2. 打开前两个外部标签。
  3. 从第二个外部标签打开前两个内部标签。
  4. 点击页面中的元素
  5. POST数据
  6.     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=change
        gridDetailPage=gridDetailPage
        j_idt106:j_idt271:1:j_idt121:j_idt110_active=0,1   // INNER OPEN TABS
        j_idt106:j_idt271_active=0,1                       // OUTER OPEN TABS
        javax.faces.ViewState=4232962649695633063:-8633977119414123467
    
    1. 呈现的页面具有前两个外部选项卡,第二个外部选项卡中的第一个内部选项卡打开(错误)
    2. 以下POST仅发布当前(错误)配置
    3. 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=change
      gridDetailPage=gridDetailPage
      j_idt106:j_idt271:1:j_idt121:j_idt110_active=0   // INNER OPEN TABS
      j_idt106:j_idt271_active=0,1                     // OUTER OPEN TABS
      javax.faces.ViewState=4232962649695633063:-8633977119414123467
      

1 个答案:

答案 0 :(得分:2)

andyba

提出的解决方案

“为了确保传播activeIndex值,您需要勾选accordionPanel,只需在顶部添加一个空的p:ajax标记(<p:ajax/>)即可。等级accordionPanel 和这项工作。“

不幸的是,这不起作用(尝试每个组合外部,内部,两个+与&amp;没有activeIndex)。

但这确实

  • 无需设置activeIndex,这没关系,因为在服务器端我对索引不感兴趣):

  • 在外面:

    <p:ajax event="tabChange"/>
    

    (基本上是您的解决方案的限制形式

  • 在内部手风琴中我添加了:

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

    这意味着在我的情况下,只有整个表单重新呈现才能更改内部选项卡状态

不幸的是,由于页面结构复杂,这会增加难看的闪烁。我希望我可以在tabchange上没有ajax的情况下解决它。

也可在primefaces forum

找到

更新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>