最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - bootstrap collapse event hidden.bs.collapse not being detected - Stack Overflow

programmeradmin0浏览0评论

I have an angular application that uses bootstrap collapse element. I've created a directive called accordion-list that host the collapsible elements. Then, to listen to the events, i've used jquery event delegation. For some reason, my application can't detect when the bootstrap fires the hidden.bs.collapse event. Here is my code:

//app.js
    'use strict';

(function () {
    var provasNaoIdentificadas = angular.module("provasNaoIdentificadas", [
        'restClient'
    ]);

    provasNaoIdentificadas.controller("accordionCtrl", ["$scope", "ListaInscricao", function($scope, ListaInscricao){
        $scope.inscricao = {
            "Secretaria": ""
        };

        $("accordion-list").on("hidden.bs.collapse shown.bs.collapse", ".collapse", function (event) {
            if ($(this).hasClass("in")) {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-minus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("fechar");
            } else {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-plus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("expandir");
            }

            console.log(1, this, event); // i have detected the problem by interpreting 
        });

        ListaInscricao.get({"id": 1}, function(data){
            if (data.Sucesso) {
                $scope.inscricao = data.Dados;
            } else {
                // toastr
            }
        });
    }]);

    provasNaoIdentificadas.directive('accordionList', function() {
        return {
            "restrict": "E",
            "templateUrl": "partials/accordion.html"
        };
    });
})();

Help you guys can help me. Thanks in advance. :)

EDIT

Here's my files:

index.html:

<!-- index.html -->
<!DOCTYPE html>
<html ng-app="provasNaoIdentificadas">
    <head>
        <title>Hábile: Inscrição De Escolas Públicas Para Provas Não Identificadas</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
        <link rel="stylesheet" href="css/vendor/bootstrap.min.css" />
        <script src="js/vendor/jquery-1.11.1.min.js"></script>
        <script src="js/vendor/bootstrap.min.js"></script>
        <script src="js/vendor/angular.min.js"></script>
        <script src="js/vendor/angular-resource.min.js"></script>
        <script src="js/app.js"></script>
        <script src="js/rest-client.js"></script>
        <style>
            .panel-heading {
                cursor: pointer;
            }

            .panel-heading .panel-title span.pull-right.text-muted {
                font-size: 10px;
            }

            .panel-heading .panel-title span.pull-right.text-muted.expandir:before {
                content: "clique para expandir";
            }

            .panel-heading .panel-title span.pull-right.text-muted.fechar:before {
                content: "clique para fechar";
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="well text-justify">
                <h3>Formul&aacute;rio de Inscri&ccedil;&atilde;o H&aacute;bile 2014</h3>
            </div>
            <div ng-controller="accordionCtrl">
                <h2 id="nomeSecretaria">{{ inscricao.Secretaria }}</h2>
                <accordion-list></accordion-list>
            </div>
            <div class="text-center">
                <button type="button" class="btn btn-lg btn-primary">Salvar Inscrição</button>
                <button type="button" class="btn btn-lg btn-warning">Finalizar Inscrição</button>
            </div>
        </div>
    </body>
</html>

partials/accordion.html

<!-- partials/accordion.html -->
<div class="panel-group" id="accordion_escolas">
    <div class="panel panel-default" ng-repeat="escola in inscricao.Escolas">
        <div class="panel-heading" data-toggle="collapse" data-target="#escola{{ $index }}" data-parent="#accordion_escolas">
            <div class="panel-title">
                <span class="glyphicon glyphicon-plus"></span>
                {{ escola.Nome }} <span class="text-muted">x alunos inscritos</span>
                <span class="pull-right text-muted expandir"></span>
            </div>
        </div>
        <div id="escola{{ $index }}" class="panel-collapse collapse">
            <div class="panel-body">
                <p>
                    <label for="qtdProfessoresEscola{{ $index }}">Qtd. Professores</label><br />
                    <input class="form-control" type="text" id="qtdProfessoresEscola{{ $index }}}}" value="{{ escola.QtdProfessores }}" />
                </p>
                <div class="panel-group" id="accordion_escola{{ $index }}">
                    <div class="panel panel-default" ng-repeat="serie in escola.Series">
                        <div class="panel-heading" data-toggle="collapse" data-target="#turma_{{ $index }}_escola{{ $parent.$index }}" data-parent="#accordion_escola{{ $parent.$index }}">
                            <div class="panel-title">
                                <span class="glyphicon glyphicon-plus"></span>
                                {{ serie.Nome }} <span class="text-muted">y alunos inscritos</span>
                                <span class="pull-right text-muted expandir"></span>
                            </div>
                        </div>
                        <div id="turma_{{ $index }}_escola{{ $parent.$index }}" class="panel-collapse collapse">
                            <div class="panel-body">
                                <table class="table table-hover table-condensed table-bordered">
                                    <thead>
                                        <tr>
                                            <th>Turma</th>
                                            <th>Qtd Alunos</th>
                                            <th>Qtd Testes A3</th>
                                            <th>Alunos PCD</th>
                                            <th></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr ng-repeat="turma in serie.Turmas">
                                            <td>{{ turma.Nome }}</td>
                                            <td><input class="form-control" type="text" value="{{ turma.QtdAlunos }}" /></td>
                                            <td><input class="form-control" type="text" value="{{ turma.QtdTestesA3 }}" /></td>
                                            <td><input class="form-control" type="text" value="{{ turma.AlunosPCD }}" /></td>
                                            <td><button class="btn btn-primary btn-sm" type="button">Excluir Turma</button></td>
                                        </tr>
                                    </tbody>
                                </table>
                                <p>
                                    <button class="btn btn-primary" type="button">Adicionar Turma</button>
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

js/app.js:

/* js/app.js */
'use strict';

(function () {
    var provasNaoIdentificadas = angular.module("provasNaoIdentificadas", [
        'restClient'
    ]);

    provasNaoIdentificadas.controller("accordionCtrl", ["$scope", "ListaInscricao", function($scope, ListaInscricao){
        $scope.inscricao = {
            "Secretaria": ""
        };

        $("accordion-list").on("hidden.bs.collapse shown.bs.collapse", ".collapse", function (event) {
            if ($(this).hasClass("in")) {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-minus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("fechar");
            } else {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-plus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("expandir");
            }

            console.log(1, this, event);
        });

        ListaInscricao.get({"id": 1}, function(data){
            if (data.Sucesso) {
                $scope.inscricao = data.Dados;
            } else {
                // toastr
            }
        });
    }]);

    provasNaoIdentificadas.directive('accordionList', function() {
        return {
            "restrict": "E",
            "templateUrl": "partials/accordion.html"
        };
    });
})();

js/rest-client.js:

/* js/rest-client.js */
'use strict';

(function(){
    var restClient = angular.module('restClient', ['ngResource']);

    restClient.factory('ListaInscricao', ['$resource', function ($resource) {
        return $resource('mock/lista_inscricao.json');
    }]);
})();

mock/lista_inscricao.json:

{
    "Sucesso": true
    ,
    "Mensagem": ""
    ,
    "Dados": {
        "Secretaria": "Secretaria de Educação ABC"
        ,
        "Escolas": [
            {
                "Nome": "Escola 1"
                ,
                "QtdProfessores": 12
                ,
                "Series": [
                    {
                        "Nome": "1º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 30
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": "27,29"
                            }
                            , {
                                "Nome": "B"
                                ,
                                "QtdAlunos": 28
                                ,
                                "QtdTestesA3": 2
                                ,
                                "AlunosPCD": ""
                            }
                        ]
                    }
                    ,
                    {
                        "Nome": "2º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 25
                                ,
                                "QtdTestesA3": 1
                                ,
                                "AlunosPCD": "7"
                            }
                        ]
                    }
                ]
            }
            ,
            {
                "Nome": "Escola 2"
                ,
                "QtdProfessores": 10
                ,
                "Series": [
                    {
                        "Nome": "3º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 30
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": "15,27"
                            }
                            , {
                                "Nome": "B"
                                ,
                                "QtdAlunos": 26
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": ""
                            }
                            , {
                                "Nome": "C"
                                ,
                                "QtdAlunos": 25
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": ""
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

I have an angular application that uses bootstrap collapse element. I've created a directive called accordion-list that host the collapsible elements. Then, to listen to the events, i've used jquery event delegation. For some reason, my application can't detect when the bootstrap fires the hidden.bs.collapse event. Here is my code:

//app.js
    'use strict';

(function () {
    var provasNaoIdentificadas = angular.module("provasNaoIdentificadas", [
        'restClient'
    ]);

    provasNaoIdentificadas.controller("accordionCtrl", ["$scope", "ListaInscricao", function($scope, ListaInscricao){
        $scope.inscricao = {
            "Secretaria": ""
        };

        $("accordion-list").on("hidden.bs.collapse shown.bs.collapse", ".collapse", function (event) {
            if ($(this).hasClass("in")) {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-minus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("fechar");
            } else {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-plus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("expandir");
            }

            console.log(1, this, event); // i have detected the problem by interpreting 
        });

        ListaInscricao.get({"id": 1}, function(data){
            if (data.Sucesso) {
                $scope.inscricao = data.Dados;
            } else {
                // toastr
            }
        });
    }]);

    provasNaoIdentificadas.directive('accordionList', function() {
        return {
            "restrict": "E",
            "templateUrl": "partials/accordion.html"
        };
    });
})();

Help you guys can help me. Thanks in advance. :)

EDIT

Here's my files:

index.html:

<!-- index.html -->
<!DOCTYPE html>
<html ng-app="provasNaoIdentificadas">
    <head>
        <title>Hábile: Inscrição De Escolas Públicas Para Provas Não Identificadas</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
        <link rel="stylesheet" href="css/vendor/bootstrap.min.css" />
        <script src="js/vendor/jquery-1.11.1.min.js"></script>
        <script src="js/vendor/bootstrap.min.js"></script>
        <script src="js/vendor/angular.min.js"></script>
        <script src="js/vendor/angular-resource.min.js"></script>
        <script src="js/app.js"></script>
        <script src="js/rest-client.js"></script>
        <style>
            .panel-heading {
                cursor: pointer;
            }

            .panel-heading .panel-title span.pull-right.text-muted {
                font-size: 10px;
            }

            .panel-heading .panel-title span.pull-right.text-muted.expandir:before {
                content: "clique para expandir";
            }

            .panel-heading .panel-title span.pull-right.text-muted.fechar:before {
                content: "clique para fechar";
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="well text-justify">
                <h3>Formul&aacute;rio de Inscri&ccedil;&atilde;o H&aacute;bile 2014</h3>
            </div>
            <div ng-controller="accordionCtrl">
                <h2 id="nomeSecretaria">{{ inscricao.Secretaria }}</h2>
                <accordion-list></accordion-list>
            </div>
            <div class="text-center">
                <button type="button" class="btn btn-lg btn-primary">Salvar Inscrição</button>
                <button type="button" class="btn btn-lg btn-warning">Finalizar Inscrição</button>
            </div>
        </div>
    </body>
</html>

partials/accordion.html

<!-- partials/accordion.html -->
<div class="panel-group" id="accordion_escolas">
    <div class="panel panel-default" ng-repeat="escola in inscricao.Escolas">
        <div class="panel-heading" data-toggle="collapse" data-target="#escola{{ $index }}" data-parent="#accordion_escolas">
            <div class="panel-title">
                <span class="glyphicon glyphicon-plus"></span>
                {{ escola.Nome }} <span class="text-muted">x alunos inscritos</span>
                <span class="pull-right text-muted expandir"></span>
            </div>
        </div>
        <div id="escola{{ $index }}" class="panel-collapse collapse">
            <div class="panel-body">
                <p>
                    <label for="qtdProfessoresEscola{{ $index }}">Qtd. Professores</label><br />
                    <input class="form-control" type="text" id="qtdProfessoresEscola{{ $index }}}}" value="{{ escola.QtdProfessores }}" />
                </p>
                <div class="panel-group" id="accordion_escola{{ $index }}">
                    <div class="panel panel-default" ng-repeat="serie in escola.Series">
                        <div class="panel-heading" data-toggle="collapse" data-target="#turma_{{ $index }}_escola{{ $parent.$index }}" data-parent="#accordion_escola{{ $parent.$index }}">
                            <div class="panel-title">
                                <span class="glyphicon glyphicon-plus"></span>
                                {{ serie.Nome }} <span class="text-muted">y alunos inscritos</span>
                                <span class="pull-right text-muted expandir"></span>
                            </div>
                        </div>
                        <div id="turma_{{ $index }}_escola{{ $parent.$index }}" class="panel-collapse collapse">
                            <div class="panel-body">
                                <table class="table table-hover table-condensed table-bordered">
                                    <thead>
                                        <tr>
                                            <th>Turma</th>
                                            <th>Qtd Alunos</th>
                                            <th>Qtd Testes A3</th>
                                            <th>Alunos PCD</th>
                                            <th></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr ng-repeat="turma in serie.Turmas">
                                            <td>{{ turma.Nome }}</td>
                                            <td><input class="form-control" type="text" value="{{ turma.QtdAlunos }}" /></td>
                                            <td><input class="form-control" type="text" value="{{ turma.QtdTestesA3 }}" /></td>
                                            <td><input class="form-control" type="text" value="{{ turma.AlunosPCD }}" /></td>
                                            <td><button class="btn btn-primary btn-sm" type="button">Excluir Turma</button></td>
                                        </tr>
                                    </tbody>
                                </table>
                                <p>
                                    <button class="btn btn-primary" type="button">Adicionar Turma</button>
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

js/app.js:

/* js/app.js */
'use strict';

(function () {
    var provasNaoIdentificadas = angular.module("provasNaoIdentificadas", [
        'restClient'
    ]);

    provasNaoIdentificadas.controller("accordionCtrl", ["$scope", "ListaInscricao", function($scope, ListaInscricao){
        $scope.inscricao = {
            "Secretaria": ""
        };

        $("accordion-list").on("hidden.bs.collapse shown.bs.collapse", ".collapse", function (event) {
            if ($(this).hasClass("in")) {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-minus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("fechar");
            } else {
                $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-plus");
                $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("expandir");
            }

            console.log(1, this, event);
        });

        ListaInscricao.get({"id": 1}, function(data){
            if (data.Sucesso) {
                $scope.inscricao = data.Dados;
            } else {
                // toastr
            }
        });
    }]);

    provasNaoIdentificadas.directive('accordionList', function() {
        return {
            "restrict": "E",
            "templateUrl": "partials/accordion.html"
        };
    });
})();

js/rest-client.js:

/* js/rest-client.js */
'use strict';

(function(){
    var restClient = angular.module('restClient', ['ngResource']);

    restClient.factory('ListaInscricao', ['$resource', function ($resource) {
        return $resource('mock/lista_inscricao.json');
    }]);
})();

mock/lista_inscricao.json:

{
    "Sucesso": true
    ,
    "Mensagem": ""
    ,
    "Dados": {
        "Secretaria": "Secretaria de Educação ABC"
        ,
        "Escolas": [
            {
                "Nome": "Escola 1"
                ,
                "QtdProfessores": 12
                ,
                "Series": [
                    {
                        "Nome": "1º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 30
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": "27,29"
                            }
                            , {
                                "Nome": "B"
                                ,
                                "QtdAlunos": 28
                                ,
                                "QtdTestesA3": 2
                                ,
                                "AlunosPCD": ""
                            }
                        ]
                    }
                    ,
                    {
                        "Nome": "2º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 25
                                ,
                                "QtdTestesA3": 1
                                ,
                                "AlunosPCD": "7"
                            }
                        ]
                    }
                ]
            }
            ,
            {
                "Nome": "Escola 2"
                ,
                "QtdProfessores": 10
                ,
                "Series": [
                    {
                        "Nome": "3º Ano Ensino Médio"
                        ,
                        "Turmas": [
                            {
                                "Nome": "A"
                                ,
                                "QtdAlunos": 30
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": "15,27"
                            }
                            , {
                                "Nome": "B"
                                ,
                                "QtdAlunos": 26
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": ""
                            }
                            , {
                                "Nome": "C"
                                ,
                                "QtdAlunos": 25
                                ,
                                "QtdTestesA3": 0
                                ,
                                "AlunosPCD": ""
                            }
                        ]
                    }
                ]
            }
        ]
    }
}
Share Improve this question edited Oct 27, 2014 at 15:32 asked Oct 24, 2014 at 21:55 user3303864user3303864 5
  • Is it collapsing on the page? Are you sure the event is fired? – Andreas Furster Commented Oct 27, 2014 at 12:43
  • it is collapsing, but the event is not logged in the console and it is not changing the collapsible icon when it closes the accordion – user3303864 Commented Oct 27, 2014 at 12:44
  • I think your problem is in your html code. Can you post it or make a fiddle? – Andreas Furster Commented Oct 27, 2014 at 12:46
  • done :) I've posted the code – user3303864 Commented Oct 27, 2014 at 15:35
  • It's an old question but I've used the MutationObserver to listen to class changes on both the target as the trigger. developer.mozilla.org/en-US/docs/Web/API/MutationObserver – Nullius Commented Dec 7, 2022 at 16:29
Add a comment  | 

2 Answers 2

Reset to default 10

for now, I've just changed my event listener. For some reason, jquery can't hear the hidden.bs.collapse. I've noticed that the click event is not suitable for this case, because if you click fast enough, you can end with a closed accordion and a minus icon on it. So, I've changed the event listener to:

$(document).on("hide.bs.collapse show.bs.collapse", ".collapse", function (event) {
    $(this).prev().find(".glyphicon").toggleClass("glyphicon-plus glyphicon-minus");
    $(this).prev().find("span.pull-right.text-muted").toggleClass("expandir fechar");
    event.stopPropagation();
});

This is working pretty well. But, as bhantol said, it not quite the angularjs way of doing things. The one with a better solution win the prize xD

We don't use jquery code in Controllers.

Controllers are not the right place for DOM manipulation.

Directives are what you need for DOM manipulation.

Also in AngularJS we generally don't use jQuery eventing programming style.

Here is approximate plunker of your orignial code. If I understand correctly you re trying to toggle the state of glyphicon state + and - using the code below:-

$("accordion-list").on("hidden.bs.collapse shown.bs.collapse", ".collapse", function (event) {
    if ($(this).hasClass("in")) {
        (this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-minus");
        $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("fechar");
    } else {
        $(this).prev().find(".glyphicon").removeClass("glyphicon-plus glyphicon-minus").addClass("glyphicon-plus");
        $(this).prev().find("span.pull-right.text-muted").removeClass("expandir fechar").addClass("expandir");
    }

    console.log(1, this, event); // i have detected the problem by interpreting 
 });

Click here for the solution plunker.

The solution is all in accordion.html notice ng-model however I hace commented out your jquery code in the controller.

ng-model="collapseState"

this is to hold the state.

then further notice

<span class="glyphicon" 
    ng-class="collapseState[$index] ? 'glyphicon-minus' : 'glyphicon-plus'">
</span>

here we choose the class based on the value of collapseState[$index].

Also notice ng-click which basically toggles the value of collapseState[$index]

ng-click="collapseState[$index]= !collapseState[$index]"

So far what we have done is used a model and altered the view by manipulating the model. This is the gist of AngularJS way.

发布评论

评论列表(0)

  1. 暂无评论