AngularJs "controller as" syntax - ชี้แจง?


121

ฉันอ่านเกี่ยวกับไวยากรณ์ใหม่จาก angularJS ที่เกี่ยวข้องcontroller as xxx

ไวยากรณ์InvoiceController as invoiceบอกให้ Angular สร้างอินสแตนซ์ตัวควบคุมและบันทึกไว้ในใบแจ้งหนี้ตัวแปรในขอบเขตปัจจุบัน

การแสดงภาพ:

ใส่คำอธิบายภาพที่นี่

โอเคฉันจะไม่มีพารามิเตอร์$scopeในคอนโทรลเลอร์ของฉันและโค้ดจะสะอาดกว่าในคอนโทรลเลอร์มาก

แต่

ฉันจะต้องระบุนามแฝงอื่นในมุมมอง

จนถึงตอนนี้ฉันสามารถทำได้:

<input type="number" ng-model="qty"  />

....controller('InvoiceController', function($scope) {
   // do something with $scope.qty <--notice

และตอนนี้ฉันทำได้:

 <input type="number" ng-model="invoic.qty"  /> <-- notice 

  ....controller('InvoiceController', function() {
       // do something with  this.qty  <--notice

คำถาม

เป้าหมายในการทำคืออะไร? นำออกจากที่หนึ่งและเพิ่มไปที่อื่น?

ฉันจะดีใจที่ได้เห็นสิ่งที่ฉันขาดหายไป


8
วิดีโอนี้อธิบายได้เป็นอย่างดี youtube.com/watch?v=tTihyXaz4 ฉันคิดว่ามันถูกใช้เพื่อทำความสะอาดโค้ดใน HTML
Fizer Khan

1
ความชัดเจน ฉันไม่ได้กังวลเกี่ยวกับการใช้ $ scope.x Vs this.x ในคอนโทรลเลอร์ แต่ในมุมมองของฉันการผูกกับ {{invoice.x}} บอกฉันได้มากกว่าแค่ {{x}} (imho) นอกจากนี้ฉันสงสัยว่าสิ่งนี้ช่วยแก้ปัญหาที่ฉันได้ยินในเชิงมุมหรือไม่ซึ่งสิ่งที่ไม่ใช่วัตถุในคอนโทรลเลอร์มีปัญหา (ดังนั้น things.x ก็ใช้ได้ แต่ x จะทำให้เกิดปัญหา)
Matt Roberts

1
@MattRoberts เพื่อกล่าวถึงความคิดเห็นล่าสุดของคุณ - ปัญหาที่ไม่ใช่วัตถุที่คุณอ้างถึงไม่ใช่ปัญหาเชิงมุมเท่ากับข้อเท็จจริงของการสืบทอดต้นแบบจาวาสคริปต์ มีคำอธิบายที่ดีว่าเหตุใดจึงเกิดขึ้นในเชิงมุมที่นี่ (พร้อมกับสาเหตุที่controller asแก้ไข)
Russ Matney

ฉันจะแทนที่ $ scope $ broadcast ได้อย่างไร ในกรณีใหม่นี้เนื่องจากการออกอากาศ. $ ของฉันดูเหมือนจะไม่ทำงาน
Gaurav

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

คำตอบ:


163

มีหลายสิ่งเกี่ยวกับเรื่องนี้

บางคนไม่ชอบ$scopeไวยากรณ์ (อย่าถามฉันว่าทำไม) พวกเขาบอกว่าthisใช้ได้ นั่นคือหนึ่งในเป้าหมาย

การทำให้ชัดเจนว่าคุณสมบัติมาจากไหนก็มีประโยชน์เช่นกัน

คุณสามารถซ้อนคอนโทรลเลอร์ได้และเมื่ออ่าน html ก็ค่อนข้างชัดเจนว่าทุกคุณสมบัติมาจากไหน

คุณยังสามารถหลีกเลี่ยงปัญหากฎจุดบางอย่างได้อีกด้วย

ตัวอย่างเช่นการมีตัวควบคุมสองตัวทั้งที่มี 'ชื่อ' เหมือนกันคุณสามารถทำได้:

<body ng-controller="ParentCtrl">
    <input ng-model="name" /> {{name}}

    <div ng-controller="ChildCtrl">
        <input ng-model="name" /> {{name}} - {{$parent.name}}
    </div>
</body>

คุณสามารถปรับเปลี่ยนทั้งผู้ปกครองและเด็กได้โดยไม่มีปัญหา แต่คุณต้องใช้$parentเพื่อดูชื่อของผู้ปกครองเพราะคุณใส่เงาไว้ในตัวควบคุมลูกของคุณ ในโค้ด html ขนาดใหญ่$parentอาจเป็นปัญหาคุณไม่รู้ว่าชื่อนั้นมาจากไหน

ด้วยcontroller asคุณสามารถทำ:

<body ng-controller="ParentCtrl as parent">
    <input ng-model="parent.name" /> {{parent.name}}

    <div ng-controller="ChildCtrl as child">
      <input ng-model="child.name" /> {{child.name}} - {{parent.name}}
    </div>
</body>

ตัวอย่างเดียวกัน แต่อ่านได้ชัดเจนกว่ามาก


10
นอกจากนี้ยังเป็นตัวอย่างที่ดีว่าทำไมวิธีนี้อาจทำให้บางคนสับสน: stackoverflow.com/questions/25405543/…
Julian Hollmann

สิ่งนี้มีประโยชน์มากเมื่อคุณทำรังคอนโทรลเลอร์!
C_J

1
ฉันมีปัญหาในการใช้คำตอบที่คล้ายกันโปรดดูstackoverflow.com/questions/38315538
Cody

นอกจากนี้ยังช่วยให้คุณใช้คลาส es6 เป็นตัวควบคุมของคุณและอ้างอิงวิธีการใน HTML เป็นวิธีที่สะอาดกว่าfoo() { ... } $scope.foo = function() { ... }
Brian McCutchon

17

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

แม้ว่าจะมีการสืบทอดขอบเขต $ ซึ่งแก้ปัญหานี้ได้บางส่วน แต่บางคนก็ชอบที่จะเขียนโค้ดในลักษณะ OOP มากกว่าซึ่งในความคิดของฉันทำให้รหัสให้เหตุผลและทดสอบได้ง่ายขึ้น

นี่คือซอที่จะสาธิต: http://jsfiddle.net/HB7LU/5796/


1
สิ่งนี้ควรได้รับการโหวตเพิ่มขึ้นเนื่องจาก Fiddle มีประโยชน์มาก
Mawg กล่าวคืนสถานะ Monica

13

ฉันเชื่อว่าข้อดีอย่างหนึ่งที่ชัดเจนเมื่อคุณมีขอบเขตที่ซ้อนกัน ตอนนี้จะชัดเจนอย่างสมบูรณ์ว่าขอบเขตการอ้างอิงคุณสมบัติมาจากอะไร


7

แหล่ง

ความแตกต่างระหว่างการสร้างคอนโทรลเลอร์โดยใช้$scope objectและการใช้“controller as”ไวยากรณ์และ vm

การสร้างคอนโทรลเลอร์โดยใช้วัตถุ $ ขอบเขต

โดยปกติเราจะสร้างคอนโทรลเลอร์โดยใช้วัตถุ $ ขอบเขตดังที่แสดงในรายการด้านล่าง:

myApp.controller("AddController", function ($scope) {



    $scope.number1;

    $scope.number2;

    $scope.result;

    $scope.add = function () {

        $scope.result = $scope.number1 + $scope.number2;

    }

});

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

โดยพื้นฐานแล้ววัตถุ $ ขอบเขตจะทำงานต่อไปนี้:

  1. ส่งผ่านข้อมูลจากคอนโทรลเลอร์ไปยังมุมมอง

  2. ส่งผ่านพฤติกรรมจากคอนโทรลเลอร์ไปยังมุมมอง

  3. กาวคอนโทรลเลอร์และดูเข้าด้วยกัน

  4. วัตถุ $ ขอบเขตได้รับการแก้ไขเมื่อมุมมองเปลี่ยนไปและมุมมองถูกแก้ไขเมื่อคุณสมบัติของวัตถุ $ ขอบเขตเปลี่ยนไป

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

การใช้ไวยากรณ์ "controller as" และ vm

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

myApp.controller("AddVMController", function () {

    var vm = this;

    vm.number1 = undefined;

    vm.number2=undefined;

    vm.result =undefined;

    vm.add = function () {

        vm.result = vm.number1 + vm.number2;

    }

});

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

<div ng-controller="AddVMController as vm">

            <input ng-model="vm.number1" type="number" />

            <input ng-model="vm.number2" type="number" />

            <button class="btn btn-default" ng-click="vm.add()">Add</button>

            <h3>{{vm.result}}</h3>

  </div>

แน่นอนเราสามารถใช้ชื่ออื่นที่ไม่ใช่ "vm" ในคอนโทรลเลอร์เป็นไวยากรณ์ ภายใต้ประทุน AngularJS สร้างวัตถุ $ ขอบเขตและแนบคุณสมบัติและพฤติกรรม อย่างไรก็ตามด้วยการใช้คอนโทรลเลอร์เป็นไวยากรณ์โค้ดจะสะอาดมากที่คอนโทรลเลอร์และมีเพียงชื่อนามแฝงเท่านั้นที่มองเห็นได้บนมุมมอง

ต่อไปนี้เป็นขั้นตอนบางประการในการใช้คอนโทรลเลอร์เป็นไวยากรณ์:

  1. สร้างคอนโทรลเลอร์โดยไม่มีวัตถุ $ ขอบเขต

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

  3. แนบข้อมูลและพฤติกรรมกับตัวแปร vm

  4. ในมุมมองให้นามแฝงแก่คอนโทรลเลอร์โดยใช้คอนโทรลเลอร์เป็นไวยากรณ์

  5. คุณสามารถตั้งชื่อให้กับนามแฝงใดก็ได้ ฉันชอบใช้ vm เว้นแต่ฉันจะไม่ทำงานกับตัวควบคุมที่ซ้อนกัน

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

ตัวควบคุมที่ซ้อนกันในแนวทางวัตถุ $ ขอบเขต

เรามีตัวควบคุมสองตัวตามที่แสดงในรายการด้านล่าง:

myApp.controller("ParentController", function ($scope) {



    $scope.name = "DJ";

    $scope.age = 32;

});

myApp.controller("ChildController", function ($scope) {



    $scope.age = 22;

    $scope.country = "India";



});

คุณสมบัติ "อายุ" อยู่ในตัวควบคุมทั้งสองตัวและในมุมมองตัวควบคุมทั้งสองนี้สามารถซ้อนกันได้ดังแสดงในรายการด้านล่าง:

<div ng-controller="ParentController">



            <h2>Name :{{name}} </h2>

            <h3>Age:{{age}}</h3>



             <div ng-controller="ChildController">

                    <h2>Parent Name :{{name}} </h2>

                    <h3>Parent Age:{{$parent.age}}</h3>

                    <h3>Child Age:{{age}}</h3>

                    <h3>Country:{{country}}</h3>

             </div>

        </div>

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

myApp.controller("ParentVMController", function () {

    var vm = this;

    vm.name = "DJ";

    vm.age = 32;

});

myApp.controller("ChildVMController", function () {

    var vm = this;

    vm.age = 22;

    vm.country = "India";



});

ในมุมมองตัวควบคุมทั้งสองนี้สามารถซ้อนกันได้ดังแสดงในรายการด้านล่าง:

<div ng-controller="ParentVMController as parent">



            <h2>Name :{{parent.name}} </h2>

            <h3>Age:{{parent.age}}</h3>



            <div ng-controller="ChildVMController as child">

                <h2>Parent Name :{{parent.name}} </h2>

                <h3>Parent Age:{{parent.age}}</h3>

                <h3>Child Age:{{child.age}}</h3>

                <h3>Country:{{child.country}}</h3>

            </div>

 </div>

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

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


4

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

ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้: http://www.syntaxsuccess.com/viewarticle/551798f20c5f3f3c0ffcc9ff


3

จากสิ่งที่ฉันได้อ่าน $ ขอบเขตจะถูกลบออกใน Angular 2.0 หรืออย่างน้อยเราก็ดูการใช้ $ scope อาจเป็นการดีที่จะเริ่มใช้คอนโทรลเลอร์เมื่อปล่อย 2.0 ใกล้

ลิงก์วิดีโอที่นี่สำหรับการสนทนาเพิ่มเติม

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