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.