01-03-2019, 10:45 AM | #1 |
تاريخ التسجيل: Feb 2019
الدولة: قلب ابي
العمر: 31
المشاركات: 1,006
التقييم: 10
|
تاريخ التسجيل: Feb 2019
الدولة: قلب ابي
العمر: 31
المشاركات: 1,006
التقييم: 10
التّابع scope.$eval
لتتمكّن من معالجة العبارة الممرّرة إلى التّوجيه كسلسلةٍ نظاميّة، ستحتاج إلى استخدام التّابع eval$.
التّابع scope.$eval بالرغم من أنّ Angular لا تعتبر أنّ الوسيط المُمرّر إلى التّوجيه عبارةٌ تحتاج إلى معالجة، إلّا أنّه يمكننا ببساطةٍ أن نعالج هذه العبارة باستخدام التّابع eval$، ولأخذ العلم، فهذه الطّريقة لا تؤدّي إلى إعادة تحديث العرض (view) عند تغيُّر النّموذج، وهذا مفيدٌ فقط في حالات الاستخدام الأساسيّة. angular.module('app') .directive('welcomeMessage', function() { return function(scope, element, attrs) { var result = scope.$eval(attrs.welcomeMessage); element.text(result); }; }); لنقم بتجربة حالة استخدامٍ بسيطة نقوم فيها بوصل سلسلتين نصّيّتين. The message is <em welcome-message="'bon' + 'jour'"></em>. الناتج: The message is bonjour. يُمكننا أيضًا باستخدام scope.$eval أن نقوم بتمرير كائنات، مّما يتيح لنا طريقةً لتلقّي العديد من الوسطاء معًا، وسنلقي نظرةً في فقرةٍ لاحقةٍ من هذا الفصل علىتوجيهات العناصر، والتي تقبل أيضًا العديد من الوسطاء المُسمّاة عن طريقة إتاحة وجود العديد من الخصائص للعنصر، أمّا الآن فسنرى في المثال التالي معالجةً لكائنٍ من نوع options، حيث نقوم بتمرير العديد من الوسطاء إلى التّوجيه. angular.module('app') .directive('welcomeMessage', function() { return function(scope, element, attrs) { var options = scope.$eval(attrs.welcomeMessage); var result = options.emoticon + ' ' + options.message + ' ' + options.emoticon; element.text(result); }; }); وبهذه الطّريقة استطعنا إدخال وسيطين بفعّاليّة، message وemoticon، واستطعنا إنجاز الوصل بينهما داخل التّوجيه. The message is <em welcome-message="{message: 'bonjour', emoticon: '\u263a'}"></em>. الناتج: The message is ☺ bonjour ☺. صِرنا الآن نفهم كيفيّة استخدام توجيهاتٍ مخصّصةٍ مع المجالات والمتحكّمات. ولكن ماذا لو أردنا استخدام خدماتٍ أخرى داخل التّوجيه؟ حقن التبعية إن أردنا الوصول إلى موارد مُدارة مثل خدمةٍ ما، أو مُرشّحٍ ما من داخل توجيهنا الخاصّ، فلن يكون علينا سوى التّصريح عن التّبعيّات كوسيطٍ في التّابع الخارجيّ. (راجع فصل حقن التّبعيّة وفصل الخدمات إن لم يكن هذا المفهوم مألوفًا لديك.) على سبيل المثال، لنفترض بأنّنا نريد توجيهًا يُمكنه تطبيق حسمٍ على السّعر وأيضًا القيام بتنسيقٍ للعملة لقيمة المتغيّر price في المجال. سيحتاج هذا التّوجيه للوصول إلى الخدمة المخصّصة calculateDiscount المُعرّفة كما يلي. angular.module('app') .value('discountRate', 0.8) .factory('calculateDiscount', function(discountRate) { return function(amount) { return amount * discountRate; }; }); والآن سنستخدم تابع الوصفة (recipe) التّغليفيّ لحقن الخدمة calculateDiscount مع المُرشّح currency أيضًا. angular.module('app') .directive('discount', function(calculateDiscount, currencyFilter) { return function(scope, element, attrs) { var price = scope.$eval(attrs.discount); var discountPrice = calculateDiscount(price); element.html(currencyFilter(discountPrice)); }; }); لاحظ بأنّنا قمنا بتمرير العنصر price كقيمةٍ لوسيط التّوجيه في القالب، ويُمكننا الحصول على هذه القيمة للوسيط عن طريق الوسيط attrs حيث نصل إلى الخاصّيّة (discount) وهي اسم التّوجيه الخاصّ بنا. في المثال التّالي، سنقوم بإسناد قيمة هذا العنصر في المجال (الّتي نحصل عليها عن طريق scope.$eval) إلى المتغيّر المحلّي المُسمّى price. <table ng-init="price = 100"> <tr> <td>Full price:</td> <td ng-bind="price | currency"></td> </tr> <tr> <td>Sale price:</td> <td discount="price"></td> </tr> </table> الناتج: Full price: $100.00 Sale price: $80.00 قد ترغب في وضع مُرشّحٍ بدلًا من التّوجيه، فالتّحويل الذي قمنا به بسيطٌ للغاية، حيث لم نضِف إلى المستند أيّ سلوكٍ تفاعليّ. لننتقل الآن إلى مثالٍ أكثر تعقيدًا بحيث يحتاج إلى إضافة وسمٍ باستخدام القالب. القوالب كُلّ العمليّات التي قمنا بتنفيذها في الأمثلة السّابقة على الوسيط element كانت سهلةً إلى حدٍّ ما، ولكن ماذا لو أردنا إضافة قطعةٍ متغيّرة الحجم من محتوىً جديدٍ إلى المستند؟ لنقم بمحاولة حلّ هذه المشكلة بالتّدريج. في البداية، لنقُل بأننا نريد فقط تغليف سلسلةٍ نصّيّةٍ نُمرّرها كوسيطٍ للتّوجيه الخاصّ بنا باستخدام عنصر strong. The message is <span strong-message="a strong hello!"></span> يُمكننا دومًا استخدام عمليّة وصل السّلاسل (concatenation). angular.module('app') .directive('strongMessage', function() { return function(scope, element, attrs) { element.html('<strong>' + attrs.strongMessage + '</strong>'); }; }); الناتج: The message is a strong hello! أو يُمكننا بناء المحتوى بطريقةٍ برمجيّة باستخدام jqLite أو jQuery. angular.module('app') .directive('strongMessage', function() { return function(scope, element, attrs) { element.html('<strong>'); element.find('strong').text(attrs.strongMessage); }; }); الناتج: The message is a strong hello! عمليّة وصل السّلاسل والتّغييرات البرمجيّة على المستند طريقةٌ جيّدةٌ عند استخدامها للأمور الصّغيرة كعنصرٍ واحدٍ مثلًا، ولكن ماذا سنفعل عندما يكون المحتوى يتضمّن العديد من العناصر المتداخلة؟ أو عندما يكون لدينا قائمةٌ متغيّرة الحجم؟ سيجيبك عن هذا السّؤال أيّ خبيرٍ في تطوير النهاية الأماميّة (front-end) بأنّ مكتبة القوالب ستسهّل الأمر كثيرًا، ولحسن الحظّ، فـAngular مكتبة قوالب، وستجعل الأمر أكثر سهولة. يُمكن لـAngular أن تقوم بإخراج (render) قوالب متداخلةٍ يقدّمها التّوجيه الخاصّ بنا، وذلك في الوقت نفسه الّذي تقوم فيه بإخراج قالب التّطبيق الخاصّ بنا. لإضافة قالبٍ للتّوجيه، سنحتاج إلى تغيير أسلوبنا السّابق، فبدلًا من إعادة (return) تابع الرّبط فقط، سنقوم بإعادة كائنٍ يحوي تابع الربط ومعه قالب. هذا تغيير كبير، لذا فلنكرّر ذلك: سيقوم المُغلّف الوصفيّ (recipe) الآن بإعادة كائنٍ بدلًا من تابع، وسنستخدم العنصر link في هذا الكائن المُعاد للوصول إلى التّابع. فيما يلي مثالٌ يستخدم قالبًا لإنشاء عددٍ غير محدّدٍ مسبقًا من عناصر li. angular.module('app') .directive('wordList', function() { return { link: function(scope, element, attrs) { scope.words = attrs.wordList.split(" "); }, template: "<li ng-repeat='word in words'>\ {{word}}\ </li>" }; }); ستستلم Angular مهمّة تضمين القالب في المجال الصحيح، ثمّ إلحاق المخرجات بالعنصر الذي استخدم التّوجيه. بما أنّ مخرجات هذا التّوجيه ستكون عناصر في قائمة، لنقم بتضمين التّوجيه في العنصر ul. <ul word-list="we love templates"></ul> الناتج: . we . love . templates أظنّ بأن المثال بدأ يوضّح لك قوّة وأناقة التّوجيهات المخصّصة. العنصر templateUrl استخدمنا في المثال البسيط السّابق رمز الشرطة الخلفيّة (\) مرّتين لنتمكّن من كتابة نصّ القالب، وكما ترى، فالقوالب السّطريّة سُرعان ما تصبح مستهجنةً داخل شيفرة JavaScript، ولذلك سنستعين بالقوالب الخارجيّة التي تدعمها Angular، سواء كانت عناصر خاصّة مخفيّة في المستند، أو موارد ويب منفصلةً تمامًا في مكانٍ مستقل. <li ng-repeat="word in words"> {{word}} </li> لقد قمنا باستخراج شيفرة القالب إلى مورد ويب موجودٍ في الرابط النّسبيّ views/word-list.html، والآن سنقوم بإضافة العنصر templateUrl إلى كائن الإعدادات الذي يعيده التّوجيه الخاص بنا، وسنقوم بإسناد مسار القالب إليه، وذلك بدلًا من استخدام العنصر template وإسناد شيفرة القالب إليه مباشرةً. angular.module('app') .directive('wordList', function() { return { link: function(scope, element, attrs) { scope.words = attrs.wordList.split(" "); }, templateUrl: '/views/word-list.html' }; }); أمّا الاستخدام فيبقى كما هو دون تغيير. <ul word-list="external templates rock"></ul> الناتج: . external . templates . rock القوالب الخارجيّة عمومًا أسهلُ بكثيرٍ للقراءة وللتّعديل من القوالب السّطريّة. العنصر replace لا بُدّ من استخدام التّوجيه في المثال السابق ضمن قائمة، ولكن ماذا لو لم يقم المستخدم باستخدام التّوجيه بشكلٍ صحيح؟ أحد الحلول هو استبدال العنصر الذي يتضمّن التّوجيه بدلًا من إلحاق العناصر به. إذًا لنقُم بإضافة عنصر ul لتغليف مخرجات قالبنا، سنحتاج أيضًا إلى عنصرٍ جديدٍ في كائن الإعدادات هو العنصر replace، وسنُسند إليه القيمة true. (القيمة الافتراضيّة له هي بالطّبع false.) لنقم أوّلًا بإضافة العنصر ul إلى قالبنا. <ul> <li ng-bind="word" ng-repeat="word in words"></li> </ul> التّغيير الوحيد الهامّ في التّوجيه هو استخدام العنصر الجديد replace. angular.module('app') .directive('wordList', function() { return { link: function(scope, element, attrs) { scope.words = attrs.wordList.split(" "); }, templateUrl: '/views/word-list-ul.html', replace: true }; }); بما أنّ العنصر الذي يتضمّن التّوجيه سيتمّ استبداله مهما كان، يُمكننا تضمين التّوجيه في عنصرٍ غريبٍ وغير ملائمٍ مثل h1. <h1 word-list="lists not headlines"></h1> الناتج: . lists . not . headlines يبيّن المثال السّابق قوّة تأثير التّوجيهات على المستند، ولكنّني أُفضّل أن يكون التّصميم أكثر وضوحًا، ودلالته صحيحة، ولذلك فبدلًا من استبدال وسوم HTML، أرى أنّ الصّواب هو التّحقّق من صحّة العنصر الذي قام بتضمين التّوجيه، وإن لم يكن صحيحًا يتمّ إلقاء خطأ (throw an error). العنصر controller في بداية هذا الفصل، رأينا مثالًا يحوي متحكّمًا يقوم بتحضير عنصرٍ في المجال، ثمّ استخدمنا هذا العنصر لاحقًا داخل تابع الربط الخاصّ بالتّوجيه. والآن بعد أن تعرّفنا على طريقة استخدام القوالب، لنقُم بإعادة كتابة هذا المثال، واستبدال تابع الرّبط الذي يحدّد نصّ العنصر في المستند بقالب. angular.module('app') .controller('MessageController', function($scope) { $scope.message = 'hello, from the external controller'; }) .directive('message', function() { return { template: "<strong>{{message}}</strong>" }; }); بما أنّ المتحكّم والتّوجيه منفصلان، فكلاهما يحتاج إلى التّضمين بشكلٍ منفصلٍ في المثال التالي. يُمكننا أن نضع المتحكّم في نفس العنصر الذي يحوي التّوجيه أو في عنصرٍ مغلّف، فلا فرق. The message is <span message ng-controller="MessageController"></span>. الناتج: The message is hello, from the external controller. كما ترى في المثال السّابق، لقد قُمنا بإزالة تابع الرّبط، فوجوده أمرٌ اختياريّ، واقتصرنا على العنصر template، وذلك لأنّ استخدام تابع الرّبط يكون للقيام بالتّغييرات البرمجيّة على المستند بطريقةٍ أكثر أُلفةً لمطوّري النّهاية الأماميّة. أمّا الآن بعد أن انتقلنا إلى استخدام القوالب، فسنحتاج إليه للقيام بمهمّاتٍ نحتاج فيها إلى الوصول إلى العنصر الحاوي للتّوجيه أو إلى خصائص العنصر (مُتضمّنةً التّوجيه بذاته، كما رأينا سابقًا.) إضافةً إلى ذلك، فإنّ تحضير بيانات النّموذج لا يحتاج إلى الوصول إلى العنصر أو إلى خصائصه، وهو من مهمّات المتحكّم، وهذا بالرّغم من إمكانيّة القيام بذلك داخل تابع الرّبط كما بيّنّا في فقرة القوالب. لذا، سيكون من الأفضل أن ننقل مسؤوليّة تحضير النّموذج إلى داخل المتحكّم، إلّا أنّ المشكلة الآن هي أنّ المتحكّم منفصلٌ ويحتاج إلى إعداداتٍ خاصّةٍ به، فهل يُمكننا نقل المتحكّم إلى داخل التّوجيه؟ نعم، يمكننا ذلك. angular.module('app') .directive('message', function() { return { template: "<strong>{{message}}</strong>", controller: function($scope) { $scope.message = 'hello, from the internal controller'; } }; }); أليس هذا رائعًا؟ لم نحصل الآن على مكوِّنٍ مغلّفٍ جيّدًا وحسب، بل تخلّصنا الآن من تضمين المتحكّم واستخدام التّوجيه ng-controller في الوسم. The message is <span message></span>. الناتج: The message is hello, from the internal controller. ويمكننا طبعًا القيام بكلّ الأشياء المعتادة مع المتحكّم، كتعريف تابعٍ في المجال وتضمين هذا التّابع من عنصر تحكّمٍ داخل القالب. راجع فصل المتحكّمات للاستزادة. الخيار restrict تُوجد أربع طرقٍ لتضمين توجيهٍ ما، إلّا أنّنا لم نرَ حتّى الآن إلّا طريقة تضمين التّوجيهات كخصائص لعناصر HTML، وذلك لأنّه الأسلوب الأكثر شيوعًا وفائدةً للقيام بذلك، وهي أيضًا القيمة الافتراضيّة للخيار restrict الذي يُمكن أن يملك واحدةً أو أكثر من الخيارات التّالية: 'A' يتمّ تضمينه كخاصّيّة (Attribute) 'C' يتمّ تضمينه كفئة (Class) 'E' يتمّ تضمينه كعنصر (Element) 'M' يتمّ تضمينه كتعليق (Comment) بالنّسبة للأساليب الثّلاثة الأخرى في التّضمين (الفئة، العنصر والتّعليق) فأسلوب التضمين كعنصرٍ هو الأكثر إثارةً للاهتمام من النّاحية العمليّة، فأسلوبا الفئة والتّعليق موجودان لدعم الحالات الهامشيّة مثل وجود تحقّق صارمٍ لصحّة نصوص HTML. أعتبر أنّ عنصر التّوجيه يُشبه مدفعًا كبيرًا، يجب عليك ألا تستخدمه إلّا إن كان الأمر يستحق ذلك. نموذجيًّا، يتمّ استخدام هذه الطّريقة عندما نحتاج إلى وضع عددٍ كبيرٍ من الوسوم داخل مكوّنٍ من مكوّنات HTML ويكون أيضًا عليك تمرير العديد من الوسطاء إليه، فعندما تستخدم عنصر التّوجيه، ستتمكّن من تمرير قيم الوسطاء على شكل خصائص لهذا العنصر. في المثال التّالي لن يكون لدينا هذا العدد الكبير من الوسوم إلّا أنّنا سنصمّم جدولًا مع كلّ الزخرفات الخاصة به. <table class="table table-condensed"> <thead> <tr> <th ng-bind="column" ng-repeat="column in columns"></th> </tr> </thead> <tbody> <tr ng-repeat="model in models"> <td ng-bind="model[column]" ng-repeat="column in columns"></td> </tr> </tbody> </table> سيستخدم تابع الرّبط الآن وسيطين في تعريف التّوجيه الخاصّ بنا، وسنصل إلى هذا الوسيطين عن طريق attrs.models و attrs.columns. angular.module('app') .directive('modelsTable', function() { return { restrict: 'E', templateUrl: '/views/models-table.html', link: function(scope, element, attrs) { scope.models = scope.$eval(attrs.models); scope.columns = attrs.columns.split(","); } }; }); قد ترغب بإسناد القيمة true إلى العنصر replace في عنصر التّوجيه إن كانت البيئة التي تعمل عليها تُسبّب لك بعض المشاكل عند استخدام أسماء عناصر غير معياريّة، على الجانب الآخر، تركُ هذا العنصر المخصص في مستندك قد يساعدك أثناء تصحيح الأخطاء في الشيفرة. سنقوم مرّةً أخرى باستخدام متحكّمٍ خارجيّ في هذا المثال. angular.module('app') .controller('ItemsController', function($scope) { $scope.items = [ {name: 'Item 1', color: 'green', price: 5.0}, {name: 'Item 2', color: 'blue', price: 4.93} ]; }); وأخيرًا، سنقوم بإضافة Bootstrap إلى صفحتنا لجعل مثالنا الأخير أكثر أناقة. <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script> الخطوة الأخيرة الآن هي تضمين عنصر التّوجيه الخاصّ بنا مع وسيطيه models وcolumns حيث سنضيفهما على شكل خصائص للوسم. <p ng-controller="ItemsController"> <models-table models="items" columns="name,color,price"></models-table> </p> رائع، لقد قمنا بإخفاء الشيفرات المزعجة الخاصّة بجدول HTML بإحكام. المصدر: منتديات رحيل لكل العرب - من قسم: قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress |
اقتباس |
أضف رد جديد |
الكلمات الدلالية (Tags) |
منتديات رحيل, رحيل, شبكة رحيل, r7il, r7il.com |
الذين يشاهدون محتوى الموضوع الآن : 1 ( الأعضاء 0 والزوار 1) | |
|
|