Pregunta

I am struggling with a problem related to multiple nested Twitter Boostrap3(TB3) accordion (or perhaps more appropriate KnockoutJs and templates (or maybe this is a trivial HTML problem)). The attached jsFiddle shows the problem in the second level of the accordion. When a City or a Person is opened, and the opposite is already opened, the one that was already opened is not closed automatically. For all other levels this works fine.

In the code, the problem is located in the two templates and specifically the "data-parent" and the use of "parentAccordionRef". The value of this variable points to an id outside the template. This is not working. Any suggestion?

jsFiddle code

<div class="panel-group" id="titleAccordion">
    <!-- ko foreach: Companies -->
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a data-toggle="collapse" data-parent="#titleAccordion" data-bind="attr: { href: '#companyDetails' + companyId }">
                    <span data-bind="html: name"></span>
                </a>
            </h4>
        </div>
        <div data-bind="attr: { id: 'companyDetails' + companyId }" class="panel-collapse collapse">
            <div class="panel-body">
                <div class="panel-group" data-bind="attr: { id: 'detailsCompany' + companyId }">
                    <div data-bind="template: { name: 'allPersons', data: { Persons: Persons, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } }"></div>
                    <div data-bind="template: { name: 'allCities', data: { Cities: Cities, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } }"></div>
                </div>
            </div>
        </div>
    </div>
    <!-- /ko -->
</div>

<script id="allPersons" type="text/html">

    <!-- ko if: Persons -->
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a class="accordion-toggle" data-toggle="collapse" data-bind="attr: { href: '#allPersonsTitle' + $parent.companyId, 'data-parent': $data.parentAccordionRef }">
                    <span>Persons</span>
                </a>
            </h4>
        </div>
        <div data-bind="attr: { id: 'allPersonsTitle' + $parent.companyId }" class="panel-collapse collapse">
            <div class="panel-body">
                <div class="panel-group" data-bind="attr: { id: 'personsGroup' + $parent.companyId }">
                    <!-- ko foreach: Persons -->
                    <div class="panel panel-default">
                        <div class="panel-heading">
                            <h4 class="panel-title">
                                <a class="accordion-toggle" data-toggle="collapse"
                                   data-bind="attr: { href: '#personDetail' + personId, 'data-parent': '#personsGroup' + $parent.companyId }">
                                    <span data-bind="html: name"></span>
                                </a>
                            </h4>
                        </div>
                        <div data-bind="attr: { id: 'personDetail' + personId }" class="panel-collapse collapse">
                            <div class="panel-body">
                                <span>Person details</span>
                            </div>
                        </div>
                    </div>
                    <!-- /ko -->
                </div>
            </div>
        </div>
    </div>
    <!-- /ko -->
</script>

<script id="allCities" type="text/html">
    <!-- ko if: Cities -->
    <div class="panel panel-default">
        <div class="panel-heading">
            <div class="panel-title">
                <a class="accordion-toggle" data-toggle="collapse" data-bind="attr: { href: '#allCitiesTitle' + $parent.companyId, 'data-parent': parentAccordionRef }">
                    <span>Cities</span>
                </a>
            </div>
        </div>
        <div data-bind="attr: { id: 'allCitiesTitle' + $parent.companyId }" class="panel-collapse collapse">
            <div class="panel-body">
                <div class="panel-group" data-bind="attr: { id: 'citiesGroup' + $parent.companyId }">
                    <!-- ko foreach: Cities -->
                    <div class="panel panel-default">
                        <div class="panel-heading">
                            <h4 class="panel-title">
                                <a class="accordion-toggle" data-toggle="collapse" data-bind="attr: { href: '#cityDetail' + cityId, 'data-parent': '#citiesGroup' + $parent.companyId }">
                                    <span data-bind="html: name"></span>
                                </a>
                            </h4>
                        </div>
                        <div data-bind="attr: { id: 'cityDetail' + cityId }" class="panel-collapse collapse">
                            <div class="panel-body">
                                <span>City details</span>
                            </div>
                        </div>
                    </div>
                    <!-- /ko -->
                </div>
            </div>
        </div>
    </div>
    <!-- /ko -->
</script>

<script>
    $(function () {

        var viewModel = {
            Companies: ko.observableArray([
                {
                    companyId: 1, name: 'Detox co', range: 1,
                    Persons: [{ personId: 1, name: 'Mr Mr', address: 'street 1' },
                              { personId: 2, name: 'Mrs Mrs', address: 'street 1' }],
                    Cities: [{ cityId: 1, name: 'London', address: 'street 1' },
                              { cityId: 2, name: 'Paris', address: 'street 1' }]

                },
                {
                    companyId: 2, name: 'Toxic world co', range: 2,
                    Persons: [{ personId: 3, name: 'Mr Green', address: 'street 2' },
                              { personId: 4, name: 'Mrs Green', address: 'street 2' }],
                    Cities: [{ cityId: 3, name: 'Madrid', address: 'street 1' },
                             { cityId: 4, name: 'Munchen', address: 'street 1' }]
                }
            ])
        };
        ko.applyBindings(viewModel);
    });
</script>
¿Fue útil?

Solución

Your issue is a result of an extra div between your panel-group and its contents. This extra div is created as a result of using the template. The placeholder of the template is still present after it replaces its contents.

You can reproduce this by adding an extra div between any of the working accordions in your example.

Unfortunately, the solution would be to not use templates.


Edit

You can use container-less template binding. (I just learned this myself!)

jsFiddle

Try replacing:

<div data-bind="template: { name: 'allPersons', data: { Persons: Persons, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } }"></div>
<div data-bind="template: { name: 'allCities', data: { Cities: Cities, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } }"></div>

With:

<!-- ko template: { name: 'allPersons', data: { Persons: Persons, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } } -->
<!-- /ko -->
<!-- ko template: { name: 'allCities', data: { Cities: Cities, companyId: companyId, parentAccordionRef: '#detailsCompany' + companyId } } -->
<!-- /ko -->
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top