AngularJS - Quyền truy cập vào phạm vi con


110

Nếu tôi có các bộ điều khiển sau:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

Cách thích hợp để parentđọc bhết là childgì? Nếu nó cần thiết để xác định btrong parent, điều đó có làm cho nó không chính xác về mặt ngữ nghĩa giả sử rằng đó blà một thuộc tính mô tả một cái gì đó liên quan đến childvà không parent?

Cập nhật: Suy nghĩ thêm về nó, nếu có nhiều hơn một đứa trẻ có bnó sẽ tạo ra một cuộc xung đột cho parentmà trên đó bđể lấy. Câu hỏi của tôi vẫn còn, cách thích hợp để truy cập btừ đó là parentgì?


1
Ngoài ra, hãy chắc chắn rằng bạn đã đọc phần này: stackoverflow.com/questions/14049480/… Một tổng quan rất tốt và chuyên sâu về phạm vi và sự kế thừa trong angleJS.
Martijn

Câu trả lời:


162

Phạm vi trong AngularJS sử dụng kế thừa nguyên mẫu, khi tìm kiếm một thuộc tính trong phạm vi con, trình thông dịch sẽ tìm kiếm chuỗi nguyên mẫu bắt đầu từ con và tiếp tục đến cha mẹ cho đến khi tìm thấy thuộc tính, không phải ngược lại.

Kiểm tra nhận xét của Vojta về vấn đề này https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

Tóm lại: Bạn không thể truy cập phạm vi con từ phạm vi cha.

Giải pháp của bạn:

  1. Xác định thuộc tính trong cha mẹ và truy cập chúng từ trẻ em (đọc liên kết ở trên)
  2. Sử dụng một dịch vụ để chia sẻ trạng thái
  3. Truyền dữ liệu qua các sự kiện. $emitgửi các sự kiện trở lên cho cha mẹ cho đến khi phạm vi gốc và $broadcastgửi các sự kiện xuống dưới. Điều này có thể giúp bạn giữ cho mọi thứ chính xác về mặt ngữ nghĩa.

8
Thêm vào đó, sự khác biệt giữa $ phát và $ broadcast là $ phát có thể hủy và $ phát không.
Azri Jamil

Một nơi bạn có thể muốn lấy phạm vi con là khi chỉ thị kiểm thử đơn vị. Nếu bạn có một chỉ thị được bao gồm thì phạm vi là con của phạm vi được sử dụng để biên dịch phần tử. Việc truy cập vào phạm vi của chỉ thị đã biên dịch để kiểm tra là một thách thức.
pmc

Cảm ơn. Một tùy chọn khác có thể là localStoragevới một phụ thuộc như ngStorage.
Akash

81

Mặc dù câu trả lời của jm-là cách tốt nhất để xử lý trường hợp này, nhưng để tham khảo trong tương lai, bạn có thể truy cập phạm vi con bằng cách sử dụng các thành viên $$ childHead, $$ childTail, $$ nextSibling và $$ prevSibling của phạm vi. Những điều này không được ghi lại nên chúng có thể thay đổi mà không cần thông báo, nhưng chúng ở đó nếu bạn thực sự cần đi qua phạm vi.

// get $$childHead first and then iterate that scope's $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

Vĩ cầm


49

Bạn có thể thử điều này:

$scope.child = {} //declare it in parent controller (scope)

sau đó trong bộ điều khiển con (phạm vi) thêm:

var parentScope = $scope.$parent;
parentScope.child = $scope;

Bây giờ phụ huynh có quyền truy cập vào phạm vi của trẻ.


1
Rất sạch sẽ và đơn giản. Để thêm vào điều này, chỉ cần nhận ra rằng không có ràng buộc nào vì vậy khi bạn khai báo nó như trên, parentScope.child đang giữ phạm vi con tại thời điểm đó. Để giải quyết vấn đề này, bạn có thể thêm $ scope. $ Watch (function () {parentScope.child = $ scope}); để sau mỗi lần thông báo, nó sẽ đẩy phạm vi mới lên cấp chính. Về phía phụ huynh, nếu bạn đang sử dụng bất kỳ phạm vi con nào cho hình ảnh trong html, bạn sẽ cần thêm một đồng hồ trên biến con của nó và yêu cầu nó cập nhật phạm vi như sau: $ scope. $ Watch ('child', function ( ) {$ scope. $ evalAsync ();}); . Hy vọng điều này sẽ tiết kiệm thời gian cho ai đó!
IfTrue

2
@IfTrue Tôi tin rằng $ watch () là không bắt buộc. Đây là các đối tượng và chúng chuyển qua tham chiếu.
Swanidhi

2
@Swanidhi = Tôi biết ý của bạn và tôi cũng nghĩ vậy nhưng nó không hoạt động khi tôi đang thử nghiệm vào thời điểm viết bình luận. Đối với những gì đáng giá là tôi chuyển từ làm điều này sang phát / phát sóng.
IfTrue

1
Làm cách nào để thực hiện việc này trong Type Script?
ATHER

Câu trả lời tốt nhất cho tôi !! Ví dụ tốt nhất của các đối tượng coi là bằng cách tham khảo trong javascript
Vikas Gautam

4

Một giải pháp khả thi là đưa bộ điều khiển con vào bộ điều khiển mẹ bằng cách sử dụng hàm init.

Có thể thực hiện:

<div ng-controller="ParentController as parentCtrl">
   ...

    <div ng-controller="ChildController as childCtrl" 
         ng-init="ChildCtrl.init()">
       ...
    </div>
</div>

Nơi ChildControllerbạn có:

app.controller('ChildController',
    ['$scope', '$rootScope', function ($scope, $rootScope) {
    this.init = function() {
         $scope.parentCtrl.childCtrl = $scope.childCtrl;
         $scope.childCtrl.test = 'aaaa';
    };

}])

Vì vậy, bây giờ ParentControllerbạn có thể sử dụng:

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

Quan trọng:
Để hoạt động bình thường, bạn phải sử dụng chỉ thị ng-controllervà đổi tên từng bộ điều khiển bằng cách sử dụng asgiống như tôi đã làm trong html, ví dụ.

Mẹo:
Sử dụng plugin chrome ng-ins Inspector trong quá trình này. Nó sẽ giúp bạn hiểu về cây.


3

Sử dụng $ phát$ phát , (như được walv đề cập trong các nhận xét ở trên)

Để kích hoạt một sự kiện trở lên (từ con đến cha mẹ)

$scope.$emit('myTestEvent', 'Data to send');

Để kích hoạt một sự kiện từ dưới lên (từ cha mẹ sang con)

$scope.$broadcast('myTestEvent', {
  someProp: 'Sending you some data'
});

và cuối cùng là lắng nghe

$scope.$on('myTestEvent', function (event, data) {
  console.log(data);
});

Để biết thêm chi tiết: - https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribe/

Thưởng thức :)


1

Có, chúng ta có thể gán các biến từ bộ điều khiển con cho các biến trong bộ điều khiển mẹ. Đây là một cách khả thi:

Tổng quan: Mục đích chính của đoạn mã dưới đây là gán $ scope.variable của bộ điều khiển con cho $ scope.assign của bộ điều khiển mẹ

Giải thích: Có hai bộ điều khiển. Trong html, lưu ý rằng bộ điều khiển mẹ bao quanh bộ điều khiển con. Điều đó có nghĩa là bộ điều khiển mẹ sẽ được thực thi trước bộ điều khiển con. Vì vậy, setValue () đầu tiên sẽ được định nghĩa và sau đó điều khiển sẽ chuyển đến bộ điều khiển con. $ scope.variable sẽ được gán là "con". Sau đó, phạm vi con này sẽ được chuyển làm đối số cho hàm của bộ điều khiển cha, trong đó $ scope.assign sẽ nhận giá trị là "con"

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script type="text/javascript">
    var app = angular.module('myApp',[]);

    app.controller('child',function($scope){
        $scope.variable = "child";
        $scope.$parent.setValue($scope);
    });

    app.controller('parent',function($scope){
        $scope.setValue = function(childscope) {
            $scope.assign = childscope.variable;
        }
    });

</script>
<body ng-app="myApp">
 <div ng-controller="parent">
    <p>this is parent: {{assign}}</p>
    <div ng-controller="child">
        <p>this is {{variable}}</p>
    </div>
 </div>
</body>
</html>
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.