Bir AngularJS kontrol cihazı aynı modüldeki başka bir kontrol ünitesinden miras alabilir mi?


198

Bir modül içinde, bir kontrolör özellikleri bir dış kontrolörden devralabilir:

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

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

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

Örnek: Ölü bağlantı : http://blog.omkarpatil.com/2013/02/controller-inheritance-in-angularjs.html

Bir modül içindeki bir kontrolör de bir kardeşten miras alabilir mi?

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
});

$injector.invokeİlk parametre olarak bir işlev gerektirdiğinden ve başvuruyu bulamadığı için ikinci kod çalışmaz ParentCtrl.



2
bir yana: bu miras gibi görünmüyor, daha çok paylaşma yöntemlerine veya enjekte etmeye benziyor. Belki de sadece anlambilim.
alockwood05

Örnek bağlantısı artık geçerli değil.
AlexS

Yanıtlar:


289

Evet, ancak $controllerdenetleyiciyi örneklemek için hizmeti kullanmanız gerekir :

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
});

ParentCtrla olmalı controllerveya kullanmak mümkün servicemü?
gontard

@gontard: Bu durumda $controller, yalnızca kayıtlı denetleyicileri kullanabileceği gibi bir denetleyici olmalıdır .
ZeissS

10
Çok iyi bir çözüm. Teşekkür ederim. Ancak Controller As sözdizimini kullanmam durumunda bunu nasıl yapabilirim?
Ka

1
Yukarıdaki keman soru olarak soruldu. Sadece o controllerAs belirterek It değerinde kapsamına denetleyici atar - Eğer değiştirecek Yani $scopeiçin this(teoride)
Dan Kiler

4
Bu benim için çalıştı, ancak ben aynı sayfada üst denetleyicisi ve alt denetleyicisi var bir şekilde yapmaya çalışıyorum. Bu, üst denetleyicideki $ http işleminin iki kez çalışmasına neden olur. Alt denetleyici üst denetleyicinin kapsamını enjekte ettiğinde $ scope.AllMembers dizisi üst denetleyicinin çalışmasına neden olduğu için iki kez doldurulur, daha sonra alt denetleyici yeniden çalışmasına neden olur. Bunu önlemenin bir yolu var mı?
Ryan Mann

20

vmDenetleyici sözdizimi kullanıyorsanız , işte benim çözümüm:

.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}));
})

Ne yazık ki, $controller.call(vm, 'BaseGenericCtrl'...)geçerli bağlamı closure (for reload()) işlevine geçirmek için kullanamazsınız, bu nedenle thisbağlamı dinamik olarak değiştirmek için miras alınan işlevin içinde yalnızca bir çözüm kullanmaktır .


Bunun yerine bunu yapamaz mıydın? > $ controller ('BaseGenericControl', {vm: vm});
herringtown

vmdenetleyicinin içindeki bir değişkendir, sanmıyorum ki Angular beklendiği gibi kullanabilir.
IProblemFactory

8

Her iki denetleyiciye de erişilebilir işlevler veya veriler sağlamak için fabrika veya hizmeti kullanmanız gerektiğini düşünüyorum.

benzer soru ---> AngularJS denetleyici kalıtım


Evet bu bir yol, teşekkürler. Çözüm ararken o yazıyla karşılaştım. Denetleyici işlevini yüklemek ve onunla "bu" genişletmek için bir yol olup olmadığını düşünüyordum.
Ka

Evrensel bir loadingdeğişkene sahip olmak istiyorum, böylece veri yüklenirken hep aynı şeyi yaparım, fabrikaların bunu yapabileceğini sanmıyorum. Ana denetleyicimin yükleme değişkeni olabilir, ancak fabrika bunu değiştiremez ... değil mi ?!
PixMach

7

Bu yanıtta gmontague tarafından dile getirilen soruna yanıt olarak, $ controller () kullanarak bir denetleyiciyi devralmak için bir yöntem buldum ve yine de denetleyiciyi "sözdizimi" olarak kullanıyorum.

İlk olarak, $ controller () çağrısını devralırken "as" sözdizimini kullanın:

    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);

    });

Daha sonra, HTML şablonunda, özellik üst öğe tarafından tanımlanmışsa, üst öğeden parent.devralınan özellikleri almak için kullanın ; çocuk tarafından tanımlanmışsa, child.geri almak için kullanın .

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

5

Bunu başka bir şekilde yaptım. Benim durumumda, aynı kontrolleri ve özellikleri diğer kontrolörlere uygulayan bir fonksiyon istedim. Parametreler haricinde hoşuma gitti. Bu şekilde, tüm ChildCtrls'lerinizin $ konumu alması gerekir.

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();
});

4

Merak edenler için, kabul edilen yanıttaki yöntemi kullanarak bileşen denetleyicilerini aynı şekilde genişletebilirsiniz.

Aşağıdaki yaklaşımı kullanın:

Ana bileşen (genişletmek için):

/**
 * 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;
  };
});

Alt bileşen (genişleyen bileşen):

/**
 * 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;
  };
});

Hile, bileşen tanımında tanımlamak yerine adlandırılmış denetleyicileri kullanmaktır.


2

Kabul edilen cevapta belirtildiği gibi, ana denetleyicinin $ scope ve diğer hizmetlerde yaptığı değişiklikleri "denetleyiciniz:" ile arayarak devralabilirsiniz $controller('ParentCtrl', {$scope: $scope, etc: etc});.

Ancak , denetleyiciyi 'sözdizimi' sözdizimi olarak kullanmaya alışkınsanız başarısız olur, örneğin

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

Eğer fooana kontrolöre (via kuruldu this.foo = ...), çocuk kontrolör buna erişemez.

Yorumlarda belirtildiği gibi, $ denetleyicisinin sonucunu doğrudan kapsama atayabilirsiniz:

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;
});

Not: Daha sonra zorundadır gelen 'olarak' parçasını kaldırmak ng-controller=artık şablonu kodunda örnek adını belirterek ve bu kadar önemli.


"Controller as" sözdiziminin kullanılmasında sorun yoktur. Cevabımı gör: stackoverflow.com/a/36549465/2197555
gm2008

2

"Controller as" sözdizimini kullanıyordum ve vm = thisbir denetleyiciyi devralmak istedim. Ana denetleyicimin bir değişkeni değiştiren bir işlevi varsa sorunları vardı.

Kullanılması IProblemFactory en ve Salman Abbas'ın cevapları, ben ana değişkenler erişimi için aşağıdaki yaptı:

(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>


0

Basit bir JavaScript devralma mekanizması kullanabilirsiniz. Ayrıca, .call yöntemini çağırmak için ihtiyaç duyulan açısal hizmetleri geçmeyi unutmayın.

//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);

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.