Làm cách nào để đưa một bộ điều khiển vào một bộ điều khiển khác trong AngularJS


97

Tôi mới sử dụng Angular và đang cố gắng tìm ra cách thực hiện mọi thứ ...

Sử dụng AngularJS, làm cách nào để tôi có thể đưa một bộ điều khiển vào để sử dụng trong một bộ điều khiển khác?

Tôi có đoạn mã sau:

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

Khi tôi thực hiện điều này, tôi gặp lỗi:

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

Tôi thậm chí nên cố gắng sử dụng một bộ điều khiển bên trong một bộ điều khiển khác hay tôi nên biến điều này thành một dịch vụ?


2
Bạn không thể đưa các bộ điều khiển vào nhau. Có, bạn nên thay đổi TestCtrl1thành một dịch vụ thay thế.
Sly_cardinal

Chính xác, sử dụng dịch vụ
Miguel Mota

3
điều gì sẽ xảy ra nếu tôi phải cập nhật thuộc tính của bộ điều khiển liên kết với chế độ xem. Thuộc tính này bị ảnh hưởng bởi sự kiện xảy ra trong bộ điều khiển khác.
Ankit Tanna

Câu trả lời:


129

Nếu ý định của bạn là nắm giữ bộ điều khiển đã được khởi tạo của một thành phần khác và nếu bạn đang theo cách tiếp cận dựa trên thành phần / chỉ thị, bạn luôn có thể requiređiều khiển (phiên bản của một thành phần) từ một thành phần khác tuân theo một hệ thống phân cấp nhất định.

Ví dụ:

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

Bây giờ việc sử dụng các thành phần trên có thể giống như sau:

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

Có nhiều cách bạn có thể thiết lập yêu cầu .

(không có tiền tố) - Định vị bộ điều khiển được yêu cầu trên phần tử hiện tại. Ném lỗi nếu không tìm thấy.

? - Cố gắng xác định vị trí bộ điều khiển cần thiết hoặc chuyển null vào liên kết fn nếu không tìm thấy.

^ - Định vị bộ điều khiển được yêu cầu bằng cách tìm kiếm phần tử và cha mẹ của nó. Ném lỗi nếu không tìm thấy.

^^ - Định vị bộ điều khiển cần thiết bằng cách tìm kiếm cha mẹ của phần tử. Ném lỗi nếu không tìm thấy.

? ^ - Cố gắng xác định vị trí bộ điều khiển cần thiết bằng cách tìm kiếm phần tử và cha của nó hoặc chuyển null vào liên kết fn nếu không tìm thấy.

? ^^ - Cố gắng định vị bộ điều khiển cần thiết bằng cách tìm kiếm cha mẹ của phần tử hoặc chuyển null vào liên kết fn nếu không tìm thấy.



Câu trả lời cũ:

Bạn cần chèn $controllerdịch vụ để khởi tạo một bộ điều khiển bên trong một bộ điều khiển khác. Nhưng lưu ý rằng điều này có thể dẫn đến một số vấn đề về thiết kế. Bạn luôn có thể tạo các dịch vụ có thể sử dụng lại tuân theo Trách nhiệm duy nhất và đưa chúng vào bộ điều khiển khi bạn cần.

Thí dụ:

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

Trong mọi trường hợp, bạn không thể gọi TestCtrl1.myMethod()vì bạn đã đính kèm phương thức trên $scopevà không phải trên phiên bản controller.

Nếu bạn đang chia sẻ bộ điều khiển, thì tốt hơn hết là bạn nên làm: -

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

và trong khi tiêu dùng làm:

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

Trong trường hợp đầu tiên thực sự $scopelà mô hình chế độ xem của bạn, và trong trường hợp thứ hai, đó là chính thể hiện bộ điều khiển.


4
Và nó phụ thuộc vào chức năng được cung cấp bởi bộ điều khiển, Nếu bạn đang làm cho nó giống như một mô hình xem mà bạn cần chia sẻ trên các thành phần, điều đó là tốt nhưng nếu nó có nhiều chức năng hơn của một nhà cung cấp dịch vụ thì tôi sẽ chỉ tạo một dịch vụ .
PSL

Nên var testCtrl1ViewModel = $scope.$new();được var testCtrl1ViewModel = $rootScope.$new();? tham khảo: docs.angularjs.org/guide/controller @PSL
leonsPAPA

Trong ví dụ trên, bạn đang truy cập vùng chứa trên bộ điều khiển chỉ thị, nhưng tôi không thể làm cho điều này hoạt động. Tôi có thể truy cập các bộ điều khiển được yêu cầu thông qua tham số thứ tư trên hàm liên kết của tôi trên chính chỉ thị. Nhưng chúng không bị ràng buộc với bộ điều khiển chỉ thị như trong ví dụ trên. Bất cứ ai khác có vấn đề này?
Sammi

33

Tôi đề xuất câu hỏi bạn nên hỏi là làm thế nào để đưa các dịch vụ vào bộ điều khiển. Dịch vụ béo với bộ điều khiển gầy là một nguyên tắc nhỏ, hay còn gọi là chỉ sử dụng bộ điều khiển để gắn dịch vụ / nhà máy của bạn (với logic kinh doanh) vào quan điểm của bạn.

Bộ điều khiển được thu thập rác khi thay đổi lộ trình, vì vậy, ví dụ: nếu bạn sử dụng bộ điều khiển để giữ logic nghiệp vụ hiển thị một giá trị, bạn sẽ mất trạng thái trên hai trang nếu người dùng ứng dụng nhấp vào nút quay lại của trình duyệt.

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

Đây là bản demo hoạt động của nhà máy được đưa vào hai bộ điều khiển

Ngoài ra, tôi khuyên bạn nên đọc hướng dẫn này về các dịch vụ / nhà máy.


13

Không cần nhập / tiêm bộ điều khiển của bạn trong JS. Bạn chỉ có thể đưa bộ điều khiển / bộ điều khiển lồng vào nhau thông qua HTML của mình. Giống :

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

2
đúng ... nhưng tôi vẫn cảm thấy tốt hơn nếu đặt tất cả các yếu tố chung vào một dịch vụ và đưa dịch vụ vào bộ điều khiển tương ứng.
Neel

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

Điều này hoạt động tốt nhất trong trường hợp của tôi, trong đó TestCtrl2 có các chỉ thị riêng.

var testCtrl2 = $controller('TestCtrl2')

Điều này mang lại cho tôi lỗi nói rằng lỗi tiêm scopeProvider.

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

Điều này không thực sự hoạt động nếu bạn có chỉ thị trong 'TestCtrl1', chỉ thị đó thực sự có phạm vi khác với chỉ thị này được tạo ở đây. Bạn kết thúc với hai phiên bản 'TestCtrl1'.


-1

Giải pháp tốt nhất:-

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

// Ở đây bạn đã nhận được lệnh gọi bộ điều khiển đầu tiên mà không thực hiện nó


-1

bạn cũng có thể sử dụng $rootScopeđể gọi một hàm / phương thức của bộ điều khiển thứ nhất từ ​​bộ điều khiển thứ hai như thế này,

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

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

1
Phản đối: Đây chỉ là mã hóa tồi: bạn chỉ đang biến chức năng của mình trở nên toàn cầu. Tốt hơn nên bỏ hoàn toàn Angular nếu đây là cách bạn muốn viết mã ... Sử dụng một dịch vụ như được đề xuất bởi hầu hết các câu trả lời khác.
HammerNL

Điều này không được khuyến khích. $ rootScope làm cho mã trở nên vụng về và dẫn đến các vấn đề về lâu dài.
Harshit Pant

-2

sử dụng typecript để viết mã của bạn, vì nó hướng đối tượng, được đánh máy nghiêm ngặt và dễ bảo trì mã ...

để biết thêm thông tin về typecipt bấm vào đây

Đây là một ví dụ đơn giản tôi đã tạo để chia sẻ dữ liệu giữa hai bộ điều khiển bằng cách sử dụng 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);

}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.