web-dev-qa-db-fra.com

AngularJS accédant à des éléments DOM dans un modèle de directive

Existe-t-il un moyen plus "angulaire" de sélectionner des éléments DOM dans un modèle de directive? Par exemple, supposons que vous ayez cette directive:

app.directive("myDirective", function() {
    return {
        template: '<div><ul><li ng-repeat="item in items"></ul></div>',
        link: function(scope, element, attrs) {
            var list = element.find("ul");
        }
    }
});

J'ai utilisé le sélecteur de style jQuery pour mettre la main sur le DOM <ul> élément rendu dans mon modèle. Y a-t-il une meilleure manière de faire cela?

64
Dustin

Vous pouvez écrire une directive pour cela, qui affecte simplement l'élément (jqLite) à la portée en utilisant un nom attribué à un attribut.

Voici la directive:

app.directive("ngScopeElement", function () {
  var directiveDefinitionObject = {

    restrict: "A",

    compile: function compile(tElement, tAttrs, transclude) {
      return {
          pre: function preLink(scope, iElement, iAttrs, controller) {
            scope[iAttrs.ngScopeElement] = iElement;
          }
        };
    }
  };

  return directiveDefinitionObject;
});

Usage:

app.directive("myDirective", function() {
    return {
        template: '<div><ul ng-scope-element="list"><li ng-repeat="item in items"></ul></div>',
        link: function(scope, element, attrs) {
            scope.list[0] // scope.list is the jqlite element, 
                          // scope.list[0] is the native dom element
        }
    }
});

Quelques remarques:

  • En raison de ordre de compilation et de liaison pour les directives imbriquées , vous ne pouvez accéder qu'à scope.list de myDirectives postLink-Function, que vous utiliserez très probablement de toute façon
  • ngScopeElement utilise une fonction preLink, de sorte que les directives imbriquées dans l'élément ayant ng-scope-element peut déjà accéder à scope.list
  • je ne sais pas comment cela se comporte en termes de performances
40
CodeSalad

Je ne pense pas qu'il existe un "moyen angulaire" de sélectionner un élément. Voir, par exemple, comment ils atteignent cet objectif dans le dernier exemple de cette ancienne page de documentation :

{
     template: '<div>' +
    '<div class="title">{{title}}</div>' +
    '<div class="body" ng-transclude></div>' +
    '</div>',

    link: function(scope, element, attrs) {
        // Title element
        var title = angular.element(element.children()[0]),
        // ...
    }
}
47
Blackhole

Cette réponse arrive un peu en retard, mais mon besoin était le même.

En observant les commentaires écrits par @ganaraj dans la question, un cas d’utilisation dont j’avais besoin était de passer un nom de classe via un attribut de directive à ajouter à une balise ng-repeat li dans le modèle.

Par exemple, utilisez la directive comme ceci:

<my-directive class2add="special-class" />

Et obtenez le code HTML suivant:

<div>
    <ul>
       <li class="special-class">Item 1</li>
       <li class="special-class">Item 2</li>
    </ul>
</div>

La solution trouvée ici appliquée avec templateUrl serait:

app.directive("myDirective", function() {
    return {
        template: function(element, attrs){
            return '<div><ul><li ng-repeat="item in items" class="'+attrs.class2add+'"></ul></div>';
        },
        link: function(scope, element, attrs) {
            var list = element.find("ul");
        }
    }
});

Juste essayé avec succès avec AngularJS 1.4.9.

J'espère que ça aide.

5
Gerardo Camacho