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 帖子/so 页面后,这就是我所期望的)

<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. 发布数据
    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=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. 以下 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=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 值,您需要对手风琴面板进行处理,您只需在顶级手风琴面板<p:ajax/>内添加一个空的 p:ajax 标记 ()即可完成此操作。”

不幸的是,这不起作用(尝试了每种组合外部,内部,都+带&不带activeIndex)。

但这确实

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

  • 在外部:

    <p:ajax event="tabChange"/>
    

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

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

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

    这意味着在我的情况下,更改内部选项卡状态时只需要重新渲染整个表单

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

也可以在primefaces 论坛上找到

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