AngularJS'de bir denetleyiciyi başka bir denetleyiciye nasıl enjekte edebilirim?


97

Angular'da yeniyim ve bir şeyleri nasıl yapacağımı anlamaya çalışıyorum ...

AngularJS kullanarak, başka bir kontrol cihazında kullanılmak üzere bir kontrolörü nasıl enjekte edebilirim?

Aşağıdaki pasajım var:

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

app.controller('TestCtrl1', ['$scope', function ($scope) {
    $scope.myMethod = function () {
        console.log("TestCtrl1 - myMethod");
    }
}]);

app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) {
    TestCtrl1.myMethod();
}]);

Bunu çalıştırdığımda şu hatayı alıyorum:

Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1

Hatta başka bir denetleyicinin içindeki bir denetleyiciyi kullanmaya çalışmalı mıyım yoksa bunu bir hizmet mi yapmalıyım?


2
Denetleyicileri birbirine enjekte edemezsiniz. Evet, TestCtrl1bunun yerine bir hizmete geçmelisiniz .
Sly_cardinal

Kesinlikle, hizmetleri kullan
Miguel Mota

3
Ya görünüme bağlanan bir denetleyicinin özelliğini güncellemem gerekirse. Bu özellik, başka bir denetleyicide meydana gelen olaydan etkilenir.
Ankit Tanna

Yanıtlar:


129

Niyetiniz, başka bir bileşenin halihazırda somutlaştırılmış denetleyicisini elde etmekse ve bileşen / yönerge tabanlı yaklaşımı izliyorsanız, her zaman requirebelirli bir hiyerarşiyi izleyen başka bir bileşenden bir denetleyiciyi (bir bileşenin örneği) kullanabilirsiniz.

Örneğin:

//some container component that provides a wizard and transcludes the page components displayed in a wizard
myModule.component('wizardContainer', {
  ...,
  controller : function WizardController() {
    this.disableNext = function() { 
      //disable next step... some implementation to disable the next button hosted by the wizard
    }
  },
  ...
});

//some child component
myModule.component('onboardingStep', {
 ...,
 controller : function OnboadingStepController(){

    this.$onInit = function() {
      //.... you can access this.container.disableNext() function
    }

    this.onChange = function(val) {
      //..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method i.e
      if(notIsValid(val)){
        this.container.disableNext();
      }
    }
 },
 ...,
 require : {
    container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.
 },
 ...
});

Şimdi yukarıdaki bileşenlerin kullanımı şuna benzer bir şey olabilir:

<wizard-container ....>
<!--some stuff-->
...
<!-- some where there is this page that displays initial step via child component -->

<on-boarding-step ...>
 <!--- some stuff-->
</on-boarding-step>
...
<!--some stuff-->
</wizard-container>

Eğer ayarlayabilirsiniz birçok yolu vardır gerektirir .

(önek yok) - Geçerli öğe üzerinde gerekli denetleyiciyi bulun. Bulunmazsa bir hata atın.

? - Gerekli denetleyiciyi bulmaya veya bulunamazsa fn bağlantısına boş vermeyi deneyin.

^ - Öğeyi ve üst öğelerini arayarak gerekli denetleyiciyi bulun. Bulunmazsa bir hata atın.

^^ - Öğenin üst öğelerini arayarak gerekli denetleyiciyi bulun. Bulunmazsa bir hata atın.

? ^ - Öğeyi ve üst öğelerini arayarak gerekli denetleyiciyi bulmaya çalışın veya bulunamazsa fn bağlantısına null değerini iletin.

? ^^ - Öğenin üst öğelerini arayarak gerekli denetleyiciyi bulmaya çalışın veya bulunamazsa fn bağlantısına null değerini iletin.



Eski Cevap:

$controllerBaşka bir denetleyicinin içindeki bir denetleyiciyi örneklemek için hizmet eklemeniz gerekir . Ancak bunun bazı tasarım sorunlarına yol açabileceğini unutmayın. Her zaman Tek Sorumluluğu izleyen yeniden kullanılabilir hizmetler oluşturabilir ve bunları ihtiyaç duyduğunuzda denetleyicilere ekleyebilirsiniz.

Misal:

app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
   var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating.
   //Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope.
   //In this case it is the child scope of this scope.
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); //And call the method on the newScope.
}]);

Her durumda TestCtrl1.myMethod(), yöntemi $scopedenetleyici örneğine değil üzerine eklediğiniz için çağrı yapamazsınız .

Denetleyiciyi paylaşıyorsanız, şunları yapmak her zaman daha iyi olacaktır: -

.controller('TestCtrl1', ['$log', function ($log) {
    this.myMethod = function () {
        $log.debug("TestCtrl1 - myMethod");
    }
}]);

ve tüketirken şunları yapın:

.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
     var testCtrl1ViewModel = $controller('TestCtrl1');
     testCtrl1ViewModel.myMethod();
}]);

İlk durumda gerçekten $scopegörünüm modeliniz ve ikinci durumda denetleyici örneğinin kendisi.


4
Ve bu, denetleyicinin sağladığı işlevselliğe bağlıdır, eğer onu bileşen arasında paylaşmanız gereken bir görünüm modeli gibi yapıyorsanız, bu sorun değil, ancak daha çok bir servis sağlayıcı işlevselliği ise, o zaman sadece bir servis oluşturmaya giderim. .
PSL

Meli var testCtrl1ViewModel = $scope.$new();olmak var testCtrl1ViewModel = $rootScope.$new();? bakınız: docs.angularjs.org/guide/controller @PSL
leonsPAPA

Yukarıdaki örnekte, yönerge denetleyicisindeki kapsayıcıya erişiyorsunuz, ancak bunu çalıştıramıyorum. Direktifin kendisinde bulunan link fonksiyonumdaki dördüncü parametre ile gerekli denetleyicilere erişebilirim. Ancak yukarıdaki örnekte olduğu gibi yönerge denetleyicisine bağlı değillerdir. Bu sorunu yaşayan başka biri var mı?
Sammi

33

Sormanız gereken soru, hizmetlerin denetleyicilere nasıl enjekte edileceğidir. İnce denetleyicilere sahip yağ hizmetleri, iyi bir kuraldır, yani yalnızca hizmetinizi / fabrikanızı (iş mantığı ile) görüşlerinize yapıştırmak için denetleyicileri kullanın.

Denetleyiciler, rota değişikliklerinde çöp toplanır, bu nedenle, örneğin, bir değer oluşturan iş mantığını tutmak için denetleyicileri kullanırsanız, uygulama kullanıcısı tarayıcı geri düğmesini tıklarsa iki sayfadaki durumunuzu kaybedersiniz.

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

app.factory('methodFactory', function () {
    return { myMethod: function () {
            console.log("methodFactory - myMethod");
    };
};

app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) {  //Comma was missing here.Now it is corrected.
    $scope.mymethod1 = methodFactory.myMethod();
}]);

app.controller('TestCtrl2', ['$scope', 'methodFactory', function ($scope, methodFactory) {
    $scope.mymethod2 = methodFactory.myMethod();
}]);

İşte iki denetleyiciye enjekte edilen fabrikanın çalışan bir demosu

Ayrıca, hizmetler / fabrikalar hakkında bu öğreticiyi okumanızı öneririm .


13

Denetleyicinizi JS'de içe aktarmanıza / enjekte etmenize gerek yoktur. Denetleyicinizi / yuvalanmış denetleyicinizi HTML'niz aracılığıyla enjekte edebilirsiniz, benim için çalıştı. Sevmek :

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>

2
doğru ... ama yine de tüm ortak unsurları bir hizmete koymanın ve hizmeti ilgili denetleyiciye enjekte etmenin daha iyi olduğunu hissediyorum.
Neel

-1
<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>

Bu, TestCtrl2'nin kendi yönergelerine sahip olduğu durumumda en iyi sonucu verir.

var testCtrl2 = $controller('TestCtrl2')

Bu bana ,copeProvider enjeksiyon hatası diyen bir hata veriyor.

   var testCtrl1ViewModel = $scope.$new();
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); 

'TestCtrl1'de yönergeleriniz varsa, bu yönergenin aslında burada oluşturulandan farklı bir kapsamı varsa, bu gerçekten işe yaramaz. İki 'TestCtrl1' örneğiyle sonuçlanırsınız.


-1

En iyi çözüm:-

angular.module("myapp").controller("frstCtrl",function($scope){$scope.name="Atul Singh";}).controller("secondCtrl",function($scope){angular.extend(this, $controller('frstCtrl', {$scope:$scope}));console.log($scope);})

// Burada, çalıştırmadan ilk denetleyici çağrısını aldınız


-1

Ayrıca aşağıdaki $rootScopegibi ikinci denetleyiciden 1. denetleyicinin bir işlevini / yöntemini çağırmak için de kullanabilirsiniz ,

.controller('ctrl1', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl();
     //Your code here. 
})

.controller('ctrl2', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl = function() {
     //Your code here. 
}
})

1
Olumsuz oy: Bu sadece kötü bir kodlama: sadece işlevinizi küresel hale getiriyorsunuz. Kodlama yöntemi buysa tamamen açısal bıraksanız iyi olur ... Diğer yanıtların çoğunun önerdiği bir hizmeti kullanın.
HammerNL

Bu tavsiye edilmez. $ rootScope kodu beceriksiz hale getirir ve uzun vadede sorunlara yol açar.
Harshit Pantolon

-2

Kodlamanız için typcript kullanın, çünkü nesne yönelimli, kesinlikle yazılmış ve kodu sürdürmek kolaydır ...

fiş türleri hakkında daha fazla bilgi için burayı tıklayın

Burada, Typescript kullanarak iki denetleyici arasında veri paylaşmak için oluşturduğum basit bir örnek ...

module Demo {
//create only one module for single Applicaiton
angular.module('app', []);
//Create a searvie to share the data
export class CommonService {
    sharedData: any;
    constructor() {
        this.sharedData = "send this data to Controller";
    }
}
//add Service to module app
angular.module('app').service('CommonService', CommonService);

//Create One controller for one purpose
export class FirstController {
    dataInCtrl1: any;
    //Don't forget to inject service to access data from service
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl1 = this.commonService.sharedData;
    }
}
//add controller to module app
angular.module('app').controller('FirstController', FirstController);
export class SecondController {
    dataInCtrl2: any;
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl2 = this.commonService.sharedData;
    }
}
angular.module('app').controller('SecondController', SecondController);

}

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.