web-dev-qa-db-fra.com

Un contrôleur AngularJS peut-il hériter d’un autre contrôleur du même module?

Dans un module, un contrôleur peut hériter des propriétés d'un contrôleur externe:

var app = angular.module('angularjs-starter', []);

var ParentCtrl = function ($scope, $location) {
};

app.controller('ChildCtrl', function($scope, $injector) {
  $injector.invoke(ParentCtrl, this, {$scope: $scope});
});

Exemple via: Lien morthttp://blog.omkarpatil.com/2013/02/controller-inheritance-in-angularjs.html

Est-ce qu'un contrôleur à l'intérieur d'un module peut également hériter d'un frère?

var app = angular.module('angularjs-starter', []);

app.controller('ParentCtrl ', function($scope) {
  //I'm the sibling, but want to act as parent
});

app.controller('ChildCtrl', function($scope, $injector) {
  $injector.invoke(ParentCtrl, this, {$scope: $scope}); //This does not work
});

Le second code ne fonctionne pas car $injector.invoke requiert une fonction en tant que premier paramètre et ne trouve pas la référence à ParentCtrl.

195
Federico Elles

Oui, vous pouvez le faire, mais vous devez utiliser le service $controller pour instancier le contrôleur: -

var app = angular.module('angularjs-starter', []);

app.controller('ParentCtrl', function($scope) {
  // I'm the sibling, but want to act as parent
});

app.controller('ChildCtrl', function($scope, $controller) {
  $controller('ParentCtrl', {$scope: $scope}); //This works
});
285
Salman Abbas

Si vous utilisez vm syntaxe de contrôleur , voici ma solution:

.controller("BaseGenericCtrl", function ($scope) {

    var vm = this;
    vm.reload = reload;
    vm.items = [];

    function reload() {
        // this function will come from child controller scope - RESTDataService.getItemsA
        this.getItems();
    }
})

.controller("ChildCtrl", function ($scope, $controller, RESTDataService) {
    var vm = this;
    vm.getItems = RESTDataService.getItemsA;
    angular.extend(vm, $controller('BaseGenericCtrl', {$scope: $scope}));
})

Malheureusement, vous ne pouvez pas utiliser $controller.call(vm, 'BaseGenericCtrl'...), pour passer du contexte actuel à la fonction de fermeture (pour reload()), une seule solution consiste donc à utiliser this dans une fonction héritée afin de changer le contexte de façon dynamique.

19
IProblemFactory

Je pense que vous devriez utiliser factory ou service pour donner des fonctions ou des données accessibles aux deux contrôleurs.

voici une question similaire ---> - Héritage du contrôleur AngularJS

8
LauroSkr

En réponse au problème soulevé dans cette réponse de gmontague , j'ai trouvé une méthode pour hériter d'un contrôleur en utilisant $ controller (), tout en utilisant la syntaxe du contrôleur "en tant que". 

Tout d'abord, utilisez la syntaxe "as" lorsque vous héritez de l'appel de $ controller ():

    app.controller('ParentCtrl', function(etc...) {
        this.foo = 'bar';
    });
    app.controller('ChildCtrl', function($scope, $controller, etc...) {
        var ctrl = $controller('ParentCtrl as parent', {etc: etc, ...});
        angular.extend(this, ctrl);

    });

Ensuite, dans le modèle HTML, si la propriété est définie par le parent, utilisez parent. pour récupérer les propriétés héritées du parent; si défini par enfant, utilisez child. pour le récupérer. 

    <div ng-controller="ChildCtrl as child">{{ parent.foo }}</div>
7
gm2008

Eh bien, je l'ai fait d'une autre manière. Dans mon cas, je voulais une fonction qui applique les mêmes fonctions et propriétés à d’autres contrôleurs. Je l'ai aimé, sauf par les paramètres. De cette façon, tous vos enfants ChildCtrls doivent recevoir $ location.

var app = angular.module('angularjs-starter', []);

function BaseCtrl ($scope, $location) {
    $scope.myProp = 'Foo';
    $scope.myMethod = function bar(){ /* do magic */ };
}

app.controller('ChildCtrl', function($scope, $location) {
    BaseCtrl.call(this, $scope, $location);

    // it works
    $scope.myMethod();
});
5
Fabio Montefuscolo

Pour ceux qui se demandent, vous pouvez étendre les contrôleurs de composants de la même manière, en utilisant la méthode de la réponse acceptée. 

Utilisez l'approche suivante:

Composant parent (à partir de):

/**
 * Module definition and dependencies
 */
angular.module('App.Parent', [])

/**
 * Component
 */
.component('parent', {
  templateUrl: 'parent.html',
  controller: 'ParentCtrl',
})

/**
 * Controller
 */
.controller('ParentCtrl', function($parentDep) {

  //Get controller
  const $ctrl = this;

  /**
   * On init
   */
  this.$onInit = function() {

    //Do stuff
    this.something = true;
  };
});

Composant enfant (celui qui s'étend):

/**
 * Module definition and dependencies
 */
angular.module('App.Child', [])

/**
 * Component
 */
.component('child', {
  templateUrl: 'child.html',
  controller: 'ChildCtrl',
})

/**
 * Controller
 */
.controller('ChildCtrl', function($controller) {

  //Get controllers
  const $ctrl = this;
  const $base = $controller('ParentCtrl', {});
  //NOTE: no need to pass $parentDep in here, it is resolved automatically
  //if it's a global service/dependency

  //Extend
  angular.extend($ctrl, $base);

  /**
   * On init
   */
  this.$onInit = function() {

    //Call parent init
    $base.$onInit.call(this);

    //Do other stuff
    this.somethingElse = true;
  };
});

L'astuce consiste à utiliser des contrôleurs nommés, au lieu de les définir dans la définition du composant.

3
Adam Reis

Comme indiqué dans la réponse acceptée, vous pouvez "hériter" des modifications apportées par un contrôleur parent à $ scope et à d'autres services en appelant: $controller('ParentCtrl', {$scope: $scope, etc: etc}); dans votre contrôleur enfant.

Cependant , cela échoue si vous êtes habitué à utiliser la syntaxe 'en tant que contrôleur', par exemple dans

<div ng-controller="ChildCtrl as child">{{ child.foo }}</div>

Si foo a été défini dans le contrôleur parent (via this.foo = ...), le contrôleur enfant n'y aura pas accès.

Comme mentionné dans les commentaires, vous pouvez affecter le résultat de $ controller directement à la portée:

var app = angular.module('angularjs-starter', []);
app.controller('ParentCtrl ', function(etc...) {
    this.foo = 'bar';
});
app.controller('ChildCtrl', function($scope, $controller, etc...) {
    var inst = $controller('ParentCtrl', {etc: etc, ...});

    // Perform extensions to inst
    inst.baz = inst.foo + " extended";

    // Attach to the scope
    $scope.child = inst;
});

Remarque: Vous devez devez supprimer la partie "as" de ng-controller=, car vous spécifiez le nom de l'instance dans le code et non plus le modèle.

2
gmontague

J'utilisais la syntaxe "Controller as" avec vm = this et je voulais hériter d'un contrôleur. J'avais des problèmes si mon contrôleur parent avait une fonction qui modifiait une variable.

En utilisant les réponses de d'IProblemFactory et de Salman Abbas , j'ai procédé comme suit pour avoir accès aux variables parent:

(function () {
  'use strict';
  angular
      .module('MyApp',[])
      .controller('AbstractController', AbstractController)
      .controller('ChildController', ChildController);

  function AbstractController(child) {
    var vm = child;
    vm.foo = 0;
    
    vm.addToFoo = function() {
      vm.foo+=1;
    }
  };
  
  function ChildController($controller) {
    var vm = this;
    angular.extend(vm, $controller('AbstractController', {child: vm}));
  };
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="ChildController as childCtrl" layout="column" ng-cloak="" ng-app="MyApp">
  <button type="button" ng-click="childCtrl.addToFoo()">
    add
  </button>
  <span>
      -- {{childCtrl.foo}} --
  </span>
</div>

2
dufaux

Vous pouvez utiliser un mécanisme d'héritage JavaScript simple. De plus, n'oubliez pas de passer des services nécessaires pour invoquer la méthode .call.

//simple function (js class)
function baseCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService) {//any serrvices and your 2

   this.id = $routeParams.id;
   $scope.id = this.id;

   this.someFunc = function(){
      $http.get("url?id="+this.id)
      .then(success function(response){
        ....
       } ) 

   }
...
}

angular
        .module('app')
        .controller('childCtrl', childCtrl);

//angular controller function
function childCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService) {      
   var ctrl = this;
   baseCtrl.call(this, $http, $scope, $location, $rootScope,  $routeParams, $log, $timeout, $window, modalService);

   var idCopy = ctrl.id;
   if($scope.id == ctrl.id){//just for sample
      ctrl.someFunc();
   }
}

//also you can copy prototype of the base controller
childCtrl.prototype = Object.create(baseCtrl.prototype);
0
trueboroda

Reportez-vous au lien mentionné ci-dessous pour connaître les héritages de AngularJs.

Controller-Inheritance in in angularjs

0
Sheo Dayal Singh