web-dev-qa-db-fra.com

Fonction de rappel dans la directive attr définie dans différents attr

J'ai donc cette directive appelée par exemple, mySave, c'est à peu près tout cela

app.directive('mySave', function($http) {
   return function(scope, element, attrs) {
      element.bind("click", function() {
          $http.post('/save', scope.data).success(returnedData) {
              // callback defined on my utils service here

              // user defined callback here, from my-save-callback perhaps?
          }
      });
   }
});

l'élément lui-même ressemble à ceci

<button my-save my-save-callback="callbackFunctionInController()">save</button>

callbackFunctionInController est pour l'instant juste 

$scope.callbackFunctionInController = function() {
    alert("callback");
}

quand je console.log()attrs.mySaveCallback dans la directive my-save, il me donne simplement une chaîne callbackFunctionInController(), je lis quelque part que je devrais $ analyser ce script et que ça irait, alors j'ai essayé de $parse(attrs.mySaveCallback) qui m'a donné une fonction, mais à peine celle que je cherchais, elle me rendit

function (a,b){return m(a,b)} 

Qu'est-ce que je fais mal? Cette approche est-elle défectueuse depuis le début?

38
fxck

Donc, ce qui semble être la meilleure solution consiste à utiliser la portée isolée suggérée par ProLoser.

app.directive('mySave', function($http) {
   return {
      scope: {
        callback: '&mySaveCallback'
      }
      link: function(scope, element, attrs) {
        element.on("click", function() {
            $http.post('/save', scope.$parent.data).success(returnedData) {
                // callback defined on my utils service here

                scope.callback(); // fires alert
            }
        });
      }
   }
});

Pour renvoyer les paramètres au contrôleur, faites ceci

[11:28] <revolunet> you have to send named parameters 
[11:28] <revolunet> eg my-attr="callback(a, b)" 
[11:29] <revolunet> in the directive: scope.callback({a:xxx, b:yyy})
61
fxck

Il y a beaucoup de façons de faire ce que vous faites. La PREMIÈRE chose que vous devriez savoir est que la $http.post() sera appelée dès que cet élément DOM sera rendu par le moteur de gabarit, et c'est tout. Si vous le mettez dans une répétition, l'appel sera effectué pour chaque nouvel élément du répéteur. Je suppose donc que ce n'est certainement pas ce que vous voulez. Et s’il est alors vous ne concevez pas vraiment les choses correctement car l’existence de DOM seul ne devrait pas dicter les requêtes au backend.

Quoi qu'il en soit, répondez directement à votre question. Si vous lisez les docs, bien que douteux, sur $ parse, il vous renvoie une expression d'évaluation. Lorsque vous exécutez cette fonction en transmettant la portée à évaluer, l'état actuel de cette expression sur la portée que vous avez transmise est renvoyé. Cela signifie que votre fonction sera exécutée.

var expression = $parse(attrs.mySave);
results = expression($scope); // call on demand when needed
expression.assign($scope, 'newValu'); // the major reason to leverage $parse, setting vals

Oui, c'est un peu déroutant au début, mais vous devez comprendre qu'un $ scope change constamment dans les applications asynchrones et tout dépend de QUAND vous voulez que la valeur soit déterminée, pas seulement comment. $parse est plus utile pour faire référence à un modèle auquel vous voulez pouvoir attribuer une valeur, pas seulement lire.

Bien sûr, vous voudrez peut-être vous renseigner sur la création d'une étendue d'isolement ou sur la manière de $eval() une expression. 

$scope.$eval(attrs.mySave);
12
ProLoser

Vous pouvez utiliser . $ Eval pour exécuter une instruction dans la portée donnée

app.directive('mySave', function($http) {
   return function(scope, element, attrs) {
      $http.post('/save', scope.data).success(returnedData) {
          // callback defined on my utils service here

          // user defined callback here, from my-save-callback perhaps?
          scope.$eval(attrs.mySaveCallback)
      }
   }
});

TD: Démo

Si vous souhaitez partager des données entre une directive et un contrôleur, vous pouvez utiliser la liaison bidirectionnelle.

app.controller('AppController', function ($scope) {
   $scope.callbackFunctionInController = function() {
      console.log('do something')
   };

   $scope.$watch('somedata', function(data) {
      console.log('controller', data);
   }, true);
});

app.directive('mySave', function($http, $parse) {
   return {
     scope: {
       data: '=mySaveData',
       callback: '&mySaveCallback' //the callback
     },
     link: function(scope, element, attrs) {
       $http.get('data.json').success(function(data) {
         console.log('data', data);
         scope.data = data;
         scope.callback(); //calling callback, this may not be required
       });
     }
   };
});

Démo: Fiddle

9
Arun P Johny
app.directive('mySave', function($http, $parse) {
   return {
     scope: {
       data: '=mySaveData',
       callback: '&' //the callback
     },
     link: function(scope, element, attrs) {
       $http.get('data.json').success(function(data) {
         console.log('data', data);
         if (scope.callback()) scope.callback().apply(data);
       });
     }
   };
});
0
ido niger

Vous devriez utiliser ng-click au lieu de créer votre propre directive.

0
ProLoser

Cela a fonctionné pour moi

Dans le script de vue

<tag mycallbackattrib="scopemethod">

À l'intérieur de la directive

$scope[attrs.mycallbackattrib](params....);

Il est correctement appelé et les paramètres sont passés, mais ce n’est peut-être pas la meilleure "manière angulaire" de travailler.

0
Sergio Rinaudo