web-dev-qa-db-fra.com

Définir la fonction à l'intérieur Angular directive portée isolée

J'écris une directive personnalisée <pagination>, qui renvoie les éléments responsables de la modification des paramètres de page et de pagination actuels (par exemple, le nombre d'éléments affichés par page). La directive a une portée isolée (pour la rendre plus réutilisable).

À l'intérieur du modèle de directive, je dois appeler des fonctions telles que changePage() ou changePaginationSettings(). Le seul moyen de passer une fonction dans la portée isolée que j'ai trouvée jusqu'à présent est de définir la fonction dans le contrôleur.

mainController.js

module.controller("mainController", function($scope) {
    $scope.changePage = function() { ... };
});

puis transmettez-le à la directive en tant qu'attribut:

pagination.js

module.directive("pagination", function() {
    return {
        restrict: "E",
        scope: {
           changePage: "="
        },
        templateUrl: "templates/pagination.html"
    }
}

pagination.html

<pagination change-page="changePage">

Cela me semble très moche, car il divise le code associé en 2 fichiers indépendants. La fonction changePage() doit donc être définie dans le fichier pagination.js, et non dans mainController.js.

Je pense que quelque chose comme ça devrait être possible:

pagination.js

module.directive("pagination", function() {
    function changePage() { ... };

    return {
        restrict: "E",
        scope: {
           changePage: changePage
        },
        templateUrl: "templates/pagination.html"
    }
}

Mais un tel code produit une erreur (sans signification pour moi): Error: definition.match is not a function.

Y a-t-il un moyen d'y parvenir? Je veux passer une fonction définie dans le même fichier dans un champ d'application isolé de la directive.

J'ai lu AngularJS Directive Docs mais ils ne répertorient même pas les valeurs légales dans scope objet d'une directive, ne donnent que des exemples "=", "&" et "@".

10
Robert Kusznier

Les seules valeurs légales pour une définition d'objet de portée isolée sont les chaînes qui commencent par &, @ ou =. (Vous pouvez également suivre ces symboles avec le nom de la propriété sur la portée parente si vous souhaitez que le nom de la propriété diffère dans la directive.1) Dans ce cas, vous souhaitez utiliser le symbole = car cela indique que Angular doit "lier changePage de la portée de la directive à changePage de la portée parente". Regardez cette réponse pour plus de détails.

Vous avez raison de dire qu'il est déplorable de devoir passer cette fonction via un attribut de la directive, mais c'est la nature d'avoir une portée isolée. Vous pouvez envisager d'avoir la variable changePage et d'autres méthodes associées dans un service, car vous pouvez ensuite l'injecter en tant que dépendance.

Modifier  

Sans une portée isolée, vous pouvez effectuer les opérations suivantes:

module.directive("pagination", function() {    
    return {
        restrict: "E",
        templateUrl: "templates/pagination.html",
        link: function(scope, elem, attrs) {
            // scope.changePage is available from the directive's parent $scope
        }
    }
}

1 Exemple: { 'nameInDirective': '=nameOnParent' }

12
sdgluck

Lorsque l'utilisateur sdgluck répond correctement, vous pouvez étendre la portée de la directive dans la fonction de liaison et ainsi garder votre code propre et séparé. La suite de l’échantillon est un peu plus complète mais elle se résume au même résultat. Cela vous permet de définir un élément comme ci-dessous. Sachez que tous les attributs sont interprétés comme des objets et que, si vous souhaitez transmettre une valeur de chaîne, vous devez placer les guillemets supplémentaires autour de cette valeur (sinon vous obtiendrez une valeur indéfinie pour cet attribut)

<my-button someattr="'my text'"></my-button>

angular.module('test', []);

angular.module('test').controller('testctrl', function($scope) {
  $scope.someValue = '';
});

angular.module('test').directive('myButton', function() {
  return {
    restrict: 'E',
    template: '<button>{{getText()}}</button>',
    replace: true,
    scope: {
      someattr: '='
    },
    link: function(scope, elements, attrs){
      scope.getText = function(){
        return scope.someattr;
      };
    }
  }
});
2
Wim Van Houts

J'avais le même problème et j'ai défini ma fonction dans une directive personnalisée au lieu de la définir dans un contrôleur. Vous pouvez voir ici un exemple:

Votre HTML:

<my-custom-directive></my-custom-directive>

Votre définition de directive:

.directive("myCustomDirective", myCustomDirectiveHanlder)

function myCustomDirectiveHandler() {
    return {
        templateUrl: "/app/templates/myCustomDirectiveTemplate.html",
        restrict: 'E',
        link: function (scope, elements, attrs) {
            //your code here
        }
    }
};
0
Lorena Pita

ici vous avez un exemple de configuration.

contrôleur principal

module.controller("mainController", function($scope) {
    $scope.changePage = function() { ... };
});

disons que c'est index.html et que vous devriez avoir la directive comme ça

<pagination change-page="changePage()">

et votre directive devrait être comme ci-dessous

module.directive("pagination", function() {
    function changePage() { ... };

    return {
        restrict: 'E',
        scope: {
           changePage: '&'
        },
        templateUrl: "templates/pagination.html"
    }
}

et votre pagination.html

<div ng-click="changePage()"></div> 

cela se liera à la fonction changePage de votre contrôleur principal.

0
bews99