Sự khác biệt giữa '@' và '=' trong phạm vi chỉ thị trong AngularJS là gì?


1067

Tôi đã đọc tài liệu AngularJS về chủ đề này một cách cẩn thận, và sau đó loay hoay với một chỉ thị. Đây là câu đố .

Và đây là một số đoạn có liên quan:

  • Từ HTML :

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
  • Từ chỉ thị khung:

    scope: { biTitle: '=', title: '@', bar: '=' },

Có một số điều tôi không nhận được:

  • Tại sao tôi phải sử dụng "{{title}}"với '@'"title"với '='?
  • Tôi cũng có thể truy cập phạm vi cha mẹ trực tiếp mà không cần trang trí phần tử của mình bằng một thuộc tính không?
  • Tài liệu nói rằng "Thường thì việc truyền dữ liệu từ phạm vi bị cô lập thông qua biểu thức và phạm vi cha mẹ" , nhưng điều đó dường như cũng hoạt động tốt với ràng buộc hai chiều. Tại sao tuyến đường biểu hiện sẽ tốt hơn?

Tôi cũng tìm thấy một câu đố khác cũng cho thấy giải pháp biểu thức: http://jsfiddle.net/maxisam/QrCXh/


18
Điểm công bằng. Khả năng nghiên cứu và tìm câu trả lời là quan trọng.
Jonathan


1
Trong các từ đơn giản =được sử dụng trong phạm vi cách ly chỉ thị để cho phép ràng buộc hai chiều và @không cập nhật mô hình, chỉ cập nhật các giá trị phạm vi Chỉ thị.
THÉP

@iwein tại sao mã fiddle của bạn tại jsfiddle.net/maxisam/QrCXh không hoạt động với googleapi - ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js ? Mã của bạn chỉ hoạt động nếu tôi sử dụng cdn của bạn - code.angularjs.org/1.0.1/angular-1.0.1.js
MukulSharma

Tôi thấy rất nhiều câu trả lời hay dưới đây, nhưng bất cứ ai cũng có thể đưa ra một con trỏ đến tài liệu góc chính thức trả lời câu hỏi này?
John Henckel

Câu trả lời:


1151

Tại sao tôi phải sử dụng "{{title}}" với ' @ ' và "title" với ' = '?

@ liên kết một thuộc tính phạm vi cục bộ / chỉ thị với giá trị được đánh giá của thuộc tính DOM . Nếu bạn sử dụng title=title1hoặc title="title1", giá trị của "title" thuộc tính DOM chỉ đơn giản là chuỗi title1. Nếu bạn sử dụng title="{{title}}", giá trị của "title" thuộc tính DOM là giá trị được nội suy của {{title}}, do đó chuỗi sẽ là bất cứ thứ gì thuộc tính "title" thuộc tính phạm vi cha mẹ hiện được đặt thành. Vì các giá trị thuộc tính luôn là các chuỗi, nên bạn sẽ luôn kết thúc bằng một giá trị chuỗi cho thuộc tính này trong phạm vi của lệnh khi sử dụng @ .

= liên kết một thuộc tính phạm vi cục bộ / chỉ thị với thuộc tính phạm vi cha . Vì vậy, với = , bạn sử dụng tên thuộc tính mô hình / phạm vi cha làm giá trị của thuộc tính DOM. Bạn không thể sử dụng {{}}s với = .

Với @, bạn có thể thực hiện những việc như title="{{title}} and then some"- {{title}} được nội suy, sau đó chuỗi "và một số" được nối với nó. Chuỗi kết hợp cuối cùng là những gì thuộc tính phạm vi cục bộ / chỉ thị nhận được. (Bạn không thể làm điều này với = , chỉ @ .)

Với @ , bạn sẽ cần sử dụng attr.$observe('title', function(value) { ... })nếu bạn cần sử dụng giá trị trong hàm liên kết (ing) của mình. Ví dụ, if(scope.title == "...")sẽ không làm việc như bạn mong đợi. Lưu ý rằng điều này có nghĩa là bạn chỉ có thể truy cập thuộc tính này không đồng bộ . Bạn không cần sử dụng $ obs () nếu bạn chỉ sử dụng giá trị trong một mẫu. Ví dụ template: '<div>{{title}}</div>'.

Với = , bạn không cần sử dụng $ obs.

Tôi cũng có thể truy cập phạm vi cha mẹ trực tiếp mà không cần trang trí phần tử của mình bằng một thuộc tính không?

Có, nhưng chỉ khi bạn không sử dụng phạm vi cô lập. Xóa dòng này khỏi chỉ thị của bạn

scope: { ... }

và sau đó chỉ thị của bạn sẽ không tạo ra một phạm vi mới. Nó sẽ sử dụng phạm vi cha. Sau đó, bạn có thể truy cập tất cả các thuộc tính phạm vi cha mẹ trực tiếp.

Tài liệu nói rằng "Thường thì việc truyền dữ liệu từ phạm vi bị cô lập thông qua một biểu thức và phạm vi cha mẹ", nhưng điều đó dường như cũng hoạt động tốt với ràng buộc hai chiều. Tại sao tuyến đường biểu hiện sẽ tốt hơn?

Có, ràng buộc hai chiều cho phép phạm vi cục bộ / chỉ thị và phạm vi cha để chia sẻ dữ liệu. "Liên kết biểu thức" cho phép lệnh gọi một biểu thức (hoặc hàm) được xác định bởi thuộc tính DOM - và bạn cũng có thể truyền dữ liệu dưới dạng đối số cho biểu thức hoặc hàm. Vì vậy, nếu bạn không cần chia sẻ dữ liệu với cha mẹ - bạn chỉ muốn gọi một hàm được xác định trong phạm vi cha - bạn có thể sử dụng cú pháp & .

Xem thêm


1
Huh, đây là một hành vi thực sự kỳ lạ, đặc biệt là khi không sử dụng phép nội suy và chỉ cố gắng truyền một chuỗi. Rõ ràng yêu cầu kéo thực sự đã được sáp nhập vào các bản dựng phát triển và nằm trong các bản dựng RC 1.1.5 và 1.2.0. Tốt cho họ để sửa chữa hành vi rất không trực quan này!
Ibrahim

50
Viết '@' hoặc '=' rõ ràng hơn rất nhiều sau đó viết "eval-dom" hoặc "Parent-scope" hoặc bất kỳ văn bản nào có thể đọc được của con người. Quyết định thiết kế tốt.
Den

13
@('at') sao chép giá trị của 'ATtribution'. =('bằng') tương đương với việc nói khóa bằng biểu thức của bạn. Điều này, ít nhất, là cách tôi giữ cho họ eo biển.
Matt DeKrey

1
Bạn có chắc chắn rằng = chỉ dành cho các thuộc tính phạm vi cha mẹ không? Bất kỳ biểu thức nào dường như hoạt động - không chỉ các thuộc tính phạm vi cha.
Jonathan Aquino

4
@JonathanAquino, vâng, nó hoạt động, nhưng @ sẽ phù hợp hơn - với foo="{{1+1}}"- bởi vì chúng tôi không cần ràng buộc dữ liệu hai chiều ở đây. Điểm tôi đã cố gắng đưa ra trong nhận xét ở trên là chúng ta nên sử dụng = chỉ khi lệnh cần ràng buộc dữ liệu hai chiều. Sử dụng @ hoặc & nếu không.
Mark Rajcok

542

Có rất nhiều câu trả lời tuyệt vời ở đây, nhưng tôi muốn cung cấp quan điểm của tôi về sự khác biệt giữa @, =&ràng buộc mà tỏ ra hữu ích cho tôi.

Tất cả ba ràng buộc là cách chuyển dữ liệu từ phạm vi cha mẹ của bạn sang phạm vi tách biệt của lệnh của bạn thông qua các thuộc tính của thành phần:

  1. @ ràng buộc là để truyền chuỗi. Các chuỗi này hỗ trợ các {{}}biểu thức cho các giá trị nội suy. Ví dụ: . Biểu thức nội suy được đánh giá theo phạm vi cha của chỉ thị.

  2. = ràng buộc là cho ràng buộc mô hình hai chiều. Mô hình trong phạm vi cha được liên kết với mô hình trong phạm vi tách biệt của chỉ thị. Thay đổi đối với một mô hình ảnh hưởng đến mô hình khác và ngược lại.

  3. & ràng buộc là để truyền một phương thức vào phạm vi chỉ thị của bạn để nó có thể được gọi trong chỉ thị của bạn. Phương thức được liên kết trước với phạm vi cha của chỉ thị và hỗ trợ các đối số. Ví dụ: nếu phương thức là hello (name) trong phạm vi cha, thì để thực thi phương thức từ bên trong lệnh của bạn, bạn phải gọi $ scope.hello ({name: 'world'})

Tôi thấy rằng việc ghi nhớ những khác biệt này dễ dàng hơn bằng cách tham khảo các ràng buộc phạm vi bằng một mô tả ngắn hơn:

  • @ Ràng buộc chuỗi thuộc tính
  • = Ràng buộc mô hình hai chiều
  • & Phương thức gọi lại ràng buộc

Các biểu tượng cũng làm cho nó rõ ràng hơn về những gì biến phạm vi thể hiện bên trong việc thực hiện chỉ thị của bạn:

  • @ chuỗi
  • = mô hình
  • & phương pháp

Theo thứ tự hữu ích (đối với tôi dù sao):

  1. = =
  2. @
  3. &

13
Trên thực tế, "&"không hỗ trợ các đối số (hoặc, đúng hơn là người địa phương) của biểu mẫu : callback({foo: "some value"}), sau đó có thể được sử dụng <my-dir callback="doSomething(foo)">. Nếu không, câu trả lời tốt
New Dev

11
Nên chấp nhận trả lời. Dưới đây là một bài viết ngắn gọn với cùng thông tin, nhưng có thêm ví dụ mã: umur.io/ Kẻ
Kevin

4
& KHÔNG phải là "ràng buộc phương thức gọi lại", đó là ràng buộc biểu thức góc. Một ví dụ đặc biệt nhưng không phải là biểu thức callback(argument). Mà vẫn không giống như callbackchính nó.
Dmitri Zaitsev

14
Trong khi tôi yêu thích câu trả lời xếp hạng cao hơn dứt khoát như thế nào, tôi thấy câu trả lời này có tác động hữu ích hơn và sau khi đọc câu trả lời này, tôi đã hiểu câu trả lời trước đó nhiều hơn nữa.
rbnzdave

1
Tôi đồng ý với nhận xét trên, câu trả lời này rõ ràng hơn, dứt khoát và hữu ích cho câu hỏi. Nó giải thích với đủ chi tiết rằng bạn có thể đi và sử dụng thông tin.
dùng3125823

64

Nghĩa =là liên kết hai chiều, do đó, tham chiếu đến một biến trong phạm vi cha. Điều này có nghĩa là, khi bạn thay đổi biến trong chỉ thị, nó cũng sẽ được thay đổi trong phạm vi cha.

@ có nghĩa là biến sẽ được sao chép (nhân bản) vào lệnh.

Theo tôi biết, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>nên làm việc quá. bi-titlesẽ nhận được giá trị biến phạm vi cha, có thể được thay đổi trong lệnh.

Nếu bạn cần thay đổi một số biến trong phạm vi cha, bạn có thể thực thi một hàm trên phạm vi cha từ trong lệnh (hoặc truyền dữ liệu qua dịch vụ).


1
Vâng, phần đó tôi nhận được, xem câu đố trong câu hỏi. Nhưng những gì về những phần không rõ ràng?
iwein

4
điều này là {{}} không hoạt động với =. = không được đánh giá, nhưng chuỗi được lấy làm tên thuộc tính. Cảm ơn câu trả lời!
iwein

1
Tôi không nghĩ rằng = chỉ dành cho các biến trong phạm vi cha. Nó hoạt động với bất kỳ biểu thức nào (ví dụ: 1 + 1).
Jonathan Aquino

1
@JonathanAquino bạn đúng khi đánh giá biểu thức. Imho điều này thực sự kỳ lạ và tôi sẽ không sử dụng nó theo cách đó. Đó là loại mánh khóe thông minh khiến cho phạm vi chỉ thị trở nên khó hiểu đối với tôi ngay từ đầu.
iwein

1
Tôi có phải là người duy nhất nghĩ rằng câu trả lời này là sai! '=' có nghĩa là góc mong đợi một biểu thức javascript và sẽ thực hiện ánh xạ hai chiều nếu một biến phạm vi được thông qua. Trong khi đó @ có nghĩa là góc mong đợi một Chuỗi và tất cả. Trên thực tế, sự thật là nếu bạn sử dụng @ in combinaison với {{}}, bạn sẽ sao chép giá trị của biến. Nhưng đó không phải là định nghĩa của @!
Luc DUZAN

39

Nếu bạn muốn xem thêm cách thức hoạt động của nó với một ví dụ trực tiếp. http://jsfiddle.net/juanmendez/k6chmnch/

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});

2
Có một số ví dụ được liên kết trong câu hỏi và câu trả lời hàng đầu. Điều này thêm gì?
iwein

10
@iwein, nó thêm rõ ràng. Nếu tôi có thể hiểu và đồng hóa các ví dụ đầy đủ tính năng, tôi sẽ không cần trang web này.
Tony Enni

3
juan, có thể sửa lỗi chính tả của bạn? 'transclude' là sai chính tả. tốt hơn hết, hãy xóa nó (và mọi thứ khác, như 'thay thế') không đóng góp trực tiếp vào vấn đề để giải pháp của bạn thậm chí còn đơn giản và rõ ràng hơn. +1 cho ví dụ.
Tony Enni

cảm ơn bạn @AnikISlamAbhi đã chỉnh sửa. Tôi muốn đóng góp nhiều hơn và tôi rất vui vì một số mẫu của tôi hữu ích. Đó là mục đích chính.
Juan Mendez

Ví dụ không đầy đủ. Trong phần trình diễn của bạn, bạn chỉ thay đổi giá trị hai chiều. Bạn thậm chí không cố gắng thay đổi giá trị có phạm vi bị cô lập. Vì vậy, nó không thể hiện đúng cách phạm vi hoạt động trong các chỉ thị.
Sudarshan_SMD

38

@ lấy làm chuỗi

  • Điều này không tạo ra bất kỳ ràng buộc nào. Bạn chỉ đơn giản là nhận được từ bạn chuyển qua dưới dạng một chuỗi

= Ràng buộc 2 chiều

  • những thay đổi được thực hiện từ bộ điều khiển sẽ được phản ánh trong tham chiếu được giữ bởi chỉ thị và ngược lại

&Điều này hành xử hơi khác một chút, bởi vì phạm vi có một hàm trả về đối tượng được truyền vào . Tôi cho rằng điều này là cần thiết để làm cho nó hoạt động. Các fiddle nên làm rõ điều này.

  • Sau khi gọi hàm getter này, đối tượng kết quả sẽ hành xử như sau:
    • nếu một hàm được truyền: thì hàm được thực thi trong bao đóng cha (bộ điều khiển) khi được gọi
    • nếu một hàm không được truyền vào: chỉ cần lấy một bản sao cục bộ của đối tượng không có ràng buộc


Fiddle này sẽ chứng minh làm thế nào họ làm việc . Đặc biệt chú ý đến các hàm phạm vi có get...trong tên để hy vọng hiểu rõ hơn về ý tôi&


36

Có ba cách phạm vi có thể được thêm vào trong chỉ thị:

  1. Phạm vi cha mẹ : Đây là sự kế thừa phạm vi mặc định.

Lệnh và phạm vi cha (bộ điều khiển / chỉ thị bên trong nó nằm) giống nhau. Vì vậy, bất kỳ thay đổi được thực hiện cho các biến phạm vi trong chỉ thị cũng được phản ánh trong bộ điều khiển cha. Bạn không cần chỉ định điều này vì nó là mặc định.

  1. Phạm vi con : directive tạo một phạm vi con kế thừa từ phạm vi cha nếu bạn chỉ định biến phạm vi của lệnh là true.

Ở đây, nếu bạn thay đổi các biến phạm vi trong chỉ thị, nó sẽ không phản ánh trong phạm vi cha, nhưng nếu bạn thay đổi thuộc tính của biến phạm vi, điều đó được phản ánh trong phạm vi cha, như bạn thực sự đã sửa đổi biến phạm vi của cha mẹ .

Thí dụ,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Phạm vi tách biệt : Điều này được sử dụng khi bạn muốn tạo phạm vi không kế thừa từ phạm vi điều khiển.

Điều này xảy ra khi bạn đang tạo các plugin vì điều này làm cho lệnh chung vì nó có thể được đặt trong bất kỳ HTML nào và không bị ảnh hưởng bởi phạm vi cha của nó.

Bây giờ, nếu bạn không muốn bất kỳ tương tác nào với phạm vi cha, thì bạn chỉ có thể chỉ định phạm vi là một đối tượng trống. giống,

scope: {} //this does not interact with the parent scope in any way

Hầu hết đây không phải là trường hợp vì chúng tôi cần một số tương tác với phạm vi cha, vì vậy chúng tôi muốn một số giá trị / thay đổi đi qua. Vì lý do này, chúng tôi sử dụng:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ có nghĩa là những thay đổi từ phạm vi điều khiển sẽ được phản ánh trong phạm vi chỉ thị nhưng nếu bạn sửa đổi giá trị trong phạm vi chỉ thị, biến phạm vi điều khiển sẽ không bị ảnh hưởng.

@ luôn mong thuộc tính ánh xạ là một biểu thức. Cái này rất quan trọng; bởi vì để làm cho tiền tố của tên @ @ hoạt động, chúng ta cần phải bọc giá trị thuộc tính bên trong {{}}.

= là hai chiều vì vậy nếu bạn thay đổi biến trong phạm vi chỉ thị, biến phạm vi điều khiển cũng bị ảnh hưởng

& được sử dụng để liên kết phương thức phạm vi điều khiển để nếu cần chúng ta có thể gọi nó từ lệnh

Ưu điểm ở đây là tên của biến không cần giống nhau trong phạm vi điều khiển và phạm vi chỉ thị.

Ví dụ, phạm vi chỉ thị có một biến "dirVar" đồng bộ với biến "contVar" của phạm vi điều khiển. Điều này mang lại nhiều sức mạnh và khái quát hóa cho chỉ thị vì một bộ điều khiển có thể đồng bộ hóa với biến v1 trong khi một bộ điều khiển khác sử dụng cùng một lệnh có thể yêu cầu dirVar đồng bộ hóa với biến v2.

Dưới đây là ví dụ về cách sử dụng:

Lệnh và bộ điều khiển là:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

Và html (lưu ý differnce cho @ và =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

Đây là một liên kết đến blog mô tả nó độc đáo.


& không phải là "ràng buộc hành vi" hay "ràng buộc phương thức", đó là ràng buộc biểu thức góc.
Dmitri Zaitsev

20

Đơn giản là chúng ta có thể sử dụng: -

  1. @ : - cho các giá trị Chuỗi cho liên kết Dữ liệu một chiều. theo một cách ràng buộc dữ liệu, bạn chỉ có thể chuyển giá trị phạm vi cho chỉ thị

  2. = : - cho giá trị đối tượng cho ràng buộc dữ liệu hai chiều. trong hai cách ràng buộc dữ liệu, bạn có thể thay đổi giá trị phạm vi trong chỉ thị cũng như trong html.

  3. & : - cho các phương thức và chức năng.

BIÊN TẬP

Trong định nghĩa Thành phần của chúng tôi cho phiên bản Angular 1.5 Và ở trên
có bốn loại ràng buộc khác nhau:

  1. = Ràng buộc dữ liệu hai chiều : - nếu chúng tôi thay đổi giá trị, nó sẽ tự động cập nhật
  2. < ràng buộc một cách : - khi chúng ta chỉ muốn đọc một tham số từ phạm vi cha và không cập nhật nó.

  3. @đây là cho tham số chuỗi

  4. &đây là cho Callbacks trong trường hợp thành phần của bạn cần xuất cái gì đó đến phạm vi cha của nó


13

Tôi đã tạo một tệp HTML nhỏ chứa mã Angular thể hiện sự khác biệt giữa chúng:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>

6

Các = cách là 2 chiều ràng buộc , cho phép bạn có sống thay đổi bên trong chỉ thị của bạn. Khi ai đó thay đổi biến đó ra khỏi lệnh, bạn sẽ có dữ liệu thay đổi đó trong lệnh của bạn, nhưng @ way không phải là ràng buộc hai chiều . Nó hoạt động như Văn bản . Bạn ràng buộc một lần, và bạn sẽ chỉ có giá trị của nó.

Để hiểu rõ hơn, bạn có thể sử dụng bài viết tuyệt vời này:

Phạm vi chỉ thị của AngularJS '@' và '='


6

Câu hỏi này đã bị đánh đến chết, nhưng dù sao tôi cũng sẽ chia sẻ câu hỏi này trong trường hợp có người khác đang vật lộn với mớ hỗn độn khủng khiếp đó là phạm vi AngularJS. Điều này sẽ che =, <, @, &::. Việc viết đầy đủ có thể được tìm thấy ở đây .


=thiết lập một ràng buộc hai chiều. Thay đổi tài sản ở cha mẹ sẽ dẫn đến thay đổi ở trẻ, và ngược lại.


<thiết lập một ràng buộc một chiều, cha mẹ với con. Thay đổi tài sản ở cha mẹ sẽ dẫn đến thay đổi ở trẻ, nhưng thay đổi tài sản con sẽ không ảnh hưởng đến tài sản của cha mẹ.


@sẽ gán cho thuộc tính con giá trị chuỗi của thuộc tính thẻ. Nếu thuộc tính chứa một biểu thức , thuộc tính con cập nhật bất cứ khi nào biểu thức ước lượng thành một chuỗi khác. Ví dụ:

<child-component description="The movie title is {{$ctrl.movie.title}}" />
bindings: {
    description: '@', 
}

Ở đây, thuộc descriptiontính trong phạm vi con sẽ là giá trị hiện tại của biểu thức "The movie title is {{$ctrl.movie.title}}", trong đó moviemột đối tượng trong phạm vi cha.


&là một chút khó khăn, và trên thực tế dường như không có lý do thuyết phục nào để sử dụng nó. Nó cho phép bạn đánh giá một biểu thức trong phạm vi cha, thay thế các tham số bằng các biến từ phạm vi con. Một ví dụ ( plunk ):

<child-component 
  foo = "myVar + $ctrl.parentVar + myOtherVar"
</child-component>
angular.module('heroApp').component('childComponent', {
  template: "<div>{{  $ctrl.parentFoo({myVar:5, myOtherVar:'xyz'})  }}</div>",
  bindings: {
    parentFoo: '&foo'
  }
});

Cho parentVar=10, biểu thức parentFoo({myVar:5, myOtherVar:'xyz'})sẽ ước tính 5 + 10 + 'xyz'và thành phần sẽ hiển thị là:

<div>15xyz</div>

Khi nào bạn muốn sử dụng chức năng phức tạp này? &thường được mọi người sử dụng để chuyển đến phạm vi con một hàm gọi lại trong phạm vi cha. Tuy nhiên, trong thực tế, hiệu ứng tương tự có thể đạt được bằng cách sử dụng '<' để truyền hàm, điều này đơn giản hơn và tránh cú pháp dấu ngoặc nhọn khó xử để truyền tham số ( {myVar:5, myOtherVar:'xyz'}). Xem xét:

Gọi lại bằng cách sử dụng &:

<child-component parent-foo="$ctrl.foo(bar)"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo({bar:'xyz'})">Call foo in parent</button>',
  bindings: {
    parentFoo: '&'
  }
});

Gọi lại bằng cách sử dụng <:

<child-component parent-foo="$ctrl.foo"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo('xyz')">Call foo in parent</button>',
  bindings: {
    parentFoo: '<'
  }
});

Lưu ý rằng các đối tượng (và mảng) được truyền bằng tham chiếu đến phạm vi con, không được sao chép. Điều này có nghĩa là ngay cả khi đó là ràng buộc một chiều, bạn đang làm việc với cùng một đối tượng trong cả phạm vi cha và con.


Để xem các tiền tố khác nhau đang hoạt động, hãy mở plunk này .

Liên kết một lần (khởi tạo) bằng cách sử dụng ::

[Tài liệu chính thức] Các
phiên bản sau của AngularJS giới thiệu tùy chọn có ràng buộc một lần, trong đó thuộc tính phạm vi con chỉ được cập nhật một lần. Điều này cải thiện hiệu suất bằng cách loại bỏ nhu cầu xem tài sản mẹ. Cú pháp khác với ở trên; để khai báo ràng buộc một lần, bạn thêm ::vào trước biểu thức trong thẻ thành phần :

<child-component 
  tagline = "::$ctrl.tagline">
</child-component>

Điều này sẽ tuyên truyền giá trị của taglinephạm vi con mà không thiết lập ràng buộc một chiều hoặc hai chiều. Lưu ý : nếu taglineban đầu undefinedtrong phạm vi cha, angular sẽ xem nó cho đến khi nó thay đổi và sau đó thực hiện cập nhật một lần của thuộc tính tương ứng trong phạm vi con.

Tóm lược

Bảng dưới đây cho thấy cách các tiền tố hoạt động tùy thuộc vào việc thuộc tính có phải là một đối tượng, mảng, chuỗi, v.v.

Làm thế nào các ràng buộc phạm vi cô lập khác nhau làm việc


4

@ thuộc tính phạm vi cục bộ được sử dụng để truy cập các giá trị chuỗi được xác định bên ngoài chỉ thị.

= Trong trường hợp bạn cần tạo liên kết hai chiều giữa phạm vi bên ngoài và phạm vi cô lập của lệnh, bạn có thể sử dụng ký tự =.

& thuộc tính phạm vi cục bộ cho phép người tiêu dùng của lệnh chuyển qua chức năng mà lệnh có thể gọi.

Vui lòng kiểm tra liên kết dưới đây cung cấp cho bạn sự hiểu biết rõ ràng với các ví dụ. Tôi thấy nó thực sự rất hữu ích vì vậy đã nghĩ đến việc chia sẻ nó.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope


3

Ngay cả khi phạm vi là cục bộ, như trong ví dụ của bạn, bạn có thể truy cập phạm vi cha thông qua thuộc tính $parent. Giả sử trong mã dưới đây, titleđược xác định trên phạm vi cha. Sau đó, bạn có thể truy cập tiêu đề như $parent.title:

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

Tuy nhiên, trong hầu hết các trường hợp, hiệu ứng tương tự thu được tốt hơn bằng cách sử dụng các thuộc tính.

Một ví dụ về nơi tôi tìm thấy ký hiệu "&", được sử dụng "để truyền dữ liệu từ phạm vi bị cô lập thông qua một biểu thức và đến phạm vi cha mẹ", không hữu ích (và không thể sử dụng cơ sở dữ liệu hai chiều) để hiển thị một cơ sở hạ tầng đặc biệt bên trong một lặp lại ng.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

Một phần của kết xuất là nút xóa và ở đây rất hữu ích khi đính kèm một thao tác xóa từ phạm vi bên ngoài thông qua &. Bên trong chỉ thị kết xuất, nó trông giống như

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

2 chiều databinding tức là data = "="không thể được sử dụng như chức năng xóa sẽ chạy trên mọi $digestchu kỳ, đó là không tốt, là kỷ lục này sau đó ngay lập tức bị xóa và không bao giờ trả lại.



3

sự khác biệt chính giữa chúng chỉ là

@ Attribute string binding
= Two-way model binding
& Callback method binding

1

@=xem các câu trả lời khác.

Một gotcha về TL; DR; nhận biểu thức (không chỉ có chức năng như trong các ví dụ trong các câu trả lời khác) từ cha mẹ và đặt nó làm hàm trong lệnh, gọi biểu thức đó. Và hàm này có khả năng thay thế bất kỳ biến nào (thậm chí tên hàm) của biểu thức, bằng cách chuyển một đối tượng bằng các biến. &

&

giải thích
& là một tham chiếu biểu thức, có nghĩa là nếu bạn truyền một cái gì đó như <myDirective expr="x==y"></myDirective>
trong lệnh này thì đây exprsẽ là một hàm, gọi biểu thức đó, như :
function expr(){return x == y}.
vì vậy trong html của <button ng-click="expr()"></button>lệnh sẽ gọi biểu thức. Trong js của chỉ thị $scope.expr()sẽ gọi biểu thức quá.
Biểu thức sẽ được gọi với $ scope.x và $ scope.y của cha.
Bạn có khả năng ghi đè các tham số!
Nếu bạn đặt chúng bằng cuộc gọi, ví dụ: <button ng-click="expr({x:5})"></button>
biểu thức sẽ được gọi với tham số của bạn xvà tham số của cha y.
Bạn có thể ghi đè cả hai.
Bây giờ bạn biết, tại sao <button ng-click="functionFromParent({x:5})"></button>làm việc.
Bởi vì nó chỉ gọi biểu thức của cha mẹ (ví dụ<myDirective functionFromParent="function1(x)"></myDirective>) và thay thế các giá trị có thể bằng các tham số đã chỉ định của bạn, trong trường hợp này x.
nó có thể là:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
hoặc
<myDirective functionFromParent="function1(x) + z"></myDirective>
với cuộc gọi con :
<button ng-click="functionFromParent({x:5, z: 4})"></button>.
hoặc thậm chí với chức năng thay thế :
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>.

nó chỉ là một biểu thức, không quan trọng nếu nó là một hàm, hoặc nhiều hàm hoặc chỉ là so sánh. Và bạn có thể thay thế bất kỳ biến của biểu thức này.

Ví dụ:
mẫu chỉ thị so với mã được gọi:
cha mẹ đã xác định $ scope.x, $ scope.y:
mẫu gốc: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button>gọi $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button>các 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button>cuộc gọi cuộc gọi5 == 6

cha mẹ đã định nghĩa $ scope.feft1, $ scope.x, $ scope.y:
mẫu cha:<myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button>cuộc gọi $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button>cuộc $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button>gọi $scope.function1(5) + 6
chỉ thị có $ scope.myFn là hàm:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> cuộc gọi$scope.myFn(5) + 6


0

Tại sao tôi phải sử dụng "{{title}}" với '@' và "title" với '='?

Khi bạn sử dụng {{title}}, chỉ giá trị phạm vi cha mẹ sẽ được chuyển sang chế độ xem chỉ thị và được đánh giá. Điều này được giới hạn theo một cách, có nghĩa là thay đổi sẽ không được phản ánh trong phạm vi cha mẹ. Bạn có thể sử dụng '=' khi bạn muốn phản ánh các thay đổi được thực hiện trong chỉ thị con cho phạm vi cha mẹ. Đây là hai cách.

Tôi cũng có thể truy cập phạm vi cha mẹ trực tiếp mà không cần trang trí phần tử của mình bằng một thuộc tính không?

Khi chỉ thị có thuộc tính scope trong đó (scope: {}), thì bạn không còn có thể truy cập trực tiếp phạm vi cha. Nhưng vẫn có thể truy cập nó thông qua phạm vi. $ Parent, v.v. Nếu bạn loại bỏ phạm vi khỏi chỉ thị, nó có thể được truy cập trực tiếp.

Tài liệu nói rằng "Thường thì việc truyền dữ liệu từ phạm vi bị cô lập thông qua một biểu thức và phạm vi cha mẹ", nhưng điều đó dường như cũng hoạt động tốt với ràng buộc hai chiều. Tại sao tuyến đường biểu hiện sẽ tốt hơn?

Nó phụ thuộc vào bối cảnh. Nếu bạn muốn gọi một biểu thức hoặc hàm bằng dữ liệu, bạn sử dụng & và nếu bạn muốn chia sẻ dữ liệu, bạn có thể sử dụng cách chuyển hướng bằng cách sử dụng '='

Bạn có thể tìm thấy sự khác biệt giữa nhiều cách truyền dữ liệu tới chỉ thị ở liên kết bên dưới:

AngularJS - Phạm vi biệt lập - @ vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isreach-scopes-vs-vs


0

@ Thuộc tính chuỗi ràng buộc (một chiều) = Liên kết mô hình hai chiều và liên kết phương thức gọi lại


0

@ liên kết một thuộc tính phạm vi cục bộ / chỉ thị với giá trị được đánh giá của thuộc tính DOM. = liên kết một thuộc tính phạm vi cục bộ / chỉ thị với thuộc tính phạm vi cha. & ràng buộc là để truyền một phương thức vào phạm vi chỉ thị của bạn để nó có thể được gọi trong chỉ thị của bạn.

@ Ràng buộc chuỗi thuộc tính = Liên kết mô hình hai chiều và liên kết phương thức gọi lạ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.