วิธีใช้ “ng-model” ใน AngularJS พร้อมตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

ng-model ใน AngularJS ผูกตัวควบคุมอินพุตเข้ากับคุณสมบัติใน $scope โดยตรงping มุมมองและโมเดลจะซิงโครไนซ์กันในทั้งสองทิศทาง หัวข้อด้านล่างจะกล่าวถึงคุณลักษณะ ตัวอย่างการใช้งานสามตัวอย่าง และข้อผิดพลาดที่ผู้เริ่มต้นมักพบเจอ

  • 🔗 การเย็บแบบสองทาง: ng-model จะส่งข้อมูลที่ผู้ใช้ป้อนเข้าไปในคุณสมบัติ $scope และจะส่งการเปลี่ยนแปลงของคอนโทรลเลอร์กลับไปยังคอนโทรลโดยอัตโนมัติ
  • 📝 การผูกข้อมูล Textarea: ผูกสตริงหลายบรรทัดเข้ากับ textarea และใช้ลำดับการหลีกเลี่ยง \n เพื่อบังคับให้ขึ้นบรรทัดใหม่ในค่าที่แสดงผล
  • ☑️ สถานะช่องทำเครื่องหมาย: ช่องทำเครื่องหมายที่ผูกกับ ng-model จะเก็บค่าบูลีน ดังนั้นค่า true จะทำให้ช่องทำเครื่องหมายถูกเลือก และค่า false จะทำให้ช่องทำเครื่องหมายว่างเปล่า
  • 📋 รายการแบบดรอปดาวน์: ใส่ข้อมูลตัวเลือก (ng-options) ลงในองค์ประกอบ select และผูกรายการที่เลือกเข้ากับคุณสมบัติของโมเดลแยกต่างหาก
  • ⚠️ ข้อผิดพลาดที่พบบ่อย: การผูกตัวเลือก (select) กับวัตถุเดียวกันกับที่ให้ข้อความตัวเลือก (option text) จะทำให้วัตถุนั้นถูกเขียนทับเมื่อมีการเลือกครั้งแรก
  • 🛠️ ฮุกการตรวจสอบความถูกต้อง: ng-model เพิ่มคลาส ng-pristine, ng-dirty, ng-valid และ ng-invalid ที่ขับเคลื่อนการกำหนดสไตล์ตามเงื่อนไขและการตรวจสอบแบบฟอร์ม

ng-model ใน AngularJS คืออะไร?

`ng-model` เป็น directive ใน AngularJS ที่ใช้แทนโมเดล โดยมีวัตถุประสงค์หลักคือการเชื่อมโยง "วิว" กับ "โมเดล" สิ่งที่ผู้ใช้พิมพ์ลงในคอนโทรลจะถูกเขียนลงใน property ของ `ng-model` โดยตรง $scopeและสิ่งใดก็ตามที่ตัวควบคุมเขียนลงในคุณสมบัตินั้น จะถูกส่งกลับไปยังตัวควบคุมโดยตรง

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

คุณสามารถใช้คำสั่ง ng-model เพื่อเชื่อมโยงฟิลด์ข้อความ "ชื่อ" และ "นามสกุล" กับโมเดลข้อมูลของคุณได้ คำสั่งนี้จะช่วยให้มั่นใจได้ว่าข้อมูลใน "มุมมอง" และ "โมเดล" ของคุณจะซิงค์กันตลอดเวลา โดยไม่ต้องเขียนโค้ดจัดการเหตุการณ์แม้แต่บรรทัดเดียว

⚠️ หมายเหตุเกี่ยวกับเวอร์ชัน: AngularJS (เวอร์ชัน 1.x) สิ้นสุดการสนับสนุนเมื่อวันที่ 31 ธันวาคม 2021 และจะไม่ได้รับการแก้ไขช่องโหว่ด้านความปลอดภัยอีกต่อไป ตัวอย่างด้านล่างยังคงใช้งานได้ แต่ใน Angular เวอร์ชันใหม่ การผูกข้อมูลแบบสองทางเดียวกันจะเขียนในรูปแบบอื่น [(ngModel)] และต้องใช้ FormsModule

แอตทริบิวต์ ng-model

ดังที่ได้กล่าวไว้ในหัวข้อข้างต้น คุณสมบัติ ng-model ใช้สำหรับเชื่อมโยงข้อมูลในโมเดลของคุณเข้ากับมุมมองที่แสดงต่อผู้ใช้

คุณลักษณะ ng-model ใช้สำหรับ

  1. การเชื่อมโยงส่วนควบคุมต่างๆ เช่น ช่องป้อนข้อมูล ช่องข้อความ และองค์ประกอบเลือกในมุมมอง เข้ากับโมเดล
  2. การเพิ่มกลไกการตรวจสอบความถูกต้อง — ตัวอย่างเช่น สามารถเพิ่มการตรวจสอบความถูกต้องให้กับช่องข้อความเพื่อให้สามารถป้อนได้เฉพาะตัวเลขเท่านั้น
  3. การรักษาสถานะของตัวควบคุม โดยสถานะในที่นี้หมายถึง การที่ตัวควบคุมและข้อมูลจะซิงค์กันอยู่เสมอ: หากค่าของข้อมูลเปลี่ยนแปลง ค่าในตัวควบคุมก็จะเปลี่ยนแปลงโดยอัตโนมัติ และในทางกลับกัน
  4. แสดงสถานะนั้นออกมาในรูปแบบคลาส CSS AngularJS เพิ่มคุณสมบัตินี้เข้าไป ng-pristine, ng-dirty, ng-valid และ ng-invalid สำหรับคอนโทรลทุกตัวที่ใช้ ng-model นั้น จะทำให้การกำหนดสไตล์แบบมีเงื่อนไขให้กับฟอร์มทำได้ง่ายขึ้น

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

วิธีการใช้งาน ng-model

1) พื้นที่ข้อความ

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

ต่อไปนี้เรามาดูตัวอย่างง่ายๆ เกี่ยวกับวิธีการเพิ่มคำสั่ง ng-model ลงในตัวควบคุม text area กัน ในตัวอย่างนี้ เราต้องการแสดงวิธีการส่งสตริงหลายบรรทัดจาก controller ไปยัง view และแนบค่าดังกล่าวเข้ากับตัวควบคุม text area

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        <textarea rows="4" cols="50" ng-model="pDescription"></textarea>
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pDescription = "This topic looks at how Angular JS works \nModels in Angular JS";
    });
</script>
</body>
</html>

Code คำอธิบาย:

  1. การขอ คำสั่ง ng-model แนบตัวแปรสมาชิกที่ชื่อว่า “p”Descriptเพิ่ม "ion" ให้กับตัวควบคุม "textarea" "pDescriptตัวแปร “ion” เก็บข้อความที่จะถูกส่งต่อไปยังตัวควบคุมพื้นที่ข้อความ rows="4" และ cols="50" คุณสมบัติเหล่านี้เพียงแค่กำหนดขนาดของตัวควบคุมเพื่อให้ข้อความหลายบรรทัดแสดงผลได้อย่างถูกต้อง
  2. ตัวแปรสมาชิก “p”Descriptไอออน” จะถูกกำหนดค่าเป็นหลายบรรทัด \n ลำดับการหลีกเลี่ยง (escape sequence) ที่อยู่ภายในสตริงจะบังคับให้ข้อความขึ้นบรรทัดใหม่เมื่อ textarea แสดงผล

Output:

จากผลลัพธ์ จะเห็นได้ชัดว่าข้อความหลายบรรทัดที่กำหนดไว้ในตัวควบคุมจะแสดงในพื้นที่ควบคุมข้อความ โดยแบ่งออกเป็นสองบรรทัดตรงจุดที่... \n นั่ง

2) องค์ประกอบอินพุต

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

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        Name : <input type="text" ng-model="pname"><br>
        Topic :<br>
        <input type="checkbox" ng-model="Topic.Controller">Controller<br>
        <input type="checkbox" ng-model="Topic.Models">Models
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pname = "Guru99";

        $scope.Topic = {
            Controller: true,
            Models: false
        };
    });
</script>
</body>
</html>

Code คำอธิบาย:

  1. คำสั่ง ng-model จะเชื่อมโยงตัวแปรสมาชิก “pname” กับตัวควบคุมการป้อนข้อความ และคุณสมบัติต่างๆ Topic.Controller และ Topic.Models ไปยังตัวควบคุมช่องทำเครื่องหมายทั้งสองช่อง
  2. ในคอนโทรลเลอร์ “pname” จะได้รับสตริง “Guru99” และออบเจ็กต์ “Topic” จะมีสมาชิกแบบบูลีนสองตัว ช่องทำเครื่องหมายที่ผูกกับ ng-model จะอ่านและเขียนค่าบูลีนเสมอ ซึ่งเป็นเหตุผลว่าทำไม true แสดงผลช่องดังกล่าวเป็นสถานะถูกเลือก และ false ทำให้ชัดเจน

Output:

จากผลลัพธ์ที่ได้

  • จะเห็นได้อย่างชัดเจนว่าค่าที่กำหนดให้กับ pname ตัวแปรคือ “Guru99. "
  • เนื่องจากค่าขอบเขตแรกคือ trueช่องทำเครื่องหมายถูกเลือกสำหรับช่องทำเครื่องหมาย “Controller” ในทำนองเดียวกัน เนื่องจากค่าที่สองคือ falseช่องทำเครื่องหมายสำหรับ "รุ่น" ไม่ได้ถูกทำเครื่องหมายไว้

3) เลือกองค์ประกอบจากดรอปดาวน์

คำสั่ง ng-model สามารถนำไปใช้กับองค์ประกอบ select ได้เช่นกัน เพื่อให้รายการที่ผู้ใช้เลือกถูกจัดเก็บไว้ในโมเดล

ตรงนี้เราจะมีช่องป้อนข้อความซึ่งเก็บชื่อ “Guru99” และรายการเลือกที่มีสองรายการย่อย ได้แก่ “ตัวควบคุม” และ “โมเดล”

⚠️ แก้ไข: ภาพหน้าจอข้างต้นแสดงรายการเดิม ซึ่งผูกองค์ประกอบการเลือกเข้ากับสิ่งเดียวกัน Topics อ็อบเจ็กต์ที่ให้ข้อความตัวเลือก เมื่อผู้ใช้เลือกตัวเลือกใดตัวเลือกหนึ่ง AngularJS จะเขียนทับค่าเดิม Topics เมื่อเลือกสตริงแล้ว ตัวเลือกทั้งสองจะหายไป รายการที่แก้ไขด้านล่างจะเก็บรายการไว้ในคุณสมบัติหนึ่ง และการเลือกไว้ในอีกคุณสมบัติหนึ่ง และใช้ ng-options เพื่อสร้างรายชื่อ

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        Name : <input type="text" ng-model="pName"><br>
        Topic :<br>
        <!-- Topics holds the list; selectedTopic holds the choice -->
        <select ng-model="selectedTopic" ng-options="t for t in Topics"></select>
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pName = "Guru99";

        $scope.Topics = ["Controller", "Models"];
        $scope.selectedTopic = $scope.Topics[0];
    });
</script>
</body>
</html>

Code คำอธิบาย:

  1. ช่องป้อนข้อความถูกผูกไว้กับ pNameและองค์ประกอบที่เลือกจะถูกผูกไว้กับ selectedTopicเนื่องจากตัวเลือกมีคุณสมบัติโมเดลของตัวเอง การเลือกตัวเลือกจึงไม่รบกวนรายการแต่อย่างใด
  2. การขอ Topics อาร์เรย์นี้เก็บค่าสองค่าคือ “Controller” และ “Models” ng-options นิพจน์จะวนไปตามอาร์เรย์นั้นและแสดงตัวเลือกหนึ่งรายการต่อหนึ่งหัวข้อ ดังนั้นการเพิ่มหัวข้อที่สามจึงไม่จำเป็นต้องเปลี่ยนแปลงมาร์กอัป
  3. selectedTopic ค่าเริ่มต้นจะถูกตั้งไว้ที่รายการแรก ซึ่งเป็นสิ่งที่ทำให้เมนูแบบดรอปดาวน์เปิดขึ้นมาพร้อมกับค่าเริ่มต้นที่เหมาะสม แทนที่จะเป็นแถวว่างเปล่า

Output:

จากผลลัพธ์ จะเห็นได้ว่าค่าที่กำหนดให้กับ pName ตัวแปรคือ “Guru99” และตัวควบคุมการเลือกมีตัวเลือก “ตัวควบคุม” และ “โมเดล” นอกเหนือจากตัวอย่างการทำงานแล้ว บางครั้งการผูกข้อมูลอาจไม่ยอมอัปเดต และเหตุผลเหล่านั้นก็คุ้มค่าที่จะทราบ

เหตุใดการผูกข้อมูลด้วย ng-model จึงล้มเหลวในบางครั้ง

ปัญหาที่พบได้บ่อยที่สุดเกี่ยวกับ ng-model ไม่ใช่บั๊กใน AngularJS แต่เป็นผลมาจากวิธีการทำงานของขอบเขต (scopes) และประเภทข้อมูลพื้นฐาน (primitives)

กรณีคลาสสิกคือการผูกค่าไว้ภายในคำสั่งที่สร้างขอบเขตย่อย เช่น ng-ซ้ำng-if หรือ ng-switch การเขียน ng-model="name" วิธีนี้จะสร้างสำเนาเงาในขอบเขตของลูก ทำให้ผู้ปกครองไม่เห็นการแก้ไขนั้น การผูกกับคุณสมบัติของวัตถุแทน — ng-model="user.name" — ช่วยให้ทุกขอบเขตชี้ไปยังการอ้างอิงเดียวกัน นี่คือเหตุผลที่นักพัฒนา AngularJS ที่มีประสบการณ์ยืนยันว่าต้องมีจุดในทุกนิพจน์ ng-model

สาเหตุอีกสองประการที่เหลือเป็นสาเหตุหลักของปัญหาที่เหลือ:

  • ตัวควบคุมหรือโมดูลหายไป: หากสะกด ng-app หรือ ng-controller ผิด การเชื่อมต่อจะไม่แสดงผลอะไรเลยแทนที่จะแสดงข้อผิดพลาด
  • ค่าที่เปลี่ยนแปลงภายนอก AngularJS: ค่าที่กำหนดจากแฮนด์เลอร์ jQuery หรือฟังก์ชันเรียกกลับ setTimeout จะอยู่นอกรอบการประมวลผล ดังนั้นมุมมองจะไม่รีเฟรชจนกว่าจะถึงเวลานั้น $scope.$apply() วิ่ง

การตรวจสอบสามสิ่งนี้จะช่วยแก้ปัญหาการเชื่อมต่อส่วนใหญ่ที่ดูเหมือนจะใช้งานไม่ได้

คำถามที่พบบ่อย

ng-bind เป็นแบบทางเดียว คือจะพิมพ์ค่าจากโมเดลลงในองค์ประกอบ ส่วน ng-model เป็นแบบสองทางและใช้งานได้เฉพาะกับส่วนควบคุมของฟอร์มเท่านั้น ดังนั้นข้อมูลที่ผู้ใช้ป้อนจะไหลกลับเข้าไปในโมเดลเช่นเดียวกับการไหลออกจากโมเดล

เพิ่ม ng-model-options ตัวอย่างเช่น ng-model-options=”{ debounce: 500 }” AngularJS จะรอครึ่งวินาทีหลังจากกดแป้นพิมพ์ครั้งสุดท้ายก่อนที่จะอัปเดตโมเดล ซึ่งมีประโยชน์สำหรับช่องค้นหาที่เรียกใช้การร้องขอ

โดยส่วนใหญ่แล้วใช่ ผู้ช่วย AI จะเขียน ng-model ใหม่เป็น [(ngModel)] และเพิ่มการนำเข้า FormsModule ฟอร์มแบบตอบสนอง ตัวแยกวิเคราะห์แบบกำหนดเอง และไปป์ไลน์ $formatters ยังคงต้องได้รับการตรวจสอบด้วยตนเอง เนื่องจาก Angular สร้างแบบจำลองสำหรับสิ่งเหล่านี้แตกต่างกันมาก

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

เฉพาะอินพุตประเภท “number” เท่านั้นที่จะถูกแปลงเป็นค่าตัวเลข ส่วนอินพุตประเภท “text” จะส่งคืนค่าสตริงเสมอ ดังนั้นการเปรียบเทียบด้วย === จึงล้มเหลว ต้องแปลงค่าอย่างชัดเจน หรือเปลี่ยนประเภทอินพุต

สรุปโพสต์นี้ด้วย: