Как я вставляю контроллер в другой контроллер в 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

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

Ответ 1

Если ваше намерение состоит в том, чтобы заполучить уже созданный экземпляр контроллера другого компонента, и если вы выполняете подход на основе компонента/директивы, вы всегда можете 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 disable method i.e
      if(notIsValid(val)){
        this.container.disableNext();
      }
    }
 },
 ...,
 require : {
    container: '^^wizardContainer' //Require a wizard component 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>

Существует множество способов настроить require.

(без префикса). Найдите требуемый контроллер для текущего элемента. Выброс ошибки, если не найден.

? - Попытайтесь найти требуемый контроллер или передать 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 - ваша модель представления, а во втором случае - сам экземпляр контроллера.

Ответ 2

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

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

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

Ниже приведена рабочая демонстрация factory, введенная в два контроллера.

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

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

//Здесь вы получили первый вызов контроллера без его выполнения

Ответ 6

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

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

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

Ответ 7

используйте 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);

}