Как я могу ввести контроллер в другой контроллер в AngularJS


Я новичок в Angular и пытаюсь понять, как это сделать...

используя AngularJS, как я могу ввести контроллер, который будет использоваться в другом контроллере?

у меня есть следующий фрагмент:

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

когда я выполняю это, я получаю ошибку:

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

должен ли я даже пытаться использовать контроллер внутри другого контроллера, или я должен сделать это услугой?

7 94

7 ответов:

если ваше намерение состоит в том, чтобы завладеть уже созданным контроллером другого компонента и что если вы следуете компонентному / директивному подходу, вы всегда можете require контроллер (экземпляр компонента) из другого компонента, который следует определенной иерархии.

например:

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

теперь использование этих выше компонентов может быть что-то вроде этого:

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

есть много способов настроить требуются.

(без префикса) - найдите необходимый контроллер на текущем элементе. Бросьте ошибку, если не найдено.

? - Попытайтесь найти требуемый контроллер или передать null в ссылку fn, если не найдено.

^ - Найдите нужный контроллер, поиск элемента и его родителей. Бросьте ошибку, если не найдено.

^^ - найдите необходимый контроллер, выполнив поиск родители стихии. Бросьте ошибку, если не найдено.

?^ - Попытка найти требуемый контроллер путем поиска элемента и его родителей или передать null в ссылку fn, если он не найден.

?^ ^ - Попытка найти требуемый контроллер путем поиска родителей элемента или передать null в ссылку fn, если он не найден.



Ответ:

вам нужно впрыснуть $controller служба для создания экземпляра контроллера внутри другого контроллера. Но имейте в виду, что это может привести к некоторым проблемам с дизайном. Вы всегда можете создать многоразовые службы, которые следуют за одной ответственностью и внедряют их в контроллеры по мере необходимости.

пример:

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

ни в коем случае нельзя называть TestCtrl1.myMethod() потому что вы прикрепили метод на $scope и не на экземпляре контроллера.

если вы разделяете контроллер, то это будет всегда лучше делать: -

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

и во время потребления сделать:

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

в первом случае действительно $scope это ваша модель представления, а во втором случае это сам экземпляр контроллера.

Я бы предложил вопрос, который вы должны задать, заключается в том, как вводить службы в контроллеры. Fat services с тощими контроллерами-это хорошее эмпирическое правило, а также просто используйте контроллеры для склеивания вашего сервиса/фабрики (с бизнес-логикой) в ваши представления.

контроллеры собирают мусор при изменении маршрута, поэтому, например, если вы используете контроллеры для хранения бизнес-логики, которая отображает значение, вы потеряете состояние на двух страницах, если пользователь приложения щелкнет браузер обратно кнопка.

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

вот такой рабочий демонстрация фабрики впрыснутой в 2 регулятора

кроме того, я бы предложил иметь прочитайте этот учебник по услугам / фабрикам.

нет необходимости импортировать / вводить контроллер в JS. Вы можете просто ввести свой контроллер / вложенный контроллер через ваш HTML.It-он работал на меня. Например:

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

это лучше всего работает в моем случае, где TestCtrl2 имеет свои собственные директивы.

var testCtrl2 = $controller('TestCtrl2')

Это дает мне ошибку, говоря scopeProvider ошибка инъекции.

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

это действительно не работает, если у вас есть директивы в 'TestCtrl1', эта директива на самом деле имеет другую область действия, чем эта, созданная здесь. Вы в конечном итоге с двумя экземплярами "TestCtrl1".

лучшее решение:-

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);})
// вы получили первый вызов контроллера без его выполнения

вы также можете использовать $rootScope чтобы вызвать функцию / метод 1-го контроллера из второго контроллера, как это,

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

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

используйте typescript для вашего кодирования, потому что это объектно-ориентированный, строго типизированный и простой в обслуживании код ...

для получения дополнительной информации о typescipt нажмите здесь

вот один простой пример, который я создал для обмена данными между двумя контроллерами с помощью Typescript...

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

}