【问题标题】:bootstrap accordion closes on buttonclick inside updatepanel引导手风琴在更新面板内单击按钮时关闭
【发布时间】:2016-01-02 23:36:41
【问题描述】:

我在一个页面上有一个引导 3.x 手风琴(折叠),我试图让用户能够添加/编辑大量信息而无需大量滚动。其中一些信息取决于其余信息,因此我在其中一个手风琴选项卡中有一个 UpdatePanel。要么更新面板没有正常工作,要么就是在其他方面无法很好地与手风琴配合使用。

这是基本的手风琴代码:

<div class="panel-group" id="ccAccordion" role="tablist" aria-multiselectable="true">
    <asp:Panel ID="pnlAddress" runat="server" class="panel panel-default">
        <div class="panel-heading" role="tab" id="billAddressHeading">
            <h4 class="panel-title">
                <a role="button" data-toggle="collapse" data-parent="#ccAccordion" href="#billToAddressTab" aria-expanded="false" aria-controls="billToAddressTab">
                    <asp:Literal ID="BillToAddressLabelTxt" runat="server" Text="Bill Address" />
                </a>
            </h4>
        </div>
        <div id="billToAddressTab" class="panel-collapse collapse" role="tabpanel" aria-labelledby="billAddressHeading">
            <div class="panel-body">
                <!-- Other controls -->
            </div>
        </div>
    </asp:Panel>
    <div class="panel panel-default">
        <div class="panel-heading" role="tab" id="thirdPartyHeading">
            <h4 class="panel-title">
                <a role="button" data-toggle="collapse" data-parent="#ccAccordion" href="#thirdPartyTab" aria-expanded="false" aria-controls="thirdPartyTab">
                    <asp:Literal ID="ThirdPartyShippingLabelTxt" runat="server" Text="Shipping Accounts" />
                </a>
            </h4>
        </div>
        <div id="thirdPartyTab" class="panel-collapse collapse" role="tabpanel" aria-labelledby="thirdPartyHeading">
            <div class="panel-body">
                <asp:UpdatePanel runat="server" UpdateMode="Always" ChildrenAsTriggers="true">
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="btnAddShipAccount" EventName="Click" />
                        <asp:AsyncPostBackTrigger ControlID="btnSaveSABA" EventName="Click" />
                        <asp:AsyncPostBackTrigger ControlID="btnAddShipAccountNo" EventName="Click" />
                    </Triggers>
                    <ContentTemplate>
                                        <asp:Button ID="btnAddShipAccount" runat="server" CssClass="btn btn-success" Text="Add New Shipping Account"
                                             OnClick="btnAddShipAccount_Click" /><!-- moved from inside panel -->
                        <asp:Panel ID="pnlBranchShipping" runat="server" DefaultButton="btnSaveSABA">
                            <div class="panel panel-default">
                                <div class="controls">
                                    <div class="form-group">
                                    <!-- Other controls -->
                                    </div>
                                    <asp:panel ID="pnlAddEditAcct" CssClass="controls" runat="server" Visible="false">
                                        <!-- Other controls -->
                                        <div>
                                            <asp:LinkButton ID="btnSaveSABA" Text="Save" runat="server" ValidationGroup="vgSAB" OnClick="btnSaveSABA_Click"
                                                CssClass="btn btn-default" />
                                        </div>
                                        <div class="form-group">
                                            <asp:Button ID="btnAddShipAccountNo" runat="server" CssClass="btn btn-default" Text="Add Shipping Account" OnClick="btnAddShipAccountNo_Click"
                                                ValidationGroup="vgShipAccount" />
                                        </div>
                                    </asp:panel>
                                </div>
                            </div>
                        </asp:Panel>

                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>
        </div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading" role="tab" id="vatHeading">
            <h4 class="panel-title">
                <a role="button" data-toggle="collapse" data-parent="#ccAccordion" href="#vatTab" aria-expanded="false" aria-controls="vatTab"> 
                    <asp:Literal ID="VatNumberLabelTxt" runat="server" Text="Tax Ids" />
                </a>
            </h4>
        </div>
        <div id="vatTab" class="panel-collapse collapse" role="tabpanel" aria-labelledby="vatHeading">
            <div class="panel-body">
                <asp:Panel ID="pnlTaxId" runat="server" class="form-group" DefaultButton="btnAddTaxId">
                <!-- Other controls -->
                </asp:Panel>
            </div>
        </div>
    </div>
</div>

当您单击其中的任何按钮时会发生什么情况,它基本上会刷新整个页面并且手风琴会恢复到其原始状态,但是当您打开按钮时,按钮所做的事情(例如显示其他字段)是可见的再次打开标签。

更新

我今天意识到上面的全部代码都在 MasterPage 中的另一个 UpdatePanel 中。此 UpdatePanel 具有所有默认设置,因此我上面代码中的回发触发了父级。我想要解决这个问题,我将不得不改变整个表单的运行方式。

【问题讨论】:

  • 你可以发布运行时 HTML(源代码)吗?我知道 ASP,但我不认为您希望我打开 VS、创建解决方案、创建自定义控件、编写后端代码、注入引导程序、调试并返回解决方案,是吗?大声笑 :) 如果您在 CODEPEN 或 JFiddle 中发布 HTML 会容易得多
  • 我把它放在 jsfiddle 中,但问题并没有在那里发生,因为回发 javascript 由于缺少底层的 ASP.NET 代码而被破坏。使用更多运行时标记和 javascript 的另一次尝试导致回发发生,但由于缺少后端,没有再次返回。也许我只是误解了 UpdatePanel 应该如何工作。

标签: asp.net twitter-bootstrap webforms


【解决方案1】:

我遇到了同样的问题并使用以下自定义代码来解决它。

(function (rc, $, undefined) {
(function (ui, $, undefined) {

    // #region Coordinator

    ui.updatePanelControlStateManagers = (function () {

        var managers = [];

        function UpdatePanelControlStateCoordinator() {
            $(function () {
                initialize(this);
            });
        }

        // #region Private

        function initialize(module) {
            Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(onBeginRequest);
            Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest);
        }

        function onBeginRequest(prm, e) {
            managers.forEach(function (m) {
                var updatePanels = e.get_updatePanelsToUpdate().map(function (v) { return $("[id$=" + v.substring(v.lastIndexOf("$") + 1) + "]"); });
                m.persistStates(updatePanels);
            });
        }

        function onEndRequest() {
            managers.forEach(function (m) {
                m.restoreStates();
            });
        }

        // #endregion

        // #region Public

        UpdatePanelControlStateCoordinator.prototype.add = function (instance) {
            managers.push(instance);
        };

        UpdatePanelControlStateCoordinator.prototype.remove = function (type) {
            var index = managers.findIndex(function (m) { return m instanceof type });

            if (index)
                managers = managers.splice(index, 1);
        };

        // #endregion

        return new UpdatePanelControlStateCoordinator();

    }());

    // #endregion

    // #region Managers

    ui.accordionControlStateManager = (function () {

        function AccordionControlStateManager() {
            this.states = [];
            this.scrollPosition = null;
        }

        // #region Public

        AccordionControlStateManager.prototype.persistStates = function (updatePanels) {
            var that = this;

            updatePanels.forEach(function (panel) {
                var $panel = $(panel);

                $panel.find(".panel-collapse").each(function (i, elem) {
                    var selector = rc.utilities.getNestedSelectorForElement(elem, $panel);
                    var expanded = $(elem).hasClass("in");

                    that.states.push({ selector: selector, expanded: expanded });
                });
            });

            this.scrollPosition = $(window).scrollTop();
        };

        AccordionControlStateManager.prototype.restoreStates = function () {
            this.states.forEach(function (state) {
                var $elem = $(state.selector);

                if ($elem.length)
                    $elem.toggleClass("in", state.expanded);
            });

            $(window).scrollTop(this.scrollPosition);

            this.scrollPosition = null;
            this.states = [];
        };

        // #endregion

        return AccordionControlStateManager;

    }());

    ui.tabsControlStateManager = (function () {

        function TabsControlStateManager() {
            this.states = [];
            this.scrollPosition = null;
        }

        // #region Public

        TabsControlStateManager.prototype.persistStates = function (updatePanels) {
            var that = this;

            updatePanels.forEach(function (panel) {
                var $panel = $(panel);

                $panel.find("ul.nav-tabs").each(function (i, elem) {
                    var selector = rc.utilities.getNestedSelectorForElement(elem, $panel);
                    var tab = $(elem).find("li.active a").attr("href");

                    that.states.push({ selector: selector, tab: tab });
                });
            });

            this.scrollPosition = $(window).scrollTop();
        };

        TabsControlStateManager.prototype.restoreStates = function () {
            this.states.forEach(function (state) {
                var $elem = $(state.selector);

                if ($elem.length)
                    $elem.find("li > a[href='" + state.tab + "']").tab("show");
            });

            $(window).scrollTop(this.scrollPosition);

            this.scrollPosition = null;
            this.states = [];
        };

        // #endregion

        return TabsControlStateManager;

    }());

    // #endregion

}(rc.ui = rc.ui || {}, $));
}(window.rc = window.rc || {}, jQuery));

其中引用了以下实用程序 js:

(function (rc, $, undefined) {
(function (utilities, $, undefined) {
    utilities.getSelectorForElement = function($elem) {
        var result = null,
            id = $elem.attr("id"),
            className = $elem[0].className,
            tagName = $elem[0].tagName;

        if (id) {
            result = "#" + id;
        } else if (className) {
            result = "." + className.replace(/\s/g, ".");
        } else {
            result = tagName;
        }

        if ($elem.parent().children(result).length > 1) {
            result = result + ":eq(" + $elem.index() + ")";
        }

        return result;
    }

    utilities.getNestedSelectorForElement = function (elem, $recurseTo) {
        var $elem = $(elem);

        if ($elem.is($recurseTo)) {
            return "";
        }

        var selector = utilities.getSelectorForElement($elem);
        var parentSelector = utilities.getNestedSelectorForElement($elem.parent(), $recurseTo);

        selector = parentSelector ? parentSelector + " > " + selector
                                  : selector;

        return selector;
    }

}(rc.utilities = rc.utilities || {}, $));
}(window.rc = window.rc || {}, jQuery));

并像这样初始化:

$(function() {
    rc.ui.updatePanelControlStateManagers.add(new rc.ui.accordionControlStateManager());
    rc.ui.updatePanelControlStateManagers.add(new rc.ui.tabsControlStateManager());
});

您可以为任何给您带来麻烦的控件(对我来说是选项卡和手风琴)创建一个自定义状态管理器,将其连接到您的初始化逻辑中,然后在任何更新面板中进行处理。

【讨论】:

  • 哇,这比我使用的实际解决方案复杂得多……我最终找到了一些东西。我会在我的 cmets 中发布一个链接。
  • 真的没那么糟糕。我想要一个可扩展的系统,允许我创建多个状态管理器(它得到了回报,因为我最终需要它来处理选项卡和手风琴)。否则,可以提取仅手风琴的逻辑并且它会小得多。请务必分享你所拥有的。
  • 用我的解决方案添加了答案。
【解决方案2】:

我实际上最终使用了这个答案中的解决方案:https://stackoverflow.com/a/25258290/727857

这同样适用于 Bootstrap 3.x.x,需要来自 https://github.com/carhartl/jquery-cookie 的 jquery-cookie.js

编辑以添加上面答案的全文,以防链接失效:

手风琴的 HTML 示例:

<div class="panel-group" id="accordion">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">Collapsible Group
                    Item #1 </a>
            </h4>
        </div>
        <div id="collapseOne" class="panel-collapse collapse in">
            <div class="panel-body">
                Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson
                ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food
                truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put
                a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim
                keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
                Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table,
                raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
                labore sustainable VHS.
            </div>
        </div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo">Collapsible Group
                    Item #2 </a>
            </h4>
        </div>
        <div id="collapseTwo" class="panel-collapse collapse">
            <div class="panel-body">
                Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson
                ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food
                truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put
                a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim
                keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
                Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table,
                raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
                labore sustainable VHS.
            </div>
        </div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a data-toggle="collapse" data-parent="#accordion" href="#collapseThree">Collapsible
                    Group Item #3 </a>
            </h4>
        </div>
        <div id="collapseThree" class="panel-collapse collapse">
            <div class="panel-body">
                Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson
                ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food
                truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put
                a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim
                keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
                Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table,
                raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
                labore sustainable VHS.
            </div>
        </div>
    </div>
</div>

Javascript (jquery) 保留此手风琴中选项卡的状态:

$(document).ready(function () {
        //when a group is shown, save it as the active accordion group
        $("#accordion").on('shown.bs.collapse', function () {
            var active = $("#accordion .in").attr('id');
            $.cookie('activeAccordionGroup', active);
          //  alert(active);
        });
        $("#accordion").on('hidden.bs.collapse', function () {
            $.removeCookie('activeAccordionGroup');
        });
        var last = $.cookie('activeAccordionGroup');
        if (last != null) {
            //remove default collapse settings
            $("#accordion .panel-collapse").removeClass('in');
            //show the account_last visible group
            $("#" + last).addClass("in");
        }
    });

我不知道 dshapiro 的答案是否有效或更好,但这是更少的 javascript,可以很容易地制成一个可在不同页面上重复的函数。

【讨论】:

  • 虽然这在理论上可以回答问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
  • 如果您需要在页面访问之间保持状态,因为它使用 cookie,这将是一个很好的解决方案。在更新面板中处理手风琴时可能不是典型的要求,但它可能是。
  • 已更正以包含原始答案中的文本。不是想把别人的功劳归功于自己。
  • 我不知道,但这快速、有效、存在并且不需要大量编码。 cookie 将在用户浏览器会话结束时过期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
  • 1970-01-01
相关资源
最近更新 更多