web-dev-qa-db-fra.com

Quelle est une bonne façon de contrôler un accordéon angulaire-ui par programme?

J'utilise la directive accordéon de http://angular-ui.github.com/bootstrap/ et j'ai besoin d'avoir plus de contrôle sur le moment où les accordéons s'ouvrent et se ferment.

Pour être plus précis, j'ai besoin d'un bouton à l'intérieur du groupe d'accordéon qui fermera son accordéon parent et ouvrira le suivant (donc imitez essentiellement ce que cliquer sur l'en-tête suivant ferait si close-others était défini sur true). J'ai également besoin de faire une validation avant de permettre à un accordéon d'être fermé et au suivant d'être ouvert, et je dois également le câbler pour cliquer sur les événements sur les en-têtes d'accordéon.

Je suis assez nouveau pour angular et nous réécrivons actuellement une application de Backbone + JQuery vers Angular. Dans la version Backbone, nous utilisions Twitter Bootstrap accordéons et nous les ouvrions et les fermions à l'aide de JQuery. Bien que nous puissions continuer à le faire, je préférerais me débarrasser complètement de la manipulation de JQuery DOM, donc je recherche une solution angular angulaire à cela).

Ce que j'ai essayé de faire en termes de validation c'est

<accordion-group ng-click="close($event)">

et dans mon contrôleur

    event.preventDefault();
    event.stopPropagation();

Cela n'a évidemment pas fonctionné car l'élément DOM est remplacé par la directive et le gestionnaire de clics n'est jamais ajouté. J'ai parcouru le code source (et trouvé quelques fonctionnalités non documentées très agréables), mais je ne sais même pas par où commencer à résoudre ce défi spécifique. J'envisageais de bifurquer angular-ui et d'essayer d'ajouter cette fonctionnalité à la directive accordéon, mais si je peux y arriver sans modifier la directive, ce serait beaucoup plus agréable.

16
ivarni

Il y a le is-open attribut sur le accordion-group qui pointe vers une expression pouvant être liée. En utilisant cette expression, vous pouvez contrôler des articles d'accordéon par programme, par exemple:

<div ng-controller="AccordionDemoCtrl">
  <accordion>
    <accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
      {{group.content}}
    </accordion-group>    
  </accordion>
  <button class="btn" ng-click="groups[0].open = !groups[0].open">Toggle first open</button>
  <button class="btn" ng-click="groups[1].open = !groups[1].open">Toggle second open</button>
</div>

et le plunk de travail ici: http://plnkr.co/edit/DepnVH?p=preview

25

Pour qui que la solution de @ pkozlowski.opensource ne fonctionne pas (moi par exemple), vous pouvez simplement forcer le composant à accepter le CSS qui le fermera (sans transition c'est-à-dire).

The Theory: La directive angular se développe en HTML standard, principalement les éléments div, où les styles CSS lui donnent l'apparence de l'accordéon. Le div avec la classe .panel-collapse est le corps de l'élément groupe accordéon. Vous pouvez échanger sa deuxième classe de .in à .collapse ainsi que quelques autres modifications, comme indiqué ci-dessous.

Le code:

$scope.toggleOpen = function(project) {

        var id = '<The ID of the accordion-group you want to close>';
        var elements = angular.element($document[0].querySelector('#'+id));
        var children = elements.children();

        for(var i = 0; i < children.length; i++) {

            var child = angular.element(children[i]);

            if(child.hasClass('panel-collapse')) {
                if(child.hasClass('in')) { // it is open
                    child.removeClass('in');
                    child.addClass('collapse');
                    child.css('height', '0px');
                } else { // it is closed
                    child.addClass('in');
                    child.removeClass('collapse');
                    child.css('height', 'auto');
                }

            }
        }
    };

Comme nous parlons d'Angular, il est très possible que vous génériez l'accordéon via une balise ng-repeat. Dans ce cas, vous pouvez également générer les identifiants pour les éléments comme:

<accordion-group ng-repeat="user in users"
                 is-disabled="user.projects.length == 0"
                 id="USER{{user._id}}">

Étant donné un utilisateur du modèle Mongoose, notez que l'ID que je donne n'est pas user._id mais "USER" est ajouté devant. C'est parce que Mongoose peut générer des identifiants qui commencent numériquement et querySelector n'aime pas ça ;-) allez comprendre!

5
Mike M