كيفية استخدام "ng-model" في AngularJS مع أمثلة

⚡ ملخص ذكي

تقوم خاصية ng-model في AngularJS بربط عنصر تحكم الإدخال مباشرةً بخاصية في $scope، احتفظping تتم مزامنة العرض والنموذج في كلا الاتجاهين. تتناول الأقسام التالية الخاصية، وثلاثة أمثلة عملية، والأخطاء الأكثر شيوعًا بين المبتدئين.

  • 🔗 تجليد ثنائي الاتجاه: يقوم ng-model بدفع مدخلات المستخدم إلى خاصية $scope ويدفع تغييرات وحدة التحكم مرة أخرى إلى عنصر التحكم تلقائيًا.
  • 📝 ربط منطقة النص: قم بربط سلسلة نصية متعددة الأسطر بمنطقة نصية واستخدم تسلسل الهروب \n لفرض فواصل الأسطر في القيمة المعروضة.
  • ☑️ حالة خانة الاختيار: يقوم مربع الاختيار المرتبط بـ ng-model بتخزين قيمة منطقية، لذا فإن القيمة true تجعل المربع محددًا والقيمة false تجعله غير محدد.
  • 📋 القوائم المنسدلة: قم بتعبئة عنصر select بخيارات ng-options واربط العنصر المختار بخاصية نموذج منفصلة.
  • ⚠️ الأعطال الشائعة: يؤدي ربط عنصر التحديد بنفس الكائن الذي يوفر نص الخيار الخاص به إلى استبدال ذلك الكائن عند التحديد الأول.
  • 🛠️ خطافات التحقق: يضيف ng-model فئات ng-pristine وng-dirty وng-valid وng-invalid التي تقود التصميم الشرطي وعمليات التحقق من النماذج.

ما هو نموذج ng في AngularJS؟

ng-model هو توجيه في AngularJS يمثل النموذج، ووظيفته الأساسية هي ربط "العرض" بـ "النموذج". أي شيء يكتبه المستخدم في عنصر تحكم يُكتب مباشرةً في خاصية على $scopeوأي شيء يكتبه المتحكم في تلك الخاصية يتم دفعه مباشرة إلى عنصر التحكم.

على سبيل المثال، لنفترض أنك تريد عرض صفحة بسيطة للمستخدم النهائي كما هو موضح أدناه، والتي تطلب منه إدخال "الاسم الأول" و"اسم العائلة" في مربعات نصية. ثم تريد التأكد من تخزين المعلومات التي أدخلها المستخدم في نموذج البيانات الخاص بك.

يمكنك استخدام توجيه ng-model لربط حقلي النص "الاسم الأول" و"الاسم الأخير" بنموذج البيانات الخاص بك. يضمن هذا التوجيه مزامنة البيانات في "العرض" مع بيانات "النموذج" باستمرار، دون الحاجة إلى كتابة أي سطر برمجي لمعالجة الأحداث.

⚠️ ملاحظة حول الإصدار: وصل AngularJS (الفرع 1.x) إلى نهاية عمره الافتراضي في 31 ديسمبر 2021، ولم يعد يتلقى تحديثات أمنية. لا تزال الأمثلة أدناه تعمل، ولكن في Angular الحديث، تتم كتابة نفس الربط ثنائي الاتجاه على النحو التالي: [(ngModel)] ويتطلب وحدة النماذج (FormsModule).

سمة نموذج ng

كما نوقش في القسم أعلاه، يتم استخدام سمة ng-model لربط البيانات في النموذج الخاص بك بالعرض المقدم للمستخدم.

يتم استخدام سمة ng-model لـ ،

  1. ربط عناصر التحكم مثل عناصر الإدخال ومنطقة النص وعناصر التحديد في العرض بالنموذج.
  2. توفير سلوك التحقق من الصحة - على سبيل المثال، يمكن إضافة التحقق من الصحة إلى مربع نص بحيث لا يمكن إدخال سوى الأحرف الرقمية.
  3. الحفاظ على حالة التحكم. ونعني بالحالة أن التحكم والبيانات يتم الحفاظ عليهما متزامنين دائمًا: إذا تغيرت قيمة البيانات، تتغير القيمة في التحكم تلقائيًا، والعكس صحيح.
  4. عرض تلك الحالة كفئات CSS. يضيف AngularJS ng-pristine, ng-dirty, ng-valid و ng-invalid لكل عنصر تحكم يحمل ng-model، وهذا ما يجعل التنسيق المشروط للنماذج أمرًا بسيطًا.

بعد فهم السمة، تتمثل الخطوة التالية في تطبيقها على أنواع التحكم الثلاثة التي ستصادفها في أغلب الأحيان.

كيفية استخدام نموذج ng

1) منطقة النص

يتم استخدام علامة منطقة النص لتحديد عنصر تحكم إدخال نص متعدد الأسطر. يمكن أن تحتوي منطقة النص على عدد غير محدود من الأحرف، ويتم عرض النص بخط ثابت العرض.

والآن، دعونا نلقي نظرة على مثال بسيط لكيفية إضافة توجيه 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>
        <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. استخدم توجيه نموذج نانوغرام يُلحق متغير العضو المسمى "p"Descript"ion" إلى عنصر التحكم "textarea". "pDescriptيحتوي المتغير "ion" على النص الذي يتم تمريره إلى عنصر تحكم منطقة النص. rows="4" و cols="50" تقوم السمات ببساطة بتحديد حجم عنصر التحكم بحيث يتم عرض النص متعدد الأسطر بشكل صحيح.
  2. المتغير العضو "p"Descriptتم تعيين قيمة متعددة الأسطر لـ "ion". \n إن تسلسل الهروب الموجود داخل السلسلة هو ما يجبر النص على الانتقال إلى سطر ثانٍ عند عرضه في منطقة النص.

الإخراج:

يتضح من المخرجات أن النص متعدد الأسطر المُعيّن في وحدة التحكم يظهر في عنصر تحكم منطقة النص، مقسمًا على سطرين بالضبط حيث \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"، ويتم إعطاء كائن "الموضوع" عنصرين منطقيين. يقوم مربع الاختيار المرتبط بـ ng-model دائمًا بقراءة وكتابة قيمة منطقية، ولهذا السبب true يجعل المربع مُحددًا و false يترك الأمر واضحاً.

الإخراج:

من الإخراج،

  • من الواضح أن القيمة المخصصة لـ pname المتغير هو "Guru99 ".
  • بما أن القيمة المحددة الأولى هي true، تم تحديد خانة الاختيار الخاصة بـ "وحدة التحكم". وبالمثل، بما أن القيمة الثانية هي false، لم يتم تحديد خانة الاختيار الخاصة بـ "النماذج".

3) حدد عنصرًا من القائمة المنسدلة

يمكن أيضًا تطبيق توجيه ng-model على عنصر التحديد، بحيث يتم تخزين العنصر الذي يختاره المستخدم في النموذج.

هنا سيكون لدينا حقل إدخال نصي يحتوي على الاسم "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 يتم ضبطها مسبقًا على الإدخال الأول، وهذا ما يجعل القائمة المنسدلة تفتح بخيار افتراضي معقول بدلاً من صف فارغ.

الإخراج:

يتضح من المخرجات أن القيمة المخصصة لـ pName المتغير هو "Guru99"، ويُتيح عنصر التحكم المُحدد خياري "وحدة التحكم" و"النماذج". وبغض النظر عن الأمثلة العملية، قد ترفض الروابط التحديث في بعض الأحيان، ومن المهم معرفة الأسباب.

لماذا تفشل روابط ng-model أحيانًا

معظم مشاكل ng-model المبلغ عنها ليست أخطاء في AngularJS ولكنها نتائج لكيفية عمل النطاقات والأنواع الأولية.

الحالة الكلاسيكية هي ربط يتم وضعه داخل توجيه يقوم بإنشاء نطاق فرعي، مثل نانوغرام تكرار، 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 نصف ثانية بعد آخر ضغطة مفتاح قبل تحديث النموذج، وهو أمر مفيد لمربعات البحث التي تُطلق طلبًا.

إلى حد كبير، نعم. تقوم مساعدات الذكاء الاصطناعي بإعادة كتابة ng-model كـ [(ngModel)] وتضيف استيراد FormsModule. لا تزال النماذج التفاعلية والمحللات المخصصة ومسارات $formatters بحاجة إلى مراجعة يدوية، لأن Angular يصممها بشكل مختلف تمامًا.

تتحقق أدوات الذكاء الاصطناعي بسرعة من الأسباب الشائعة للمشاكل: ربط نوع بيانات بدائي داخل نطاق فرعي، واسم وحدة تحكم مكتوب بشكل خاطئ، وقيمة مُسندة خارج دورة المعالجة. ينتج عن كل منها فشل صامت بدلاً من ظهور خطأ في وحدة التحكم.

يتم تحليل نوع الإدخال "رقم" فقط إلى قيمة رقمية. أما نوع الإدخال "نص" فيُنتج دائمًا سلسلة نصية، لذا تفشل المقارنات باستخدام ===. قم بالتحويل صراحةً، أو غيّر نوع الإدخال.

تلخيص هذه التدوينة بـ: