web-dev-qa-db-fra.com

Modification de DOM (slideDown / slideUp) avec AngularJS et jQuery

J'essaie d'implémenter une animation slideDown/slideUp avec AngularJS. Je ne peux pas utiliser la transition de CSS3 (malheureusement) car le height est réglé sur auto (et je ne veux pas utiliser le max-height solution ), donc j'essaie d'utiliser la méthode slideToggle de jQuery.

Étant donné le balisage suivant:

<ul>
    <li ng-repeat="entry in data">
        <span>{{entry.title}}</span>
        <a ng-click="clicked($event)" href>more?</a>
        <p>{{entry.description}}</p>
    </li>
</ul>

J'ai implémenté la méthode suivante dans mon contrôleur:

$scope.clicked = function($event) {
    var a = jQuery($event.target);
    var p = a.next();
    p.slideToggle();
};

[~ # ~] violon [~ # ~]

Même si cela semble fonctionner comme prévu, j'ai compris que la modification du DOM se fera exclusivement dans les directives.

Après avoir lu documentation d'AngularJS (ce que je trouve un peu léger à mon humble avis), les directives sont encore un peu vagues pour moi, donc quelqu'un pourrait-il me dire si la directive suivante respecte les meilleures pratiques d'AngularJS ou pas?

.directive('testDirective', [
function() {
    return {
        restrict: 'A',
        scope: {
            entry: '=testDirective'
        },
        template: '<span>{{entry.title}}</span> ' +
                  '<a ng-click="clicked($event)" href>more?</a>' +
                  '<p>{{entry.description}}</p>',
        link: function(scope, element) {
            var p = jQuery(element.find('p'));
            scope.clicked = function($event) {
                p.slideToggle();
            };
        }
    };
}])

[~ # ~] violon [~ # ~]

Pourrait-il être amélioré? Suis-je autorisé pour utiliser jQuery dans une directive? Respecte-t-il la séparation des préoccupations?

20
sp00m

Alternativement, vous pouvez utiliser le $animate D'AngularJS:

.animation('.slide', function() {
    var NG_HIDE_CLASS = 'ng-hide';
    return {
        beforeAddClass: function(element, className, done) {
            if(className === NG_HIDE_CLASS) {
                element.slideUp(done); 
            }
        },
        removeClass: function(element, className, done) {
            if(className === NG_HIDE_CLASS) {
                element.hide().slideDown(done);
            }
        }
    }
});

Utilisez ng-hide Ou ng-show Pour afficher ou masquer la description.

    <li ng-repeat="entry in data">
        <span>{{entry.title}}</span>
        <a ng-click="expand = !expand" href="#">more?</a>
        <p class="slide" ng-show="expand">{{entry.description}}</p>
    </li>

Voir JSFiddle

P.S. vous devez inclure jquery et angular-animate.js

40
LostInComputer

Je veux montrer un exemple de la façon dont cela se fait avec ng-if, car je cherchais une solution pendant des heures dans plusieurs approches complètement différentes qui fonctionnent avec ng-show seulement. Vous pouvez utiliser ng-if contre ng-show si vous avez besoin de directives initialisées uniquement lorsqu'elles deviennent visibles.

Pour utiliser jQuery slideDown/slideUp avec ng-if, vous pouvez également utiliser ngAnimate mais en utilisant différents crochets: enter et leave.

app.animation('.ng-slide-down', function() {
  return {
    enter: function(element, done) {
      element.hide().slideDown()
      return function(cancelled) {};
    },
    leave: function(element, done) { 
      element.slideUp();
    },
  };
});

<div class="ng-slide-down" ng-if="isVisible">
     I will slide down upon entering the DOM.
</div>

Cela a été étonnamment difficile à réaliser, même en essayant diverses approches basées sur JS et uniquement des approches CSS. En fin de compte, il y a un temps et un lieu pour les animations de jQuery.

8