Tại sao $ rootScope không thể được truy cập trong khuôn mẫu của một chỉ thị với phạm vi cô lập?


81

Với phạm vi cô lập, mẫu của chỉ thị dường như không thể truy cập vào biến điều khiển ('Ctrl') $ rootScope, tuy nhiên, biến này xuất hiện trong trình điều khiển của chỉ thị. Tôi hiểu tại sao biến phạm vi điều khiển ('Ctrl') $ không hiển thị trong phạm vi cô lập.

HTML:

<div ng-app="app">
    <div ng-controller="Ctrl">
        <my-template></my-template>
    </div>

    <script type="text/ng-template" id="my-template.html">
        <label ng-click="test(blah)">Click</label>
    </script>
</div>

JavaScript:

angular.module('app', [])
    .controller('Ctrl', function Ctrl1($scope,  $rootScope) {
        $rootScope.blah = 'Hello';
        $scope.yah = 'World'
    })
    .directive('myTemplate', function() {
        return {
            restrict: 'E',
            templateUrl: 'my-template.html',
            scope: {},
            controller: ["$scope", "$rootScope", function($scope, $rootScope) {
                console.log($rootScope.blah);
                console.log($scope.yah);,

                $scope.test = function(arg) {
                    console.log(arg);
                }
            }]
        };
    });

JSFiddle

Biến được truy cập mà không có phạm vi cô lập - có thể thấy bằng cách nhận xét dòng phạm vi cô lập:

        // scope: {},

Bạn đã thử chèn $ rootScope vào chỉ thị chưa ... directive('myTemplate', function($rootScope) { ... })?
Marc Kline

@MarcKline Chỉ cần thử điều đó và không có may mắn.
camden_kid


1
Có lý do gì khiến việc sử dụng dịch vụ không đủ cho mục đích của bạn không?
Marc Kline

1
@Kalyan - Cá nhân tôi nghĩ rằng $ rootScope chỉ nên được sử dụng cho các sự kiện và Factory để chuyển dữ liệu đến các chỉ thị. Một lý do là việc sử dụng $ rootScope giống như sử dụng các biến toàn cục không lý tưởng. Ngoài ra, Nhà máy có thể là một trình bao bọc được xác định rõ có thể được mở rộng vào một ngày sau đó.
camden_kid

Câu trả lời:


164

Bạn có thể thử cách này bằng cách sử dụng $root.blah

Mã làm việc

html

 <label ng-click="test($root.blah)">Click</label>

javascript

  angular.module('app', [])
    .controller('Ctrl', function Ctrl1($scope,  $rootScope) {
        $rootScope.blah = 'Hello';
        $scope.yah = 'World'
    })
    .directive('myTemplate', function() {
        return {
            restrict: 'E',
            templateUrl: 'my-template.html',
            scope: {},
            controller: ["$scope", "$rootScope", function($scope, $rootScope) {
                console.log($rootScope.blah);
                console.log($scope.yah);

                $scope.test = function(arg) {
                    console.log(arg);
                }
            }]
        };
    });

6
Tôi đánh dấu đây là câu trả lời vì nó 'giải quyết' những gì tôi muốn đạt được (tôi không biết về '$ root' hoặc nó có thể được sử dụng như thế này). Tuy nhiên , tôi cho rằng câu trả lời của Mark Kline nói chung là giải pháp tốt nhất.
camden_kid

5
kinh ngạc! nó khá hữu ích khi biết rằng $ rootScope thay đổi thành $ root thành các khung nhìn, cảm ơn rất nhiều!
Cris R

Đây là hoàn hảo từ những gì tôi cần làm là truy cập vào một chức năng được xác định trong rootScope
Alfredo A.

Tốt. Nó cũng đang hoạt động ở đây. Bạn có thể vui lòng giải thích tại sao $ root thay vì $ rootScope không? Tôi cũng đã tiêm $ rootScope nhưng nó không được xác định trong khi gọi hàm.
Unknown_Coder

32

Nói chung, bạn nên tránh sử dụng $rootScopeđể lưu trữ các giá trị bạn cần chia sẻ giữa các bộ điều khiển và lệnh. Nó giống như sử dụng hình cầu trong JS. Sử dụng một dịch vụ thay thế:

Một hằng số (hoặc giá trị ... sử dụng tương tự):

.constant('blah', 'blah')

https://docs.angularjs.org/api/ng/type/angular.Module

Một nhà máy (hoặc dịch vụ hoặc nhà cung cấp):

.factory('BlahFactory', function() {
    var blah = {
        value: 'blah'
    };

    blah.setValue = function(val) {
      this.value = val;
    };

    blah.getValue = function() {
        return this.value;
    };

    return blah;
})

Đây là một nhánh của Fiddle của bạn trình bày cách bạn có thể sử dụng


3
+1 Rất cảm ơn vì điều này và đã chỉ cho tôi hướng đi chính xác cho những gì tôi đang cố gắng đạt được. Tôi nghĩ NidhishKrishnan's nên được chấp nhận là 'câu trả lời' vì lý do được nêu trong bình luận của tôi.
camden_kid

1
+1 cho trường hợp sử dụng của hằng số vì chúng hiếm khi được sử dụng. Ngoài ra, lưu ý về việc không sử dụng $ rootScope là một mẹo chuyên nghiệp.
Farzad YZ

23

1) Do phạm vi cô lập $scopetrong bộ điều khiển của bạn Ctrl và trong bộ điều khiển chỉ thị không tham chiếu đến cùng một phạm vi - giả sử chúng ta có phạm vi1 trong Ctrl và phạm vi2 trong chỉ thị.

2) Vì phạm vi cô lập scope2 không kế thừa nguyên mẫu từ $rootScope; vì vậy nếu bạn xác định $rootScope.blahthì không có cơ hội nào bạn có thể nhìn thấy nó trong scope2 .

3) Những gì bạn có thể truy cập trong mẫu chỉ thị của mình là scope2

Nếu tôi tổng hợp lại, đây là lược đồ kế thừa

    _______|______
    |            |
    V            V
$rootScope     scope2
    |
    V
  scope1


$rootScope.blah
> "Hello"
scope1.blah
> "Hello"
scope2.blah
> undefined

1
Rất hữu ích nhưng cách giải quyết của nidhishkrishnan không hoạt động nếu bằng cách nào đó sử dụng các giá trị rootScope là cần thiết. Đó là một hack tốt đẹp.
Marc Kline

1
Vâng, những gì bạn nói là logic để trả lời tại sao tôi không thể sử dụng các biến $ rootScope trong html (không có $ root.), Nhưng khi tôi sử dụng plugin Batarang để xem $ phạm vi, tôi có thể thấy rõ ràng rằng $ rootScope là phạm vi $ cha của tất cả các phạm vi khác (bao gồm cả phạm vi bị cô lập trong các chỉ thị). Ngoài ra, định nghĩa từ các tài liệu chính thức góc cạnh cho biết: "Mọi ứng dụng đều có một phạm vi gốc duy nhất. Tất cả các phạm vi khác là phạm vi con cháu của phạm vi gốc" ( docs.angularjs.org/api/ng/service/$rootScope )
IsraGab

1

Tôi biết đây là một câu hỏi cũ. Nhưng nó không thỏa mãn điều tra của tôi về lý do tại sao phạm vi bị cô lập sẽ không thể truy cập các thuộc tính trong $ rootcope.

Vì vậy, tôi đã tìm kiếm trong lib góc cạnh và tìm thấy -

$new: function(isolate) {
  var ChildScope,
      child;

  if (isolate) {
    child = new Scope();
    child.$root = this.$root;
    child.$$asyncQueue = this.$$asyncQueue;
    child.$$postDigestQueue = this.$$postDigestQueue;
  } else {

    if (!this.$$childScopeClass) {
      this.$$childScopeClass = function() {
        // blah blah...
      };
      this.$$childScopeClass.prototype = this;
    }
    child = new this.$$childScopeClass();
  }

Đây là hàm được gọi bởi góc bất cứ khi nào một phạm vi mới được tạo. Ở đây rõ ràng là bất kỳ phạm vi cô lập nào không phải là kế thừa nguyên mẫu của rootcope. thay vì chỉ rootcope được thêm vào dưới dạng thuộc tính '$ root' trong phạm vi mới. Vì vậy, chúng ta chỉ có thể truy cập các thuộc tính của rootcope từ thuộc tính $ root trong phạm vi cô lập mới.

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.