อะไรคือความแตกต่างระหว่าง '@' และ '=' ในขอบเขตคำสั่งใน AngularJS?


1067

ฉันได้อ่านเอกสารของAngularJSในหัวข้ออย่างระมัดระวังแล้วเล่นกับคำสั่ง นี่คือไวโอลิน

และนี่คือตัวอย่างบางส่วนที่เกี่ยวข้อง:

  • จากHTML :

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
  • จากคำสั่งบานหน้าต่าง:

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

มีหลายสิ่งที่ฉันไม่ได้รับ:

  • ทำไมฉันต้องใช้"{{title}}"กับ'@'และ"title"กับ'='?
  • ฉันสามารถเข้าถึงขอบเขตพาเรนต์โดยตรงได้หรือไม่โดยไม่ต้องตกแต่งองค์ประกอบด้วยแอตทริบิวต์
  • เอกสารอธิบายว่า"บ่อยครั้งที่ต้องการส่งข้อมูลจากขอบเขตแยกผ่านการแสดงออกและขอบเขตหลัก"แต่ดูเหมือนว่าจะทำงานได้ดีกับการเชื่อมโยงสองทิศทางเช่นกัน ทำไมเส้นทางนิพจน์ถึงดีกว่า

ฉันพบซออื่นที่แสดงวิธีแก้ปัญหาการแสดงออกเช่นกัน: http://jsfiddle.net/maxisam/QrCXh/


18
จุดยุติธรรม ความสามารถในการวิจัยและค้นหาคำตอบเป็นสิ่งสำคัญ
Jonathan


1
คำง่ายๆ=นั้นใช้ในขอบเขตการแยก@โดยตรงเพื่อเปิดใช้งานการรวมสองทางและไม่อัปเดตโมเดลเพียงอัปเดตค่าขอบเขต Directive เท่านั้น
STEEL

@iwein ทำไมรหัสซอของคุณที่ jsfiddle.net/maxisam/QrCXhไม่ทำงานกับ googleapi - ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js ? รหัสของคุณใช้งานได้เฉพาะในกรณีที่ฉันใช้ cdn ของคุณ - code.angularjs.org/1.0.1/angular-1.0.1.js
MukulSharma

ฉันเห็นคำตอบที่ดีมากมายด้านล่าง แต่ทุกคนสามารถให้ตัวชี้ไปยังเอกสารเชิงมุมอย่างเป็นทางการที่ตอบคำถามนี้ได้หรือไม่
John Henckel

คำตอบ:


1151

ทำไมฉันต้องใช้ "{{title}}" กับ ' @ ' และ "title" กับ ' = '

@ผูกท้องถิ่น / สั่งคุณสมบัติขอบเขตกับมูลค่าประเมินของแอตทริบิวต์ DOM ถ้าคุณใช้title=title1หรือtitle="title1"มูลค่าของ DOM แอตทริบิวต์ "ชื่อ" title1เป็นเพียงสตริง หากคุณใช้title="{{title}}"ค่าของแอตทริบิวต์ DOM "title" เป็นค่าที่ถูกสอดแทรก{{title}}ดังนั้นสตริงจะเป็นสิ่งที่คุณสมบัติ "ขอบเขต" พาเรนต์ขอบเขตถูกตั้งเป็น ตั้งแต่ค่าแอตทริบิวต์สตริงเสมอคุณมักจะจบลงด้วยค่าสตริงสำหรับคุณสมบัตินี้อยู่ในขอบเขตของคำสั่งเมื่อใช้@

=ผูกคุณสมบัติขอบเขตโลคัล / คำสั่งกับคุณสมบัติขอบเขตพาเรนต์ ดังนั้นด้วย=คุณใช้ชื่อคุณสมบัติโมเดลขอบเขต / เป็นแม่แบบของค่าของแอตทริบิวต์ DOM คุณไม่สามารถใช้{{}}S กับ=

ด้วย @ คุณสามารถทำสิ่งต่าง ๆ เช่นtitle="{{title}} and then some"- {{title}} ถูกสอดแทรกจากนั้นสตริง "และพวกเขาบางส่วน" จะถูกรวมเข้าด้วยกัน สตริงที่ต่อกันสุดท้ายคือสิ่งที่คุณสมบัติขอบเขตท้องถิ่น / คำสั่งได้รับ (คุณไม่สามารถทำได้ด้วย= , เฉพาะ@ .)

ด้วย@คุณจะต้องใช้attr.$observe('title', function(value) { ... })ถ้าคุณต้องการใช้ค่าในฟังก์ชั่นลิงค์ (ไอเอ็นจี) ของคุณ เช่นif(scope.title == "...")จะไม่ทำงานอย่างที่คุณคาดหวัง โปรดทราบว่านี่หมายความว่าคุณสามารถเข้าถึงคุณลักษณะนี้แบบอะซิงโครนัสเท่านั้น คุณไม่จำเป็นต้องใช้ $ observ () ถ้าคุณใช้ค่าในเทมเพลตเท่านั้น เช่นtemplate: '<div>{{title}}</div>'.

ด้วย=คุณไม่จำเป็นต้องใช้ $ observ

ฉันสามารถเข้าถึงขอบเขตพาเรนต์โดยตรงได้หรือไม่โดยไม่ต้องตกแต่งองค์ประกอบด้วยแอตทริบิวต์

ใช่ แต่ถ้าคุณไม่ได้ใช้ขอบเขตแบบแยก ลบบรรทัดนี้ออกจากคำสั่งของคุณ

scope: { ... }

แล้วคำสั่งของคุณจะไม่สร้างขอบเขตใหม่ มันจะใช้ขอบเขตหลัก จากนั้นคุณสามารถเข้าถึงคุณสมบัติขอบเขตหลักทั้งหมดได้โดยตรง

เอกสารอธิบายว่า "บ่อยครั้งที่ต้องการส่งข้อมูลจากขอบเขตแยกผ่านนิพจน์และขอบเขตหลัก" แต่ดูเหมือนว่าจะทำงานได้ดีกับการเชื่อมโยงสองทิศทางเช่นกัน ทำไมเส้นทางนิพจน์ถึงดีกว่า

ใช่การเชื่อมโยงแบบสองทิศทางอนุญาตให้ขอบเขตโลคัล / คำสั่งและขอบเขตพาเรนต์ใช้ข้อมูลร่วมกัน "การโยงนิพจน์" อนุญาตให้คำสั่งเรียกนิพจน์ (หรือฟังก์ชัน) ที่กำหนดโดยแอตทริบิวต์ DOM - และคุณสามารถส่งผ่านข้อมูลเป็นอาร์กิวเมนต์ไปยังนิพจน์หรือฟังก์ชันได้ ดังนั้นหากคุณไม่ต้องการแบ่งปันข้อมูลกับผู้ปกครอง - คุณเพียงแค่ต้องการเรียกใช้ฟังก์ชันที่กำหนดในขอบเขตหลัก - คุณสามารถใช้&ไวยากรณ์

ดูสิ่งนี้ด้วย


1
หืมนี่เป็นพฤติกรรมแปลก ๆ โดยเฉพาะอย่างยิ่งเมื่อไม่ได้ใช้การแก้ไขและแค่พยายามส่งสตริง เห็นได้ชัดว่าคำขอการดึงได้รับการรวมเข้ากับการพัฒนาอย่างแท้จริงแล้วและอยู่ใน 1.1.5 และ 1.2.0 การสร้าง RC ดีสำหรับพวกเขาสำหรับการแก้ไขพฤติกรรมที่ไม่ใช้งานง่ายมาก!
อิบราฮิม

50
การเขียน '@' หรือ '=' นั้นชัดเจนกว่ามากแล้วจึงเขียน "eval-dom" หรือ "parent-scope" หรือข้อความอื่น ๆ ที่มนุษย์อ่านได้ ตัดสินใจออกแบบที่ดี
Den

13
@('at') คัดลอกค่าของ 'ATtribute' =('เท่ากับ') เท่ากับการบอกว่าคีย์เท่ากับนิพจน์ของคุณ อย่างน้อยนี่คือวิธีที่ฉันทำให้พวกเขาใจแคบ
Matt DeKrey

1
คุณแน่ใจหรือว่า = ใช้สำหรับคุณสมบัติขอบเขตพาเรนต์เท่านั้น การแสดงออกใด ๆ ที่ดูเหมือนว่าจะทำงาน - ไม่เพียง แต่คุณสมบัติขอบเขตผู้ปกครอง
Jonathan Aquino

4
@JonathanAquino ใช่แล้วใช้ได้ แต่ @ จะเหมาะสมกว่าด้วยเมื่อfoo="{{1+1}}"เราไม่ต้องการผูกข้อมูลสองทางที่นี่ จุดที่ฉันพยายามทำในความคิดเห็นด้านบนคือเราควรใช้ = เฉพาะเมื่อคำสั่งต้องการการผูกข้อมูลแบบสองทาง ใช้ @ หรืออย่างอื่น
Mark Rajcok

542

มีจำนวนมากของคำตอบที่ดีอยู่ที่นี่ แต่ผมอยากจะนำเสนอมุมมองของฉันเกี่ยวกับความแตกต่างระหว่าง@, =และ&ผูกพันที่พิสูจน์แล้วว่ามีประโยชน์สำหรับฉัน

การโยงทั้งสามนี้เป็นวิธีการส่งผ่านข้อมูลจากขอบเขตพาเรนต์ของคุณไปยังขอบเขตแยกของคำสั่งผ่านแอตทริบิวต์ขององค์ประกอบ:

  1. @ binding คือการผ่านสตริง สตริงเหล่านี้รองรับการ{{}}แสดงออกสำหรับค่าที่ถูกสอดแทรก ตัวอย่างเช่น: . นิพจน์แบบสอดแทรกถูกประเมินค่ากับขอบเขตพาเรนต์ของ directive

  2. = binding สำหรับการผูกโมเดลสองทาง โมเดลในขอบเขตพาเรนต์เชื่อมโยงกับโมเดลในขอบเขตแยกของ directive การเปลี่ยนแปลงรูปแบบหนึ่งมีผลกระทบต่ออีกรูปแบบหนึ่งและในทางกลับกัน

  3. & การผูกไว้สำหรับการส่งวิธีการในขอบเขตของคำสั่งของคุณเพื่อให้สามารถเรียกได้ภายในคำสั่งของคุณ วิธีนี้ถูกผูกไว้ล่วงหน้ากับขอบเขตหลักของไดเรกทีฟและสนับสนุนอาร์กิวเมนต์ ตัวอย่างเช่นหากเมธอดนั้นเป็นสวัสดี (ชื่อ) ในขอบเขตพาเรนต์ดังนั้นเพื่อดำเนินการเมธอดจากภายในคำสั่งของคุณคุณต้องโทร $ scope.hello ({name: 'world'})

ฉันพบว่าการจดจำความแตกต่างเหล่านี้ทำได้ง่ายขึ้นโดยอ้างอิงการเชื่อมโยงขอบเขตโดยคำอธิบายที่สั้นกว่า:

  • @ การผูกสตริงแอตทริบิวต์
  • = การรวมโมเดลสองทาง
  • & วิธีการโทรกลับมีผลผูกพัน

สัญลักษณ์ยังทำให้ชัดเจนขึ้นว่าตัวแปรขอบเขตแสดงถึงการนำไปใช้ของคำสั่งของคุณ:

  • @ เชือก
  • = แบบ
  • & วิธี

เพื่อประโยชน์ (สำหรับฉันยังไง):

  1. =
  2. แอท
  3. &

13
อันที่จริง"&"ไม่สนับสนุนข้อโต้แย้ง (หรือมากกว่าชาวบ้าน) ของรูปแบบ: ซึ่งจากนั้นจะสามารถนำมาใช้callback({foo: "some value"}) <my-dir callback="doSomething(foo)">มิฉะนั้นคำตอบที่ดี
ใหม่ Dev

11
ควรเป็นคำตอบที่ได้รับการยอมรับ นี่เป็นบทความสั้น ๆ ที่มีข้อมูลเดียวกัน แต่มีตัวอย่างโค้ดเพิ่มเติม: umur.io/ …
Kevin

4
& ไม่ใช่ "การเชื่อมโยงวิธีการโทรกลับ" แต่เป็นการรวมการแสดงออกในเชิงมุม พิเศษ callback(argument)แต่ไม่เพียงตัวอย่างคือการแสดงออก ซึ่งยังคงไม่เหมือนcallbackตัวมันเอง
Dmitri Zaitsev

14
ในขณะที่ฉันชอบความชัดเจนของคำตอบการจัดอันดับที่สูงขึ้นฉันพบว่าสิ่งนี้มีผลกระทบที่เป็นประโยชน์มากขึ้นและหลังจากอ่านคำถามนี้ฉันเข้าใจคำตอบก่อนหน้านี้มากขึ้น
rbnzdave

1
ฉันเห็นด้วยกับความคิดเห็นข้างต้นคำตอบนี้ชัดเจนยิ่งขึ้นชัดเจนและเป็นประโยชน์ต่อคำถาม มันอธิบายด้วยรายละเอียดเพียงพอที่คุณสามารถไปและใช้ข้อมูล
user3125823

64

=หมายถึงสองทิศทางผูกพันดังนั้นการอ้างอิงกับตัวแปรขอบเขตแม่ ซึ่งหมายความว่าเมื่อคุณเปลี่ยนตัวแปรในคำสั่งจะมีการเปลี่ยนแปลงในขอบเขตผู้ปกครองเช่นกัน

@ หมายถึงตัวแปรจะถูกคัดลอก (โคลน) ลงในคำสั่ง

เท่าที่ฉันรู้<pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>ควรทำงานด้วย bi-titleจะได้รับค่าตัวแปรขอบเขตของพาเรนต์ซึ่งสามารถเปลี่ยนแปลงได้ในคำสั่ง

หากคุณต้องการเปลี่ยนตัวแปรหลายอย่างในขอบเขตพาเรนต์คุณสามารถเรียกใช้ฟังก์ชันบนขอบเขตพาเรนต์จากภายในคำสั่ง (หรือส่งผ่านข้อมูลผ่านบริการ)


1
ใช่ฉันได้ส่วนนั้นดูซอในคำถาม แต่สิ่งที่เกี่ยวกับชิ้นส่วนที่ไม่ชัดเจน?
iwein

4
สิ่งนี้คือ {{}} ใช้งานไม่ได้กับ = = ไม่ได้รับการประเมิน แต่สตริงจะใช้เป็นชื่อคุณสมบัติตามที่เป็นอยู่ ขอบคุณสำหรับคำตอบ!
iwein

1
ฉันไม่คิดว่า = เป็นเพียงตัวแปรในขอบเขตหลัก มันทำงานร่วมกับการแสดงออกใด ๆ (เช่น 1 + 1)
Jonathan Aquino

1
@JonathanAquino คุณถูกต้องที่จะประเมินการแสดงออก imho นี่มันแปลกจริง ๆ และฉันจะไม่ใช้มันอย่างนั้น มันเป็นกลอุบายที่ฉลาดแบบนี้ที่ทำให้ขอบเขตของคำสั่งยากสำหรับฉันที่จะเข้าใจตั้งแต่แรก
iwein

1
ฉันเป็นคนเดียวที่คิดว่าคำตอบนี้ผิด! '=' หมายถึงมุมที่ต้องการนิพจน์จาวาสคริปต์และจะทำการแมปแบบสองทิศทางหากตัวแปรขอบเขตถูกส่งผ่าน ในขณะที่ @ หมายถึงเชิงมุมคาดหวังว่าสตริงและที่ทั้งหมด ในความเป็นจริงมันเป็นความจริงที่ว่าถ้าคุณใช้ @ ใน combinaison ด้วย {{}} คุณจะโคลนมูลค่าของตัวแปร แต่มันไม่ใช่นิยามของ @!
Luc DUZAN

39

หากคุณต้องการที่จะเห็นมากขึ้นวิธีการทำงานกับตัวอย่างสด 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
มีหลายตัวอย่างที่เชื่อมโยงในคำถามและคำตอบยอดนิยม สิ่งนี้เพิ่มอะไร?
iwein

10
@iwein มันเพิ่มความชัดเจน ถ้าฉันสามารถเข้าใจและทำตัวกลมกลืนตัวอย่างที่มีคุณลักษณะครบถ้วนฉันไม่ต้องการไซต์นี้
Tony Ennis

3
จวนอาจแก้ไขความผิดพลาดของคุณ? 'transclude' ถูกสะกดผิด ยังดีกว่าเอามันออก (และทุกอย่างอื่นเช่น 'แทนที่') ที่ไม่ได้มีส่วนร่วมโดยตรงกับปัญหาเพื่อให้การแก้ปัญหาของคุณง่ายและชัดเจนยิ่งขึ้น +1 สำหรับตัวอย่าง
Tony Ennis

ขอบคุณ @AnikISlamAbhi สำหรับการแก้ไข ฉันต้องการมีส่วนร่วมมากขึ้นและฉันดีใจที่มีบางตัวอย่างของฉันเป็นประโยชน์ นั่นคือจุดประสงค์หลัก
Juan Mendez

ตัวอย่างที่ไม่สมบูรณ์ ในการสาธิตของคุณคุณกำลังเปลี่ยนเฉพาะค่าสองทิศทาง คุณไม่ได้พยายามเปลี่ยนค่าที่แยกขอบเขต ดังนั้นจึงไม่ได้แสดงให้เห็นอย่างถูกต้องว่าขอบเขตทำงานอย่างไรในคำสั่ง
Sudarshan_SMD

38

@ รับเป็นสตริง

  • สิ่งนี้ไม่ได้สร้างการผูกมัดใด ๆ คุณแค่ได้คำที่คุณส่งเป็นสตริง

= มีผลผูกพัน 2 ทาง

  • การเปลี่ยนแปลงที่ทำจากคอนโทรลเลอร์จะสะท้อนให้เห็นในการอ้างอิงที่ถือโดยคำสั่งและในทางกลับกัน

&นี้จะทำงานแตกต่างกันเล็กน้อยเพราะขอบเขตที่ได้รับฟังก์ชั่นที่ให้ผลตอบแทนวัตถุที่ถูกส่งผ่านใน ฉันคิดว่านี่เป็นสิ่งที่จำเป็นเพื่อให้มันใช้งานได้ ซอควรทำให้เรื่องนี้ชัดเจน

  • หลังจากเรียกใช้ฟังก์ชัน getter วัตถุผลลัพธ์จะทำงานดังนี้:
    • ถ้าฟังก์ชั่นถูกส่งผ่าน: ฟังก์ชั่นจะถูกดำเนินการในการปิด parent (ตัวควบคุม) เมื่อเรียก
    • ถ้าไม่ใช่หน้าที่ถูกส่งเข้า: เพียงแค่ได้รับสำเนาของวัตถุที่ไม่มีการผูก


ซอนี้ควรจะแสดงให้เห็นถึงวิธีการทำงาน ให้ความสนใจเป็นพิเศษกับฟังก์ชั่นขอบเขตด้วยget...ในชื่อเพื่อหวังว่าจะเข้าใจสิ่งที่ฉันหมายถึงได้ดียิ่งขึ้น&


36

มีสามวิธีในการเพิ่มขอบเขตในคำสั่ง:

  1. ขอบเขตหลัก : นี่คือการสืบทอดขอบเขตเริ่มต้น

ขอบเขตคำสั่งและผู้ปกครอง (ตัวควบคุม / คำสั่งภายในซึ่งมันอยู่) ขอบเขตเหมือนกัน ดังนั้นการเปลี่ยนแปลงใด ๆ ที่ทำกับตัวแปรขอบเขตภายในคำสั่งจะมีผลในตัวควบคุมหลักเช่นกัน คุณไม่จำเป็นต้องระบุสิ่งนี้เนื่องจากเป็นค่าเริ่มต้น

  1. ขอบเขตลูก : คำสั่งสร้างขอบเขตลูกซึ่งสืบทอดมาจากขอบเขตแม่ถ้าคุณระบุตัวแปรขอบเขตของคำสั่งเป็นจริง

ที่นี่หากคุณเปลี่ยนตัวแปรขอบเขตภายในคำสั่งมันจะไม่สะท้อนในขอบเขตพาเรนต์ แต่ถ้าคุณเปลี่ยนคุณสมบัติของตัวแปรขอบเขตที่สะท้อนในขอบเขตพาเรนต์เนื่องจากคุณปรับเปลี่ยนตัวแปรขอบเขตของพาเรนต์จริง .

ตัวอย่าง,

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. ขอบเขตที่แยก : ใช้เมื่อคุณต้องการสร้างขอบเขตที่ไม่สืบทอดจากขอบเขตของตัวควบคุม

สิ่งนี้เกิดขึ้นเมื่อคุณกำลังสร้างปลั๊กอินเนื่องจากจะทำให้เกิดคำสั่งทั่วไปเนื่องจากสามารถวางใน HTML ใด ๆ และไม่ได้รับผลกระทบจากขอบเขตหลัก

ทีนี้ถ้าคุณไม่ต้องการการโต้ตอบใด ๆ กับขอบเขตหลักคุณก็สามารถระบุขอบเขตเป็นวัตถุเปล่าได้ ชอบ,

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

ส่วนใหญ่นี่ไม่ใช่กรณีที่เราต้องการการโต้ตอบกับขอบเขตหลักดังนั้นเราต้องการให้ค่า / การเปลี่ยนแปลงบางอย่างผ่านไป ด้วยเหตุผลนี้เราจึงใช้:

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

@หมายความว่าการเปลี่ยนแปลงจากขอบเขตคอนโทรลเลอร์จะแสดงในขอบเขต directive แต่หากคุณแก้ไขค่าในขอบเขต directive ตัวแปรขอบเขตคอนโทรลเลอร์จะไม่ได้รับผลกระทบ

@ คาดว่าแอตทริบิวต์ที่แมปจะเป็นนิพจน์เสมอ สิ่งนี้สำคัญมาก เนื่องจากเพื่อให้คำนำหน้า“ @” ทำงานได้เราจำเป็นต้องห่อค่าแอตทริบิวต์ไว้ใน {{}}

=เป็นแบบสองทิศทางดังนั้นหากคุณเปลี่ยนตัวแปรในขอบเขต directive ตัวแปรขอบเขตคอนโทรลเลอร์จะได้รับผลกระทบเช่นกัน

&ถูกใช้เพื่อผูกเมธอด scope controller ดังนั้นหากจำเป็นเราสามารถเรียกมันได้จาก directive

ข้อดีของที่นี่คือชื่อของตัวแปรไม่จำเป็นต้องเหมือนกันในขอบเขตของตัวควบคุมและขอบเขตของคำสั่ง

ตัวอย่างขอบเขต directive มีตัวแปร "dirVar" ซึ่งซิงค์กับตัวแปร "contVar" ของขอบเขตควบคุม สิ่งนี้ให้พลังงานและการวางนัยทั่วไปสำหรับ directive เนื่องจากคอนโทรลเลอร์หนึ่งสามารถซิงค์กับตัวแปร v1 ในขณะที่คอนโทรลเลอร์อื่นที่ใช้ directive เดียวกันสามารถขอให้ dirVar ซิงค์กับตัวแปร v2 ได้

ด้านล่างเป็นตัวอย่างของการใช้งาน:

คำสั่งและตัวควบคุมคือ:

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

และ html (สังเกตความแตกต่างของ @ และ =):

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

นี่คือลิงค์ไปยังบล็อกซึ่งอธิบายไว้เป็นอย่างดี


& ไม่ใช่ "การเชื่อมโยงพฤติกรรม" หรือ "การผูกวิธีการ" เป็นการเชื่อมการแสดงออกในเชิงมุม
Dmitri Zaitsev

20

เพียงแค่เราสามารถใช้: -

  1. @ : - สำหรับค่า String สำหรับการเชื่อมต่อข้อมูลทางเดียว ในการเชื่อมโยงข้อมูลทางเดียวคุณสามารถส่งค่าขอบเขตไปยังคำสั่งเท่านั้น

  2. = : - สำหรับค่าวัตถุสำหรับการผูกข้อมูลสองทาง ในการผูกข้อมูลสองทางคุณสามารถเปลี่ยนค่าขอบเขตในคำสั่งเช่นเดียวกับใน html ด้วย

  3. & : - สำหรับวิธีการและฟังก์ชั่น

แก้ไข

ในการกำหนดส่วนประกอบของเราสำหรับแองกูลาร์เวอร์ชัน 1.5ขึ้นไป
มีการเชื่อมสี่ประเภทที่แตกต่างกัน:

  1. = การเชื่อมโยงข้อมูลแบบสองทาง : - หากเราเปลี่ยนค่าจะเป็นการอัปเดตโดยอัตโนมัติ
  2. < การรวมทางเดียว : - เมื่อเราต้องการอ่านพารามิเตอร์จากขอบเขตพาเรนต์และไม่อัปเดต

  3. @สิ่งนี้ใช้สำหรับพารามิเตอร์สตริง

  4. &สิ่งนี้มีไว้สำหรับการโทรกลับในกรณีที่องค์ประกอบของคุณต้องการส่งออกบางอย่างไปยังขอบเขตหลัก


13

ฉันสร้างไฟล์ HTML เล็กน้อยที่มีรหัส Angular แสดงให้เห็นถึงความแตกต่างระหว่างพวกเขา:

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

=ทางเป็น2 ทางที่มีผลผูกพันซึ่งจะช่วยให้คุณที่จะมีการถ่ายทอดสดการเปลี่ยนแปลงภายในคำสั่งของคุณ เมื่อใครบางคนเปลี่ยนแปลงตัวแปรที่ออกจากคำสั่งคุณจะมีการเปลี่ยนแปลงข้อมูลที่อยู่ภายในคำสั่งของคุณ แต่@วิธีที่ไม่เป็นสองวิธีมีผลผูกพัน มันทำงานเหมือนข้อความ คุณผูกหนึ่งครั้งและคุณจะมีค่าของมันเท่านั้น

เพื่อให้ชัดเจนยิ่งขึ้นคุณสามารถใช้บทความที่ยอดเยี่ยมนี้:

ขอบเขตสั่ง AngularJS '@' และ '='


6

คำถามนี้ได้ถูกเอาชนะไปแล้ว แต่ฉันจะแบ่งปันเรื่องนี้ต่อไปในกรณีที่มีคนอื่นกำลังดิ้นรนกับความยุ่งเหยิงที่น่ากลัวซึ่งเป็นขอบเขตของ AngularJS นี้จะครอบคลุม=, <, @, และ& ::เขียนเต็มสามารถพบได้ที่นี่


=สร้างการผูกสองทาง การเปลี่ยนคุณสมบัติในพาเรนต์จะส่งผลให้เกิดการเปลี่ยนแปลงในเด็กและในทางกลับกัน


<สร้างการเชื่อมโยงทางเดียวกับผู้ปกครองไปยังลูก การเปลี่ยนคุณสมบัติในพาเรนต์จะส่งผลให้เกิดการเปลี่ยนแปลงในลูก แต่การเปลี่ยนคุณสมบัติลูกจะไม่ส่งผลต่อคุณสมบัติพาเรนต์


@จะกำหนดคุณสมบัติสตริงให้กับคุณสมบัติของแท็ก หากแอ็ตทริบิวต์มีนิพจน์คุณสมบัติของชายด์จะอัพเดตทุกครั้งที่นิพจน์ประเมินเป็นสตริงอื่น ตัวอย่างเช่น:

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

ที่นี่descriptionคุณสมบัติในขอบเขตลูกจะเป็นค่าปัจจุบันของการแสดงออก"The movie title is {{$ctrl.movie.title}}"ซึ่งmovieเป็นวัตถุในขอบเขตหลัก


&ค่อนข้างยุ่งยากและในความเป็นจริงดูเหมือนจะไม่มีเหตุผลที่น่าสนใจที่จะใช้มัน อนุญาตให้คุณประเมินค่านิพจน์ในขอบเขตพาเรนต์แทนที่พารามิเตอร์ด้วยตัวแปรจากขอบเขตลูก ตัวอย่าง ( เสียงดังปัง ):

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

ป.ร. ให้ไว้parentVar=10, การแสดงออกparentFoo({myVar:5, myOtherVar:'xyz'})จะประเมิน5 + 10 + 'xyz'และส่วนประกอบจะทำให้เป็น:

<div>15xyz</div>

คุณต้องการใช้ฟังก์ชันการทำงานที่ซับซ้อนนี้เมื่อใด &บ่อยครั้งที่บุคคลใช้เพื่อส่งผ่านขอบเขตย่อยฟังก์ชันการเรียกกลับในขอบเขตหลัก ในความเป็นจริงอย่างไรก็ตามเอฟเฟ็กต์แบบเดียวกันสามารถทำได้โดยใช้ '<' เพื่อส่งผ่านฟังก์ชั่นซึ่งตรงไปตรงมามากขึ้นและหลีกเลี่ยงการใช้ซิงก์วงเล็บปีกกาที่น่าอึดอัดใจในการส่งพารามิเตอร์ ( {myVar:5, myOtherVar:'xyz'}) พิจารณา:

โทรกลับโดยใช้&:

<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: '&'
  }
});

โทรกลับโดยใช้<:

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

โปรดทราบว่าวัตถุ (และอาร์เรย์) ถูกส่งผ่านโดยอ้างอิงไปยังขอบเขตลูกไม่ได้คัดลอก สิ่งนี้หมายความว่าแม้ว่าจะเป็นการรวมทางเดียวคุณกำลังทำงานกับวัตถุเดียวกันทั้งในขอบเขตหลักและลูก


หากต้องการดูคำนำหน้าที่แตกต่างกันให้เปิดปังตัวนี้นี้

ใช้การรวมครั้งเดียว (การกำหนดค่าเริ่มต้น) ::

[เอกสารอย่างเป็นทางการ]
รุ่นที่ใหม่กว่าของ AngularJS แนะนำตัวเลือกให้มีผลผูกพันเพียงครั้งเดียวซึ่งคุณสมบัติขอบเขตลูกได้รับการอัพเดตเพียงครั้งเดียว สิ่งนี้ช่วยปรับปรุงประสิทธิภาพโดยไม่จำเป็นต้องดูคุณสมบัติหลัก ไวยากรณ์แตกต่างจากด้านบน ในการประกาศการเชื่อมโยงครั้งเดียวคุณเพิ่ม::ด้านหน้าของนิพจน์ในแท็กคอมโพเนนต์ :

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

สิ่งนี้จะเผยแพร่ค่าของtaglineขอบเขตลูกโดยไม่สร้างการโยงทางเดียวหรือสองทาง หมายเหตุ : ถ้าtaglineเริ่มแรกundefinedในขอบเขตพาเรนต์เชิงมุมจะตรวจสอบมันจนกว่าจะเปลี่ยนจากนั้นทำการอัพเดตคุณสมบัติที่เกี่ยวข้องในขอบเขตลูกเพียงครั้งเดียว

สรุป

ตารางด้านล่างแสดงให้เห็นว่าคำนำหน้าทำงานอย่างไรขึ้นอยู่กับว่าคุณสมบัตินั้นเป็นวัตถุอาร์เรย์สตริง ฯลฯ

การทำงานของขอบเขตการแยกไอเท็มต่างๆ


4

คุณสมบัติ@ local scope ใช้เพื่อเข้าถึงค่าสตริงที่กำหนดไว้นอกคำสั่ง

=ในกรณีที่คุณต้องการสร้างการเชื่อมโยงสองทางระหว่างขอบเขตด้านนอกและขอบเขตการแยกของคำสั่งคุณสามารถใช้อักขระ =

และคุณสมบัติขอบเขตท้องถิ่นช่วยให้ผู้บริโภคของคำสั่งที่จะผ่านในการทำงานที่สั่งสามารถเรียก

โปรดตรวจสอบลิงค์ด้านล่างซึ่งจะช่วยให้คุณเข้าใจชัดเจนขึ้นด้วยตัวอย่างฉันพบว่ามันมีประโยชน์มากดังนั้นคิดว่าการแบ่งปันมัน

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


3

$parentแม้ในขณะที่ขอบเขตมีในท้องถิ่นเช่นในตัวอย่างของคุณคุณอาจเข้าถึงขอบเขตแม่ผ่านคุณสมบัติ สมมติว่าในรหัสด้านล่างที่titleกำหนดไว้ในขอบเขตหลัก จากนั้นคุณสามารถเข้าถึงชื่อเป็น$parent.title:

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

อย่างไรก็ตามในกรณีส่วนใหญ่จะได้รับเอฟเฟกต์เดียวกันโดยใช้แอตทริบิวต์

ตัวอย่างที่ฉันพบสัญกรณ์ "&" ซึ่งใช้ "เพื่อส่งผ่านข้อมูลจากขอบเขตแยกผ่านนิพจน์และขอบเขตหลัก" มีประโยชน์ (และไม่สามารถใช้ฐานข้อมูลแบบสองทาง) ได้ในทิศทาง สำหรับการเรนเดอร์โครงสร้างข้อมูลพิเศษภายใน ng-repeat

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

ส่วนหนึ่งของการแสดงผลเป็นปุ่มลบและที่นี่มันมีประโยชน์ในการแนบการลบจากขอบเขตภายนอกผ่าน & ภายในคำสั่งแสดงผลดูเหมือนว่า

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

data = "="ไม่สามารถใช้ฐานข้อมูลแบบ 2 ทางได้เนื่องจากฟังก์ชั่นลบจะทำงานในทุก$digestรอบซึ่งไม่ดีเนื่องจากบันทึกจะถูกลบทันทีและไม่แสดงผล



3

ความแตกต่างที่สำคัญระหว่างพวกเขาเป็นเพียง

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

1

@และ=ดูคำตอบอื่น ๆ

หนึ่งgotchaเกี่ยวกับTL; DR; ได้รับการแสดงออก (ไม่เพียง แต่ฟังก์ชั่นเช่นในตัวอย่างในคำตอบอื่น ๆ ) จากผู้ปกครองและตั้งเป็นฟังก์ชั่นในคำสั่งที่เรียกการแสดงออก และฟังก์ชั่นนี้มีความสามารถในการแทนที่ตัวแปรใด ๆ (แม้แต่ชื่อฟังก์ชั่น) ของการแสดงออกโดยผ่านวัตถุที่มีตัวแปร &

&

อธิบาย
&คือการอ้างอิงการแสดงออกซึ่งหมายความว่าถ้าคุณผ่านสิ่งที่ต้องการ <myDirective expr="x==y"></myDirective>
ในคำสั่งนี้จะมีฟังก์ชั่นที่เรียกร้องการแสดงออกเช่น:expr ดังนั้นในคำสั่ง html จะเรียกการแสดงออก ใน js ของคำสั่งจะเรียกการแสดงออกเช่นกัน นิพจน์จะถูกเรียกด้วย $ scope.x และ $ scope.y ของพาเรนต์ คุณมีความสามารถในการแทนที่พารามิเตอร์! หากคุณตั้งพวกเขาโดยการเรียกเช่น นั้นการแสดงออกจะถูกเรียกว่ามีพารามิเตอร์ของคุณและพารามิเตอร์ของผู้ปกครอง คุณสามารถแทนที่ทั้งสอง ตอนนี้คุณรู้แล้วทำไมใช้งานได้ดี เพราะมันแค่เรียกการแสดงออกของผู้ปกครอง (เช่น
function expr(){return x == y}
<button ng-click="expr()"></button>$scope.expr()


<button ng-click="expr({x:5})"></button>
xy

<button ng-click="functionFromParent({x:5})"></button>
<myDirective functionFromParent="function1(x)"></myDirective>) และแทนที่ค่าที่เป็นไปได้ด้วยพารามิเตอร์ที่คุณระบุในกรณีx.
อาจเป็น:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
หรือ
<myDirective functionFromParent="function1(x) + z"></myDirective>
ด้วยการเรียกลูก:
<button ng-click="functionFromParent({x:5, z: 4})"></button>. หรือแม้กระทั่งกับการเปลี่ยนฟังก์ชั่น:

<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>

มันเป็นเพียงการแสดงออกไม่สำคัญว่ามันจะเป็นฟังก์ชั่นหรือฟังก์ชั่นจำนวนมากหรือเพียงแค่การเปรียบเทียบ และคุณสามารถเปลี่ยนใด ๆตัวแปรในการแสดงออกนี้

ตัวอย่าง:
directive template เทียบกับรหัสที่เรียกว่า:
parent ได้กำหนด $ scope.x, $ scope.y:
parent template: การ<myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button>โทรเพื่อ$scope.x==$scope.y
<button ng-click="expr({x: 5})"></button>โทร5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button>ออก5 == 6

parent ได้กำหนด $ scope.function1, $ scope.x, $ scope.y:
แม่แบบเทมเพลต:<myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button>การเรียกการ$scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button>เรียกการ$scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button>เรียกใช้$scope.function1(5) + 6
มี $ scope.myFn เป็นฟังก์ชัน: การ
<button ng-click="expr({function1: myFn, x:5, y:6})"></button>เรียก$scope.myFn(5) + 6


0

ทำไมฉันต้องใช้ "{{title}}" กับ '@' และ "title" กับ '='

เมื่อคุณใช้ {{title}} เฉพาะค่าขอบเขตหลักเท่านั้นที่จะถูกส่งไปยังมุมมองคำสั่งและประเมินผล สิ่งนี้ จำกัด เพียงวิธีเดียวหมายความว่าการเปลี่ยนแปลงจะไม่ถูกสะท้อนในขอบเขตหลัก คุณสามารถใช้ '=' เมื่อคุณต้องการสะท้อนให้เห็นถึงการเปลี่ยนแปลงที่ทำในคำสั่งลูกกับขอบเขตผู้ปกครองยัง นี่เป็นสองทาง

ฉันสามารถเข้าถึงขอบเขตพาเรนต์โดยตรงได้หรือไม่โดยไม่ต้องตกแต่งองค์ประกอบด้วยแอตทริบิวต์

เมื่อไดเรกทีฟมีแอ็ตทริบิวต์ขอบเขตอยู่ภายใน (ขอบเขต: {}) คุณจะไม่สามารถเข้าถึงขอบเขตหลักได้อีกต่อไป แต่ก็ยังเป็นไปได้ที่จะเข้าถึงผ่านขอบเขต $ parent ฯลฯ หากคุณลบขอบเขตออกจากคำสั่งมันสามารถเข้าถึงได้โดยตรง

เอกสารอธิบายว่า "บ่อยครั้งที่ต้องการส่งข้อมูลจากขอบเขตแยกผ่านนิพจน์และขอบเขตหลัก" แต่ดูเหมือนว่าจะทำงานได้ดีกับการเชื่อมโยงสองทิศทางเช่นกัน ทำไมเส้นทางนิพจน์ถึงดีกว่า

มันขึ้นอยู่กับบริบท หากคุณต้องการโทรหานิพจน์หรือฟังก์ชั่นที่มีข้อมูลคุณใช้ & และถ้าคุณต้องการแชร์ข้อมูลคุณสามารถใช้วิธี biderectional โดยใช้ '='

คุณสามารถค้นหาความแตกต่างระหว่างวิธีการส่งผ่านข้อมูลไปยังคำสั่งด้านล่าง:

AngularJS - ขอบเขตที่แยกได้ - @ vs = vs &

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


0

@ การผูกสตริงของแอตทริบิวต์ (ทางเดียว) = การรวมรูปแบบสองทางและการผูกกลับวิธี


0

@ ผูกคุณสมบัติขอบเขตท้องถิ่น / คำสั่งกับค่าการประเมินผลของแอตทริบิวต์ DOM = ผูกคุณสมบัติขอบเขตโลคัล / คำสั่งกับคุณสมบัติขอบเขตพาเรนต์ & การผูกไว้คือการส่งวิธีการในขอบเขตของคำสั่งของคุณเพื่อให้สามารถเรียกได้ภายในคำสั่งของคุณ

@ การผูกสตริงของแอตทริบิวต์ = การรวมรูปแบบสองทางและการผูกกลับวิธี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.