web-dev-qa-db-fra.com

angularJS: Comment appeler une fonction de portée enfant dans la portée parent

Comment peut-on appeler une méthode définie dans la portée de l'enfant depuis sa portée parent?

function ParentCntl() {
    // I want to call the $scope.get here
}

function ChildCntl($scope) {
    $scope.get = function() {
        return "LOL";    
    }
}

http://jsfiddle.net/wUPdW/

92
9blue

Vous pouvez utiliser $broadcast du parent à un enfant:

function ParentCntl($scope) {

    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$parent.msg = $scope.get();            
    });

    $scope.get = function(){
        return "LOL";    
    }
}

Le violon en marche: http://jsfiddle.net/wUPdW/2/

[~ # ~] update [~ # ~] : Il existe une autre version, moins couplée et plus testable:

function ParentCntl($scope) {
    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }

    $scope.$on('pingBack', function(e,data) {  
        $scope.msg = data;        
    });
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$emit("pingBack", $scope.get());        
    });

    $scope.get = function(){
        return "LOL";    
    }
}

Violon: http://jsfiddle.net/uypo360u/

141
Cherniv

Me laisser suggérer une autre solution:

var app = angular.module("myNoteApp", []);


app.controller("ParentCntl", function($scope) {
    $scope.obj = {};
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

Moins de code et utilisation d'un héritage prototypique.

Plunk

31
Canttouchit

Enregistrez la fonction de l'enfant sur le parent lorsque celui-ci est en cours d'initialisation. J'ai utilisé la notation "comme" pour plus de clarté dans le modèle.

MODÈLE

<div ng-controller="ParentCntl as p">
  <div ng-controller="ChildCntl as c" ng-init="p.init(c.get)"></div>
</div>

CONTROLEURS

...
function ParentCntl() {
  var p = this;
  p.init = function(fnToRegister) {
    p.childGet = fnToRegister;
  };
 // call p.childGet when you want
}

function ChildCntl() {
  var c = this;
  c.get = function() {
    return "LOL";    
  };
}

"Mais", dites-vous, "ng-initn'est pas censé être utilisé de cette façon ! ". Eh bien, oui, mais

  1. cette documentation n'explique pas pourquoi, et
  2. Je ne crois pas que les auteurs de la documentation ont envisagé TOUS les cas d'utilisation possibles.

Je dis que c'est un bon usage. Si vous voulez me baisser, commentez avec des raisons! :)

J'aime cette approche car elle permet aux composants d'être plus modulaires. Les seules liaisons sont dans le modèle, et cela signifie que

  • le contrôleur enfant n'a pas besoin de savoir à quel objet ajouter sa fonction (comme dans la réponse de @ canttouchit)
  • le contrôle parent peut être utilisé avec tout autre contrôle enfant ayant une fonction get
  • ne nécessite pas de diffusion, ce qui deviendra très moche dans une grosse application à moins de contrôler étroitement l'espace de noms des événements

Cette approche est plus proche idée de Terra de modulariser avec des directives (notez que dans son exemple modularisé, contestants est passé de la directive parent à la directive "enfant" IN THE TEMPLATE).

En effet, une autre solution pourrait être d’envisager de mettre en œuvre le ChildCntl en tant que directive et d’utiliser le & liaison pour enregistrer la méthode init.

11
poshest