<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Angular</title><link>https://academy.hsoub.com/programming/javascript/angular/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Angular</description><language>ar</language><item><title>&#x62D;&#x642;&#x646; &#x627;&#x644;&#x62A;&#x628;&#x639;&#x64A;&#x629; (Dependency-injection) &#x641;&#x64A; AngularjS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%AD%D9%82%D9%86-%D8%A7%D9%84%D8%AA%D8%A8%D8%B9%D9%8A%D8%A9-dependency-injection-%D9%81%D9%8A-angularjs-r198/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/angular-dependency-injection_(1).png.5926f1c277b99764f963fd17aa098f0d.png" /></p>

<p>تدير Angular الموارد باستخدام <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">نظام الوحدات</a>، ولهذا السّبب فهي تحتاج أيضًا إلى تقديم طريقةٍ للوصول إلى هذه الموارد المنظّمة ضمن حاويات (container-managed)، حيث تقوم Angular بذلك باستخدام <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Creational_pattern">نمطٍ إنشائيّ</a> يُدعى حقن التبعية.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/angular-dependency-injection_(1).png.c3c9b6c3fc20b9bc30529e99a93fae28.png"><img data-fileid="6180" class="ipsImage ipsImage_thumbnailed" alt="angular-dependency-injection_(1).thumb.p" src="https://academy.hsoub.com/uploads/monthly_2015_10/angular-dependency-injection_(1).thumb.png.ba9cf0cf88ade565fb67b65fbabd8b66.png"></a></p><p style="text-align: center;"> </p><p>إن لم يكن لديك معرفةٌ مسبقةٌ بهذا المفهوم فسأقوم هنا بأفضل ما لديّ لتلخيصه لك: لنفترض أنّك تحتاج إلى الحصول على مَوردٍ (resource) من Angular، المَورد هو الحاوية. للحصول عليه يجب أن تكتب تابعًا يُعرّف وسيطًا له نفس اسم هذا المَورد بالضّبط. تقوم الحاوية باكتشاف التّابع الذي كتبته، وتتعرّف على توافق الوسيط مع المَورد المطلوب، فتقوم بإنشاء نُسخةٍ (instance) من هذا المَورد (أو تقوم بأخذ النُّسخة المنفردة (singleton) من هذا المَورد، إن كان من النّوع المنفرد) ثُمّ تقوم باستدعاء التّابع الخاص بك وجعل هذه النّسخة هي قيمة الوسيط الخاص بالتابع. بما أنّ الحاوية هنا تلعب الدّور الفعّال (على عكس الطلب الذي تقوم به للحصول على نسخة من المَورد)، لذلك يُعتبر حقن التّابعيّة عكسًا للتّحكّم (<a rel="external nofollow" href="http://martinfowler.com/bliki/InversionOfControl.html">inversion of control</a>)، ويُقدّم على أنّه تطبيق <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Hollywood_principle">لمبدأ Hollywood</a>، "لا تكلّمنا، نحن سوف نكلِّمُك".</p><p>أعتقد بأنّ مخترعي Angular قد اختاروا طريقة حقن التّابعيّة بسبب تاريخ Google الطّويل مع منصّة Java، بيئة برمجة ساكنة يقوم فيها حقنُ التّابعيّة بدورٍ فعّال في عمليّات تغيير الأنواع أثناء وقت التّشغيل. (لقد تخطّت Google الحدود في ذلك إلى درجة أنّها أنشأت إطار عمل Java خاصٍّ بها، <a rel="external nofollow" href="https://github.com/google/guice">Guice</a>، الذي يعتمد على حقن التّابعيّة كُلّيًّا.) أمّا في JavaScript، وهي البيئة المرنة والديناميكيّة، حيث يمكن أن تتغيّر الأنواع أثناء وقت التّشغيل، فقد حظِيَ فيها أسلوب محدّد موضع الخدمة (<a rel="external nofollow" href="http://martinfowler.com/articles/injection.html#UsingAServiceLocator">service locator</a>) البسيط والمباشَر بشعبيّة هائلة عن طريق الواجهة البرمجيّة لـ<a rel="external nofollow" href="http://wiki.commonjs.org/wiki/CommonJS">CommonJS</a>، وهي عبارة require المستخدمة في Node.js و<a rel="external nofollow" href="http://browserify.org/">browserify</a>. والأكثر من ذلك، أنّ الطريقة البدائيّة في القيام بحقن التّابعيّة قد تبيّن أنّ لها نقطة ضعفٍ عند استخدامها في JavaScript من طرف العميل، وذلك بسبب تعديل أسماء الوُسطاء باستخدام المُقصّرات (<a rel="external nofollow" href="http://en.wikipedia.org/wiki/Minification_%28programming%29">minifiers</a>). ولنستطيع التّعامل مع هذه المشكلة، من الضّروريّ أن توجد أداة بناءٍ بديلة، أو أن نتعلّم ونستخدم <a rel="external nofollow" href="http://www.angularjsbook.com/angular-basics/chapters/dependency-injection/#annotation">حواشي</a> التّبعيّات، وسنصل إلى ذلك بعد قليل، ولكن لنتعرّف أوّلًا على النّموذج البدائيّ.</p><h2>التبعيات الضمنية</h2><p>لن نستخدم خارج هذا الفصل للقيام بحقن التّبعيّة غير طريقة <a rel="external nofollow" href="https://docs.angularjs.org/guide/di#implicit-dependencies">التّبعيّات الضّمنيّة</a> لأنّها الأسهل بين جميع الطُّرق. كما ذكرت سابقًا، يمكننا جلب مرجعٍ لأحد الموارد المتاحة عن طريق وضعه كوسيطٍ في تابعنا الإنشائيّ، ولقد قمنا بذلك للمرّة الأولى عندما أضفنا الوسيط scope$ الذي يعطي تابع التّحكّم مرجعًا إلى كائن <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AC%D8%A7%D9%84%D8%A7%D8%AA-scopes-%D9%81%D9%8A-angularjs-r188/">المجال</a> المنظّمٍ ضمن حاوية (container-managed).</p><p>يقوم نظام حقن التّبعيّة في Angular بالعثور على نسخةٍ للمَورد المطلوب (أو بإنشاء نسخةٍ لهذا المَورد) وتمريره إلى المتحكّم. لنرى مرّةً أخرى كيف نقوم بذلك على المَورد المدمج في Angular، الخدمة <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.%24locale">locale$</a>.</p><p>نحتاج إلى تعريف وحدتنا <span style="font-family:courier new,courier,monospace;">app</span> لأنّ بعض أمثلة هذا الفصل تستخدم <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">نظام الوحدات</a>.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app', []);</pre><p>وبعد ذلك سنقوم بتحميل الوحدة عن طريق تمرير اسمها إلى التّوجيه <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/directive/ngApp">ng-app</a>. (أكرّر التّنبيه إلى أنّ الاسم <span style="font-family:courier new,courier,monospace;">app</span> ليس إجباريًّا ويمكن استخدام أيّ اسم آخر.)</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;body ng-app="app"&gt;
  &lt;!-- الأمثلة توضع هنا --&gt;
&lt;/body&gt;</pre><p>نحن الآن جاهزون للانطلاق مع مثالنا الأوّل، وبطريقةٍ مماثلةٍ لإضافة الوسيط <span style="font-family:courier new,courier,monospace;">scope$</span> سنضيف الوسيط <span style="font-family:courier new,courier,monospace;">locale$</span>، وستلاحظ Angular هذين الوسيطين وتقوم بحقنهما. تقوم Angular بحقن الموارد داخل التّابع لأنّ هذا التّابع يمثّلُ <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AA%D8%AD%D9%83%D9%85%D8%A7%D8%AA-controlers-%D9%81%D9%8A-angularjs-r186/">متحكّمًا</a>.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app')
  .controller('LocaleController', function($scope, $locale) {
    $scope.locale = $locale.id;
  });</pre><p>داخل جسم المتحكّم قمنا ببساطةٍ بإسناد المتغيّر <span style="font-family:courier new,courier,monospace;">locale</span> الذي يمكننا تغيير اسمه إلى أيّ اسمٍ آخر، إلى العنصر id من الوسيط locale$ الذي لا يمكننا استخدام اسمٍ آخر له.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="LocaleController"&gt;
  Your locale is &lt;strong ng-bind="locale"&gt;&lt;/strong&gt;
&lt;/p&gt;</pre><p><strong style="line-height: 22.4px;">الناتج:</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="line-height: 22.4px;">Your locale is <strong>en-us</strong></pre><p>يُفترض أن ترى شيئًا مماثلًا لعبارة "Your locale is en-us" في المخرجات. ما الذي سيحدث لو أنّك أضفت الوسيط <span style="font-family:courier new,courier,monospace;">myResource</span> إلى تابع التّحكّم؟ هل عطّلت عمل المثال؟ هل يمكنك قراءة الخطأ في الـconsole الخاصة بـJavaScript في متصفّحك؟ تعرض أخطاء Angular غالبًا <a rel="external nofollow" href="https://docs.angularjs.org/error/%24injector/unpr?p0=myResourceProvider%20%3C-%20myResource%20%3C-%20LocaleController">رابطا مفيدا</a>، يمكنك عن طريق هذا الرابط أن تحصل على درسٍ رائع وقصير عن حلّ مشاكل حقن التّبعيّة، انقر على الرّابط السّابق واقرأ الشرح إن أردت.</p><h2>الحواشي (Annotations)</h2><p>تمثّلُ <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Java_annotation">الحاشية</a> في لغة برمجةٍ مثل Java، معلوماتٍ إضافيّة تُضاف إلى الشيفرة المصدريّة ويتجاهلها المترجم. أمّا في سياق الحديث عن حقن التّبعيّة في Angular، فتعني كلمة الحاشية التّصريح عن الموارد التي نريد حقنها بطريقةٍ صريحةٍ تحافظ على أسماء الوسطاء قصيرةً باستخدام أسلوب التّصغير (minification). (استخدام أداة البناء <a rel="external nofollow" href="https://github.com/mishoo/UglifyJS">UglifyJS</a> مثالٌ على أسلوب التّصغير.) لنتابع الآن طريقة Angular التي تسمح لنا فيها بإضافة الحواشي إلى التّبعيّات.</p><h3>ng-annotate</h3><p>من الطرق الملائمة للتخلص من إزعاج مهمّة بناء ما، استخدام مهمّة بناءٍ أخرى. ستقوم أداة البناء <a rel="external nofollow" href="https://github.com/olov/ng-annotate">ng-annotate</a> بإضافة الحواشي للتّبعيّات، ومن ثمّ ستسمح لنا بمواصلة استخدام طريقة التّبعيّات الضّمنيّة التي شرحناها في الفقرة السّابقة. ستحتاج فقط إلى تشغيل <span style="font-family:courier new,courier,monospace;">ng-annotate</span> قبل أن تُشغّل المقصّر (minifier) الخاصّ بك. هذه الأداة المركزيّة صُمّمت لتُستخدم عن طريق سطر الأوامر، إلّا أنّه يوجد غلافٌ لها لتفادي التّعامل مع سطر الأوامر، كما يوجد غلافٌ لمعظم أدوات البناء وحزم الأدوات، من ضمنها <a rel="external nofollow" href="https://www.npmjs.com/package/grunt-ng-annotate">grunt-ng-annotate</a> و<a rel="external nofollow" href="https://www.npmjs.com/package/gulp-ng-annotate/">gulp-ng-annotate</a> و<a rel="external nofollow" href="https://www.npmjs.com/package/browserify-ngannotate">browserify-ngannotate</a> و<a rel="external nofollow" href="https://www.npmjs.com/package/ng-annotate-webpack-plugin">ng-annotate-webpack-plugin</a>.</p><h3>الحاشية السطرية</h3><p>هناك أسلوبان لكتابة الحواشي، وأكثرهما شُهرةً يُعرف باسم الحاشية السّطريّة (<a rel="external nofollow" href="https://docs.angularjs.org/guide/di#inline-array-annotation">inline annotation</a>)، وهي تتضمّن وضع تابع التّحكّم داخل مصفوفةٍ كما يلي.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app')
  .controller('LocaleController', ['$scope', '$locale', function(s, l) {
    s.locale = l.id;
  }]);</pre><p style="line-height: 22.4px;"><strong style="line-height: 22.4px;">الناتج:</strong></p><div><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="line-height: 22.4px;">Your locale is <strong>en-us</strong></pre></div><p>في المثال السّابق، قُمت بمحاكاة تأثير التّقصير عن طريق تغيير أسماء الوُسطاء من scope$ و locale$ إلى s وl بالترتيب. بالطّبع لا يمكن لـAngular أن تجد مَوردين لهما الأسماء s وl لو اعتمدنا على أسلوب إضافة الحواشي الضّمنيّ، ولكن هنا، ولأنّ المصفوفة تحوي أسماء الوسطاء الحقيقيّين ستتمكّن من حقنهم بنجاح.</p><h3>إضافة الحاشية بواسطة inject$</h3><p>إن كان قد انتابك شعورٌ بأن طريقة إضافة الحواشي السّطريّة، قبيحة، فالأرجح أنك ستجد الطريقة البديلة هذه أكثر قبحًا. فهي تعتمد على إنشاء عنصرٍ ذا اسمٍ مخصّص، <span style="font-family:courier new,courier,monospace;">inject$</span>، في التّابع الإنشائيّ، وهذا سبب تسمية الطّريقة بهذا <a rel="external nofollow" href="https://docs.angularjs.org/guide/di#-inject-property-annotation">الاسم</a>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">var LocaleController = function(s, l) {
  s.locale = l.id;
};
 
LocaleController['$inject'] = ['$scope', '$locale'];
 
angular.module('app')
  .controller('LocaleController', LocaleController);</pre><p><strong style="line-height: 22.4px;">الناتج:</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="line-height: 22.4px;">Your locale is <strong>en-us</strong></pre><p>المهمّ أنّك الآن تعرف الخيارات المتاحة للقيام بإضافة الحواشي.</p><h2>angular.injector</h2><p>أرجو أن تكون عند هذه النّقطة قد قمت بإضافة <a rel="external nofollow" href="https://github.com/olov/ng-annotate">ng-annotate</a> إلى بُنيتك، لتتمكّن من استخدام الأسلوب البدائيّ في التّبعيّات الضّمنيّة التي ستراها في هذه السلسلة دون مشاكل. على أيّ حال، إن لم تكن قد قمت بذلك، لديّ اقتراح لك، إلّا أنّه ليس اقتراحًا جادًّا: قم بكتابة تابع <span style="font-family:courier new,courier,monospace;">require</span> الخاصّ بك، وأفصح عن التّبعيّات الّتي تريد ضمن عمليّة البحث المباشر عن الخدمات، وذلك بدلًا من استخدام أسلوب حقن التّبعيّة. يمكنك القيام بذلك عن طريق استدعاء تابع <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/function/angular.injector">angular.injector</a> مباشرةً، وعليك تمرير وسيط وحيدٍ إليه هو مصفوفةٌ فيها أسماء الوحدات التي ترغب بالبحث ضمنها، ويجب عليك تمرير اسم الوحدة <span style="font-family:courier new,courier,monospace;">ng</span> دومًا وجعلها في بداية القائمة.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var require = function(name) {
  return angular.injector(['ng','app']).get(name);
};

angular.module('app')
  .controller('LocaleController', ['$scope', function($scope) {
    var $locale = require('$locale');
    $scope.locale = $locale.id;
  }]);</pre><p><strong>الناتج:</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Your locale is <strong>en-us</strong></pre><p>لاحظ أنّ المثال لايزال يعتمد على حقن التّبعيّة في تمرير كائن المجال الصّحيح للمتحكّم، سأسعى في الفقرة القادمة لأبيّن لك أحد أهمّ المشاكل العمليّة مع الحواشي في الأنظمة الضّخمة، وذلك خشية أن يتبادر إلى ذهنك بأنّ الاستثناء الّذي واجهناه للتّو يلغي الحاجة إلى تبنّي طريقة محدّد موضع الخدمة.</p><h2>مخاطر</h2><p>المثال التّالي سيستبق الأحداث، ويأخذنا إلى الفصل القادم، الخدمات. سنستخدم في هذا المثال التّابع factory، ورغم أنّك لم تألف استخدامه من قبل إلّا أنّه بإمكانك تخمين وظيفته، فهو يقوم بإعداد مصنعٍ للمكوّن باستخدام نظام الوحدات. لاحظ أيضًا أنّ الخدمة <span style="font-family:courier new,courier,monospace;">http$</span> (التي سنناقشها في فصلٍ لاحق HTTP) ستكون خدمةً نموذجيّةً ومثالًا من الحياة العمليّة لاستخدام حقن التّبعيّة داخل خدماتٍ كهذه.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app')
  .factory('fullPrice', ['$http', function($http) {
    return function() {
      // Use $http to fetch remote data.
      return 100;
    }
  }])
  .factory('discountPrice', ['$http', function($http) {
    return function() {
      // Use $http to fetch remote data.
      return 40;
    }
  }]);</pre><p>استلهمتُ المثال التّالي من تطبيق Angular حقيقيّ، حيث استُبدلت التّبعيّات بقائمةً طويلةً من الخدمات المدمجة في Angular، ولكنّ طول القائمة هو نفسه تقريبًا.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app')
  .controller('PriceController',
    ['$scope',
    '$anchorScroll',
    '$animate',
    '$cacheFactory',
    '$compile',
    '$controller',
    '$document',
    '$exceptionHandler',
    '$filter',
    '$http',
    '$httpBackend',
    '$interpolate',
    '$interval',
    'fullPrice',
    'discountPrice',
    '$locale',
    '$location',
    '$log',
    '$parse',
    '$q',
    '$rootElement',
    '$rootScope',
    '$sce',
    '$sceDelegate',
    '$templateCache',
    '$timeout',
    '$window',
    function(
      $scope,
      $anchorScroll,
      $animate,
      $cacheFactory,
      $compile,
      $controller,
      $document,
      $exceptionHandler,
      $filter,
      $http,
      $httpBackend,
      $interpolate,
      $interval,
      discountPrice,
      fullPrice,
      $locale,
      $location,
      $log,
      $parse,
      $q,
      $rootElement,
      $rootScope,
      $sce,
      $sceDelegate,
      $templateCache,
      $timeout,
      $window) {
        $scope.fullPrice = fullPrice();
        $scope.discountPrice = discountPrice();
  }]);</pre><p>من الواضح أنني اختصرت جسم المتحكّم <span style="font-family:courier new,courier,monospace;">PriceController</span> وكذلك اختصرت شيفرة العرض التّالية.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;table ng-controller="PriceController"&gt;
  &lt;tr&gt;
    &lt;td&gt;Full price:&lt;/td&gt;
    &lt;td&gt;{{fullPrice}}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Discount price:&lt;/td&gt;
    &lt;td&gt;{{discountPrice}}&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</pre><p><strong>الناتج:</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Full price:	    40
Discount price:	100</pre><p>لقد تعمّدت القيام بخطأٍ في المثال السابق، فالمفترض أن يكون السعر الكلّي أكبر دومًا من السّعر المخفّض، ولكنّهما انعكسا لسببٍ ما، والمشكلة ليست في شيفرة العرض أو في جسم المتحكّم، هل يمكنك إيجادها؟ ماذا تستنتج من ذلك بخصوص كتابة حاشية التّبعيّات يدويًّا في المشاريع الحقيقيّة؟</p><h2>خاتمة</h2><p>هذا هو الفصل الثّاني من أصل ثلاثة فصول في هذه السلسلة تغطّي البنية التّحتيّة لـAngular الخاصّة بإدارة شيفرة التّطبيق. الفصل الأوّل، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">الوحدات</a>، بيّنَ كيف سنقوم بتهيئة خشبة المسرح الّتي سيقف عليها الممثّلون ليقوم كلٌّ منهم بدوره. وفي هذا الفصل شرحنا ببعض التّفصيل الآليّات المتاحة لجعل كلِّ ممثّلٍ يقفُ في مكانه الصّحيح. أمّا الفصل الثّالث ضمن هذا المجال، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D8%AE%D8%AF%D9%85%D8%A7%D8%AA-services-%D9%81%D9%8A-angularjs-r200/">الخدمات</a>، سيشرح كيفيّة إنشاء الممثّلين أنفسهم.</p><p>ترجمة وبتصرّف <a rel="external nofollow" href="http://www.angularjsbook.com/angular-basics/chapters/dependency-injection/">للفصل السابع</a> من كتاب: <a rel="external nofollow" target="_blank" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p>
]]></description><guid isPermaLink="false">198</guid><pubDate>Wed, 21 Oct 2015 12:12:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A; Modules &#x641;&#x64A; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/modules-angularjs.png.c99e81988ee1849d8a8811b4a7507937.png" /></p>

<p>
	إنّ هدف الوحدات عمومًا هو توزيع المهام عن طريق تعريف توابع الواجهة البرمجية (<abbr title="واجهة برمجية | Application Programming Interface"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>) والحدّ من رؤية السلوك (أجسام التوابع) والبيانات (العناصر والمتغيّرات).
</p>

<p>
	معظم المنصّات البرمجيّة تتضمّن دعمًا داخليًّا للوحدات، حتّى أصبح استخدامها أمرًا مسلّمًا به. ولكنّ JavaScript المستخدمة من طرف العميل لا تستخدم الوحدات حاليًّا، وتؤدي إلى احتدام النقاشات المليئة بين مؤيّد ومعارض للحلّ المشهور (الإضافات add-ons) مثل <a href="http://www.commonjs.org/" rel="external nofollow">CommonJS</a> و <a href="http://requirejs.org/docs/whyamd.html" rel="external nofollow">تعريف الوحدة غير المتزامن (AMD)</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/modules-angularjs.png.a908541e1391ec7535e48e49a94d9213.png" data-fileid="6089" rel=""><img alt="modules-angularjs.thumb.png.c90528c25cab" class="ipsImage ipsImage_thumbnailed" data-fileid="6089" src="https://academy.hsoub.com/uploads/monthly_2015_10/modules-angularjs.thumb.png.c90528c25cabc9d777d201b8264f5b84.png"></a>
</p>

<p>
	أبقِ في ذهنك عندما تقوم بمقارنة الحلول المطروحة، أنّ <a href="http://docs.angularjs.org/guide/module" rel="external nofollow">نظام الوحدات</a> في Angular لا يقوم بتحميل الوحدة. فهو لا يقوم بتحميل الشيفرة المصدرية من ملفّاتٍ أو من الإنترنت. فالحلّ الذي تقدّمه Angular هو نظام الوحدات المدمج فيها، والذي يرتبط ارتباطًا وثيقًا بنظام حقن التابعية المدمج أيضًا في Angular. معًا، يكوّن هذان النّظامان جزءًا كبيرًا من البنية التّحتيّة لـAngular. ولكن هل نحن بحاجةٍ إليها حقًّا؟ صحيحٌ أنّ بإمكان أيّ مطوّر تعلّمها، ولكن لمَ نحتاجها؟
</p>

<p>
	تُشكّل الوحدات وحقن التّابعيّة كلّ بنية Angular، ولكن كما رأينا فإنّ Angular تسمح لنا بالبدء دون استخدام نظام الوحدات. حتّى الآن، كان بإمكاننا إنجاز الكثير ببساطة عن طريق تعريف <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AA%D8%AD%D9%83%D9%85%D8%A7%D8%AA-controlers-%D9%81%D9%8A-angularjs-r186/" rel="">المتحكمات</a> كتوابع معرّفة في المجال العامّ. ولكنّ ذلك لم يكن ليعمل لولا القليل من الإعدادات، وهذه الإعدادات سمحت للتّوجيه<span style="font-family:courier new,courier,monospace;"> ng-controller</span> بالبحث عن توابع التّحكّم في المجال العام وأيضًا في نظام الوحدات. هذه الطريقة السهلة في استخدام المجال العام مسموحةٌ في Angular، ولكن فقط إلى هذه النقطة.
</p>

<h2>
	لماذا نستخدم وحدات Angular؟
</h2>

<p>
	لابدّ لك من فهم وإتقان نظام الوحدات في Angular لتتمكّن من تجاوز الأساسيّات فيها والغوص في المفاهيم العميقة. لا تسعى هذه السلسلة لإقناعك بالأهمّيّة الكامنة في الوحدات وفي حقن التّابعيّة في Angular، فعندما تواجهك مشكلة إدارة التّعقيد في تطبيقك فالأمر يعود إلى تجربتك الشّخصيّة في أفضل الممارسات البرمجيّة، والحلّ الأبسط سيكون الأفضل. سيغطّي هذا الكتاب الوحدات في Angular ومبدأ حقن التّابعيّة بما يشمل الجزء الأهمّ منها في Angular.
</p>

<p>
	لنبدأ بنظرةٍ عامّة إلى المزايا الهامّة التي تدفعنا لاستخدام نظام الوحدات:
</p>

<ul>
<li>
		<strong>مكوّنات مخصّصة</strong> - لتعريف المتحكّمات الخاص بك، التّوجيهات، المرشّحات، والمؤثّرات الخاصّة، لا بدّ من استخدام نظام الوحدات.(يمكننا استثناء المتحكّمات كما أشرنا سابقًا.)
	</li>
	<li>
		<strong>حقن التّابعيّة</strong> - الخدمات ليست إلّا كائنات وتوابع JavaScript عاديّة، إلّا أنّ الخدمات التي يتمّ إنشاؤها في نظام الوحدات يمكن أن تُحقن بسهولة مع التّبعيّات الخاصّة بها، وذلك إن كانت تتيح حقن التّابعيّة فيها.
	</li>
	<li>
		<strong>الوحدات الخارجيّة</strong> - هناك نظامٌ بيئيّ مثيرٌ للاهتمام، مجّانيٌّ ومفتوح المصدر من الإضافات لـAngular، وقد قام بكتابة بعض هذه الإضافات فريق تطوير قلب Angular وكذلك المطوّرون كطرفٍ ثالث. لاستخدام أيٍّ من هذه المكاتب في تطبيقك لا بُدّ من استخدام نظام الوحدات.
	</li>
	<li>
		<strong>إعدادات وقت-التّحميل</strong> - يسمح نظام الوحدات في Angular بالوصول إلى تعلّقات دورة الحياة (lifecycle hooks) المتعلّقة بالإعدادات الدّاخليّة لـAngular، وكذلك المتعلّقة بإعدادات الوحدات المضافة، وسنتطرّق لها في نهاية الفصل الأخير، حيث سنقوم بإعداد رأس HTML مخصص.
	</li>
	<li>
		<strong>الاختبار</strong> - إنّ <a href="https://docs.angularjs.org/guide/unit-testing" rel="external nofollow">البنية التّحتيّة الخاصّة بالاختبار</a> في Angular تبيّن فاعليّة نظام حقن التّابعيّة والّذي يعتمد بدوره على نظام الوحدات.
	</li>
</ul>
<p>
	سيبيّن فصلٌ لاحقٌ، فصل <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D8%AE%D8%AF%D9%85%D8%A7%D8%AA-services-%D9%81%D9%8A-angularjs-r200/" rel="">الخدمات</a>، كيف نقوم بتعريف مقدم لمكوّنات JavaScript المخصّصة. سنرى في هذا الفصل كيف نعرّف متحكّمًا، وسنقوم أيضًا بتحميل وحدةٍ خارجيّةٍ، وأثناء تنفيذ ذلك سنتعلّم أساسيّات نظام الوحدات في Angular.
</p>

<h2>
	إنشاء وحدة التطبيق
</h2>

<p>
	يمكن تهيئة تطبيق Angular باستخدام وحدةٍ جذريّة واحدة فقط. سنقوم بتسمية الوحدة في أمثلة هذا الفصل بالاسم <span style="font-family:courier new,courier,monospace;">app</span> ويمكنك اختيار أيّ اسمٍ آخر إن أردت، إلّا أنّ هذا الاسم شائع الاستخدام في مرجع Angular.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
angular.module('app', []);</pre>

<p>
	أرجو أن تركّز على الوسيط الثاني للتابع <a href="http://docs.angularjs.org/api/angular.module" rel="external nofollow">module</a> في مثالنا السابق، ورغم أنّه يبدو فارغًا، وله مظهر مصفوفة بريئة خالية ([]) إلّا أنّ وجود هذا الوسيط الثاني شديد الأهمّيّة، فبدونه سيتغيّر سلوك التّابع <span style="font-family:courier new,courier,monospace;">angular.module </span>كليا، وسأشرح لك سلوك هذا التابع كما يلي:
</p>

<p>
	عند استدعاء التابع <span style="font-family:courier new,courier,monospace;">angular.module</span> مع وجود الوسيط الثاني، سيعمل التّابع في نمط الإنشاء (create)، وسيقوم بإنشاء وحدةٍ ويسمّيها <span style="font-family:courier new,courier,monospace;">app</span> إن لم يكن هناك وحدة بنفس الاسم سابقًا، أمّا عند استدعائه دون الوسيط الثّاني فسيعمل في نمط البحث (lookup)، فإن عثر على وحدةٍ بالاسم المعطى سيقوم بإعادتها، أمّا إن لم يجدها فسيقوم برمي خطأٍ يطلب تمرير الوسيط الثاني. قمنا في المثال السابق بالاستخدام الصحيح للتابع، ولكن كن حذرًا دومًا من الفرق بين الطريقتين في استدعاء هذا التّابع, أمّا بالنّسبة لهذه المصفوفة التي تمرر كوسيط، فهي تُستخدم لجلب الوحدات الخارجية التي سنناقشها في هذا الفصل، باستخدام وحدة <span style="font-family:courier new,courier,monospace;">animation</span> في أمثلتنا.
</p>

<h2>
	تحميل وحدة التطبيق
</h2>

<p>
	في مستند HTML الذي يستضيف التّطبيق، يمكننا أن نأمر Angular بتحميل وحدة هذا التّطبيق عن طريق تمرير اسمه إلى التّوجيه <a href="http://docs.angularjs.org/api/ng.directive:ngApp" rel="external nofollow">ng-app</a>.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
&lt;body ng-app="app"&gt;
  &lt;!-- الأمثلة توضع هنا --&gt;
&lt;/body&gt;</pre>

<p>
	ستكون جميع المكوّنات التي نضيفها إلى وحدة التّطبيق متاحةً للاستخدام. لنرى الآن كيف نقوم بتعريف متحكّم داخل وحدةً بدلًا من تعريفه في المجال العام.
</p>

<h2>
	تعريف متحكم
</h2>

<p>
	تتضمّن الواجهة البرمجية للعنصر module توابع لتعريف مكوّنات Angular المخصّصة. والمكوّن الوحيد الذي تعرفنا عليه سابقًا هو المتحكّم، لذا لنقم باستخدام التابع controller لإنشاء متحكّم.
</p>

<p>
	سنحتاج أوّلًا إلى جلب مرجعٍ لوحدة التّطبيق، وكما ذكرنا سابقًا، يجب أن نقوم باستدعاء التابع <span style="font-family:courier new,courier,monospace;">angular.module </span>بدون تمرير الوسيط الثاني، وذلك كي يعمل في نمط البحث lookup.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var app = angular.module('app');

app.controller('MessageController', function($scope) {
  $scope.message = "This is a model.";
});</pre>

<p>
	والآن، في مكان ما ضمن العنصر الذي قمنا فيه باستدعاء الوحدة عن طريق <span style="font-family:courier new,courier,monospace;">"ng-app="app</span>، يمكننا استخدام التّوجيه<span style="font-family:courier new,courier,monospace;"> ng-controller</span> لتحميل المتحكّم.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
&lt;p ng-controller="MessageController"&gt;
  {{message}}
&lt;/p&gt;</pre>

<p>
	<strong>الناتج</strong>
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
This is a model.</pre>

<p>
	وكما يمكنك أن ترى، فتعريف المتحكّم داخل الوحدة يحتاج إلى عمل أكثر بقليل من تعريفه في المجال العام، ولكنّه ليس بهذه الصعوبة أبدًا.
</p>

<h2>
	سلسلة التعريفات
</h2>

<p>
	لنفترض بأننا نريد تعريف متحكّمين للقالب التالي.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
&lt;p ng-controller="MessageController"&gt;
  {{message}}
&lt;/p&gt;
&lt;p ng-controller="AnotherMessageController"&gt;
  {{message}}
&lt;/p&gt;</pre>

<p>
	إنّ توابع التعريف ضمن العنصر Module قابلةٌ للسَّلسَلة، حيث يمكننا إنشاء متحكّمين باستخدام عبارةٍ واحدة.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
angular.module('app')

  .controller('MessageController', function($scope) {
    $scope.message = "This is a model.";
  })

  .controller('AnotherMessageController', function($scope) {
    $scope.message = "This is another model.";
  });</pre>

<p>
	<strong style="line-height: 22.4px;">الناتج</strong>
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
This is a model.

This is another model.</pre>

<p>
	لاحظ أن الاستدعاء الأول للتابع controller لم تتبعه فاصلةٌ منقوطة.
</p>

<p>
	إن لم تعجبك هذه الطريقة في سَلسَلة الاستدعاءات، يمكنك استدعاء التابع module كلّما أردت الحصول على مرجعٍ للوحدة، أو يمكنك تخزين هذا المرجع في متغيّر، كما يبيّن المثال التالي. عند استخدامك لمتغيّر، سيكون من الجيّد أن تضعه ضمن تابعٍ يُستدعى آنيًّا (<a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/" rel="external nofollow">IIFE</a>) أو أيّ مجالٍ مغلقٍ آخر، لمنع ذلك المتغيّر من أن يُنشأ في المجال العام.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var app = angular.module('app');

app.controller('MessageController', function($scope) {
  $scope.message = "This is a model.";
});

app.controller('AnotherMessageController', function($scope) {
  $scope.message = "This is another model.";
});</pre>

<p>
	يمكنك اختيار أيٍّ من الطريقتين، ولكنّ طريقة السَّلسلة هي الأكثر شيوعًا.
</p>

<h2>
	تحميل الوحدات
</h2>

<p>
	يُعدّ التحريك (<a href="http://docs.angularjs.org/guide/animations" rel="external nofollow">animations</a>) ميزةً جديدةً في Angular تمّت إضافتها إلى حزمة منفصلة اسمها <a href="http://docs.angularjs.org/api/ngAnimate" rel="external nofollow">ngAnimate</a>. الخطوة الأولى لاستخدام التحريك هي تضمين ملف JavaScript المحتوي على الوحدة. <a href="https://github.com/angular/angular.js/blob/master/src/ngAnimate/" rel="external nofollow">الشيفرة المصدريّة</a> للوحدة جزءٌ من قلب Angular، ولكنّها موجودةٌ في ملفٍّ منفصل، كما نرى أدناه.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
&lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"&gt;&lt;/script&gt;
&lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-animate.js"&gt;&lt;/script&gt;</pre>

<p>
	حان الوقت لنستخدم الوسيط الثّاني للتابع module كما يجب، فبدلًا من تمرير مصفوفةٍ خاليةٍ فيه سنقوم الآن بالتصريح عن الوحدات المتعلّقة بوحدتنا.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
angular.module('app', ['ngAnimate']);</pre>

<p>
	لقد قمنا الآن بتحميل <span style="font-family:courier new,courier,monospace;">ngAnimate</span> إلى داخل وحدة التّطبيق، والآن ستقوم التّوجيهات <span style="font-family:courier new,courier,monospace;">ng-show</span> و <span style="font-family:courier new,courier,monospace;">ng-hide</span> و <span style="font-family:courier new,courier,monospace;">ng-class</span> و العديد من <a href="http://docs.angularjs.org/api/ngAnimate#usage" rel="external nofollow">التّوجيهات الأخرى</a> بالتّحقّق من التحريك الخاصّ بـCSS وJavaScript أيضًا الذي يمكن تطبيقه على أحداث المستند مثل add و enter و leave و move و remove، وتطبيق هذا التّحريك شفّاف فهو لا يتطلّب أيّ تغيير على شيفرة القالب المكتوبة، وإن لم نكن قد طبّقنا هذا التّحريك سواء على شكل CSS أو كـJavaScript عن طريق تسجيل الحركة عبر <a href="http://docs.angularjs.org/api/ngAnimate#usage" rel="external nofollow">module.animation</a>، فإنّ الشيفرة ستسلك السّلوك الافتراضيّ لها بشكل طبيعيّ.
</p>

<pre class="html ipsCode prettyprint" data-pbcklang="html" data-pbcktabsize="4">
&lt;input type="checkbox" ng-model="showMessage"&gt;
    Check the box to show the message
&lt;h2 ng-show="showMessage"&gt;
    The secret message.
&lt;/h2&gt;
</pre>

<p>
	بالنّقر على الـcheckbox ستقوم<span style="font-family:courier new,courier,monospace;"> ng-show</span> بعملها كالمعتاد، وسيتمّ التّبديل بين إظهار وإخفاء العنصر بشكلٍ فوريّ دون تدرّج أو تأثير اختفاءٍ بسيط، إلى أن نكتب شيفرة التّحريك في CSS أو JavaScript. في المثال التّالي سنستخدم CSS، وهي عمومًا الخيار الأفضل للتحريك بسبب الأسلوب التصريحي في كتابتها. يمكنك على أيّ حالٍ استخدام التابع <a href="http://api.jquery.com/animate/" rel="external nofollow">animate</a> في jQuery ليقوم بالمهمّة إن وجدت ذلك أسهل، أما Angular فتقوم بذلك عن طريق الوحدة <span style="font-family:courier new,courier,monospace;">module.animation</span>.
</p>

<p>
	يتطلّب التّحكّم بتأثير الاختفاء التّدريجيّ استخدام أربع فئات CSS تقوم بالتّعلّق (hook)، وذلك حسب توثيق الواجهة البرمجية الخاصّ بالتّوجيه <a href="http://docs.angularjs.org/api/ng.directive:ngShow#description_a-note-about-animations-with-ngshow" rel="external nofollow">ng-show</a>. هذه الفئات الأربعة هي<span style="font-family:courier new,courier,monospace;"> ng-hide-add</span> و <span style="font-family:courier new,courier,monospace;">ng-hide-add-active</span> و<span style="font-family:courier new,courier,monospace;"> ng-hide-remove</span> و <span style="font-family:courier new,courier,monospace;">ng-hide-remove-active</span>.
</p>

<pre class="css ipsCode prettyprint" data-pbcklang="css" data-pbcktabsize="4">
.ng-hide-add,
.ng-hide-remove {
  transition: all linear 1s;
  display: block !important;
}

.ng-hide-add.ng-hide-add-active,
.ng-hide-remove {
  opacity: 0;
}

.ng-hide-add,
.ng-hide-remove.ng-hide-remove-active {
  opacity: 1;
}</pre>

<p>
	قد تحتاج إلى إضافة خصائص محدّدة من قبل المصنّع لبعض المتصفّحات حسب زوّار موقعك، مثل <span style="font-family:courier new,courier,monospace;">webkit-transition-</span> الخاص بمتصفّح سفاري 6 لأنظمة iOS. (يُعدّ موقع <a href="http://caniuse.com/" rel="external nofollow">caniuse.com</a> مرجعًا جيّدًا لتوافق المتصفّحات مع HTML5 و CSS3.) أرجو أن تنتبه أيضًا إلى أنّ هذا التّحريك سيتمّ تطبيقه في كلّ الأماكن التي ستستخدم فيها<span style="font-family:courier new,courier,monospace;"> ng-show</span> و<span style="font-family:courier new,courier,monospace;"> ng-hide </span>في تطبيقك. يمكنك إضافة فئة CSS مخصّصة لتزيد قدرتك على التّحكّم، وذلك للعنصر ولمحدّد CSS الذي تتعامل معه، مثلًا يمكنك كتابة <span style="font-family:courier new,courier,monospace;">my-class.ng-hide-add.</span> و <span style="font-family:courier new,courier,monospace;">my-class.ng-hide-remove.</span> وهكذا.
</p>

<h2>
	خاتمة
</h2>

<p>
	أتمنى أن تكون سهولة إضافة <span style="font-family:courier new,courier,monospace;">ngAnimate</span> قد أقنعتك بأهمّية فهم نظام الوحدات في Angular. ومن المفرح أن تعلم بأنّ <span style="font-family:courier new,courier,monospace;">ngAnimate</span> ليست إلّا البداية ضمن الكثير من الوحدات المُضافة إلى Angular. يمكنك أن تختار وحداتٍ أخرى متاحةّ بشكلٍ مجّانيّ من هذا النّظام البيئيّ سريع النموّ الذي يعتمد على إبداعات المطوّرين من مواقع مثل <a href="http://github.com/" rel="external nofollow">GitHub</a>، وذلك إضافةً إلى الوحدات التي تتيحها Angular أصلًا مثل <a href="http://docs.angularjs.org/api/ngResource" rel="external nofollow">ngResource</a> و<a href="http://docs.angularjs.org/api/ngRoute" rel="external nofollow">ngRoute</a>. أحد أكثر المشاريع شُهرةً هو <a href="http://angular-ui.github.io/" rel="external nofollow">AngularUI</a>، الذي يحوي وحداتٍ عظيمة الأهمّيّة مثل <a href="https://github.com/angular-ui/ui-router" rel="external nofollow">UI Router</a> و<a href="https://github.com/angular-ui/bootstrap" rel="external nofollow">UI Bootstrap</a>، ومعظم هذه الوحدات يمكن تحميله بسهولة في مشروعك باستخدام <a href="http://bower.io/" rel="external nofollow">Bower</a>، مدير حزم الويب، ولربّما ستبدأ بنشر وحدات Angular الخاصّة بك مفتوحة المصدر على GitHub وBower عندما تملك زمام Angular، وهذا ما أتمنّاه.
</p>

<p>
	تقدّم الوحدة <span style="font-family:courier new,courier,monospace;">ngAnimate</span> إثباتًا واضحًا للقوّة المتاحة في الوحدات المضافة، ولكنّها لا تتضمّن استخدام البنية التّحتيّة لحقن التّابعيّة في Angular بسبب أسلوبها الجزئيّ في التكامل. سنغطّي <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%AD%D9%82%D9%86-%D8%A7%D9%84%D8%AA%D8%A8%D8%B9%D9%8A%D8%A9-dependency-injection-%D9%81%D9%8A-angularjs-r198/" rel="">حقن التّابعيّة</a> في الفصل القادم، وذلك لأنّه يعمل يدًا بيد مع الوحدات.
</p>

<section data-controller="core.front.core.lightboxedImages"><p>
		ترجمة وبتصرّف <a href="http://www.angularjsbook.com/angular-basics/chapters/modules/" rel="external nofollow">للفصل السادس</a> من كتاب: <a href="http://www.angularjsbook.com/" rel="external nofollow" target="_blank">Angular Basics</a> لصاحبه: Chris Smith.
	</p>
</section>
]]></description><guid isPermaLink="false">196</guid><pubDate>Sun, 18 Oct 2015 19:41:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62C;&#x645;&#x648;&#x639;&#x627;&#x62A; (Collections) &#x641;&#x64A; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A7%D8%AA-collections-%D9%81%D9%8A-angularjs-r191/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-collections.png.cff1683734360a59629c1dd7d9a4021a.png" /></p>

<p>في الفصل السابق، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AC%D8%A7%D9%84%D8%A7%D8%AA-scopes-%D9%81%D9%8A-angularjs-r188/">المجالات</a>، تعلّمنا أنّ Angular تقوم بإنشاء مجالٍ جديد في كلّ مرّةٍ يتمّ فيها استدعاء الباني الخاصّ بالمتحكّم عن طريق<span style="font-family:courier new,courier,monospace;"> ng-controller</span>. هناك حالاتٌ أخرى أيضًا تقوم فيها Angular بإنشاء مجالاتٍ جديدة، وربّما تكون الحالات الأكثر شيوعًا هي عند التّعامل مع مجموعاتٍ من كائناتٍ متشابهة، كما سنرى في هذا الفصل.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-collections.png.183008f18dfeca9676f548d4fb492892.png"><img data-fileid="5876" class="ipsImage ipsImage_thumbnailed" alt="angularjs-collections.thumb.png.15e02645" src="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-collections.thumb.png.15e02645826022fbf9fd3f6732de01f8.png"></a></p><p>لا تملك Angular مكوّنًا اسمه Collection على عكس <a rel="external nofollow" href="http://backbonejs.org/#Collection">Backbone</a>، ولكنّ دعم Angular الواسع للمجموعات ذات الكائنات المتشابهة يستحقّ إفراد فصلٍ كاملٍ لها، كما سنرى الآن.</p><h2>التهيئة</h2><p>قمنا سابقًا بتضمين <a rel="external nofollow" href="https://developers.google.com/speed/libraries/devguide?hl=ja#angularjs">المكتبة المستضافة عند Google</a> في رأس مستندات HTML الخاصة بأمثلة الفصول السابقة، وسنضيف في هذا الفصل أسلوب <a rel="external nofollow" href="http://getbootstrap.com/">Bootstrap</a> في تنسيق الجداول والقوائم لإعطائها مظهرًا أجمل.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"&gt;
&lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"&gt;&lt;/script&gt;</pre><p>بعد ذلك نقوم بتحميل وحدة <span style="font-family:courier new,courier,monospace;">app</span> بتمرير اسمها إلى التّوجيه <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/directive/ngApp">ng-app</a>. يمكنك اختيار أيّ اسم للوحدة بدلًا من <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">app</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;body ng-app="app"&gt;
  &lt;!-- الأمثلة توضع هنا --&gt;
&lt;/body&gt;</pre><p>كما شرحنا سابقًا، سنحتاج إلى إضافة بعض الشّيفرات المعيارية لنتجنّب استخدام الوحدات في أمثلة هذا الدرس، وسنغطّي ذلك المفهوم في الفصل القادم في هذا الكتاب.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
    $controllerProvider.allowGlobals();
}]);</pre><p>نحن جاهزون الآن لنتقدّم في استكشافنا التّفاعليّ للمجموعات (collections) والمرور على العناصر (iteration) ولـAngular.</p><h2>المرور على العناصر</h2><p>في JavaScript المعتادة، عندما تمرّ على عناصر مجموعة من كائنات متشابهة عن طريق حلقة <span style="font-family:courier new,courier,monospace;">for</span>، قد تقوم بالتّصريح عن متغيّر محلّيّ ليحتفظ بمرجعٍ للعنصر الحاليّ، على سبيل المثال:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var items = [{name: "Item 1"},{name: "Item 2"}];
for (var i = 0; i &lt; items.length; i++) {
    var item = items[i];
}
document.body.innerHTML = item.name;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Item 2</pre><p>ربما تظنّ (تتمنّى؟ تأمل؟ ترجو؟) أن يكون المتغيّر item في المثال السابق موجودًا ضمن <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Lexical_scope#Lexical_scoping">مجال أسماءٍ</a> تُنشئه JavaScript عند كل دورةٍ لحلقة <span style="font-family:courier new,courier,monospace;">for</span>، للأسف، JavaScript لا تقوم بذلك كما يبيّن السطر الأخير في المثال السّابق.فالمتغيّر <span style="font-family:courier new,courier,monospace;">item</span> متاح للاستخدام خارج الحلقة، لقراءة المزيد عن هذه النقطة، يُرجى مراجعة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures#Creating_closures_in_loops.3A_A_common_mistake">دليل Mozilla في JavaScript</a>.</p><p>ولكنّ Angular تتجنّب هذا المأزق عن طريق دعمها الدّاخليّ للمرور على العناصر.وكي نرى كيف تقوم بذلك لنقم أوّلًا بنقل المصفوفة <span style="font-family:courier new,courier,monospace;">items</span> إلى داخل متحكّم.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function ItemsController($scope) {
  $scope.items = [
    {name: 'Item 1', price: 1.99},
    {name: 'Item 2', price: 2.99}
  ];
}</pre><p>تخيّل لو أنّ <span style="font-family:courier new,courier,monospace;">items</span> مجموعةٌ غير معروفة الطّول، ونحتاج إلى المرور على جميع عناصرها، وإظهار قيمة العنصر <span style="font-family:courier new,courier,monospace;">name</span> لكلّ عنصرٍ فيها، ما الذي سنقوم به؟</p><h2>ng-repeat</h2><p>رأينا سابقًا كيف تقوم Angular بإنشاء مجالٍ للعبارات لحمايتنا من إنشاء المتغيّرات في مجال JavaScript العام، وبطريقةٍ مماثلةٍ لذلك، يقوم التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngRepeat">ng-repeat</a> بحمايتنا من الحالة التي رأيناها في المثال الأوّل، وذلك بإنشاء مجال Angular لكلّ دورة تكرار للحلقة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;ol ng-controller="ItemsController"&gt;
  &lt;li ng-repeat="item in items" ng-bind="item.name"&gt;&lt;/li&gt;
  &lt;li ng-bind="item.name"&gt;&lt;/li&gt;
&lt;/ol&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">ْ1. Item 1
2. Item 2
3. 
</pre><p>كما ترى، العنصر <span style="font-family:courier new,courier,monospace;">item</span> غير متاحٍ خارج حلقة <span style="font-family:courier new,courier,monospace;">ng-repeat</span>.</p><p>تقوم <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">ng-repeat</span> بإنشاء مجالٍ ابنٍ جديد لكلّ عنصرٍ جديد من المجموعة مع الخصائص التي تحددها العبارة المحددة للمجموعة. في مثالنا السّابق، كان اسم الخاصّيّة هو <span style="font-family:courier new,courier,monospace;">item</span> ولكن يمكن أن نستبدله بأيّ اسم. جرّب تغيير المثال السّابق وغيّر <span style="font-family:courier new,courier,monospace;">item</span> إلى شيءٍ آخر، جرّب i أو x.</p><h2>عناصر الكائنات</h2><p>التركيب النّحوي (مفتاح، قيمة) للكائن يسمح لك بالمرور على عناصر الكائنات. سيفيدك ذلك إن كنت تحتاج إلى كتابة محتوى كائنٍ ما بشكلٍ كامل في العرض.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;table class="table table-condensed"&gt;
  &lt;tr ng-repeat="(propertyName, propertyValue) in {b: 'two', a: 1.0, c: 3}"&gt;
    &lt;td ng-bind="propertyName"&gt;&lt;/td&gt;
    &lt;td ng-bind="propertyValue"&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">b	two
a	1
c	3</pre><p>ماذا لو أردنا استخراج عنصرٍ معيّن؟ كيف نقوم باستخراج عنصرٍ له اسمٌ محدّد من جميع الكائنات الموجودة في المجموعة؟</p><p>التركيب النحوي item in items الذي استخدمناه في مثال<span style="font-family:courier new,courier,monospace;"> ng-repeat</span> السابق، يشبه كثيرًا باني القائمة، ولكنّ <span style="font-family:courier new,courier,monospace;">ng-repeat</span> لا تسمح للأسف بإرجاع أيّ شيءٍ غير عناصر الكائن أو المصفوفة في الطرف الأيمن للعبارة، لنحاول على أيّ حال.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;ol ng-controller="ItemsController"&gt;
  &lt;!-- Invalid code! Syntax error, because 'for' is not supported! --&gt;
  &lt;li ng-repeat="item.name for item in items" ng-bind="item.name"&gt;&lt;/li&gt;
&lt;/ol&gt;
</pre><p>لم تعمل كما أخبرتك. باني القائمة الحقيقيّ يسمح لك بإرجاع أيّ شيء تريده من التعداد الأصليّ، عادةً باستخدام الكلمة المفتاحيّة for. تقدّم CoffeeScript <a rel="external nofollow" href="http://en.wikipedia.org/wiki/List_comprehension#CoffeeScript">مثالًا ممتازًا</a> على ذلك.</p><h2>index$</h2><p>تقوم <span style="font-family:courier new,courier,monospace;">ng-repeat</span> بإسناد الرقم التسلسلي للعنصر الحالي إلى متغيّرٍ خاصٍ هو <span style="font-family:courier new,courier,monospace;">index$</span> وذلك إضافةً إلى المتغيّر الّذي يحوي قيمة العنصر. في المثال التّالي سنقوم بإعادة اختراع العجلة، وسننشئ طريقةً جديدةً لكتابة قوائم HTML المرقّمة، حيث سنستخدم قيمة المتغيّر<span style="font-family:courier new,courier,monospace;"> index$</span> في الإخراج.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="ItemsController"&gt;
  &lt;div ng-repeat="item in items"&gt;
     {{$index + 1}}. {{item.name}}
  &lt;/div&gt;
&lt;/div&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1. Item 1
2. Item 2</pre><p>لنحاول الآن القيام باستخدامٍ متداخلٍ للتّوجيه <span style="font-family:courier new,courier,monospace;">ng-repeat</span>. أوّلًا، لننشئ هيكل نموذج بياناتٍ أكثر تعقيدًا حيث يحوي كلّ عنصرٍ في الطبقة العلويّة مصفوفةً من الأبناء.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function ItemsController($scope) {
  $scope.items = [
    {name: 'Item 1',
      items: [
       {name: 'Nested Item 1.1'},
       {name: 'Nested Item 1.2'}
      ]
    },
    {name: 'Item 2',
      items: [
       {name: 'Nested Item 2.1'},
       {name: 'Nested Item 2.2'}
      ]
    }
  ];
}</pre><p>والآن لنقم بإدخال حلقةٍ داخل أخرى، ستقوم الشّيفرة التّالية بإضافة اسم كلّ عنصرٍ إلى قائمةٍ مرقّمة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="ItemsController"&gt;
  &lt;ol&gt;
    &lt;li ng-repeat="item in items"&gt;
      {{item.name}}
      &lt;ol&gt;
        &lt;li ng-repeat="item in item.items"&gt;
          {{item.name}}
        &lt;/li&gt;
      &lt;/ol&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1. Item 1
    1. Nested Item 1.1
    2. Nested Item 1.2
2. Item 2
    1. Nested Item 2.1
    2. Nested Item 2.2</pre><p>ولكن ماذا لو أردنا إنشاء <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Counters#Nesting_counters">عدّاداتٍ متداخلة</a>؟ كيف سنمنع المتغيّر index$ الّذي تمّت تحديد قيمته في الحلقة الخارجيّة من أن يتمّ تظليله بالمتغيّر ذي الاسم نفسه الّذي تُنشئه الحلقة الدّاخليّة؟</p><h2>ng-init</h2><p>ربّما تتذكّر من الفصل الأول، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-angularjs-r176/">المبادئ</a>، أنّ Angular تسمح لنا بتهيئة متغيّرات المجال في منطقة العرض باستخدام التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngInit">ng-init</a>. حلّ مشكلتنا يكمُن في استخدام<span style="font-family:courier new,courier,monospace;"> ng-init</span> للقيام بإعادة تعيين، أو عمل اسمٍ مستعارٍ، لمتغيّر الحلقة الخارجيّة <span style="font-family:courier new,courier,monospace;">index$</span> قبل أن يتمّ تظليله.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="ItemsController"&gt;
  &lt;div ng-repeat="item in items" ng-init="outerCount = $index"&gt;
    {{outerCount + 1}}. {{item.name}}
    &lt;div ng-repeat="item in item.items"&gt;
       {{outerCount + 1}}.{{$index + 1}}. {{item.name}}
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1. Item 1
1.1. Nested Item 1.1
1.2. Nested Item 1.2
2. Item 2
2.1. Nested Item 2.1
2.2. Nested Item 2.2</pre><p>لا تكتفي <span style="font-family:courier new,courier,monospace;">ng-repeat</span> بالمتغيّر <span style="font-family:courier new,courier,monospace;">index$</span> فهي تقوم بإسناد عددٍ من المتغيّرات البوليانيّة في كلّ دورٍ للحلقة، وهي: <span style="font-family:courier new,courier,monospace;">first$</span> و<span style="font-family:courier new,courier,monospace;">middle$</span> و<span style="font-family:courier new,courier,monospace;">last$ </span>و<span style="font-family:courier new,courier,monospace;">even$</span> و<span style="font-family:courier new,courier,monospace;">odd$</span>. يمكنك تجربة كلِّ واحدٍ منها ضمن المثال التّالي، وهذا المثال يستخدم التّوجيه المفيد <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/directive/ngClass">ng-class</a> حيث يتمّ وسم الخانة باللون الأخضر عندما تكون العبارة الشّرطيّة محقّقة. هل يمكنك اكتشاف الطّريقة الّتي تجعل العنصرين الأوّل والأخير فقط موسومين باللون الأخضر؟ (ملاحظة: ستحتاج إلى إضافة العمليّة ! فقط.)</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;ol&gt;
  &lt;li ng-repeat="val in [1,2,3,4,5]"&gt;
    &lt;span class="label label-default"
          ng-class="{'label-success': $middle}"&gt;
      {{val}}
    &lt;/span&gt;
  &lt;/li&gt;
&lt;/ol&gt;</pre><p>هل لاحظت شيئًا عند استخدام المتغيّرين<span style="font-family:courier new,courier,monospace;"> even$</span> و<span style="font-family:courier new,courier,monospace;">odd$</span>؟ تقوم Angular بتحديد قيمة المتغيّرات وفق الطّريقة التّقليديّة التي تعتمد بدء التّرقيم من الصّفر في حلقات <span style="font-family:courier new,courier,monospace;">for</span>. قد لا يبدو الأمر مثيرًا للاهتمام للوهلة الأولى، ولكن لو لاحظت جيّدًا فترقيم العناصر يبدأ من الصّفر بينما يبدأ ترقيم القائمة المرتّبة من الواحد، وهذا يعني أنّ المتغيّرين<span style="font-family:courier new,courier,monospace;"> even$</span> و<span style="font-family:courier new,courier,monospace;">odd$</span> سيعملات بشكلٍ معاكسٍ لاسمهما بالنّسبة لترقيم القائمة.</p><h2>التفرد</h2><p>كملاحظةٍ جانبيّة، يجب عليك الانتباه عند استخدام المتغيّرات البدائيّة (primitives) داخل <span style="font-family:courier new,courier,monospace;">ng-repeat</span> بأن لا تكون جميع عناصر المجموعة متفرّدة، أي أنّه لا يوجد أي تكرار لأي قيمة في المجموعة، ومن يحدّد تطابق العناصر هو عمليّة المساواة المتشدّدة<strong> ===</strong> في JavaScript.</p><h3>المساواة المتشددة</h3><p>لنقم ببعض التّجارب لإنعاش معلوماتنا في كيفيّة عمل <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">عمليّة المساواة الصّارمة</a><strong> ===</strong> في JavaScript. يختبر القالب التّالي المساواة بين أعدادٍ، سلاسل نصّيّةٍ وكائنات.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;table class="table table-condensed"&gt;
  &lt;tr&gt;
    &lt;td&gt;1 === 1&lt;/td&gt;
    &lt;td&gt;{{1 === 1}}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;'1' === '1'&lt;/td&gt;
    &lt;td&gt;{{'1' === '1'}}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1 === '1'&lt;/td&gt;
    &lt;td&gt;{{1 === '1'}}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;{} === {}&lt;/td&gt;
    &lt;td&gt;{{ {} === {} }}&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;{name: 1} === {name: 1}&lt;/td&gt;
    &lt;td&gt;{{ {name: 1} === {name: 1} }}&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1 === 1	                    true
'1' === '1'	                true
1 === '1'	                false
{} === {}	                false
{name: 1} === {name: 1}	    false</pre><p>بيّنّا بأنّ التّساوي بين عناصر المجموعة مرفوض، وسيبيّن المثال التّالي الخطأ الّذي سينتج عن تكرار العدد 1 في المجموعة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;ol&gt;
  &lt;!-- Invalid code! Duplicate element error, because '1' is repeated! --&gt;
  &lt;li ng-repeat="val in [1,2,1]" ng-bind="val"&gt;&lt;/li&gt;
&lt;/ol&gt;</pre><p>قم بتعديل المثال السّابق، واستخدم خليطًا من الأعداد والسّلاسل النّصّيّة بدلًا من الأعداد فقط، جرّب المصفوفة التّالية<strong> [1,2,'1']</strong>. ماذا كانت النّتيجة؟ والآن حاول تغييرها باستخدام الكائنات بدلًا من الأعداد، جرّب المصفوفة التّالية<strong> [{name: 1},{name: 2},{name: 1}]</strong>. ستحتاج إلى تغيير العبارة <span style="font-family:courier new,courier,monospace;">"ng-bind="val</span> إلى <span style="font-family:courier new,courier,monospace;">"ng-bind="val.name</span> لتتمكّن من رؤية القيم.</p><h3>track by</h3><p>إنّ حلّ مشكلة مصفوفة الأعداد السّابقة يكمُن في إضافة تعليمة <span style="font-family:courier new,courier,monospace;">track by</span> إلى عبارة <span style="font-family:courier new,courier,monospace;">ng-repeat</span> وذلك لكي يتمّ تجاوز اختبار المساواة الّذي يتمّ القيام به تلقائيًّا للعناصر. يمكنك تتبّع عناصر المجموعة باستخدام أيّ متغيّر متفرّد (لا تتكرّر القيم الّتي يأخذها عند كلّ عنصر)، وإن لم يكن لديك متغيّر متفرّد (فالقيم العدديّة الموجودة داخل المصفوفة ليست كذلك)، يمكنك استخدام المتغيّر index$.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;ol&gt;
  &lt;li ng-repeat="val in [1,2,1] track by $index" ng-bind="val"&gt;&lt;/li&gt;
&lt;/ol&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1. 1
2. 2
3. 1</pre><p>يجب عليك استخدام متغيّرات متفرّدة في نماذج كائناتك كلّما أمكنك ذلك، كأن تستخدم معرّفًا رقميًّا متفرّدًا يتمّ إنشاؤه عن طريق مخزن بيانات في الـbackend أو عن طريق نوعٍ ما من مولّد <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a> في طرف المستخدم. إن لم يكن لديك مفرٌّ من استخدام المتغيّر <span style="font-family:courier new,courier,monospace;">index$</span> فكن حذرًا لأنّ التّغييرات في المجموعة قد تٌسبّب مشاكل في الأحداث الخاصة بالصفحة.</p><h3>توابع الاستدعاء الخلفي</h3><p>تسهّل Angular الحصول على مرجعٍ لعنصرٍ ما في المجموعة لتتمكّن من استخدامه داخل متحكّم ما. ليس عليك إلّا أن تمرّر عنصر المجموعة إلى تابع استدعاءٍ خلفيّ (callback) في التّوجيه الذي يسمح بتمرير تابع استدعاءٍ خلفيّ، مثل<span style="font-family:courier new,courier,monospace;"> ng-click</span>.</p><p>على سبيل المثال، لنقم بكتابة شيفرة للسماح للمستخدم بحذف أحد عناصر المجموعة، سنحتاج إلى تعريف تابع استدعاء خلفيّ في المتحكّم بحيث يقبل مرجع العنصر المُراد حذفه كوسيطه الوحيد. يمكننا تسمية هذا التّابع بأي اسم، لنقم بتسميته destroy (سيكون هذا ملائمًا له).</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function ItemsController($scope) {
  $scope.items = [
    {id: 1, name: 'Item 1'},
    {id: 2, name: 'Item 2'},
    {id: 3, name: 'Item 3'},
    {id: 4, name: 'Item 4'}
  ];

  $scope.destroy = function(item) {
    var index = $scope.items.indexOf(item);
    $scope.items.splice(index, 1);
  };
}</pre><p>قد تبدو طريقة حذف العنصر من المصفوفة في الشّيفرة السابقة مزعجة بعض الشيء إلا أنها الطريقة المُتّبعة في JavaScript للقيام بذلك، ولن تُسبّب أي خطأ مع Angular في ذلك.</p><p>كُلّ ما بقي هو إضافة <span style="font-family:courier new,courier,monospace;">"(ng-click="destroy(item</span> إلى عنصرٍ ما داخل الحلقة. كما يشير التّوجيه <span style="font-family:courier new,courier,monospace;">ng-click</span>، فالزر هو الخيار الأفضل، ولكن لا بدّ من الإشارة إلى أنّه يمكننا استخدام التّوجيه <span style="font-family:courier new,courier,monospace;">ng-click</span> مع أيّ عنصرٍ قابلٍ للنّقر.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="ItemsController"&gt;
  &lt;h4 ng-pluralize count="items.length"
      when="{'one': '1 item', 'other': '{} items'}"&gt;
  &lt;/h4&gt;
  &lt;table class="table table-condensed"&gt;
    &lt;tr ng-repeat="item in items"&gt;
      &lt;td ng-bind="item.name"&gt;&lt;/td&gt;
      &lt;td&gt;
        &lt;button class="btn btn-xs btn-default" ng-click="destroy(item)"&gt;
          destroy
        &lt;/button&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;</pre><p>أعتبرُ طريقة Angular في ربط تابع الاستدعاء الخلفيّ destroy مثالًا واضحًا على الأسلوب التّصريحيّ الذي تتبعه Angular. كفائدةٍ إضافيّة، يعرض المثال السّابق استخدام التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngPluralize">ng-pluralize</a> لكتابة نصٍّ يميّز بين المفرد والجمع بشكلٍ مشروط، حسب عدد العناصر ضمن مجموعة ما. إعداد هذا التّوجيه صعبٌ قليلًا ولكنك قد تحتاج لاستخدامه.</p><h2>start- وend-</h2><p>رغم أنه ليس شائعًا، إلّا أنك قد ترغب بإخراج عناصر "إخوة" لكلّ عضوٍ في المجموعة. وكمثالٍ على ذلك قائمة الوصف، أو العنصر dl، الذي يحوي زوجي العناصر dt وdd. وهنا تظهر المشكلة، فالتّوجيه <span style="font-family:courier new,courier,monospace;">ng-repeat</span> مُصمّمٌ ليتمّ تطبيقه على عنصر HTML واحد. ولكنّ حلّ هذه المشكلة هو بتوسيع نطاق التنفيذ لهذا التّوجيه ليشمل العديد من عناصر HTML باستخدام اللاحقتين <span style="font-family:courier new,courier,monospace;">start-</span> و<span style="font-family:courier new,courier,monospace;">end-</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;dl ng-controller="ItemsController"&gt;
  &lt;dt ng-repeat-start="item in items"&gt;name&lt;/dt&gt;
  &lt;dd ng-bind="item.name"&gt;&lt;/dd&gt;
  &lt;dt&gt;price&lt;/dt&gt;
  &lt;dd ng-repeat-end ng-bind="item.price"&gt;&lt;/dd&gt;
&lt;/dl&gt;</pre><p>هناك العديد من التّوجيهات الأخرى التي تستخدم اللاحقتين <span style="font-family:courier new,courier,monospace;">start</span>- و<span style="font-family:courier new,courier,monospace;">end-</span> وليس التّوجيه <span style="font-family:courier new,courier,monospace;">ng-repeat</span> فقط، ويجب عليك أن تتأكد من عدم انتهاء التّوجيهات المخصصة التي تقوم بإنشائها (كما ستتعلم في فصل التوجيهات اللاحق) بأيٍّ من اللاحقتين <span style="font-family:courier new,courier,monospace;">start-</span> و<span style="font-family:courier new,courier,monospace;">end-</span>.</p><h2>خلاصة</h2><p>تدعم Angular المجموعات بقوّةٍ ومرونة عن طريق التّوجيه <span style="font-family:courier new,courier,monospace;">ng-repeat</span>، وتسمح لنا ببناء واجهة مستخدمٍ سريعة لتطبيقات CRUD. تنتهي في هذا الفصل نظرتنا العامّة للوظائف الغنيّة في تطوير الويب التي يمكننا تعلّمها دون الغوص كثيرًا في بنية Angular الدّاخليّة. ولكن من الآن فصاعدًا، سنبدأ بالغوص أعمق فأعمق في Angular الموسّعة، ولنتمكّن من القيام بذلك سيكون علينا تعلُّم كيفيّة قيام Angular بإدارة المكوّنات. وسيغطّي الفصل القادم النّظام الّذي طوّرته Angular لذلك، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">الوحدات</a>.</p><p>ترجمة وبتصرّف <a rel="external nofollow" href="http://www.angularjsbook.com/angular-basics/chapters/collections/">للفصل الخامس</a> من كتاب: <a rel="external nofollow" target="_blank" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p>
]]></description><guid isPermaLink="false">191</guid><pubDate>Tue, 13 Oct 2015 22:32:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62C;&#x627;&#x644;&#x627;&#x62A; (scopes) &#x641;&#x64A; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D9%85%D8%AC%D8%A7%D9%84%D8%A7%D8%AA-scopes-%D9%81%D9%8A-angularjs-r188/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/scopes-angularjs.png.7fde7b899de651ef31f8e3e51a23edcd.png" /></p>

<div id="wmd-preview-section-33"><p id="المجالات">ما الذي تعنيه كلمة "<a rel="external nofollow" href="http://docs.angularjs.org/guide/scope">مجال</a>" برأيك؟ قد تبدو من اسمها بأنّها تشير إلى جزءٍ من شيفرة التّطبيق، ربّما تم عملها لنتجنّب استخدام المجال العام الذي يسبّب العديد من المشاكل. يبدو أنّ الأمر بسيط، وإنّه لمن الحكمة أن يقوم إطار العمل بتطبيق شيءٍ كهذا، ربّما ليس علينا التّفكير في أمر المجالات أكثر من ذلك، هل يمكننا الانتقال للفصل التالي؟</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/scopes-angularjs.png.183d428b179a8617df69cf5cf5294941.png"><img data-fileid="5771" class="ipsImage ipsImage_thumbnailed" alt="scopes-angularjs.thumb.png.32d87c4ea483b" src="https://academy.hsoub.com/uploads/monthly_2015_10/scopes-angularjs.thumb.png.32d87c4ea483bcb94b4ed9bf37128bb4.png"></a></p><p>ليس بهذه السّرعة، لن يكون هذا الفصل طويلًا ولكنه سيغطي أمرين شديدي الأهمّيّة: وراثة المجالات، وهرميّة المجالات، فقد يحوي تطبيق Angular نموذجيًّا على العشرات، المئات وربّما الآلاف من المجالات.</p><p>قبل أن نبدأ، لنقم بإعداد البيئة لتُلائم أمثلة هذا الفصل.</p></div><div id="wmd-preview-section-34"><h2 id="التهيئة">التهيئة</h2><p>في فصل <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-angularjs-r176/">المبادئ</a>، تعلّمنا كيف نقوم بإضافة التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngApp">ng-app</a> إلى العنصر الذي نرغب بأن تقوم Angular بمعالجته.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;body ng-app="app"&gt;
  &lt;!-- الأمثلة هنا --&gt;
&lt;/body&gt;</pre><p>الوسيط الذي نمرره إلى التّوجيه <span style="font-family:courier new,courier,monospace;">ng-app</span> هو اسم الوحدة التي تشكل جذر التطبيق الحالي (في المثال قمنا باستخدام الاسم <span style="font-family:courier new,courier,monospace;">app</span> على سبيل الاصطلاح).</p><p>سنقوم بتغطية <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">الوحدات</a> بعمق في فصل لاحق. أما الآن فاعتبر السّطور التّالية مجرّد شيفرات اصطلاحية يمكنك نسخها دون فهم محتواها.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
    $controllerProvider.allowGlobals();
}]);</pre><p>والآن بعد كتابة تلك الشّيفرات الخارجة عن الدّرس، يمكننا الدخول في الموضوع.</p></div><div id="wmd-preview-section-35"><h2 id="scope">scope$</h2><p>في الفصل الماضي، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AA%D8%AD%D9%83%D9%85%D8%A7%D8%AA-controlers-%D9%81%D9%8A-angularjs-r186/">المتحكمات</a>، تعلّمنا كيفيّة تحضير النّموذج عن طريق ربط العناصر (الخصائص properties) إلى المرجع <span style="font-family:courier new,courier,monospace;">scope$</span>. لنقم بتكرار التمرين ثانيةّ.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function NameController($scope) {
    $scope.name = "First";
}</pre><p>باستخدام التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngController">ng-controller</a> يمكننا استدعاء تابع التّحكم المكتوب أعلاه، وذلك ضمن سياق أحد عناصر المستند، وعندها ستكون أيّ بيانات قمنا بإسنادها للمجال متاحةً للاستخدام داخل العنصر.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="NameController"&gt;
  {{name}}
&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">First</pre><p>عناصر المستند التي تقع خارج العنصر الذي قمنا باستدعاء المتحكّم <span style="font-family:courier new,courier,monospace;">NameController</span> فيه، لن تكون قادرةً على الوصول إلى العناصر المرتبطة بالمتحكّم، لنجرّب ذلك.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div&gt;
  &lt;p&gt;
    Outside the scope: {{name}}
  &lt;/p&gt;
  &lt;div ng-controller="NameController"&gt;
    &lt;p&gt;
      Inside the scope: {{name}}
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Outside the scope:

Inside the scope: First</pre><p>وهذا المثال يوضّح ارتباط عمل المتحكّم والمجال معًا، والآن لننظر إلى الحالة المعاكسة، تطبيق Angular بمجال واحد.</p></div><div id="wmd-preview-section-36"><h2 id="rootscope">rootScope$</h2><p>تحاول Angular جاهدةً أن تتأكد من ابتعادنا عن المشاكل أثناء استخدام المجالات، لذا تقوم بإنشاء مجالٍ جديد لكلّ متحكّم.</p><p>يتمّ بناء المجالات وفق بنيةٍ هرميّة، ويتربّع في جذر هرم المجالات في كلّ تطبيقات Angular مجالٌ أبٌ وحيدٌ لجميع المجالات، يمكننا الوصول إلى هذا الجذر باستخدام الوسيط ذو الاسم المخصص <span style="font-family:courier new,courier,monospace;">rootScope$</span> داخل المتحكّم، واستخدامه بدلًا من المرجع المعتاد (والمستحسن) <span style="font-family:courier new,courier,monospace;">scope$</span>.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function RootNameController($rootScope) {
  $rootScope.name = "First";
}</pre><p>الشّيفرة واضحة وليس فيها صعوبة، وهي تعمل بشكل طبيعي.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="RootNameController"&gt;
  {{name}}
&lt;/p&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">First</pre><p>ولكنّ المشاكل تبدأ بالظّهور عندما نحاول الوصول إلى عنصر له الاسم نفسه من متحكّم آخر.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">function SecondRootNameController($rootScope) {
  $rootScope.name = "Second";
}</pre><p>هذا لا يبشّر بالخير، فالمرجع <span style="font-family:courier new,courier,monospace;">rootScope$</span> وحيد (singleton) داخل التّطبيق، ولا يمكن أن يكون هناك سوى عنصر واحد له الاسم <span style="font-family:courier new,courier,monospace;">name</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="RootNameController"&gt;
  {{name}}
&lt;/p&gt;
&lt;p ng-controller="SecondRootNameController"&gt;
  {{name}}
&lt;/p&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Second

Second</pre><p>من الواضح أنّ المتحكّم <span style="font-family:courier new,courier,monospace;">SecondRootNameController</span> قد استبدل القيمة التي أسندها <span style="font-family:courier new,courier,monospace;">RootNameController</span> للعنصر <span style="font-family:courier new,courier,monospace;">name</span>. حسنًا، هذه هي مشكلة المتغيرات العامة، أليس كذلك؟</p></div><div id="wmd-preview-section-37"><h2 id="العزل">العزل</h2><p>تقدم Angular لنا بيئة آمنة عن طريق إنشاء مجالٍ خاصّ بكلّ متحكّم، لنقم بإعادة كتابة المتحكّمات السّابقة لتقوم بتهيئة النّموذج تهيئةً صحيحة، باستخدام المرجع <span style="font-family:courier new,courier,monospace;">scope$</span> بدلًا من <span style="font-family:courier new,courier,monospace;">rootScope$</span>، وحاول مقارنة ذلك مع المثال السّابق الذي استخدمنا فيه <span style="font-family:courier new,courier,monospace;">rootScope$</span> لتعرف سبب إنشاء مجال لكلّ متحكّم، سنستخدم المتحكّمين التاليين:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">function SecondNameController($scope) {
  $scope.name = "Second";
}</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="NameController"&gt;
  {{name}}
&lt;/p&gt;
&lt;p ng-controller="SecondNameController"&gt;
  {{name}}
&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">First

Second</pre><p>أظهر المثال المخرجات الصحيحة، القيمة الصحيحة للعنصر name لكلا المتحكّمين.</p><p>هذا العزل هو النّتيجة التي نحصل عليها عندما لا يكون أيٌّ من المتحكّمين ابنًا للآخر، أيّ أننا لم نقم بتعريف أحد المتحكّمين داخل عنصر في المستند محتوًى داخل متحكّمٍ آخر. ما الذي سيحدث لو قمنا بجعلهم متداخلين بدلًا من ذلك؟</p></div><div id="wmd-preview-section-38"><h2 id="المجالات-المتداخلة">المجالات المتداخلة</h2><p>بتعديلٍ صغيرٍ على المثال السابق، سنقوم بتحريك <span style="font-family:courier new,courier,monospace;">SecondNameController</span> إلى عنصرٍ ابن للعنصر <span style="font-family:courier new,courier,monospace;">div</span> الذي يقوم بتحميل المتحكّم <span style="font-family:courier new,courier,monospace;">NameController</span>، وهذه الحالة هي ما يسمّى بالمجالات المتداخلة (nested).</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="NameController"&gt;
  &lt;p&gt;
    {{name}}
  &lt;/p&gt;
  &lt;p ng-controller="SecondNameController"&gt;
    {{name}}
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">First

Second</pre><p>الأمور تسير على ما يُرام، ولا يزال العنصر <span style="font-family:courier new,courier,monospace;">name</span> معزولًا في كلا المجالين، ماذا لو قمتَ بعكس ترتيب العنصرين p في المثال السابق؟ هيا قم بتجربة ذلك، يُفترض بأنك سترى أنّ العنصرين <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> قد انعكس ترتيبهما.</p><p>في الحقيقة، لا يعني ذلك بأنّ المجالين معزولين، فـAngular تقوم بتنظيم المتحكّمات في بنية هرميّة بالاعتماد على موضع المتحكّم في بنية المستند، والمتحكّم الابن يرث عناصر وخصائص أبيه.</p><p>يرجع السبب في عدم حدوث تغيير في قيمة العنصر <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> في المثال السابق، إلى خاصّيّة <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Variable_shadowing">التظليل</a>، حيث يقوم العنصر <span style="font-family:courier new,courier,monospace;">name</span> في الابن بتظليل قيمة العنصر <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> في الأب.</p><p>لنجرّب الحصول على دليلٍ على هذا السلوك عن طريق تغيير اسم العنصر في المتحكّم الابن.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function ChildController($scope) {
  $scope.childName = "Child";
}</pre><p>سنحاول إخراج قيمتي العنصرين في كلا المجالين، الأب والابن.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="NameController"&gt;
  &lt;p&gt;
    {{name}} and {{childName}}
  &lt;/p&gt;
  &lt;p ng-controller="ChildController"&gt;
    {{name}} and {{childName}}
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">First and

First and Child</pre><p>من الواضح أنّ المتحكّم الأب <span style="font-family:courier new,courier,monospace;">NameController</span> لا يملك صلاحيّةً للوصول إلى عناصر المتحكّم الابن، بينما يمكن للمتحكّم الابن <span style="font-family:courier new,courier,monospace;">ChildController</span> أن يصل إلى عناصره وعناصر أبيه.</p><p>بما أنّ العنصر <span style="font-family:courier new,courier,monospace;">name</span> هو عنصر موروث من الأب، لا بدّ من أنّ التغيير على قيمته في مجال المتحكّم الابن سيؤدّي إلى تغيير قيمته في مجال الأب. سنضيف خانة إدخال ونربطها بالعنصر <span style="font-family:courier new,courier,monospace;">name</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="NameController"&gt;
  &lt;p&gt;
    {{name}}
  &lt;/p&gt;
  &lt;p ng-controller="ChildController"&gt;
    {{name}}
  &lt;/p&gt;
  &lt;input type='text' ng-model='name'&gt;
&lt;/div&gt;</pre><p>إذا حاولت تعديل قيمة العنصر <span style="font-family:courier new,courier,monospace;">name</span> في المثال السابق، ستجد أنّه يعمل كما هو متوقّع، فقيمة العنصر <span style="font-family:courier new,courier,monospace;">name</span> تتغيّر في كلا المجالين، ولكن لاحظ بأنّنا نقوم بالتّغيير ضمن مجال الأب فقط.</p></div><div id="wmd-preview-section-39"><h2 id="الوراثة">الوراثة</h2><p>قد ترغب أيضًا بتغيير قيمة العنصر <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> أيضًا في مجال الابن، ربّما تظنّ بأنّ هذا التغيير يجب أن ينعكس أيضًا على المتغير <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> في مجال الأب، لنجرّب ذلك، سنقوم بإضافة خانة إدخال لتسمح لنا بتعديل العنصر <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">name</span> في مجال الابن أيضًا.</p><p>في العرض الخاصّ بالمثال، قم بالخطوات التالية بنفس الترتيب الذي سأذكره لك:أوّلًا، غيّر القيمة في خانة الإدخال العليا، ستلاحظ أنّ جميع القيم المرتبطة بالعنصر name قد تمّ تحديثها.ثانيًا، غيّر القيمة في خانة الإدخال السّفلى.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="NameController"&gt;
  &lt;p&gt;
    name: {{name}}
    &lt;br&gt;
    &lt;input type='text' ng-model='name'&gt;
  &lt;/p&gt;
  &lt;p ng-controller="ChildController"&gt;
    name: {{name}}
    &lt;br&gt;
    &lt;input type='text' ng-model='name'&gt;
  &lt;/p&gt;
&lt;/div&gt;</pre><p>هل فاجَأَتك النّتيجة؟</p><p>تستخدم Angular طريقة JavaScript في وراثة الهيكل الخارجي (<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">prototypal inheritance</a>) هذا جيّدٌ إن كنت متمرّسًا فيها، فليس عليك تعلّم أيّ شيءٍ جديدٍ هنا، ولكنّه سيّءٌ لمن لم يواجه هذا النّوع من الوراثة من قبل، ففهمه ليس أمرًا بديهيًّا.</p><p>تقول القاعدة: “إنّ تغيير قيمة عنصر ما في كائن في JavaScript، يؤدّي إلى إنشاء هذا العنصر في الكائن”، وهذه القاعدة البسيطة تشكّل مشكلةً أثناء التّعامل مع العناصر الموروثة التي تكون مظلّلة بالعنصر الخاص بالكائن الابن.</p><p>حدث الأمر كالتّالي: في البداية لم يكن هناك أيّ عنصر اسمه <span style="font-family:courier new,courier,monospace;">name</span> داخل الابن، ولكن عندما قمنا بتعديل النّصّ في خانة الإدخال السّفلى قامت Angular بإسناد النّص إلى العنصر <span style="font-family:courier new,courier,monospace;">name</span> في الابن حيث تمّ إنشاء هذا العنصر في الابن، وعند حدوث ذلك، قام هذا العنصر بتظليل العنصر <span style="font-family:courier new,courier,monospace;">name</span> في الأب، ومن ثمّ لم يعُد بإمكاننا الوصول إليه من الابن.</p><p>كيف يمكننا التّعامل مع هذا الأمر في Angular، بحيث نتمكّن من تعديل بيانات النّموذج في مجالٍ موروث؟</p><p>لن يكون ذلك صعبًا، سيكون علينا فقط نقل العنصر name إلى داخل كائنٍ آخر.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function InfoController($scope) {
  $scope.info = {name: "First"};
}</pre><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function ChildInfoController($scope) {
  $scope.info.childName = "Child";
}</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="InfoController"&gt;
  &lt;p&gt;
    {{info.name}} and {{info.childName}}
    &lt;br&gt;
    &lt;input type='text' ng-model='info.name'&gt;
  &lt;/p&gt;
  &lt;p ng-controller="ChildInfoController"&gt;
    {{info.name}} and {{info.childName}}
    &lt;br&gt;
    &lt;input type='text' ng-model='info.name'&gt;
  &lt;/p&gt;
&lt;/div&gt;</pre><p>لاحظ أن <span style="font-family:courier new,courier,monospace;">ChildInfoController</span> يعتمد على أبيه في إنشاء الكائن <span style="font-family:courier new,courier,monospace;">info</span>، ما الذي سيحدث لو قمنا بتعديل شيفرة المتحكّم <span style="font-family:courier new,courier,monospace;">ChildInfoController</span> واستبدلنا جسم التابع بالعبارة: </p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">scope.info = {childName: "Second$"};</pre><p>جرّب ذلك، سترى بأننا عدنا إلى إنشاء عنصرٍ جديد في الابن، مع تأثير التظليل الذي رأيناه سابقًا.</p></div><div id="wmd-preview-section-40"><h2 id="scopewatch">scope.$watch</h2><p>تتعامل Angular أثناء عمليات الربط ثنائيّ الاتجاه مع العناصر في المجال بالطريقة التالية: عندما تستخدم خانة الدّخل المرتبطة للقيام بأيّ تغيير، يتمّ تحديث واجهة المستخدم في كلّ مكان، وهذا يختلف عن “الخصائص المحسوبة”(<a rel="external nofollow" href="http://emberjs.com/guides/object-model/computed-properties/">computed properties</a>) وهي البيانات المأخوذة من مجال بيانات آخر. في المثال التالي، العنصر <span style="font-family:courier new,courier,monospace;">sum</span> هو خصيصة محسوبة.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function SumController($scope) {
  $scope.values = [1,2];
  $scope.newValue = 1;
  $scope.add = function() {
    $scope.values.push(parseInt($scope.newValue));
  };

  // Broken -- doesn't trigger UI update
  $scope.sum = $scope.values.reduce(function(a, b) {
    return a + b;
  });
}</pre><p>يتم حساب قيمة العنصر <span style="font-family:courier new,courier,monospace;">sum</span> فعليًّا عن طريق عملية بسيطة تستخدم التابع reduce في العبارة الأخيرة في المتحكّم <span style="font-family:courier new,courier,monospace;">SumController</span>.</p><p>في القالب الخاص بهذا المثال، سنستخدم أداة الدّخل select للسّماح للمستخدم باختيار الرّقم (2،1 أو 3) لإضافته إلى نهاية المصفوفة values.(كنقطة جانبيّة: لاحظ أنّ المتحكّم يعطي قيمةً ابتدائيّة للمتغيّر <span style="font-family:courier new,courier,monospace;">newValue</span>, ولو لم نقم بذلك لكانت Angular ستضيف الاختيار الفارغ للقائمة في العنصر <span style="font-family:courier new,courier,monospace;">select</span>، وذلك لتجنّب القيمة العشوائيّة التي يخزّنها <span style="font-family:courier new,courier,monospace;">newValue</span> للخيار الأوّل المولّد عن طريق التّوجيه<span style="font-family:courier new,courier,monospace;"> ng-options</span>. هذا السلوك لا علاقة له بالمجالات ولكنّ العلم به أمرٌ مفيد.)</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="SumController"&gt;
  &lt;select ng-model="newValue" ng-options="n for n in [1,2,3]"&gt;&lt;/select&gt;
  &lt;input type="button" value="Add" ng-click="add()"&gt;
  The sum of {{values}} is {{sum}}.
&lt;/p&gt;</pre><p>عند النقر على <span style="font-family:courier new,courier,monospace;">Add</span> ستتغيّر القيمة المعروضة لـ<span style="font-family:courier new,courier,monospace;">sum</span>، ولكن للأسف، الشّيفرة الخاصة بالمتحكّم تحتوي على أخطاء، ولن يعمل المتحكّم كما توقّعنا.</p><p>لنقم الآن بتصحيح الخطأ، وذلك بنقل العبارة التي تقوم بالحساب الحقيقي للقيمة <span style="font-family:courier new,courier,monospace;">sum</span> إلى تابع استدعاءٍ خلفيّ (callback). وعندما سنمرر هذا التابع كوسيط إلى <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/type/%24rootScope.Scope#%24watch">scope.$watch$</a> مع وسيط آخر يمثّل عبارة المتابعة (في هذه الحالة هو اسم العنصر الذي يتم حساب <span style="font-family:courier new,courier,monospace;">sum</span> منه)، سيؤدّي ذلك إلى جعل <span style="font-family:courier new,courier,monospace;">sum</span> يتمّ إعادة حسابها كلّما تغيّر <span style="font-family:courier new,courier,monospace;">values</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">function SumController($scope) {
  $scope.values = [1,2];
  $scope.newValue = 1;
  $scope.add = function() {
    $scope.values.push(parseInt($scope.newValue));
  };
  $scope.$watch('values', function () {
    $scope.sum = $scope.values.reduce(function(a, b) {
      return a + b;
    });
  }, true);
}</pre><p>والآن ستتغيّر قيمة العنصر <span style="font-family:courier new,courier,monospace;">sum</span> ديناميكيًّا عند إضافة العناصر للمصفوفة.</p></div><div id="wmd-preview-section-41"><h2 id="scopeapply">scope.$apply</h2><p>جميع التّوجيهات المدمجة في Angular والخاصة بعمليّة الربط ثنائيّ الاتجاه كاملة المزايا، ولكنّك قد تجد من فترة إلى أخرى سلوكًا تحتاج إلى إضافته. مثلًا، ماذا لو أردنا أن يقوم المستخدم بمسح الحالتين الحالة الحاليّة لخانة الدخل النّصّيّة و الحالة المرتبطة بها وذلك عندما يضغط زرّ <span style="font-family:courier new,courier,monospace;">esc</span>؟ كيف يمكننا كتابة شيفرة التّعامل مع هذا الحدث؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="EscapeController"&gt;
  &lt;input type="text" ng-model="message"&gt;
  is bound to
  "&lt;strong ng-bind="message"&gt;&lt;/strong&gt;".
  Press &lt;code&gt;esc&lt;/code&gt; to clear it!
&lt;/div&gt;</pre><p>يجب علينا أوّلًا أن نصرّح عن المتغيّر ذو الاسم المخصّص<span style="font-family:courier new,courier,monospace;"> element$</span> وتمريره كوسيط للمتحكّم، وذلك للسّماح لـAngular بحقن مرجعٍ في العنصر المرتبط بالمتحكّم.</p><p>يمكننا استخدام التابع <span style="font-family:courier new,courier,monospace;">bind</span> لتسجيل استدعاء خلفيّ لحدث keyup الذي يختبر ضغط الزّرّ <span style="font-family:courier new,courier,monospace;">esc</span>، وداخل تابع الاستدعاء الخلفيّ هذا، سنقوم بتحديث عنصر المجال.</p><p>قم بتجربة المثال التالي، اكتب شيئًا ثم اضغط <span style="font-family:courier new,courier,monospace;">esc</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">function EscapeController($scope, $element) {
  $scope.message = '';
  $element.bind('keyup', function (event) {
    if (event.keyCode === 27) { // esc key

      // Broken -- doesn't trigger UI update
      $scope.message = '';
    }
  });
}</pre><p>ليس بعد، بما أنّنا نتعامل مباشرةً (تقريبًا) مع عناصر المستند، سنحتاج إلى إخبار Angular عندما نريد أن تقوم بإعادة رسم العرض. نقوم بذلك عن طريق تغليف التّغييرات التي نقوم بها بتابع استدعاءٍ خلفيّ نمرّره إلى <a rel="external nofollow" href="https://docs.angularjs.org/api/ng/type/%24rootScope.Scope#%24apply">scope.$apply$</a>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">function EscapeController($scope, $element) {
  $scope.message = '';
  $element.bind('keyup', function (event) {
    if (event.keyCode === 27) { // esc key

      $scope.$apply(function() {
        $scope.message = '';
      });
    }
  });
}</pre><p>جرّبها الآن، بعد أن أخبرنا Angular بما نريد، سيعمل كلّ شيء كما يجب.</p></div><div id="wmd-preview-section-42"><h2 id="خلاصة">خلاصة</h2><p>إن حاولت تطبيق مفاهيم نموذج-عرض-متحكم <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">(Model-view-controller (MVC</a> على Angular، ستكون المجالات لغزًا بالنّسبة لك، قد تظنّ بأنّ الأمر بسيط، وأنّ المجالات هي جزءٌ من طبقة النّموذج، ولكن في Angular لا يكون الكائن نموذجًا حتّى يكون قابلًا للوصول إليه كعنصرٍ في المجال. ولكنّ القصّة تصبح أكثر إثارةً عندما ترى طريقة ارتباط المجالات بالمستند عن طريق المتحكّمات والتّوجيهات. بوضع سؤالنا الأكاديميّ جانبًا، فإن المجالات بديهيّةٌ وسهلة الاستخدام كما بيّنت أمثلة هذا الفصل.</p></div><p>ترجمة وبتصرّف <a href="http://www.angularjsbook.com/angular-basics/chapters/scopes/" rel="external nofollow">للفصل الرابع</a> من كتاب: <a rel="external nofollow" target="_blank" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p>
]]></description><guid isPermaLink="false">188</guid><pubDate>Sun, 11 Oct 2015 21:27:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62A;&#x62D;&#x643;&#x645;&#x627;&#x62A; Controllers &#x641;&#x64A; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D9%85%D8%AA%D8%AD%D9%83%D9%85%D8%A7%D8%AA-controllers-%D9%81%D9%8A-angularjs-r186/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-controlers_(1).png.bd832e7239af652b1e7356f30e5a179d.png" /></p>

<div id="wmd-preview-section-103"><p id="المتحكمات">طلبت منك في الفصل السابق (<a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-angularjs-r176/">المبادئ</a>) أن تكبح جماح JavaScript بداخلك ريثما نستكشف القيمة الحقيقيةّ التي تقدّمها Angular، وهي تقديم امتدادات قويّة لـHTML لمطوّر النّهاية الأمامية front-end.</p><p style="text-align: center;"> </p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-controlers_(1).png.3df001cc4c772df664b3d703e7071fd8.png"><img data-fileid="5711" class="ipsImage ipsImage_thumbnailed" alt="angularjs-controlers_(1).thumb.png.14147" src="https://academy.hsoub.com/uploads/monthly_2015_10/angularjs-controlers_(1).thumb.png.14147d85d6830f2b7d48226c16023c41.png"></a></p><p>لا تنتهي قصّة Angular هنا بالطّبع، والمنهج في مشاريع Angular هو تخصيص السّلوكيات عن طريق JavaScript، فإذا كنت تتحرّق شوقًا في الفصل الأوّل للبدء بكتابة شيفرات حقيقيّة فقد حان الوقت لذلك، إنه وقت كتابة شيفرات JavaScript.</p><p>أكثر الطرق شيوعًا لتعديل العرض في Angular باستخدام JavaScript هي عن طريق استخدام <a rel="external nofollow" href="https://docs.angularjs.org/guide/controller">متحّكم</a>، وأبسط طريقة لكتابة متحكّم هي باستخدام تابع بناء (constructor) بسيط.</p><p>لنبدأ بمثالٍ بسيط لنفهم تمامًا ما الذي يحدث، المثال التّالي لا يقوم بأي شيء، ولا يطبع "!Hello World" حتّى.</p><p>ها هو متحكّمنا البسيط.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function EmptyController() {

};</pre><p>سنحتاج إلى تضمين مكتبة Angular ضمن الصفحة لتتم معالجة خصائص المجال التي تم تحضيرها عن طريق المتحكّم، ولذا يجب نسخ الشّيفرة التّالية ولصقها داخل العنصر head في كلّ الأمثلة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;html&gt;
    &lt;head&gt;
        &lt;script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body ng-app="app"&gt;
        &lt;!-- كل الأمثلة توضع هنا --&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre><p>يجب علينا ضبط إعدادات تطبيق Angular داخل مستند HTML ليقوم بتحميل الوحدة <span style="font-family:courier new,courier,monospace;">app</span>، فقد تعرفّنا في الوحدة الأولى <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-angularjs-r176/">المبادئ</a> على التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngApp">ng-app</a> الذي نضيفه لأيّ عنصر في المستند لتقوم Angular بمعالجة ما بداخله، انظر الآن إلى استخدام <span style="font-family:courier new,courier,monospace;">ng-app</span> في المثال التّالي، هل يمكنك الانتباه إلى الإضافة الجديدة؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;body ng-app="app"&gt;

&lt;/body&gt;</pre><p>يُمكن تعريف المتحكّمات كتوابع بناء معرّفة في المجال العام (global scope)، وهذه هي الطّريقة التي سنستخدمها في أمثلتنا في هذا الفصل.</p><p>كان الشكل البسيط للمتحكّمات مدعومًا في Angular حتى النسخة 1.3 لتسهيل انطلاق المطوّرين مع المكتبة، ولكنّ ذلك يتطلب الآن إنشاء وتسمية وحدة للتطبيق.</p><p>سنناقش تفاصيل استخدام <span style="font-family:courier new,courier,monospace;">angular.module</span> في الفصول القادمة <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%81%D9%8A-angularjs-r196/">الوحدات</a>، <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%AD%D9%82%D9%86-%D8%A7%D9%84%D8%AA%D8%A8%D8%B9%D9%8A%D8%A9-dependency-injection-%D9%81%D9%8A-angularjs-r198/">حقن التابعة</a>، و<a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D8%AE%D8%AF%D9%85%D8%A7%D8%AA-services-%D9%81%D9%8A-angularjs-r200/">الخدمات</a>.</p><p>يمكنك التعامل مع المثال التّالي على أنّه شيفرة معياريّة مطلوبة:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
    $controllerProvider.allowGlobals();
}]);</pre><p>والآن بعد كتابة هذه الشّيفرة الخارجة عن سياق الحديث، لنعد إلى متحكّمنا <a rel="external nofollow" href="http://en.wikipedia.org/wiki/NOP">عديم الفائدة</a>.</p></div><div id="wmd-preview-section-104"><h2 id="ng-controller">ng-controller</h2><p>كالعادة، الطّريقة التي سنتّبعها للقيام بأيّ شيء، هي استخدام الموجّهات، سنستخدم الموجه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngController">ng-controller</a> الذي يقوم بالعثور على التّابع الذي يتمّ تمرير اسمه إليه ثم استدعائه.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="EmptyController"&gt;

&lt;/p&gt;</pre><p>وكما توقّعتَ، لن يقوم هذا التّابع بأيّ شيء، والآن إذًا ما هي هذه المتحكّمات وكيف نستخدمها؟</p></div><div id="wmd-preview-section-105"><h2 id="بناء-النموذج">بناء النموذج</h2><p>ينصّ المرجع الرسمي في <a rel="external nofollow" href="http://docs.angularjs.org/guide/concepts#controller">النظرة العامة للمفهوم</a> على أنّ وظيفة المتحكّم هي "الكشف عن المتغيرات والوظائفيّة للعبارات والتّوجيهات" وتشير كلمة "الوظائفية" إلى توابع الاستدعاء الخلفي (callback)، وسنتطرق إليها قريبًا، أمّا الآن فسنتكلّم عن تهيئة "المتغيّرات"، أو بعبارة أخرى تحضير النّموذج.</p><p>أرجو منك أن تبقي في ذهنك أنّ وحدة Angular ليست سوى JavaScript عاديّة يمكن الوصول إليها ضمن مجال عبارة ما، وبذلك سيكون تحضير النّموذج أمرًا سهلًا للغاية.</p><p>سنتمكّن من كتابة JavaScript عاديّة دون أيّ قيود، لنقم بإضافة عنصر إلى المتحكّم الفارغ، وليكن هذا العنصر سلسلة نصّيّة.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function MessageController() {
    this.message = "This is a model.";
}</pre><p>أمرٌ بسيط، أليس كذلك؟ هل قمنا الآن بإنشاء وحدة؟ ماذا تتوقّع؟ <br>الإجابة هي "تقريبًا"، فعندما يكون بإمكاننا الوصول إلى العنصر message ضمن مجال العرض، ستكون هذه وحدةً بالفعل.</p><p>أحد طرق القيام بذلك هي الكشف عن كامل المتحكّم كعنصرٍ بداخل المجال، ولن يكون هذا صعبًا كما تظنّ، كلّ ما عليك معرفته هو التركيب النحويّ المناسب للقيام بذلك.</p></div><div id="wmd-preview-section-106"><h2 id="controller-as-propertyname">Controller as propertyName</h2><p>يشرح توثيق المكتبة بالنّسبة للتّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngController">ng-controller</a> بأنه يمكنك تمرير عبارة Controller as propertyName كوسيط للتّوجيه <span style="font-family:courier new,courier,monospace;">ng-controller</span>، وهذه الميزة متاحة في <a rel="external nofollow" href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#120-timely-delivery-2013-11-08">النسخة 1.2</a> فما فوق.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="MessageController as controller"&gt;
    {{controller.message}}
&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">This is a model.</pre><p>رائع، لقد قمنا للتّو بتحضير بيانات النّموذج باستخدام متحكّم.</p><p>صحيحٌ بأنّ هذه الطّريقة في ربط الخاصّية بالمرجع <span style="font-family:courier new,courier,monospace;">this</span> مباشرة وليس فيها الكثير من التّعقيد، إلّا أنها تعطي انطباعًا خاطئًا بأنّ المتحكّم جزءٌ من النّموذج، وهذا غير صحيح، فالمتحكّم في الحقيقة يقوم بـتحضير النّموذج فقط.</p><p>سيكون اختبار الشّيفرة وتتبّع أخطائها أكثر سهولةً عندما يتم الحدّ من الوصول إلى البيانات بمقدار ما يحتاج إليه العمل لا أكثر، كما أنّ الطّريقة السّابقة تضيف بعض الضجّة إلى شيفرة العرض، فجميع العناصر سيتم الوصول إليها عبر مرجع (reference) للمتحكّم.</p><p>شيفرة العرض هي المكان الأكثر حساسيةً للضجيج في تطبيق ويب، فهي أوّل مكانٍ قد نبدأ فيه بفقد القدرة على فهم الهدف من الشّيفرة بلمحة سريعة.</p><p>أخيرًا، المتحكّمات تعمل يدًا بيد مع المجال، لذا ولأهدافٍ تعليميّة سيكون من الأفضل رؤية مرجع (reference) للمجال وامتلاك القدرة على التّحكم به، ومع متحكّم كهذا سيكون بإمكاننا الكشف عن العناصر التي نحتاجها في العرض فقط، بدل الكشف عن المتحكّم بما فيه، وسنتّبع في هذا الكتاب هذه الطّريقة بالكشف الصّريح عن العناصر المستخدمة في العرض داخل المتحكّم.</p><p>أوّل سؤالٍ يتبادر إلى الذّهن الآن هو: "كيف سنحصل على مرجعٍ للمجال؟"، هل سننشئ واحدًا عن طريق new أم سنطلب الحصول على واحدٍ بطريقة ما؟</p></div><div id="wmd-preview-section-107"><h2 id="حقن-التابعية">حقن التابعية</h2><p>سنحصل عليه عن طريق حقن التابعية، ربما تكون قد لاحظت أيضًا أنني لم أكتب أي شيفرة لإنشاء المتحكّم مثل:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var controller = new MessageController(); </pre><p>مثلًا، فمن الذي يقوم بإنشاء المتحكّم المستخدم في العرض إذًا؟</p><p>Angular هي من يقوم بذلك طبعًا، فـAngular هي حاوية لتبادل التحكم <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Inversion_of_control">Inversion of Control</a> تدير دورة حياة مكونات التّطبيق، فعندما نحتاج إلى متحكّم جديد أو إلى مكوّنٍ آخر، ستقوم Angular ببنائه تلقائيًّا، وهذا يوفر الجهد، ولكنّ الأمر الأكثر أهمية هو أنه يسمح لـAngular بـحقن المصادر، أو التّبعيّات إلى المكوّن الجديد.</p></div><div id="wmd-preview-section-108"><h2 id="scope">scope$</h2><p>يحتاج متحكّمنا فقط إلى مُعامل يُسمّى <span style="font-family:courier new,courier,monospace;">scope$</span> وذلك بفضل إطار العمل الذي يُدار عن طريق حقن التّابعية، كما أنّ تسمية هذا المُعامل هامّة جدًّا. <br>ويجب عليك أن تعرف خطورة تقصير شفرة JavaScript داخل مشروعك، فهذا قد يؤدي إلى تدمير آلية عمل حقن التّابعية. (ولكن لا تقلق، فهناك حلّ التفافيّ لهذه المشكلة، سنتطرّق إليه في فصل <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%AD%D9%82%D9%86-%D8%A7%D9%84%D8%AA%D8%A8%D8%B9%D9%8A%D8%A9-dependency-injection-%D9%81%D9%8A-angularjs-r198/">حقن التابعية</a>).</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint" style="line-height: 22.4px;">function MessageController($scope) {
   $scope.message = "This is a model.";
}</pre><p>بإضافتنا للمعامل scope$ إلى تابع البناء نكون قد أخبرنا Angular بحاجتنا إلى مرجع لمجال العرض، والآن بدلًا من تعريف العنصر message داخل this (أي داخل المتحكّم)، قمنا بتعريفه مباشرةً داخل المجال.</p><p>في المثال التّالي، قمنا بإزالة as controller من التّوجيه ng-controller، كما أنّ العبارة controller.message أصبحت فقط message وهي العنصر الوحيد الذي قمنا بربطه بالمجال.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">&lt;p ng-controller="MessageController"&gt;
    {{message}}
&lt;/p&gt;
</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">This is a model.</pre><p>رغم أن الطّريقتين تعملان بشكل صحيح، إلا أننا سنستخدم طريقة المرجع <span style="font-family:courier new,courier,monospace;">scope$</span>، فكما ترى، حقن التّابعية هو جزء مكمّل لاستخدام Angular، ويجب أن يصير مألوفًا لنا.</p></div><div id="wmd-preview-section-109"><h2 id="النموذج-العرض-المتحكم">النموذج-العرض-المتحكم MVC</h2><p>يشير تعريف المتحكّم في المرجع الرسمي إلى أنّه يكشف “الوظائفيّة” للعرض، وقبل أن ننتقل إلى هذا الجزء يجدر بنا الحديث عن الفرق بين متحكّمات Angular وبين نموذج MVC التقليدي.(قد ترغب في تجاوز هذه الفقرة).</p><p>تنصّ ويكيبيديا في مقال <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">النّموذج-العرض-المتحكّم (MVC)</a> على أنّ المتحكّم “يستلم المدخلات ويحوّلها إلى أوامر للنموذج أو للعرض.”، قد تكون عبارة “أوامر للنّموذج أو للعرض” صعبة الفهم في سياق الحديث عن Angular، فـAngular قامت بتبسيط نموذج MVC الخاص بها، باستخدام النّماذج الضّعيفة (anemic models) التي لا تحوي منطقًا برمجيًّا فيها.</p><p>النّمط السّائد في Angular هذه الأيّام هو وضع كل منطق العمل، أو ما يُعرف أيضًا بمنطق النّطاق (domain logic) داخل المتحكّم. <br>بعبارةٍ أخرى، تتّجه Angular نحو نموذج نحيل ومتحكّم سمين.</p><p>إذا كنت تألف بعض الأنماط مثل نموذج النطاق الغنيّ <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Domain_model">(rich domain model)</a> فربّما تجد طريقة Angular متخلّفةً بعض الشيء، أما أنا فأرى الأمر مجرّد طريقة لترتيب الأولويّات.</p><p>فعند برمجة طرف المستخدم يكون الفرق الأكثر أهمّية هو بين شيفرة العرض التّريحية الموجّهة نحو المستند من جهة، وبين شيفرة JavaScript التي تتبع أسلوب الأوامر والمقادة بالبيانات والتي تعالج منطق العمل والبنية التحتية للتطبيق من جهة أخرى.</p><p>أنا سعيدٌ لأن Angular ركّزت على ذلك فهذا انتصارٌ كبيرٌ لها، وقد يصبح ذات يومٍ فصل منطق العمل عن باقي مسؤوليات المتحكّم هو الأمر الأكثر أولويّة، وقد نرى توجّهات نحو نموذج أغنى.</p></div><div id="wmd-preview-section-110"><h2 id="التوابع">التوابع</h2><p>لنقم بكتابة متحكّم يكشف عن تابع بسيطٍ جدًّا، فقط لنختبر إمكانية استدعاء التوابع داخل العرض.</p><p>لا بد من أنّك تذكر من الفصل الماضي أن Angular لا تسمح بتعريف التوابع داخل العرض.</p><p>المتحكّم التّالي يقوم بإسناد تابع بسيط إلى عنصرٍ في العرض.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function CountController($scope) {
    $scope.count = function() { return 12; }
}</pre><p>ويمكننا استدعاء التّابع في العرض بكتابة شيفرة JavaScript عاديّة، اسم العنصر مع أقواس، فقط.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="CountController"&gt;
    There are {{count()}} months in a year.
&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">There are 12 months in a year.</pre><p>لاحظ أن التّابع لم يتم استدعاؤه ونسيانه بعد ذلك ببساطة، بل تمّ ربطه بالنّموذج.</p><p>ما الذي يعنيه ذلك؟ ربّما بدأت بالتسليم بأن البنية التحتية في Angular هي الربط (binding)، ومرّة أخرى سأكرّر: لا تقوم Angular باستدعاء التّابع فقط عندما يتم إخراج العرض للمرة الأولى فقط، بل في أيّ وقتٍ يتم فيه تغيير النّموذج المرتبط، لنتمكّن من رؤية ذلك أثناء العمل سيتوجّب علينا كتابة تابع يستخدم عنصرًا من النّموذج.</p><p>يستخدم التّابع add في المثال التّالي عنصرين في النّموذج، تم تعريفهما في المجال، وهما operand1 و operand1. <br>ستقوم Angular باستدعاء التّابع وإخراج النتيجة كلّما تغيّر أحد العنصرين أو كليهما.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function AdditionController($scope) {
  $scope.operand1 = 0;
  $scope.operand2 = 0;
  $scope.add = function() {
    return $scope.operand1 + $scope.operand2;
  }
  $scope.options = [0,1,2,3,4];
}</pre><p>لقد قمنا في الفصل الماضي بتغطية العديد من الأمثلة عن التّوجيه <span style="font-family:courier new,courier,monospace;">input</span> في Angular، لذا سنستخدم الآن التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:select">select</a> لتغيير قيم النّموذج. <br>لا بدّ من أنك لاحظت السّطر الأخير في الشّيفرة السابقة، حيث تمّ فيه تحضير نموذج خيارات options، وسنستخدم هذا النّموذج لبناء سلسلة داخل وسيط التّوجيه <span style="font-family:courier new,courier,monospace;">ng-options</span>. <br>سنستخدم العبارة <span style="font-family:courier new,courier,monospace;">x for x</span> في بناء السّلسلة، ورغم أنها قد تبدو بلا فائدة لأنها تعيد عناصر السلسلة الأصلية كما هي، إلا أن التّوجيه يحتاج إلى كتابتها على أي حال.(عندما يكون النّموذج مكوّنًا من مصفوفة كائنات objects وهو الأكثر شيوعًا، يمكنك كتابة بانٍ للسّلسلة يقوم بإخراج العنصر <span style="font-family:courier new,courier,monospace;">name</span> من الخيار المحدد، وذلك باستخدام <span style="font-family:courier new,courier,monospace;">x.name for x</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="AdditionController"&gt;
  &lt;select ng-model="operand1" ng-options="x for x in options"&gt;&lt;/select&gt;
  + &lt;select ng-model="operand2" ng-options="x for x in options"&gt;&lt;/select&gt;
  = {{add()}}
&lt;/p&gt;
</pre><p>إنه يعمل بشكل جيّد، ولكن بإمكاننا تحسين تصميم التّابع <span style="font-family:courier new,courier,monospace;">add</span> عن طريق التّعميم، الذي سيكون مفيدًا إن أردنا استخدام التّابع مع وسطاء غير operand1 و operand2. </p><p>فلنبدأ إذا بتعديل الشفرة ولنقم باستخراج الوسطاء من التابع.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function AdditionController($scope) {
  $scope.number = 2;
  $scope.add = function(operand1, operand2) {
    return operand1 + operand2;
  }
}</pre><p>يمكنك تمرير العناصر والقيم الفوريّة داخل العبارات، كما في JavaScript المعتادة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-controller="AdditionController"&gt;
  {{add(number, 2)}} is not the same as {{add(number, "2")}}
  &lt;br&gt;
  2 + 2 + 2 + 2 = {{add(2, add(2, add(2, 2)))}}
&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">4 is not the same as 22 
2 + 2 + 2 + 2 = 8</pre><p>لنقم الآن بالكشف عن تابع استدعاء خلفي (callback) يمكنه معالجة عملٍ ما.</p></div><div id="wmd-preview-section-111"><h2 id="الاستدعاءات-الخلفيةcallbacks">الاستدعاءات الخلفية (Callbacks)</h2><p>في الفصل السابق، قمنا بتمرير عبارة إلى التّوجيه <span style="font-family:courier new,courier,monospace;">ng-click</span> واستخدمناها للتّقليب بين قيمتين بوليانيتين للعنصر authorized، حيث قمنا بتهيئة القيمة الابتدائية للنموذج authorized باستخدام التّوجيه <span style="font-family:courier new,courier,monospace;">ng-init</span> ثم تلاعبنا بقيمته عن طريق استدعاء خلفيّ سطريّ، فكتبنا<span style="font-family:courier new,courier,monospace;"> "ng-click="authorized = !authorized</span>، لنقم الآن بتعديل المثال عن طريق نقل التهيئة ووضع المتغيّر في مكانه الصحيح، في المتحكّم.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function AuthController($scope) {
  $scope.authorized = true;
  $scope.toggle = function() {
    $scope.authorized = !$scope.authorized
  };
}</pre><p>والآن صار التّابع toggle متاحًا للاستخدام داخل المجال، والوسيط الذي سيتمّ تمريره للتوجيه <span style="font-family:courier new,courier,monospace;">ng-click</span> سيبدو كأنه استدعاء للتابع: <span style="font-family:courier new,courier,monospace;">()toggle </span>ولكنه ليس كذلك كما ذكرنا سابقًا، إنها فقط سلسلة نصّيّة سيتم معالجتها لاحقًا عندما يقوم المستخدم بالنقر على الزر.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-controller="AuthController"&gt;
  &lt;p&gt;
    The secret code is
    &lt;span ng-show="authorized"&gt;0123&lt;/span&gt;
    &lt;span ng-hide="authorized"&gt;not for you to see&lt;/span&gt;
  &lt;/p&gt;
  &lt;input class="btn btn-xs btn-default" type="button" value="toggle" ng-click="toggle()"&gt;
&lt;/div&gt;</pre><p>لا يزال المثال يعمل، والآن صار منطق التّابع toggle البسيط في مكانٍ أفضل.</p><p>تشرح الكتب عادةً تقنيّاتٍ لإدارة التعقيدات باستخدام أمثلة شديدة البساطة لإيصال الإحساس العام بفائدة هذه التقنية، وقد قمنا بذلك هنا أيضًا.</p><p>لقد طلبت إليك في الفصل الماضي أن تؤجّل حكمك على استخدام العبارات داخل نصوص HTML، فإذا كنت الآن قد أحببت طريقة Angular في تحسين نصوص HTML مع سلوك تفاعليّ، فقد تتساءل لم هذا التعقيد الزائد في المتحكّمات.</p><p>أحد الأسباب التّقليدية لنقل الشّيفرة من سياقٍ معقّد(كالقالب) إلى واحدٍ أبسط (كالمتحكّم) هو تسهيل الاختبار وتصحيح الأخطاء لاحقًا.</p><p>تتضح الفائدة من تسليم التعامل مع سلوك المستخدم إلى المتحكّم عندما نحتاج إلى كتابة شيفرات معقّدة، مثل مزامنة بيانات النّموذج مع المخدّم البعيد.</p></div><div id="wmd-preview-section-112"><h2 id="خلاصة">خلاصة</h2><p>تعرفنا في هذا الفصل على JavaScript بداخل Angular، مكتوبة على شكل متحكّمات، والتي تتحمل مسؤولية تحضير البيانات للعرض كما ينصّ نمط MVC. <br>تجعل المتحكّمات البيانات متاحةً للعرض عن طريق التصريح عن العناصر في كائن المجال <span style="font-family:courier new,courier,monospace;">scope$</span>.</p><p>في الفصل القادم سنأخذ نظرة أقرب <a href="https://academy.hsoub.com/programming/javascript/angularjs/%D8%A7%D9%84%D9%85%D8%AC%D8%A7%D9%84%D8%A7%D8%AA-scopes-%D9%81%D9%8A-angularjs-r188/">لكائنات المجال</a>، وسنتعرّف على كيفيّة تنظيمها في بنيةٍ هرميّة تتبع تقريبًا بنية الجزء الذي نعالجة في تطبيقنا ضمن مستند.</p><p>ترجمة وبتصرّف <a rel="external nofollow" href="http://www.angularjsbook.com/angular-basics/chapters/controllers/">للفصل الثالث</a> من كتاب: <a rel="external nofollow" target="_blank" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p></div>
]]></description><guid isPermaLink="false">186</guid><pubDate>Sat, 10 Oct 2015 08:41:00 +0000</pubDate></item><item><title>&#x645;&#x628;&#x627;&#x62F;&#x626; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-angularjs-r176/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-basics.png.fcf213b2a3b53c3223ec09f687f9e726.png" /></p>

<p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-basics.png.ed384e34fe44ce982f0457087b7dc787.png"><img data-fileid="5333" class="ipsImage ipsImage_thumbnailed" alt="angularjs-basics.thumb.png.e25f9cc208cb0" src="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-basics.thumb.png.e25f9cc208cb0b675f145b16057d006a.png"></a></p><p><a rel="external nofollow" href="http://angularjs.org/">AngularJS</a> هي إطار عمل لتطبيقات الويب من طرف المستخدم يقوم بتفسير نصوص HTML مرة ثانية، ولو كنت خبيرا في تطوير الويب فمن الطبيعي أن تحاول مقارنة AngularJS مع منصات ومكتبات JavaScript التي تألفها مثل <a rel="external nofollow" href="http://jquery.com/">jQuery</a> ،<a rel="external nofollow" href="http://knockoutjs.com/">Knockout</a> ،<a rel="external nofollow" href="http://backbonejs.org/">Backbone</a> ،<a rel="external nofollow" href="http://emberjs.com/">Ember</a> وربّما مع <a rel="external nofollow" href="http://facebook.github.io/react/">React</a> أيضا، وربما حاولت بناءً على معارفك السابقة ببرمجة واجهة المستخدم الرسومية <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Graphical_user_interface">GUI</a> أن تربط AngularJS بـ<a rel="external nofollow" href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a> أو <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</a>، إلّا أنّ هذه المقارنات ستجعل معرفتك بـAngularJS أكثر ضبابية، لذا سأطلب منك في هذا الفصل فقط أن تتوقف عن النظر إلى AngularJS على أنها إطار عمل للغة JavaScript، كما أرجو منك أن تتخلّى في البداية عن رغبتك في فهم آلية عمل Angular وأن تحاول أخذها كما هي دون تفاصيل، فلتعتبرها مجموعة قوية من التطويرات لـHTML.</p><p>سنبدأ دروسنا مع البنى الثّلاث الأساسيّة في AngularJS : العبارات expressions، التّوجيهات directives والمجالات scopes ولكننا سنبدأ قبل ذلك بالتعرف على كيفية تشغيل Angular في صفحة ويب.</p><h2 id="التثبيت">التثبيت</h2><p>يمكنك جلب Angular من <a rel="external nofollow" href="https://angularjs.org/">الموقع الرسمي</a> ثم تحميلها إلى صفحتك عن طريق <a rel="external nofollow" href="https://developers.google.com/speed/libraries/devguide?hl=ja#angularjs">المكاتب المستضافة عند Google</a> (كـ<a rel="external nofollow" href="http://en.wikipedia.org/wiki/Content_delivery_network">CDN</a>) وهي طريقة ملائمة وتعمل جيدا، وقد قمنا بتشغيل شيفرات Angular عن طريق إضافة الاستدعاء التّالي في رأس ملف HTML:</p><p><strong>index.html</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"&gt;&lt;/script&gt;</pre><p>والآن بإمكاننا البدء معًا.</p><p>بعد تضمينك لملف المكتبة في رأس الصفحة ستكون الخطوة الأولى تحديد الجزء الذي ستعالجه Angular داخل مستند HTML، تذكر دومًا أن Angular موجّهة نحو HTML أكثر من توجهها نحو JavaScript، فمبدؤها العام هو: بدلا من كتابة شيفرة JavaScript ثم تنفيذها، نقوم بكتابة خصائص HTML غير معياريّة تفهمها Angular وتقوم بمعالجتها.</p><p>وهنا سنتعرّف على الخاصّية الأولى <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngApp">ng-app</a> التي يمكن إضافتها إلى أي عنصر من عناصر مستند HTML، وقد اخترنا وضعها كخاصية للعنصر <code>body</code> في مثالنا هذا، فعند وضعها في <code>body</code> أو في <code>html</code> ستقوم Angular بمعالجة المستند كاملًا بحثًا عن تعليماتها لتقوم بتنفيذها، وبالطّبع يمكنك تحديد مجال أضيق كفقرة أو عنوان فقط، إن أردت أن تستعمل بيئة عمل أخرى إلى جانب Angular أو تحميل عدّة تطبيقات لـAngular في نفس المستند.</p><p>إذًا لنكتب في المستند الذي نعمل عليه الشيفرة التالية:</p><p><strong>index.html</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;html&gt;
    &lt;head&gt;
        &lt;script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body ng-app&gt;
        &lt;!-- كل الأمثلة توضع هنا --&gt;
    &lt;/body&gt;
&lt;/html&gt;
</pre><p>بهذه الخاصية السحرية سنتمكن من جعل Angular تعالج تعليماتها الموجودة داخل الصفحة، والآن لنتعرف على إمكانيات هذه المكتبة وما الذي يمكنها فعله.</p><h2 id="العبارات-expressions">العبارات Expressions</h2><p><strong>تحذير</strong>: إذا كنت تتبنّى فكرة <a rel="external nofollow" href="https://ar.wikipedia.org/wiki/%D8%AC%D8%A7%D9%81%D8%A7_%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA_%D8%A7%D9%84%D9%85%D8%AE%D9%81%D9%8A%D8%A9">إخفاء شفرات جافا سكريبت</a> فالمثال التالي سيثير حفيظتك حول Angular فهي تعتمد على كتابة عبارات شبيهة بعبارات JavaScript داخل نصوص HTML.</p><p>تشمل عبارات Angular أي عبارة بسيطة وصحيحة في JavaScript إلّا أنّها لا تسمح بتعليمات التّحكم بسير البرنامج مثل الحلقات وغيرها، وأرجو منك تأجيل أحكامك المسبقة بينما نستكشف الأمور المسموحة (والتي يمكن ألا تكون مستحسنة) في Angular بطرق التّجريب التّقليدية.</p><p>لنبدأ بجمع عددين إلى بعضهما:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;The number {{11 + 12}}.&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">The number 23.</pre><p>هيا انطلق، قم بتغيير 12+11 في المثال السابق إلى أي عبارة رياضيّة أخرى، جرب إن كان بإمكانك إيجاد شيء لا يمكن لـAngular معالجته (عندما تفشل Angular في معالجة عبارة ما، فإنّها تعرض السلسلة الأصلية دون تغيير، أو لا تعرض شيئا في بعض الحالات الأخرى).</p><p>الأقواس المتعرجة المزدوجة هي التي تحدد قالب Angular، وقد تكون قد شاهدتها من قبل لو تعاملت مع <a rel="external nofollow" href="http://mustache.github.io/">Mustache</a> أو مع <a rel="external nofollow" href="http://handlebarsjs.com/">Handlebars</a>، أحيانًا يمكنك التّفكير في Angular بانها مكتبة قوالب شديدة التعقيد، فهي تتعامل مع كل شيءٍ داخل العنصر الذي قمت بإضافة الخاصية <code>ng-app</code> إليه على أنه قالب وتقوم <a rel="external nofollow" href="http://docs.angularjs.org/guide/compiler">بترجمته</a> عند تحميل الصّفحة، ثم تقوم بإعادة عملية الإخراج كلما حدث تغيير على البيانات (لا تقلق إن لم يكن مفهوم القوالب مألوفًا لك فسوف نتطرّق إلى مبادئه لاحقًا).</p><p>ماذا عن اختبار المساواة لقيمتين؟ بالطّبع يمكننا القيام بهذا أيضًا.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;Are strings and numbers equal? {{'2' == 2}}&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Are strings and numbers equal? true</pre><p>النّتيجة موافقةٌ لما هي عليه في JavaScript، إذا كنت متفاجئًا بناتج عمليّة المقارنة السّابقة فقم بمراجعةٍ سريعة لعملية المقارنة ثم قم بتغيير == إلى === في المثال السّابق، لترى اختلاف النّتيجة.</p><p>فيما يلي مثال لدمج سلسلتين نصيتين، ويوضح قدرتنا على الوصول إلى توابع مكتبة JavaScript المعيارية مثل توابع السلاسل النصية كالتابع toUpperCase.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;code&gt;&lt;p&gt;{{"Angular" + "js".toUpperCase()}}&lt;/p&gt;&lt;/code&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">AngularJS</pre><p>هل تشعر الآن بأنّه بإمكانك القيام بأي شيء داخل عبارات Angular؟ لا تكن متسرّعًا يا شريك، وانظر إلى المثال التّالي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;!-- كود خاطئ! هذه الدالة ليست مسموح بها داخل عبارة --&gt;
&lt;p&gt;{{alert("Hello world")}}&lt;/p&gt;</pre><p>لا يمكنك استخدام التّابع <code>alert</code> كما لا يمكنك الوصول إلى معظم الكائنات العامة مثل <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math?redirectlocale=en-US&amp;redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FMath">Math</a>، <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number?redirectlocale=en-US&amp;redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FNumber">Number</a> و <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date?redirectlocale=en-US&amp;redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FDate">Date</a> وهلم جرا.</p><p>حاول استبدال <span style="font-family:courier new,courier,monospace;">("</span><code><span style="font-family:courier new,courier,monospace;">alert("Hello world</span> </code>في المثال السّابق بـ <span style="font-family:courier new,courier,monospace;">("</span><code><span style="font-family:courier new,courier,monospace;">parseInt("1</span> </code>أو  <span style="font-family:courier new,courier,monospace;">()</span><code><span style="font-family:courier new,courier,monospace;">Date.now</span> </code>أو <span style="font-family:courier new,courier,monospace;"><code>Number.Nan</code></span> أو <span style="font-family:courier new,courier,monospace;">()<code>Math.random</code></span>، إن لم تنتج أي مخرجات فهذا يعني أن Angular قد رفضت معالجة العبارة.</p><p>لا بد من أن التساهل في مسألة دمج الشيفرة التنفيذية مع نصوص HTML قد أتعبك، وزاد عليه محدوديّة ما يمكنك القيام به داخل عبارات Angular، ولكن لا تتوقّف هنا فهناك الكثير بانتظارك، لنحاول الوصول إلى حدود إمكانيات العبارات في Angular، هل تظن بأنها تسمج بإسناد المتغيرات؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;{{a = 1; a + a}}&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">2</pre><p>إنها تعمل، ولكن حاول إضافة الكلمة المفتاحية <span style="font-family:courier new,courier,monospace;"><code>var</code></span> إلى اسم المتغير، فلن تقوم Angular بمعالجة العبارة وستصدر خطأ، فعندما ترى العبارة كما هي مع الأقواس المتعرجة فهذا يعني حدوث خطأ في الترجمة، لا تشعر بالاستياء، فتخريب الأشياء يكون أحيانًا وسيلة ممتازة للتعلم.</p><p>هكذا تكون التجربة، لا أدري إن كان بالإمكان تعريف متغيّر في مجموعة من الأقواس المتعرّجة ثمّ استخدامه داخل مجموعة أخرى، لم لا نجرّب ذلك؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;{{a = 1}} remains {{a}}&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1 remains 1</pre><p>إنّها تعمل أيضًا، ولكن ماذا لو نقلنا تهيئة المتغيّر إلى العبارة الثّانية؟ هيّا جرّبها، هل عملت؟ هل يمكنك معرفة <a rel="external nofollow" href="http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html">السبب</a> المحتمل وراء ذلك؟</p><p>حسنًا، العبارات تدعم عمليّة إسناد المتغيّرات، ما رأيك بتجربة معامل الشّرط الثلاثي؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;There {{count = 1; (count == 1 ? "is " : "are ") + count}} of them.&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">There is 1 of them.</pre><p>من حسن حظّنا أنها تعمل أيضًا، فهذه العمليّة الثلاثية توفّر لنا تركيبًا مختصرا عمليًا داخل القوالب، والآن ماذا عن عملية الزّيادة "++"، هل يمكننا استخدامها؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;{{a = 1; ++a}}&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1</pre><p>من الواضح أنّها لم تعمل، فهل هذا يعني بأنّ حلقة <span style="font-family:courier new,courier,monospace;"><code>for</code></span> غير موجودة في Angular، لم لا نستغني عن الكلمة <span style="font-family:courier new,courier,monospace;"><code>var</code></span> ونستبدل عملية الزّيادة "++" بجمع عادي.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;{{for (i = 0; i &lt; 10; i = i + 1) {i}}}&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">{{for (i = 0; i &lt; 10; i = i + 1) {i}}}</pre><p>لم يتمّ تشغيل شيفرة الحلقة، كما أنّها سبّبت إصدار خطأ نحوي يمكن رؤيته من نافذة المتصفح console، رغم أنّ الحلقة ليس فيها أي خطأ ويمكن نسخها ولصقها في النافذة ليتم تشغيلها وستصل إلى العدد 9، جرّبها لتتأكّد بنفسك.</p><p>إذًا لقد وصلنا إلى بعض الحدود، عبارات Angular ليست JavaScript، فـ<a rel="external nofollow" href="http://docs.angularjs.org/guide/expression">لغة العبارات</a> لا تدعم الشروط، الحلقات ولا رمي الأخطاء واستلامها.</p><p>يبدو أنّنا وصلنا إلى حدود العبارات، بالنّسبة لي فأنا أتقبّل وجود بعض شيفرات JavaScript داخل نص HTML إن كانت شيفرات مختصرة ومتعلقة بالعرض، لذا فأنا أقدّر الطبيعة المتساهلة لـAngular مع هذا الأمر، ولكن هذا لا يعني أنّني أشجع على كتابة شيفرات JavaScript أكبر من ذلك، فذلك سيتحوّل سريعًا إلى خربشات مربكة وغير مقروءة.</p><p>من الجيّد أنّ العبارات لا تلعب إلّا دورًا بسيطًا في Angular، ويجب ألّا يكون هناك داع لكتابة الكثير من الشيفرات داخل العبارة الواحدة، فالمفتاح الحقيقي للإنتاجيّة المذهلة لـAngular هو التوجيه directive.</p><h2 id="التوجيهات-directives">التوجيهات Directives</h2><p><a rel="external nofollow" href="http://docs.angularjs.org/guide/directive">التّوجيهات</a> هي روح Angular وقلبها النّابض، وأنصحك بأن تنظر إليها على أنها HTML معدلة، ففي كثير من الأحيان ترى أنها تشابه إلى حد كبير <a rel="external nofollow" href="http://en.wikipedia.org/wiki/HTML_attribute">خصائص HTML</a> التي يمكن استخدامها مع عناصر عاديّة ومألوفة.</p><p>تبدأ التوجيهات المدمجة مع Angular عادة بالسابقة <code>ng-</code> التي تدل على الحرفين الثاني والثالث من كلمة A**<strong>ng</strong>**ular، كما أنّك ستجد عددًا هائلًا من التّوجيهات التي برمجها <a rel="external nofollow" href="https://github.com/search?q=directive">طرف ثالث</a> متاحة للاستخدام.</p><p>أول ما عليك التفكير به عندما تواجه شيفرة JavaScript مطولة داخل أحد التعبيرات في Angular هو أنه <strong>لا بد من وجود توجيه يقوم بذلك</strong>.</p><p>لقد قمنا باستخدام أحد التّوجيهات مسبقًا بالفعل، هل تذكر التّوجيه الذي يجعل Angular تعالج محتويات العنصر <code>body</code>، إنه التوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngApp"><code>ng-app</code></a>، ففي هذه الحالة استخدمنا التوجيه دون تمرير أي وسطاء إليه، ولتمرير الوسطاء إلى التوجيهات ما عليك سوى استخدام "=" كما تقوم بإسناد القيم إلى خصائص HTML تمامًا.</p><p>يمكنك على سبيل المثال تمرير اسم التّطبيق كوسيط "<code>ng-app="myApp</code>. (اسم التطبيق يشكل فعليا اسم وحدة وهي جزء هام من بنية Angular، وسنقوم بتغطيته في فصل الوحدات)</p><h3 id="ng-bind">ng-bind</h3><p>تقبل بعض التوجيهات تمرير سلاسل نصية تحوي عبارات لتقوم بتفيذها، (يمكنك التعرف على محددات كل توجيه من التوجيهات بزيارة <a rel="external nofollow" href="http://docs.angularjs.org/api">توثيق <abbr title="واجهة برمجية | Application Programming Interface">API</abbr></a> الخاصّبه)، فمثلًا يقوم التوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngBind">ng-bind</a> بمعالجة العبارات وإخراجها، تمامًا كالأقواس المتعرّجة المزدوجة التي رأيناها في الفقرة السابقة، والمثال التالي يوضح استخدامه:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p&gt;The number &lt;span ng-bind="11 + 12"&gt;&lt;/span&gt;.&lt;/p&gt;</pre><p><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">The number 23.</pre><p>قد تجد أنّ المثال السابق مطابق لأول مثال تطرّقنا إليه، إلا أنّ هناك فرقًا هاما هو أن <code>ng-bind</code> تسبب إخفاء العبارة ريثما تقوم Angular بالترجمة وعملية الإخراج، ولذلك فهي الطريقة الأكثر تفضيلًا لاستخدام العبارات في Angular، فأثناء فتح الصّفحة وترجمتها ثمّ إخراجها لن تظهر العبارات والأقواس المتعرّجة، ولك أن تتخيّل شكل صفحة مليئةٍ بالعبارات قبل أن تنتهي عمليّة الإخراج خصوصًا إن كان هناك تأخير كبير بسبب كِبَرِ حجم الصّفحة وكثرة عباراتها.</p><p>ربما ترغب في إخفاء كامل المحتوى أو جزءًا كبيرًا منه ريثما تنتهي عمليّة الإخراج بشكل كامل، وهذا ما تتيحه لك <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngCloak"><code>ng-cloak</code></a>، <strong>لا بد من وجود توجيه يقوم بذلك</strong>.</p><h3>ng-init</h3><p>هل تذكر قيامنا بتهيئة المتغيّر في العبارة لنرى هل يعمل أم لا، حسنًا لا بدّ أن تحزر الآن، هناك توجيهٌ للقيام بهذا أيضًا، فالتّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngInit">ng-init</a> يسمح لك بتهيئة المتغيّرات لاستخدامها في أي مكان داخل العنصر الذي طبقت هذا التوجيه عليه.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="line-height: 22.4px;">&lt;div ng-init="sum = 3 + 2"&gt;
  &lt;p&gt;
    {{sum + 1}} is more than
    &lt;span ng-bind='sum - 1'&gt;&lt;/span&gt;
  &lt;/p&gt;
&lt;/div&gt;</pre><p style="line-height: 22.4px;"><strong>الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="line-height: 22.4px;">6 is more than 4</pre><p>كما يمكنك استخدام الفاصلة المنقوطة لتعريف عدّة متغيّرات داخل توجيه <code>ng-init</code> كما يوضّح المثال التّالي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init="count = 7; units = 'days'; collection = 'week'"&gt;
  &lt;p&gt;
    There are {{count}} {{units}} in a {{collection}}.
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">There are 7 days in a week.</pre><p>وقد تجد عند مرحلة ما أنه من الضروري تنظيم متغيّراتك داخل كائنات.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init="time = {count: 12, units: 'months', collection: 'year'}"&gt;
  &lt;p&gt;
    There are {{time.count}} {{time.units}} in a {{time.collection}}.
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">There are 12 months in a year.</pre><p>والمصفوفات مفيدة أيضًا.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init="months = ['January','February','March','April']"&gt;
  &lt;p&gt;
    {{months[3]}} follows {{months[2]}} in {{months}}.
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">April follows March in ["January","February","March","April"].</pre><p>انتبه، فلا مجال للخطأ في أسماء العناصر داخل الكائن، فـAngular لا تساعدك في تحديد هذا الخطأ وكلّ ما تقوم به هو عدم ترجمة العبارة وتجاهلها، وكذلك الحال في أخطاءِ الوصول إلى عناصر كائنٍ غير موجود أصلًا والوصول إلى عناصر خارج حدود المصفوفة.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init="paragraph = {sentence: {words: ['first','second','third']}}"&gt;
  &lt;p&gt;
    "{{typo.sentence.words[0]}}",
    "{{paragraph.typo.words[1]}}",
    "{{paragraph.sentence.typo[2]}}",
    "{{paragraph.sentence.words[3]}}".
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">"", "", "", "".</pre><p>كنت أتمنّى لو أن Angular تحتوي على عملية <a rel="external nofollow" href="http://coffeescript.org/#operators">اختبار الوجود</a> كالموجودة في CoffeeScript لجعل التّساهل مع هذه الأخطاء خيارًا وليس القاعدة.</p><p>والآن بعد أن رأينا سماحيّات Angular هل تتوقع بأنها تسمح بتعريف التوابع داخل <code>ng-init؟</code> ما الذي تتوق<span style="color: rgb(0, 0, 0); font-size: 15px; line-height: normal;">There are months in a year.</span>عه؟</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init="count = function() { return 12; }"&gt;
  &lt;p&gt;
    There are {{count()}} months in a year.
  &lt;/p&gt;
&lt;/div&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">There are months in a year.</pre><p>لا، لا تسمح Angular بعبارات تعريف التوابع، كما أنها تقوم برمي خطأ parse:syntax$ أثناء معالجة الوسيط الممرّر للتوجيه <code>ng-init</code>، ويمكنك رؤيته في نافذة المتصفح console، فالمتحكم هو المكان الصحيح لتعريف التوابع لاستخدامها في عبارات Angular، وسنتعرف عليها في فصل المتحكمات وهي في الحقيقة المكان المناسب لتحضير جميع بيانات التطبيق للعرض، أمّا التّوجيه <code>ng-init</code> فوظيفته الأساسية هي تغيير أسماء المتغيرات لسبب سنراه لاحقًا في فصل المجموعات.</p><h3 id="ng-non-bindable">ng-non-bindable</h3><p>يمكن استخدام التوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ng-non-bindable"><code>ng-non-bindable</code></a> لمنع Angular من معالجة جزء من المستند، كما يوضح المثال التالي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-non-bindable&gt;
  {{2 * 2}} is the same as &lt;span ng-bind='2 + 2'&gt;?&lt;/span&gt;
&lt;/p&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">{{2 * 2}} is the same as ?</pre><p>جرب إزالة التوجيه السابق لترى ما سيحدث.</p><h3 id="ng-show">ng-show</h3><p>حان الوقت للتّعرف على أمور أكبر من مجرّد معالجة وإخراج ناتج عبارة، سؤالٌ للمبتدئين: كيف يمكننا إظهار وإخفاء عنصر HTML حسب شرطٍ ما؟</p><p>احتجت مرة لإخفاء نموذج استمارةٍ بعد أن يقوم المستخدم بملئها بنجاح، فقمت بإضافة استدعاء للتابع <a rel="external nofollow" href="http://api.jquery.com/hide"><code>jQuery.hide</code></a> داخل متحكّم قمت بإنشائه في Angular، لقد عمل بشكل صحيح رغم أن تلك الطريقة ليست هي الأفضل للقيام بذلك، ولكن الرغبة في إنهاء المشروع سريعًا دفعتني لتجنب البحث عن <em>التّوجيه الّذي يقوم بذلك</em> في Angular، وبالفعل وجدت توجيهين للقيام بذلك لا واحدًا فقط، <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngHide">ng-hide</a> و<a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngShow">ng-show</a> وسيبيّن المثال التالي استخدامهما معًا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-init="authorized = true"&gt;
  The secret code is
  &lt;span ng-show="authorized"&gt;0123&lt;/span&gt;
  &lt;span ng-hide="authorized"&gt;not for you to see&lt;/span&gt;
&lt;/p&gt;</pre><p><strong style="line-height: 22.4px;">الناتج</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">The secret code is 0123</pre><p>جرّب تغيير <code>true</code> إلى <code>false</code> في المثال السابق لترى ما سيحدث، إنّ Angular تراقب التحديثات الّتي تطرأ على المتغيرات طوال الوقت، ولذلك فسيؤدّي تغيير المتغير <code>authorized</code> في أي مكان إلى تغيير نتيجة المثال السابق في العرض.</p><p>أرى أنه يمكننا التعمق الآن في الحديث عن المتغيرات لنعرف ماهيّتها الحقيقيّة.</p><h2 id="المجالات-scopes">المجالات Scopes</h2><p>تُعدّ المجالات مصدر البيانات الوحيد داخل تطبيقك، والفكرة من ورائها هي أنّه مهما كان عدد الأماكن الّتي تسخدم فيها المتغيّر في طبقة العرض، يجب عليك الالتزام بموضع واحدٍ لتغيير قيمته ويجب أن ينتشر هذا التغيير تلقائيًا إلى أماكن استخدام هذا المتغيّر في العرض.</p><p>بما أنّ عملية الإخراج وإعادة الإخراج تحتاج بنيةً تحتيّة، فأكثر ما ستلاحظه في كائنات JavaScript الّتي تضعها في <a rel="external nofollow" href="https://docs.angularjs.org/guide/scope">مجالات</a> Angular هو كم هي مألوفة واعتياديّة بالنسبة لك.</p><p>قد تكون ملمًّا بمفهوم كائنات نموذج المجال القديمة البسيطة، والذي أصله كائنات Java القديمة البسيطة أو ما يُعرف اختصارًا لـPOJO، فعندما قام Martin Fowler <a rel="external nofollow" href="http://www.martinfowler.com/bliki/POJO.html">بشرح مفهوم POJO</a> للمرّة الأولى، كان يعني الكائنات الأساسيّة الاعتياديّة التي يقدّمها قلب اللغة في وقت التشغيل runtime، على عكس كائنات نموذج المجال domain model المعقّدة الّتي ترث قدرات خاصّة من فئة متفوّقة superclass في إطار العمل.</p><p>لقد تمّ توسيع هذا المصطلح ليشمل الكائنات التي <em>تبدو</em> بأنّها بسيطة إلّا أنّ إطار العمل يحسّنها بإضافة قدرات خاصّة بشكل خفي في وقت التشغيل بشكل مستمر عادة.</p><p>الكائنات المرتبطة بمجالات Angular هي POJOs خاصة بـJavaScript، ويبدو أن Angular ستصبح حقا إطار عمل جافا سكربت البسيطة القديمة عندما سينتشر استخدام الميزة الجديدة Object.observe بين أوساط المبرمجين، وذلك لأنّها تقوم بعمليات معقدة للتّعرف على التّغييرات أثناء وقت التشغيل لتسمح بانتشار تأثير هذه التّغييرات.</p><p>لقد مررنا مسبقاً على العديد من خصائص المجالات scope properties في هذا الفصل، هل تذكر المتغيّر الّذي قمنا بتهيئته داخل العبارات واستخدمنا ng-init في المثال أعلاه، كلّ هذه كانت من خصائص المجالات، هل تذكر محاولة إضافة الكلمة المفتاحية var إلى إحدى العبارات؟ إنّ استخدامها ممنوعٌ لأنّ ما كنت أقول بأنه متغيّرٌ لم يكن كذلك في الحقيقة(وأعتذر لأنّني كذبت بشأنه) فهو في الحقيقة أحد الخصائص في كائن المجال، يتمّ إنشاؤه تلقائياً خلف الكواليس وسنغطّي في الدّرس القادم المجالات بتفاصيل أعمق، وسنكتفي هنا ببعض الأمثلة الّتي تبين كيفيّة استخدام خصائص المجالات.</p><h3 id="الربط-ثنائي-الاتجاه">الربط ثنائي الاتجاه</h3><p>كل الأمثلة السّابقة كانت تستخدم ربطًا أحادي الاتجاه، حيث يتم تحديث بيانات المجال باستمرار في العرض view، وسيزداد الأمر إثارةً عندما نستخدم HTML للتّحكم بهذه البيانات وتغييرها، ومعًا ستشكّل هاتان الطّريقتان في تغيير البيانات <em><a rel="external nofollow" href="https://docs.angularjs.org/guide/databinding">الربط ثنائيّ الاتّجاه</a></em> كمثال مبدئي أوّل، سنستخدم التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngClick">ng-click</a> للتعديل على خاصّية بوليانية boolean.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;p ng-init="authorized = true"&gt;
  The secret code is
  &lt;span ng-show="authorized"&gt;0123&lt;/span&gt;
  &lt;span ng-hide="authorized"&gt;not for you to see&lt;/span&gt;
  &lt;br&gt;
  &lt;input type="button" value="toggle" ng-click="authorized = !authorized"&gt;
&lt;/p&gt;
</pre><p>يمكن أن يكون الوسيط الممرّر للتوجيه <span style="font-family:courier new,courier,monospace;"><code>ng-click</code></span> أي عبارة، ورغم أنّ هذا التّوجيه غير محدود بالعمل ضمن خصائص المجالات، إلا أن الشّيفرة الّتي كتبناها لقلب القيمة البوليانية تعمل بشكل صحيح لأنها بسيطةٌ جدًّا، ولكن كيف يمكننا ربط أدوات الدّخل الأخرى والتّعامل مع أنواع متغيّرات أكثر تعقيدًا؟</p><h3 id="ng-model">ng-model</h3><p>يبدو أنّ جميع شروحات Angular لربط البيانات تسخدم مثالًا لربط دخلٍ نصّيّ بخاصّيةٍ من نوع سلسلةٍ نصّيّة، وها قد حان دورنا لكتابة هذا المثال.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;input type="text" ng-model="title"&gt;
    is bound to
    "&lt;strong ng-bind="title"&gt;&lt;/strong&gt;".
    Type something in the box!</pre><p>هذا المثال هو الطّريقة الأمثل لتوضيح مسألة الربط ثنائيّ الاتجاه، فعندما نضيف التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:ngModel">ng-model</a> إلى عنصر <span style="font-family:courier new,courier,monospace;"><code>input</code></span> الخاصّ بـHTML، فإنّ Angular تقوم بتغليف تحكّم HTML به عن طريق توجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:input">input</a> الخاصّ بها.</p><p>ما الذي يمكننا القيام به أكثر من هذا؟ بإمكاننا دومًا استخدام <span style="font-family:courier new,courier,monospace;"><code>ng-init</code></span> لتهيئة قيمة ابتدائية للخاصية.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;input type="text" ng-init="title = 'Angular'" ng-model="title"&gt;
    is bound to
    "&lt;strong ng-bind="title"&gt;&lt;/strong&gt;".
    Change it!</pre><p>لنجرّب الآن بعض أدوات الإدخال الأخرى، لنبدأ بـ<a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:input.checkbox">checkbox</a>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;input type='checkbox' ng-init='optIn = true' ng-model='optIn'&gt;
    is bound to
    &lt;strong ng-bind="optIn"&gt;&lt;/strong&gt;.
    Change it!</pre><p>القيمة المرتبطة بصندوق <code>checkbox</code> يمكن أن تكون سلسلةً نصّيّةً بدلًا من كونها قيمة بوليانيّة، وذلك بتأهيل قيمة كلٍ من التّوجيهين <span style="font-family:courier new,courier,monospace;"><code>ng-true-value</code></span> و<span style="font-family:courier new,courier,monospace;"><code>ng-false-value</code></span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;input type='checkbox' ng-init='feeling = "love it"' ng-model='feeling'
    ng-true-value='"love it"' ng-false-value='"hate it"'&gt;
is bound to
"&lt;strong ng-bind="feeling"&gt;&lt;/strong&gt;".
Change it!</pre><p>هل يمكنك توقّع وظيفة التّوجيه <a rel="external nofollow" href="http://docs.angularjs.org/api/ng.directive:select">select</a> في Angular؟ لاحظ أنّ Angular تتجاهل تمامًا وجود الخاصّية <span style="font-family:courier new,courier,monospace;"><code>selected</code></span> في الخيارات المقدّمة، وحتّى لو قمت بإزالة التّوجيه <span style="font-family:courier new,courier,monospace;"><code>ng-init</code></span> فستبقى بلا تأثير.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;select ng-init='answer = "maybe"' ng-model='answer'&gt;
  &lt;option value='yes' selected&gt;Yes&lt;/option&gt;
  &lt;option value='no'&gt;No&lt;/option&gt;
  &lt;option value='maybe'&gt;Maybe&lt;/option&gt;
&lt;/select&gt;
is bound to
"&lt;strong ng-bind="answer"&gt;&lt;/strong&gt;".
Change it!</pre><p>يبدو أنّ المثال السّابق يناسبه وجود <span style="font-family:courier new,courier,monospace;"><code>radio buttons</code></span> أكثر من قائمة الخيارات، هيّا نغيّره إذًا.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div ng-init='answer = "maybe"'&gt;
  &lt;input type='radio' ng-model='answer' value='yes'&gt; Yes
  &lt;input type='radio' ng-model='answer' value='no'&gt; No
  &lt;input type='radio' ng-model='answer' value='maybe'&gt; Maybe
  is bound to
  "&lt;strong ng-bind="answer"&gt;&lt;/strong&gt;".
  Change it!
&lt;/div&gt;</pre><p>لديك الآن بعض خبرات الواقع العمليّ في التّعامل مع بيانات المجالات باستخدام توجيهات Angular، ولا يزال هناك الكثير من التّوجيهات المدمجة في Angular، وسنتعرف على العديد منها في الفصول القادمة.</p><h2 id="خلاصة">خلاصة</h2><p>لقد طلبت منك في مطلع هذا الفصل ألا تنظر إلى Angular على أنها إطار عمل لـJavaScript، بل كامتداد لـHTML، فكما أخبَرَنا Miško Hevery مخترع Angular في <a rel="external nofollow" href="http://www.youtube.com/watch?v=X0VsStcCCM8">هذه المقابلة الرائعة</a> فإن الهدف الأساسي من Angular هو أن تكون طريقة لزيادة إنتاجية مطوري الـ front-end لتحسين صفحات الويب، وقد صارت لاحقًا إطار عمل لـJavaScript.</p><p>لقد تم الانطلاق من فكرة كون نمط <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Declarative_programming">البرمجة التصريحية</a> هو أفضل الخيارات لتسريع عملية تطوير واجهات المستخدم الرسومية GUI، وقد اختار مطوروها ألا تكون لغة محصورة في مجال محدد مثل ما كانت <a rel="external nofollow" href="http://en.wikipedia.org/wiki/MXML">MXML</a> و<a rel="external nofollow" href="http://en.wikipedia.org/wiki/XUL">XUL</a> بل أرادوا جعلها تعتمد على تشابهها الكبير مع نصوص HTML.</p><p>لقد رأينا بما يكفي أن Angular لا تستخدم دون JavaScript معدلة، كما أن التطبيقات في الواقع العملي في Angular تستخدم دومًا المتحكمات والخدمات والمسرات كما تدعم الوحدات وحقن التابعية إضافة إلى اعتمادها على البنية التحتية لـ<a rel="external nofollow" href="http://www.angularjsbook.com/angular-basics/chapters/http/">Ajax</a>، وسنغطي في هذه السلسلة جميع هذه الأمور، وعلى أي حال فإن وعد الإنتاجية الذي تقدمه Angular يمكن تحقيقه في فضاء تصريحي، مع درجة من الاعتماد على <strong>لا بد من وجود توجيه يقوم بذلك</strong>، كما أنّ كتابة توجيهات مخصصة لملء الفجوات هو الأمر الأكثر تحدّيًا في Angular، وهذا ما سيحاول الفصل الأخير إيصاله ليستقرّ في ذهن القارئ.</p><p>والآن بعد أن استوعبت أن الهدف الأسمى لـAngular هو إيجاد امتدادات لـHTML لزيادة الإنتاجيّة وليس كتابة شيفرات JavaScript داخل إطار عمل، فأنت الآن جاهز لتبحر في تفاصيلها مع الفصول القادمة.</p><p>ترجمة وبتصرّف <a href="http://www.angularjsbook.com/angular-basics/chapters/basics/" rel="external nofollow">للفصل الثاني</a> من كتاب: <a rel="external nofollow" target="_blank" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p>
]]></description><guid isPermaLink="false">176</guid><pubDate>Tue, 29 Sep 2015 22:45:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62A;&#x639;&#x644;&#x645; AngularJS</title><link>https://academy.hsoub.com/programming/javascript/angular/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-angularjs-r171/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-intro.png.16c6d6547291e07b30ca6bf6b17498ff.png" /></p>

<p>أقدّم بين أيديكم هذه السلسلة التي استلهمت فكرتها من كتب برمجة صغيرة مجّانيّة ومحبّبة، مثل كتاب <a rel="external nofollow" href="http://arcturo.github.io/library/coffeescript/index.html">The Little Book on CoffeeScript</a> لمؤلّفه Alex MacCaw. لقد ألّفت هذه السلسلة لتعليم Angular بالطّريقة التي تمنّيت أن أتعلمها بها، ولذلك فهذه السلسلة معينك للانطلاق السريع مع Angular واستخدام هذه المكتبة الرائعة في عملك كمطوّر ويب.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-intro.png.28c6f12f4668576ff76e1ec94681db12.png"><img data-fileid="4947" class="ipsImage ipsImage_thumbnailed" alt="angularjs-intro.thumb.png.19a99176e43c66" src="https://academy.hsoub.com/uploads/monthly_2015_09/angularjs-intro.thumb.png.19a99176e43c66bbccd966542cd27497.png"></a></p><p>أسلوب هذه السلسلة مستلهم من <a rel="external nofollow" href="https://ar.wikipedia.org/wiki/%D9%85%D8%A8%D8%AF%D8%A3_%D8%A8%D8%A7%D8%B1%D9%8A%D8%AA%D9%88">مبدأ باريتو Pareto</a> فهي تعلّمك جزءًا كبيرًا من نقاط قوّة Angular دون أن تثقل كاهلك بالكثير من تعقيداتها، وستتمكّن بعد إنهائك لهذه السلسلة من كتابة تطبيقات واجهة front-end قويّة، وستدهشك سهولة ذلك، بالرّغم من أنّ السلسلة لا تقدّم إلا جزءًا محدودًا ممّا عليك تعلّمه لاحتراف Angular بشكل كامل، لكنها ستمنحك الثّقة الكافية للقيام بذلك لأنّ خبرتك ستكون مبنيّة على التّجربة العمليّة أثناء قراءتك لدروسها، فهي بحدّ ذاتها صفحات ويب ديناميكيّة تحوي آخر نسخة من Angular وتستخدمها لتنفيذ جميع الأمثلة بشكل مباشر، وجميع الشّيفرات البرمجيّة تتيح التّعديل المباشر عليها ممّا يغيّر المخرجات مباشرة، وأتمنّى لو تقوم بكلّ التّجارب والتّعديلات التي تخطر على بالك عند كل مثال.</p><p>إذا كنت ترغب في معرفة سبب كتابتي لهذه السلسلة يمكنك قراءة هذه المقدّمة إلى نهايتها فهي تتضمّن بعضًا من ذكرياتي مع Angular، ثم سنناقش أفضليّة استخدام Angular في مشاريعك.</p><h2>هل هي صعبة أم سهلة؟</h2><p>لقد عملت من قبل على تطبيقات معتمدة على <a rel="external nofollow" href="https://ar.wikipedia.org/wiki/%D9%86%D9%85%D8%B7-%D8%B9%D8%B1%D8%B6-%D9%85%D8%AA%D8%AD%D9%83%D9%85_(%D8%A5%D9%85_%D9%81%D9%8A_%D8%B3%D9%8A)">Web MVC</a> لما يزيد عن عشر سنوات، واستعملت الكثير من الأدوات بدءًا من <a rel="external nofollow" href="http://struts.apache.org/">Struts</a> وانتهاءً بـ<a rel="external nofollow" href="http://projects.spring.io/spring-framework/">Spring MVC</a> مرورًا بـ<a rel="external nofollow" href="http://rubyonrails.org/">Ruby on Rails</a> و<a rel="external nofollow" href="http://backbonejs.org/">Backbone</a>، حتّى أنّني قمت بكتابة كتاب <a rel="external nofollow" href="http://www.scriptybooks.com/books/backbone-coffeescript">Backbone and CoffeeScript</a> لذا كان من الطّبيعي بالنّسبة لي أن أفترض أنّ تعلّم ِAngular سيكون بسيطًا بالنسبة لي، إلّا أنّ تقدّمي في تعلّمها واجه سدًّا كبيرًا من المصطلحات غير المألوفة بعد غوصي في توثيق هذه المكتبة، مصطلحاتٌ مثل <strong><em>transclusion</em></strong>، توجيه<em> <strong>directive</strong></em> والمجال المعزول<em> <strong>isolate scope،</strong></em> وكلّما قرأت أكثر في التّوثيق الرّسمي للّغة ودروسها تأكّدت أكثر بأنّني كنت أتوهّم عندما ظننت بأنّ Angular أداةٌ سهلة، وأتذكّر بشكل خاصّ مروري على <a rel="external nofollow" href="http://code.angularjs.org/1.0.7/docs/guide/directive#directivedefinitionobject">العبارة التّالية</a>:</p><blockquote><blockquote class="ipsQuote" data-cite="اقتباس" data-ipsquote=""><p>إنّ فائدة الـtransclusion تكمن في أنّ تابع الرّبط يستقبل تابع transclusion قد تمّ ربطه مسبقًا بالمجال الصحيح. تقوم الأداة بإنشاء مجال معزول في عمليّة تهيئة مثاليّة، إلّا أنّ الـtransclusion لا يكون ابنًا للمجال المعزول بل نسيبًا له، وهذا يسمح للأداة بأن يكون لها حالة خاصّة، ويسمح للـtransclusion بأن يكون مرتبطًا بمجال الأب (قبل العزل).</p></blockquote></blockquote><p>لن تجد العبارة السابقة هذه الأيام داخل توثيق اللّغة، والشّكر يعود للجهود الجادّة التي بذلها فريق ِAngluar لتحسين التّوثيق، وعلى أيّ حال فالاقتباس السّابق جعلني أشعر بالجهل وبدأت الشّكوك تراودني والقلق يساورني: هل هذه المكتبة مجال جديد كلّيّا عليّ؟ كانت الإجابة تأتيني من كلّ الجهات تقريبًا: إنّ ِAngular تقنيّة معقدّة، ولا مجال للعبث معها، ففي ملتقيات المبرمجين على <a rel="external nofollow" href="http://stackoverflow.com/questions/tagged/angularjs">Stack Overflow</a> و<a rel="external nofollow" href="https://groups.google.com/forum/#%21forum/angular">مجموعة AngularJS على Google</a> وفي كلّ مكان آخر، كانت تفاصيل هذه المكتبة محلّ النّقاشات المطوّلة، مع توثيقات مرعبة للمشاكل والأفخاخ والحيل فيها، فشمّرت عن ساعد الجد كأي محترف يحترم نفسه وقبلت هذا التّحدّي، ومع مرور الوقت أصبحت أكثر ألفة مع هذه المفاهيم والمصطلحات، وتقبّلت أنّ تعلّمي هذه الأداة سيكون بطيئًا، إلى أن جاء ذلك اليوم الذي شاهدت فيه <a rel="external nofollow" href="http://www.youtube.com/watch?v=X0VsStcCCM8">مقابلة</a> مع Miško Hevery مخترع Angular، وبعد ذلك اكتشفت حقيقة بسيطةً إلّا أنّها كانت شديدة الأهمّيّة:</p><blockquote><p><strong>الهدف الأصليّ من Angular هو سهولة الاستخدام.</strong></p></blockquote><p>لقد بيّن Hevery بأنّه أراد أن تكون Angular أداة ليستخدمها غير المبرمجين، ليتمكّنوا من بناء صفحات ويب ديناميكيّة باستخدامهم لنصوص تصريحية بسيطة، لقد اكتشفت بأنّني قد تعمّقت في الكثير من تفاصيل Angular دون أن أجني منها فائدة مكافئة للوقت والجهد المبذول، ورغم أنّ مشروع Angular ومجتمع Angular أصبحا معتمدين على بعضهما بشكل وثيق حيث تقدّم المكتبة التّحديات والتّعقيدات التي تشبع شغف هؤلاء، إلّا أنّه كان هناك طريق أفضل لاستخدام المكتبة كما أراد مخترعها، بعيدا عن مبدأ عملها المصنوع بعناية، وقد كان الصّواب بالنسبة إليّ الابتعاد عن هذه الأمور الدّاخليّة الدّقيقة وتركها آمنة لتقود كلّ شيء دون المساس بها، وبعد أن اعتمدت هذا المبدأ في التعامل معها وبالرّغم من وجود العديد من الأدوات الأخرى إلّا أنّ شمس Angular صارت تشرق لي عند مواجهة العديد من الحالات.</p><h2>هل تناسبك؟</h2><p>تعتمد إجابة هذا السّؤال على معرفتك لمشروعك بدقّة، فعليك معرفة فيما إن كان يحتاج بالفعل لمعالجة البيانات وإخراج HTML في طرف الزّبون، أم أنّك تخدع نفسك ببعض المتطلّبات الإضافيّة لتعطيها دافعًا لتعلّم أداة جميلة وجذّابة، فقد لا تلزمك Angular إن كان بإمكانك الاعتماد على بعض المعالجة من طرف الخادوم مع "رشّةٍ" من التّفاعل المعتمد على <a href="https://academy.hsoub.com/programming/javascript/jquery/">jQuery</a>.</p><p>ضع في حسابك أنّ Angular واسعة وتدعو للتشبّث بها، فبالرّغم من أنّنا ندعوها "مكتبة" إلا أنّ دعمها الذّاتي للـوحدات<em> modules</em> ولـحقن التّبعيّة<em> dependency injection</em> سيفرض على المطوّر طريقة إدارة مشروعه، وقد يُفضّل حلًّا آخر على Angular، ربّما سيختار أداة أقدم منها ومتميزةً بكونها الأفضل في وقتها، لكنّه قد يجد أنّه من الصّعب أو المستحيل أن تحلّ محلّ Angular، أضف إلى ذلك أنّك لن تحتاج إلى الدّعم الفنّي من فريق تطوير Angular إن لم تكن تنوي أن يصبح مشروعك كبيرًا بالقدر الّذي يعتبره مهندسو Google مثاليًّا.</p><p>هناك مشكلة أخرى تظهر عندما تحاول دمج شيفرات Angular مع شيفرات غير Angular وتريدها أن تعمل إلى جانب تغليف Angular للبيانات أو آلية إخراج الصفحة فيها، سيكون عليك عندها الغوص في تفاصيل غامضة في Angular غوصًا عميقا، قارن ذلك مع <a rel="external nofollow" href="http://backbonejs.org/">Backbone</a> التي تعد طبقة رقيقة فوق jQuery فهي أصغر وأقرب للفهم، وإن كان تطبيقك معتمدًا بشكل كبير على ملحقات jQuery فسيكون عليك استخدام Backbone لتزيد من التّحسين في تصميم تطبيقك.</p><p>أخيرًا، إنّ لطريقة Angular الأساسيّة للرّبط ثنائي الاتجاه بين عناصر واجهة المستخدم وكائنات النمذجة حدودًا تعتمد على مدى تعقيد التّطبيق، وقد تشارك المطوّرون في Facebook <a rel="external nofollow" href="http://facebook.github.io/react/docs/flux-overview.html">خيبة أملهم بربط البيانات ثنائيّ الاتجاه</a> فقالوا:</p><blockquote><blockquote class="ipsQuote" data-cite="اقتباس" data-ipsquote=""><p>لقد وجدنا أنّ استخدام ربط البيانات ثنائيّ الاتجاه سيؤدّي إلى تحديثات متعاقبة، حيث يؤدّي التّغيير في كائن واحد إلى التّغيير في كائن آخر، والّذي قد يؤدّي بدوره إلى قدح المزيد من التّحديثات في كائنات أخرى، و هذا يعني أنّه سيكون من الصّعب التّنبّؤ بالتّغييرات التي ستحصل نتيجة تفاعلٍ واحدٍ فقط من المستخدم مع الصفحة في المشاريع الكبيرة.</p></blockquote></blockquote><p>وبالرّغم من كون مكتبة <a rel="external nofollow" href="http://facebook.github.io/react/">React</a> الخاصة بـFacebook بالكاد تهتمّ بالإخراج ومن ثمّ فهي تعدّ حلّا جزئيًّا بالمقارنة مع Angular، إلّا أنّ تطبيقات طرف الزّبون التي تعتمد عليها تستحقّ التقدير حقًّا.</p><h2>أسباب هامة تدفعك لاستخدام Angular</h2><p>لا شك أنّ Angular هي أشهر مكتبات JavaScript المختصّة بحلول النّمذجة والعرض عالميًّا في هذه الأيام، فقد حصلت على أكثر من <a rel="external nofollow" href="https://github.com/angular/angular.js">33000 نجمة على GitHub</a>، وربّما ازدادت أكثر من ذلك بكثير منذ وقت كتابة هذه السلسلة إلى اليوم، فقد تربّعت على قمّة قائمة الحلول المطروحة التي تمّت دراستها ومقارنتها بواسطة مشروع <a rel="external nofollow" href="http://todomvc.com/">TodoMVC</a> وسنناقش الآن بعض أسباب نجاح Angular.</p><h3>الإنتاجية الآنية</h3><p>إذا كان مشروعك بحاجة إلى واجهة مستخدم معقّدة إلى حدّ ما لتقوم بعمليات إدارة البيانات <a rel="external nofollow" href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> على البيانات من طرف الزّبون، فإنّ Angular ستفي بوعدها لك بتحقيق إنتاجيّة شبه آنيّة، فبإضافتك لرشّةٍ من بعض الخصائص المميّزة غلى نصّ HTML الأصلي، والقليل من شيفرات Javascript، ستتمكّن من جعل صفحتك تتفاعل مع المستخدم، في حين كنت ستحتاج إلى الكثير من المهارات وبذل الجهود لتقوم بذلك باستخدام مكتبة أدنى مستوى.</p><h3>الألفة</h3><p>تعتمد Angular على كتابة شيفرات JavaScript السّهلة ونصوص مطابقة تقريبًا لتعليمات HTML، لقد قلت "تقريبًا" لأنّ Angular تقدّم عناصر وخصائص جديدة وبعض الشيفرات المستغربة، إلّا أنها بالمقارنة مع أنظمة القوالب الأخرى تبقى قريبةً جدًّا إلى HTML النّقيّة، وهذا يجعلها سهلة الفهم لأغلبية مطوري الويب.</p><h3>المرونة</h3><p>تتبنّى Angular التّوجّه الحالي نحو التكيف مع واجهات المستخدم في أطر عمل JavaScript، دون الكثير من التّضحية بإنتاجيّتها، فإن كنت تحبّ العمل مع أحد أطر العمل الشهيرة المختصة بواجهة المستخدم مثل <a href="https://academy.hsoub.com/programming/css/bootstrap/">Bootstrap</a> فستتمكّن من الاستفادة من الإضافة المقدّمة من مشاريع طرف ثالث مثل <a rel="external nofollow" href="http://angular-ui.github.io/">AngularUI</a> لتقوم بتكامل سهل.</p><p>لذا سواء كنت تريد زخرفة صفحة ويب تقليديّة ببعض التّطبيقات التفاعلية هنا وهناك، أو كنت تريد تطوير تطبيقٍ كاملٍ وحيد الصّفحة فإن Angular ستكون الأفضل للعمل ضمن شروطك ومحدداتك.</p><h3>المعايير المستقبلية</h3><p>لا أدري أيّهما أكثر صحّة، إن كانت Angular متبصّرة بالمستقبل أو أنّ Google والدةَ Angular ستصنع المستقبل، إلا أنّه من الواضح أنّ استخدامك لـAngular سيكون طريقة ناجحة لتألف المعايير المقترحة مثل <a rel="external nofollow" href="http://www.w3.org/TR/components-intro/">Web Components</a> وأضف إلى ذلك أنّني أتوقّع بقاء Angular واستمرارها لأنّها تواكب ميزات JavaScript المرتقبة مثل <a rel="external nofollow" href="http://wiki.ecmascript.org/doku.php?id=harmony:observe">Object.observe</a>.</p><h3>مجتمع Angular</h3><p>لابدّ أنّ أحد أقوى الأسباب لاختيار Angular بدلًا من منافساتها هو أنّها الأكثر شيوعًا، فهي تُستخدم الآن في عدد غير محدود من مواقع الويب كثيرة الزيارة، ولكن تذكّر بأنّ الجري وراء الأغلبية ليس الصّواب دومًا وليس لكلّ النّاس ولا في كلّ الأحيان، وعليك أن تدرس متطلّبات مشروعك الحقيقيّة بعناية.</p><h2>عن هذه السلسلة</h2><p>لقد جاءتني فكرة <a rel="external nofollow" href="http://www.scriptybooks.com/">الكتب التفاعلية</a> منذ عدّة سنوات أثناء قراءتي لكتاب إلكترونيّ عن البرمجة باستخدام JavaScript على حاسوبي المحمول، فقد توجّب عليّ لتجربة أحد أمثلة الكتاب أن أقوم بتحميله من موقع النّاشر، ثم البحث عن موضع الملفّ الذي تم تحميله وإيجاد مكان لفكّ ضغطه، ثم الإبحار عبر الكثير من الملفّات إلى أن أعثر على الشّيفرة المطلوبة، وأفتحها أخيرًا في أحد المحرّرات، ثمّ أكتشف بأنّ عليّ إنشاء ملف HTML ليُشغّل السكربت، وبعد كلّ هذا لا تعمل الشيفرة وأكون قد ضيّعت وقتي في مطاردة أماكن الملفّات والارتباطات.</p><p>لم كلّ هذا؟ إن كنت أقرأ كتابًا عن تقنية front-end على الحاسوب فهل عليّ أن أعاني كلّ تلك المعاناة لأشغّل المثال؟ لقد اكتشفت بعد مدّة قصيرة من ذلك النّسخةَ الأولى لكتاب Marijn Haverbeke المسمّى <a rel="external nofollow" href="http://eloquentjavascript.net/contents.html">Eloquent JavaScript</a> واكتشفت بأنّه بإمكاني استخدام مشروعه <a rel="external nofollow" href="http://codemirror.net/">CodeMirror</a> لأنشر رؤيتي الخاصّة: كتاب إلكترونيّ رائع المظهر، أنيق الحروف وجميل التّصميم، ولكن مع أمثلة حية قابلة للتّعديل والتّشغيل مباشرة من الدّرس ذاته، ولهذا ستجد جميع أمثلة السلسلة داخل محرّرات حيّة تفاعليّة، وستجد مخرجات هذه الشيفرات مباشرة تحت المثال داخل صندوق iframe.</p><div data-height="268" data-theme-id="19099" data-slug-hash="rOLMEQ" data-default-tab="html" data-user="HsoubAcademy" class="codepen"><pre><code>&lt;div ng-app=""&gt;

&lt;strong&gt;The lucky number {{11+12}}&lt;/strong&gt;

&lt;/div&gt;

</code></pre><p>See the Pen <a rel="external nofollow" href="http://codepen.io/HsoubAcademy/pen/rOLMEQ/">angular-intro</a> by Hsoub Academy (<a rel="external nofollow" href="http://codepen.io/HsoubAcademy">@HsoubAcademy</a>) on <a rel="external nofollow" href="http://codepen.io">CodePen</a>.</p></div><script async src="https://assets.codepen.io/assets/embed/ei.js"></script><p>هيّا حاول تغيير المثال أعلاه الآن، رغم أنك لم تتعلم شيئًا بعد عن Angular، قم ببعض التغييرات على المثال وراقب التّغييرات.</p><h2>ماذا بعد؟</h2><p>سيأخذك الفصل الأوّل من هذه السلسلة في رحلة لطيفة للتّعرف على مبادئ Angular في القولبة templating من طرف الزّبون وفي الرّبط ثنائيّ الاتّجاه، وقد أقرّ العديد من المطوّرين المحترفين في ِAngular بأنهم استفادوا من هذا الفصل رغم أنّ جميع أمثلته بسيطة ويمكن فهمها بلمحة سريعة.</p><p>ترجمة وبتصرّف للجزء الأول من كتاب: <a rel="external nofollow" href="http://www.angularjsbook.com/">Angular Basics</a> لصاحبه: Chris Smith.</p>
]]></description><guid isPermaLink="false">171</guid><pubDate>Sun, 20 Sep 2015 21:58:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x644;&#x64A;&#x644; &#x627;&#x644;&#x643;&#x627;&#x645;&#x644; &#x644;&#x62A;&#x639;&#x644;&#x645; Angular JS &#x641;&#x64A; &#x64A;&#x648;&#x645; &#x648;&#x627;&#x62D;&#x62F;</title><link>https://academy.hsoub.com/programming/javascript/angular/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%84-%D9%84%D8%AA%D8%B9%D9%84%D9%85-angular-js-%D9%81%D9%8A-%D9%8A%D9%88%D9%85-%D9%88%D8%A7%D8%AD%D8%AF-r11/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/angular_480x300.png.47fb89f1f6c83f1e91f4c4433f905c7b.png" /></p>

<h2>ما هو AngularJS؟</h2><p><strong>AngularJS</strong> هو إطار عمل JavaScript لطرف العميل يتبع بنية Model-View-Controller/Model-View-View-Model، ويعتبر اليوم مُهمًا لبناء تطبيقات ويب وحيدة الصفحة (SAP) أو حتى المواقع العادية. يُعتبر Angular JS قفزة كبيرة نحو مستقبل HTML وما يجلبه الإصدار الخامس منها (مع التطورات على صعيد JavaScript بالطبع!)، ويبعث الحياة من جديد في تعاملنا مع الويب الحديث. هذا المقال جولة شاملة في Angular JS مستخلصة من تجاربي ونصائح وممارسات تعلمتها خلال استخدامي.</p><p><a class="ipsAttachLink ipsAttachLink_image" rel="external nofollow" href="https://academy.hsoub.com/uploads/monthly_2015_02/angularjs-logo.png.4ff92a6765b63d4d48d5704dd1ec1577.png"><img class="ipsImage ipsImage_thumbnailed" data-fileid="9" alt="angularjs-logo.thumb.png.e1c62a999f100ed" src="https://academy.hsoub.com/uploads/monthly_2015_02/angularjs-logo.thumb.png.e1c62a999f100ed00170fc55a8a1463a.png"></a></p><h2>المُصطلحات</h2><p>ليس عليك أن تبذل جهداً كبيراً لتعلم Angular، وأهم ما يجب معرفته هو معاني المُصطلحات وتبني نمط MVC، وMVC هو اختصار لـ<em>Model-View-Controller</em>، أي <em>نموذج-طريقة عرض-مُتحكِّم</em>. فيما يلي بعض المصطلحات والواجهات البرمجية الأساسية التي تزوّدنا بها Angular.</p><h3>MVC</h3><p>ربما سمعت بهذا الاختصار من قبل، وهو مستخدم في لغات برمجة عديدة كوسيلة لبناء هيكل التطبيقات أو البرامج. وهاك تلخيص سريع لمعناه:</p><ul><li><strong>النموذج (Model):</strong> بنية البيانات التي تقوم عليها أجزاء التطبيقات، غالبًا ما تُمثل بصيغة JSON. يفضل أن تكون لديك معرفة مسبقة بـJSON قبل تعلم Angular، لأنها ضرورية للتواصل بين الخادوم وطريقة العرض (سنأتي على شرحها في النقطة التالية). على سبيل المثال، لنفترض أنه لدينا مجموعة من المستخدمين، يمكن تمثيل <em>بيانات تعريفهم</em> كما يلي:</li></ul><pre class="javascript ipsCode prettyprint">{
"users" : [{
    "name": "أحمد",
    "id": "82047392"
  },{
    "name": "سامر",
    "id": "65198013"
  }]
}</pre><p>عادة ما تُجلب هذه المعلومات من خادوم بطلب <code>XMLHttpRequest</code>، ويقابله في jQuery الإجراء <code>$.ajax</code>، وفي Angular الكائن <code>$http</code>. وقد تكون هذه المعلومات مكتوبة ضمن النص البرمجي أثناء تفسير الصفحة (من قاعدة بيانات أو مخزن بيانات). بعد ذلك يكون بإمكانك تعديل هذه المعلومات وإعادة إرسالها.</p><ul><li><strong> <em>طريقة العرض</em> (<em>View</em>):</strong> وهو أمر سهل التفسير، فهي ببساطة المُخرج النهائي أو صفحة HTML التي تعرض البيانات (النموذج) على المستخدم مثلاً. باستخدام إطار عمل MVC، تُجلب البيانات من النموذج وتُعرض المعلومات المناسبة في صفحة HTML.</li></ul><ul><li><strong><em>المُتحكِّم</em> (<em>Controller</em>):</strong> وله من اسمه نصيب، فهو يتحكم بالأشياء، ولكن أية أشياء؟ البيانات. المُتحكمات هي الطريقة التي تصل من خلالها بين <em>الخادوم</em> و<em>طريقة العرض</em>، فتسمح بتحديث البيانات سريعًا من خلال التواصل مع كلا الخادوم والعميل.</li></ul><h2>إعداد مشروع Angular JS (الأساسيات)</h2><p>يجب أولاً تهيئة الأساسيات التي يقوم عليها مشروعنا. يجب أن نبدأ بتطبيق (<code>ng-app</code>) الذي يُعرِّف التطبيق (و<code>ng</code> هي بادئة تعني Angular وتسبق عادة كل مكونات Angular JS)، ثم متحكم (Controller) ليتواصل مع طريقة العرض، ثم ربط DOM ولا ننسى تضمين Angular بالطبع. إليك الأساسيات:</p><h2>نص HTML مع تصريحات <code>ng-*</code>:</h2><pre class="javascript ipsCode prettyprint">&lt;div ng-app="myApp"&gt;
  &lt;div ng-controller="MainCtrl"&gt;
    &lt;!-- محتويات المتحكم --&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><h3>وحدة Angular مع متحكم:</h3><pre class="javascript ipsCode prettyprint">var myApp = angular.module('myApp', []);

myApp.controller('MainCtrl', ['$scope', function ($scope) {
  // أوامر المتحكم
}]);</pre><p>قبل أن نستبق الأمور، نحتاج لإنشاء <em>وحدة Angular</em> (أو <em>Angular module</em>)، التي ستتضمن كل النص البرمجي المُتعلق بالمشروع. هناك أكثر من طريقة للتصريح عن الوحدات، إحداها سَلسَلة كل النص البرمجي معًا (لا أفضل هذه الطريقة):</p><pre class="javascript ipsCode prettyprint">angular.module('myApp', [])
       .controller('MainCtrl', ['$scope', function ($scope) {...}])
       .controller('NavCtrl', ['$scope', function ($scope) {...}])
       .controller('UserCtrl', ['$scope', function ($scope) {...}]);</pre><p>ولكن الطريقة التي أفضلها، والتي أثبتت أنها الأفضل لكل مشاريع Angular التي صمّمتها هي تعريف الوحدة العامة بشكل منفصل. الطريقة التي تعتمد على تسلسل التصريحات قد تجعلك تنسى إغلاق بعض الأقواس وتجعل قراءة النص البرمجي وتصحيحه أكثر تعقيدًا. لذا أُفضّل هذا الأسلوب:</p><pre class="html ipsCode prettyprint">var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope', function ($scope) {...}]);
myApp.controller('NavCtrl', ['$scope', function ($scope) {...}]);
myApp.controller('UserCtrl', ['$scope', function ($scope) {...}]);</pre><p>بهذه الطريقة أُقسّم النص البرمجي على عدة ملفات، وفي كل ملف أربط مكوّناً من المكونات مع فضاء الأسماء myApp فيصبح تلقائيًا جزءًا من تطبيقي. نعم، الأمر كما فهمت، أفضل أن أنشئ ملفًا مستقلًا لكل متحكم ومُرشِد (directive) ومعمل (factory) وأي شيء آخر (ستشكرني على هذا). فيما بعد يمكنك دمجها معًا وتقليصها لتصبح ملفًا واحدًا (مستخدمًا مُدير مهام مثل Grunt أو Gulp) فتدفعَه إلى <code>DOM</code>.</p><h3>المُتحكّمات (Controllers)</h3><p>أصبحت تعرف الآن مفهوم MVC وتعلمت طريقة إعداد مشروع جديد، فلنطّلع الآن على الكيفية التي يُطبِّق فيها Angular JS العمل بالمتحكّمات.<br>بناء على المثال السابق، بإمكاننا الآن أن نخطو خطوة بسيطة نحو عرض بعض البيانات ضمن طريقة العرض مستخدمين مُتحكّمًا. يستخدم Angular تركيب <em>" handlebars"</em> لقولبة HTML. ببساطة يعني هذا أنه بإمكان المتحكمات أن تعرض البيانات في صفحة HTML بأن تستبدل كل عبارة فيها مكتوبة ضمن الأقواس المزدوجة هكذا: <code>{{ data }}</code> قيمة يُعيّنها المُتحكم. في الحالة المثالية يجب أن لا تحوي صفحة HTML نصًا حقيقيًا أو قيمًا مُدرجة مسبقًا، ويجب أن تترك هذه المهمة لمتحكمات Angular. فيما يلي مثال يُبيّن كيف يمكن عرض نص أو سلسلة حروف <code>String</code> بسيطة ضمن الصفحة:</p><pre class="html ipsCode prettyprint">&lt;div ng-app="myApp"&gt;
  &lt;div ng-controller="MainCtrl"&gt;
    {{ text }}
  &lt;/div&gt;
&lt;/div&gt;</pre><p>في ملف JavaScript:</p><pre class="javascript ipsCode prettyprint">var myApp = angular.module('myApp', []);

myApp.controller('MainCtrl', ['$scope', function ($scope) {

  $scope.text = 'مرحباً بمعجبي Angular!';

}]);</pre><p>والناتج النهائي: <a rel="external nofollow" href="http://jsfiddle.net/toddmotto/mN7QB/light/">رابط المثال</a></p><p>أهم مفهوم هنا هو مفهوم النطاق (<code>$scope</code>) والذي ستربطه بكل الوظائف ضمن متُحكّم مُعيّن. يُشير <code>$scope</code> إلى العُنصر أو المنطقة الحالية في DOM (فهو لا يُساوي <code>this</code> ضمن النص البرمجي) وبهذا يخلق نطاقًا يُحيط بكل البيانات والوظائف ضمن العناصر (DOM elements)، ويعزلها عن العناصر الأخرى، فيبدو وكأنه ينقل مجالات JavaScript العامة/الخاصة إلى DOM، وهذا شيء رائع.<br>قد يبدو مفهوم النطاق مخيفًا للوهلة الأولى، لكنه طريقك الواصل بين الخادوم (أو حتى البيانات المحلية) من جهة وDOM من الجهة الأخرى. يعطيك <a rel="external nofollow" href="http://jsfiddle.net/toddmotto/425KU/light/">هذا المثال</a> فكرة عن الطريقة التي "تُدفع" بها البيانات إلى DOM.</p><p><span style="color:#333333;">لنٌلقِ نظرة على بيانات حقيقية نفترض أننا جلبناها من خادوم لنعرض تفاصيل تسجيل دخول المستخدم، سنكتفي في هذه المرحلة باستخدام بيانات جاهزة، وسنتعلم كيفية جلبها من الخادوم على هيئة JSON لاحقًا.</span></p><p>أولاً سنكتب شفرة JavaScript:</p><pre class="javascript ipsCode prettyprint">var myApp = angular.module('myApp', []);

myApp.controller('UserCtrl', ['$scope', function ($scope) {

  // لنجعل معلومات المستخدم ضمن عنصر فرعي
  $scope.user = {};
  $scope.user.details = {
    "username": "Todd Motto",
    "id": "89101112"
  };

}]);</pre><p>ثم ننتقل إلى DOM لعرض هذه البيانات</p><pre class="html ipsCode prettyprint">&lt;div ng-app="myApp"&gt;
    &lt;div ng-controller="UserCtrl"&gt;
        &lt;p class="username"&gt;Welcome, {{ user.details.username }}&lt;/p&gt;
        &lt;p class="id"&gt;User ID: {{ user.details.id }}&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/425KU/light/">النتيجة</a></p><p>من المهمّ أن تتذكر أن المتحكمات تستخدم فقط <em>للبيانات</em> ولإنشاء وظائف تتواصل مع الخادوم وتجلب أو ترسل بيانات JSON. لا تستخدم المتحكمات لمعالجة DOM (كأن تنقل عنصرًا ضمن الصفحة أو تخفيه أو تظهره...)، فمعالجة DOM مهمة المُرشِدات (directives)، وهي ما سنشرحه لاحقًا، المهم أن تتذكر أن موضع jQuery وغيرها من المكتبات التي تتعامل مع DOM ليس ضمن المتحكّمات.</p><p><strong>تنويه</strong>: خلال اطلاعك على وثائق Angular الرسمية، ستلاحظ أن الأمثلة المقدمة تعتمد الأسلوب التالي لإنشاء المتحكمات:</p><pre class="javascript ipsCode prettyprint">var myApp = angular.module('myApp', []);

function MainCtrl ($scope) {
  //...
};</pre><p>لا تفعل ذلك. هذا سيجعل كل الوظائف المُصرّحة تابعةً للنطاق العامّ (global scope) ولا يربطها بشكل جيد مع التطبيق. هذا يعني كذلك أن عمليات التقليص للنص البرمجي والتجارب ستكون أكثر صعوبة. لا تلوّث فضاء الأسماء العام، بل اجعل المتحكمات <em>ضمن</em> التطبيق.</p><h3>المُرشِدات (Directives)</h3><p>الُمرشد في أبسط صوره هو نص HTML مٌقولَب، يفضل أن يكون استخدامه متكررًا ضمن التطبيق. توفر المرشدات طريقة سهلة لإدخال أجزاء DOM ضمن التطبيق دون عناء. تعلم استخدام المرشدات ليس أمرًا سهلًا على الإطلاق، وإتقانها يتطلب جهدًا، ولكن الفقرات التالية ستضعك على الطريق الصحيح.</p><p>إذن، ما فائدة المُرشدات؟ إنها مفيدة في عدة أمور، منها إنشاء عناصر DOM، مثل علامات التبويب (tabs) وقوائم التصفح - ففائدتها تعتمد على ما يفعله تطبيقك في الواجهة. لتسهيل الشرح، سأقول ببساطة: إن كنت استعملت <code>ng-show</code> و<code>ng-hide</code> من قبل، فقد استعملت المرشدات (حتى وإن كان هذان لا يُدرجان أية عناصر DOM).<br>على سبيل التمرين، سنُنشئ نوعًا خاصًّا من الأزرار ونُسميه <em><code>customButton</code></em>، يُدرج هذا العنصر بعض العناصر الفرعية التي لا نريد كتابتها في كل مرة. تتنوع طرق التصريح عن المرشدات في DOM، وهي مبينة في النص البرمجي التالي:</p><pre class="html ipsCode prettyprint">&lt;!-- 1: تصريح عن مُرشد كخاصّة (attribute) --&gt;
&lt;a custom-button&gt;انقرني&lt;/a&gt;

&lt;!-- 2: كعنصر مخصص (custom elements) --&gt;
&lt;custom-button&gt;انقرني&lt;/custom-button&gt;

&lt;!-- 3: كصنف (class) (للتوافق مع النسخ القديمة من IE) --&gt;
&lt;a class="custom-button"&gt;انقرني&lt;/a&gt;

&lt;!-- 4: كتعليق (comment) (ليس ملائماً لهذا التمرين) --&gt;
&lt;!-- directive: custom-button --&gt;</pre><p> </p><p>أفضّل استخدام المرشدات كخواصّ (attributes)، أما العناصر المُخصصة (custom elements) فقادمة في النسخ المستقبلية من HTML باسم Web Components، يوفر Angular ما يشبهها، ولكنها قد تنطوي على بعض العيوب والعلل في المتصفحات القديمة.<br>الآن نعرف كيف نصرح عن المرشدات ضمن الصفحة، سننتقل إلى إنشائها ضمن JavaScript. لاحظ أنني سأربطه مع فضاء الأسماء العام myApp؛ في صيغته الأبسط يُكتب المرشد كما يلي:</p><pre class="javascript ipsCode prettyprint">myApp.directive('customButton', function () {
  return {
    link: function (scope, element, attrs) {
      // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه
    }
  };
});</pre><p>عرّفنا المرشد باستخدام الدالة <em><code>.directive()</code></em>، ومررنا إليها اسم المرشد <code>'customButton'</code>. عندما تكتب حرفًا كبيرًا بالإنجليزية في اسم المُرشد، فإنه ينبغي استخدام اسم المرشد ضمن DOM بصيغته التي يُفصل بها باستخدام الشرطة (-) بين الحروف الكبيرة (كما في المثال السابق: استخدمنا <code>'customElement'</code> في JavaScript و<code>"custom-button"</code> في HTML).<br>يُرجع المُرشد كائنًا (Object) له عدد من الخصائص. أهم ما يجب تعلّمه منها: <code>restrict</code> و<code>replace</code> و<code>transclude</code> و<code>template</code> و<code>templateUrl</code> وأخيرًا <code>link</code>. لنُضف بعضها إلى شفرتنا البرمجية:</p><pre class="html ipsCode prettyprint">myApp.directive('customButton', function () {
  return {
    restrict: 'A',
    replace: true,
    transclude: true,
    template: '&lt;a href="" class="myawesomebutton" ng-transclude&gt;' +
                '&lt;i class="icon-ok-sign"&gt;&lt;/i&gt;' +
              '&lt;/a&gt;',
    link: function (scope, element, attrs) {
      // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه
    }
  };
});</pre><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/VC4H2/light/">النتيجة</a></p><p>تأكد من فحص العنصر (من الأمر Inspect element في المُتصفح) لرؤية العناصر الجديدة التي أُدخلت في الصفحة. اعلم أن الرمز لم يظهر ضمن العنصر الجديد، ببساطة لأنني لم أُضمّن Font Awesome ضمن المشروع، ولكن يمكنك فهم كيف تعمل المرشدات. لنتعرف الآن ما تعنيه كل واحدة من خصائص المرشد السابقة الذكر:<br><strong>الخاصية <code>restrict</code><em>: </em></strong>تُقيّد هذه الخاصة كيفية استخدام المُرشد، كيف نريد أن نستخدمه؟ إن كنت تبني مشروعًا يتطلب دعم النسخ القديمة من IE، فعليك استخدامه كخاصّة (attribute) أو صنف (class). القيمة <code>'A'</code> تعني حصر استخدام المرشد بالخواص (attributes) فقط. <code>'E'</code> تعني Element و<code>'C'</code> صنف و<code>'M'</code> تعليق. القيمة الافتراضية هي <code>'EA'</code> (أي عنصر وخاصة).<br><strong>الخاصية <code>replace</code></strong>: تعني استبدال HTML العنصر المصرّح عن المُرشد ضمن الصفحة بالقالب (template) الذي يُحدد في الخاصة <code>template</code> (مشروحة أدناه).<br><strong>الخاصة<code>transclude</code></strong><em>:</em> تسمح بنسخ المحتوى الأصلي للعنصر المُصرّح عن المُرشد في الصفحة ودمجه ضمن المرشد (عند التنفيذ، ستلاحظ أن العبارة "انقرني" انتقلت إلى المُرشد).<br><strong>الخاصية <code>template</code></strong>: قالب (كذلك المستخدم في المثال) يُدخل إلى الصفحة. يفضّل استخدام القوالب الصغيرة فقط. تُعالج القوالب وتبنى من قبل Angular مما يسمح باستخدام صيغة handlebars ضمنها.<br><strong>الخاصة <em><code>templateUrl</code></em></strong>: مشابهة للسابقة، ولكنها تُجلب من ملف أو من وسم <code>&lt;script&gt;</code> بدل كتابتها ضمن تعريف المُرشد. كل ما عليك هو تعيين مسار الملف الذي يحوي القالب. يكون هذا الخيار مناسبًا عندما تريد الاحتفاظ بالقوالب خارج النص البرمجي لملفات JavaScript:</p><pre class="javascript ipsCode prettyprint"> myApp.directive('customButton', function () {
     return {
       templateUrl: 'templates/customButton.html'
       // directive stuff...

   });</pre><p>وضمن الملف، نكتب:</p><pre class="html ipsCode prettyprint">&lt;!-- inside customButton.html --&gt;
   &lt;a href="" class="myawesomebutton" ng-transclude&gt;
     &lt;i class="icon-ok-sign"&gt;&lt;/i&gt;
   &lt;/a&gt;</pre><p><strong>ملاحظة</strong>: لا يخضع اسم الملف إلى أية قاعدة، وليس من الضروري أن يوافق اسمَ المُرشد.<br>عند استخدام الأسلوب السابق، سيحتفظ المتصفح بنسخة مُخبأة (cached) من ملف HTML، وهو أمر رائع، الخيار البديل هو استخدام قالب ضمن وسم <code>&lt;script&gt;</code> وهنا لا تُخبأ نسخة منه في المتصفح:</p><pre class="html ipsCode prettyprint"> &lt;script type="text/ng-template" id="customButton.html"&gt;
  &lt;a href="" class="myawesomebutton" ng-transclude&gt;
    &lt;i class="icon-ok-sign"&gt;&lt;/i&gt;
  &lt;/a&gt;
  &lt;/script&gt;</pre><p>هنا أخبرنا Angular بأن وسم <code>&lt;script&gt;</code> هذا هو قالب (<em><code>ng-template</code></em>) وأعطيناه المُعرف. سيبحث Angular عن القالب أو عن ملف html، فاستخدم ما تراه مناسبًا. شخصيًا، أفضّل إنشاء ملفات html لسهولة تنظيمها ولتحسين الأداء وإبقاء DOM نظيفًا، فقد يستخدم مشروعك مع الوقت عشرات المُرشدات، وترتيبها في ملفات مستقلة يجعل مراجعتها أسهل.</p><h3>الخدمات (Services)</h3><p>كثيرًا ما تثير الخدمات في Angular ارتباك المطورين، ومن خبرتي وأبحاثي، أعتقد أن الخدمات وُضعت كنمط وأسلوب للتصميم أكثر من اختلافها بالوظيفة التي تؤديها. بعد التنقيب في مصدر Angular، وجدت أنها تُعالج وتبنى باستخدام المُجمّع (compiler) ذاته، وكذلك فهي تقدم العديد من الوظائف المشابهة. أنصح باستخدام الخدمات لبناء <em>الكائنات المُتفرِّدة</em> (<em>singletons</em>)، واستخدام المعامل (Factories) لبناء وظائف أكثر تعقيدًا كالكائنات الحرفيّة (Object Literals).<br>فيما يلي مثال لاستخدام خدمة توجد ناتج الضرب لعددين:</p><pre class="javascript ipsCode prettyprint">myApp.service('Math', function () {
  this.multiply = function (x, y) {
    return x * y;
  };
});</pre><p>يمكنك بعد هذا استخدامها ضمن مُتحكم كما يلي:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', function ($scope) {
    var a = 12;
    var b = 24;

    // الناتج: 288
    var result = Math.multiply(a, b);
}]);</pre><p>نعم بالطبع إيجاد ناتج الضرب سهل ولا يحتاج خدمة، لكننا نستخدمه لإيصال الفكرة فحسب.<br>عندما ننشئ خدمة (أو معملاً) نحتاج إلى إخبار Angular عن متطلبات هذه الخدمة، وهو ما يسمى "حقن المتطلبات Dependency Injection" - إن لم تُصرّح عن المتطلبات فلن يعمل المتحكم المعتمد على الخدمة، وسيحدث خطأ عند التجميع. ربما لاحظت الجزء <code>function ($scope)</code> ضمن التصريح عن المتحكم أعلاه، وهذا هو ببساطة حقن المتطلبات. ستُلاحظ أيضًا <code>[$scope]</code> قبل الجزء <code>function ($scope)</code>، وهو ما سأشرحه لاحقًا. فيما يلي طريقة استخدام حقن المتطلبات لإخبار Angular أنك تحتاج إلى الخدمة التي أنشأتها للتو:</p><pre class="javascript ipsCode prettyprint">// مرر الخدمة Math
myApp.controller('MainCtrl', ['$scope', 'Math', function ($scope, Math) {
    var a = 12;
    var b = 24;

    // يُعطي 288
    var result = Math.multiply(a, b);
}]);</pre><h3>المعامل (Factories)</h3><p>إيضاح فكرة المعامل سهل إذا كنت قد استوعبت فكرة الخدمات، بإمكاننا إنشاء كائن حرفي (Object Literal) ضمن المعمل أو عبر طرق أكثر تعقيدًا:</p><pre class="javascript ipsCode prettyprint">function ($http) {
  return {
    get: function(url) {
      return $http.get(url);
    },
    post: function(url) {
      return $http.post(url);
    },
  };
}]);</pre><p>هنا أنشأنا مُغلفات (wrappers) مخصصة لخدمة <code>$http</code> في Angular المسؤولة عن طلبات <code>XHR</code>. بعد حقن المتطلبات ضمن المتحكم يمكننا استخدام هذا المعمل بسهولة:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', 'Server', function ($scope, Server) {
    var jsonGet = 'http://myserver/getURL';
    var jsonPost = 'http://myserver/postURL';
    Server.get(jsonGet);
    Server.post(jsonPost);
}]);</pre><p>إذا أرت طلب التحديثات من الخادوم، بإمكانك إنشاء دالة <code>Server.poll</code> أو إن كنت تستخدم مقبسًا  (ٍSocket)، فربما سترغب في إنشاء دالة <code>Server.socket</code> وهكذا... المعامل تسمح لك بتنظيم نصك البرمجي ضمن وحدات يمكن إدراجها ضمن المتحكمات منعًا لتكرار النص البرمجي فيها والحاجة المتكررة لصيانته.</p><h3>المُرشّحات</h3><p>تستخدم المرشحات مع مصفوفات (arrays) من البيانات وخارج الحلقات (loops). إن احتجت للمرور على عناصر من مصفوفة بيانات والحصول على بعض منها فقط، فأنت في المكان الصحيح، يمكنك أيضًا استخدام المرشحات لتصفية ما يكتبه المستخدم ضمن حقل إدخال <code>&lt;input&gt;</code> مثلًا. هناك عدة طرق لاستخدام المُرشحات: ضمن متحكم أو دالة مُعرفة. فيما يلي الطريقة الأخيرة:</p><pre class="javascript ipsCode prettyprint">myApp.filter('reverse', function () {
    return function (input, uppercase) {
        var out = '';
        for (var i = 0; i &lt; input.length; i++) {
            out = input.charAt(i) + out;
        }
        if (uppercase) {
            out = out.toUpperCase();
        }
        return out;
    }
});

// Controller included to supply data
myApp.controller('MainCtrl', ['$scope', function ($scope) {
    $scope.greeting = 'Todd Motto';
}]);</pre><p>وفي HTML:</p><pre class="html ipsCode prettyprint">&lt;div ng-app="myApp"&gt;
    &lt;div ng-controller="MainCtrl"&gt;
        &lt;p&gt;No filter: {{ greeting }}&lt;/p&gt;
        &lt;p&gt;Reverse: {{ greeting | reverse }}&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/pmh4s/light/">رابط المثال</a></p><p>وهنا نستخدم المُرشح ضمن حلقة <code>ng-repeat</code>:</p><pre class="html ipsCode prettyprint">&lt;ul&gt;
  &lt;li ng-repeat="number in myNumbers |filter:oddNumbers"&gt;{{ number }}&lt;/li&gt;
&lt;/ul&gt;</pre><p>مثال عن مُرشح ضمن متحكم:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', function ($scope) {

    $scope.numbers = [10, 25, 35, 45, 60, 80, 100];

    $scope.lowerBound = 42;

    // Does the Filters
    $scope.greaterThanNum = function (item) {
        return item &gt; $scope.lowerBound;
    };

}]);</pre><p>واستخدامه حلقة <code>ng-repeat</code>:</p><pre class="html ipsCode prettyprint">&lt;li ng-repeat="number in numbers | filter:greaterThanNum"&gt;
  {{ number }}
&lt;/li&gt;</pre><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/cZbCf/light/">رابط المثال</a></p><p>كان هذا القسم الأكبر مما تحتاج لمعرفته عن AngularJS وواجهاتها البرمجية، ومع أن ما تعلمناه كافٍ لبناء تطبيق Angular، ولكننا إلى الآن لم نسكتشف أغوراها بعد.</p><h3>ربط البيانات ثنائي الاتجاه</h3><p>عندما سمعت للمرة الأولى عن <strong>ربط البيانات ثنائي الاتجاه</strong> لم أفهم ما يعنيه. باختصار يمكن القول إنه حلقة متصلة من البيانات المُزامنة: حدّث النموذج (Model) لتُحدَّث طريقة العرض (View)، أو حدّث طريقة العرض ليُحدَّث النموذج (Model). هذا يعني أن البيانات تبقى محدثة دومًا دون عناء. إن ربطت نموذج <code>ng-model</code> مع حقل إدخال <code>&lt;input&gt;</code> وكتبت فيه، فهذا يُنشئ (أو يُحدِّث) نموذجاً في الوقت ذاته.<br>فيما يلي نقوم بإنشاء حقل <code>&lt;input&gt;</code> ونربطه بنموذج نسميه <code>myModel</code>، يمكنني الآن استخدام صياغة <em>handlebars</em> لعكس هذا النموذج وما يطرأ عليه من تحديثات في طريقة العرض في الوقت ذاته:</p><pre class="html ipsCode prettyprint">&lt;div ng-app="myApp"&gt;
    &lt;div ng-controller="MainCtrl"&gt;
        &lt;input type="text" ng-model="myModel" placeholder="Start typing..." /&gt;
        &lt;p&gt;My model data: {{ myModel }}&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

 

myApp.controller('MainCtrl', ['$scope', function ($scope) {
    // Capture the model data
    // and/or initialise it with an existing string
    $scope.myModel = '';
}]);</pre><p> </p><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/qrr3q/light/">النتيجة</a></p><h3>طلبات <code>XHR</code>/Ajax/<code>$http</code> وربط <code>JSON</code></h3><p>نعرف الآن كيف نرسل بيانات بسيطة ضمن المجال (<code>$scope</code>)، ونعرف ما يكفي عن كيفية عمل النماذج وربط البيانات ثنائي الجانب، والآن حان الوقت لمحاكاة طلبات <code>XHR</code> حقيقية للخادوم. ليس هذا ضروريًا لمواقع الويب العادية، لكنه مناسب جدًا لجلب البيانات في تطبيقات الويب.<br>عندما تطور تطبيقك على جهازك المحلي، فغالبًا ما ستستخدم لغة مثل Java أو ASP.NET أو PHP أو غيرها لتشغيل خادوم محلي. وسواء كنا نتصل بقاعدة بيانات محلية أم بخادوم بعيد كواجهة برمجية، فإننا نتبع نفس الخطوات بالضبط.</p><p>هنا يأتي دور <code>$http</code>، صديقك المخلص من اليوم فصاعدًا. الدالة <code>$http</code> هي مُغلّف <code>wrapper</code> تقدمه Angular للوصول إلى البيانات من الخادوم، وهو سهل الاستخدام للغاية ولا يحتاج لأية خبرة. فيما يلي مثال عن طلب <code>GET</code> لجلب البيانات من الخادوم. الصياغة مشابهة جدًا لصياغة jQuery، وهذا يُسهل الانتقال من الأخيرة إلى Angular:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
  $http({
    method: 'GET',
    url: '//localhost:9000/someUrl'
  });
}]);</pre><p>يُعيد Angular إلينا أمرًا يُصطلح على تسميته <strong>الوعد (Promise)</strong> ، وهو بديل أسهل استخدامًا من الاستدعاءات الراجعة (callbacks). يمكن تركيب الوعود في سلسلة باستخدام النقطة، ويمكننا ربطها مع مستقبلات النجاح والفشل:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', function ($scope) {
  $http({
    method: 'GET',
    url: '//localhost:9000/someUrl'
  })
  .success(function (data, status, headers, config) {
    // successful data retrieval
  })
  .error(function (data, status, headers, config) {
    // something went wrong :(
  });
}]);</pre><p>سهلة الاستخدام والقراءة. هنا نربط طريقة العرض والخادوم بربط نموذج أو تحديثه. لنفترض أنه لدينا خادومًا مُعدًّا ولنقم بدفع اسم المستخدم إلى طريقة العرض عن طريق طلب <code>AJAX</code>.</p><p>علينا --لو كنا حريصين على المثالية-- أن نصمم بيانات <code>JSON</code> التي نريدها أولاً. دعونا الآن نُبسط الأمور، ولندع هذا الأمر ليتولاه من يفهم في أمور النهاية الخلفية (backend)، ولكن لنقل أننا تفترض أن نستقبل بيانات مثل هذه:</p><pre class="javascript ipsCode prettyprint">{
  "user": {
    "name": "Todd Motto",
    "id": "80138731"
  }
}</pre><p>هذا يعني أننا سنحصل على كائن <code>Object</code> من الخادوم (سنسميه <code>data</code>، وسترى أنه يُمرر إلى مستقبلات الوعد الذي أنشأناه).<br>علينا الآن أن نربط هذا الكائن بالخاصة <code>data.user</code>، وضمنها لدينا <code>name</code> و<code>id</code>.<br>يمكن ببساطة الوصول إلى هذه القيم باستخدام <code>data.user.name</code> للحصول على "Todd Motto" مثلاً.</p><p>فيما يلي الشفرة البرمجية (اطلع على التعليقات المضمنة):</p><pre class="javascript ipsCode prettyprint">myApp.controller('UserCtrl', ['$scope', '$http', function ($scope, $http) {

  // create a user Object
  $scope.user = {};

  // Initiate a model as an empty string
  $scope.user.username = '';

  // نريد أن نرسل طلباً ونحصل على اسم المستخدم
  $http({
    method: 'GET',
    url: '//localhost:9000/someUrlForGettingUsername'
  })
  .success(function (data, status, headers, config) {
    // عند نجاح الطلب، نُسنِد الاسم إلى النموذج الذي أنشأناه
    $scope.user.username = data.user.name;
  })
  .error(function (data, status, headers, config) {
    // وقع خطأ ما! :(
  });
}]);</pre><p>الآن ضمن الصفحة يمكننا ببساطة كتابة:</p><pre class="html ipsCode prettyprint">&lt;div ng-controller="UserCtrl"&gt;
  &lt;p&gt;{{ user.username }}&lt;/p&gt;
&lt;/div&gt;</pre><p>هذا سيعرض اسم المستخدم. لننتقل الآن إلى خطوة أبعد بفهم <strong>ربط البيانات التصريحي (Declarative data-binding)</strong> حيث تصبح الأمور أكثر إثارة.</p><h3>ربط البيانات التصريحي</h3><p>تقوم فلسفة Angular على إنشاء نصوص HTML ديناميكية قادرة على القيام بوظائف بنفسها لم نكن نتوقع أنها ممكنة ضمن المتصفح. هذه هي المهمة التي تقوم بها Angualar على خير وجه.<br>لنتخيل أننا أرسلنا طلب AJAX لجلب قائمة بعناوين البريد الإلكتروني وسطر الموضوع فيها مع تاريخ إرسالها، ولنفترض أننا نريد عرضها ضمن الصفحة. في هذا المكان بالضبط تذهلنا Angular بقدراتها. لننشئ أولاً متحكماً بالبريد الإلكتروني:</p><pre class="html ipsCode prettyprint">yApp.controller('EmailsCtrl', ['$scope', function ($scope) {

  // نُنشئ كائناً يدعاً `emails`
  $scope.emails = {};

  // لنفترض أننا حصلنا على هذه البيانات من الخادوم
  // هذه **مصفوفة** من **الكائنات**
  $scope.emails.messages = [{
        "from": "Steve Jobs",
        "subject": "I think I'm holding my phone wrong :/",
        "sent": "2013-10-01T08:05:59Z"
    },{
        "from": "Ellie Goulding",
        "subject": "I've got Starry Eyes, lulz",
        "sent": "2013-09-21T19:45:00Z"
    },{
        "from": "Michael Stipe",
        "subject": "Everybody hurts, sometimes.",
        "sent": "2013-09-12T11:38:30Z"
    },{
        "from": "Jeremy Clarkson",
        "subject": "Think I've found the best car... In the world",
        "sent": "2013-09-03T13:15:11Z"
    }];

}]);</pre><p>علينا الآن دفعها ضمن الصفحة. هنا نستخدم الربط التصريحي لنُعلن عما سيفعله تطبيقنا: إنشاء أول جزء من عناصر HTML الحيوية. سنستخدم مُرشد <code>ng-repeat</code> المبني ضمن Angular، والذي سوف يمر على البيانات ويعرض الناتج دون عناء الاستدعاءات الرجعية أو تغيير الحالة، بهذه السهولة:</p><pre class="html ipsCode prettyprint">&lt;ul&gt;
  &lt;li ng-repeat="message in emails.messages"&gt;
    &lt;p&gt;From: {{ message.from }}&lt;/p&gt;
    &lt;p&gt;Subject: {{ message.subject }}&lt;/p&gt;
    &lt;p&gt;{{ message.sent | date:'MMM d, y h:mm:ss a' }}&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;</pre><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/TAVQc/light/">النتيجة</a></p><p>قمت أيضًا باستخدام مُرشّح التاريخ لأبين لك كيف يمكن أن تعرض تواريخ UTC.</p><p>اطلع على المُرشدات التي توفرها Angular لتتعرف على القدرات الكاملة للربط التصريحي. بهذا نكون قد عرفنا كيف نصل البيانات بين الخادوم وطريقة العرض.</p><h3>وظائف المجال (Scope functions)</h3><p>تعتبر وظائف المجال الخطوة التالية في بناء وظائف التطبيق واستكمالاً للربط التصريحي. فيما يلي وظيفة بسيطة تحذف إحدى الرسائل:</p><pre class="html ipsCode prettyprint">myApp.controller('MainCtrl', ['$scope', function ($scope) {

  $scope.deleteEmail = function (index) {
    $scope.emails.messages.splice(index, 1)
  };

}]);</pre><p><strong>تنويه</strong>: من المهم أن تفكر في حذف البيانات من النموذج، لا تحذف العناصر أو أي شيئ من الصفحة، دع Angular يتولى هذا بربطه ثنائي الجانب للبيانات، فقط فكر بذكاء واكتب شفرة برمجية تستجيب لبياناتك.</p><p>ربط الوظائف مع طريقة العرض يمر عبر المُرشدات، هذه المرة نستخدم مُرشد <code>ng-click</code>:</p><pre class="html ipsCode prettyprint">&lt;a ng-click="deleteEmail($index)"&gt;Delete email&lt;/a&gt;</pre><p>هذا يختلف تمامًا عن مستقبلات النقر التقليدية في JavaScript، لأسباب عديدة سنشرحها لاحقًا.<br>لاحظ أنني أيضًا أمرر فهرس العنصر <code>$index</code>، إذ يعرف Angualr ما العنصر المُراد حذفه (كم يوفر هذا من العناء؟)</p><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/BgZmt/light/">النتيجة</a></p><h3>دوال DOM التصريحية</h3><p>ننتقل الآن لدوال DOM، وهي أيضًا مُرشدات تؤدي وظيفة ضمن الصفحة بدونها كنا سنكتب شفرات برمجية طويلة. أحد الأمثلة المناسبة لإيضاح الفكرة هنا هو إظهار أو إخفاء قسم التنقل ضمن الصفحة باستخدام <code>ng-show</code> و<code>ng-click</code>، لنرَ بساطة هذا:</p><pre class="html ipsCode prettyprint">&lt;a href="" ng-click="toggle = !toggle"&gt;Toggle nav&lt;/a&gt;
  &lt;ul ng-show="toggle"&gt;
    &lt;li&gt;Link 1&lt;/li&gt;
    &lt;li&gt;Link 2&lt;/li&gt;
    &lt;li&gt;Link 3&lt;/li&gt;
&lt;/ul&gt;</pre><p>هنا ندخل عالم MVVM (اختصار Model-View-View-Model)، لاحظ أننا لم نستخدم متحكمًا، وسنشرح فكرة MVVM بعد قليل.</p><p>الناتج (جرب الإظهار والإخفاء):</p><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/ZUyW5/light/">النتيجة</a></p><h3>التعابير (Expressions)</h3><p>من أفضل ما يقدمه Angular، يقدم بديلاً عن الحاجة لكتابة الكثير من JavaScript والنصوص المكررة.</p><p>هل قمت يومًا ما بكتابة شيء كهذا؟</p><pre class="html ipsCode prettyprint">elem.onclick = function (data) {
  if (data.length === 0) {
    otherElem.innerHTML = 'No data';
  } else {
    otherElem.innerHTML = 'My data';
  }
};</pre><p>ربما يكون هذا استدعاءً راجعًا عن طلب GET، ونحتاج لنغير محتوى في الصفحة بناء على البيانات، يقدم Angular هذا بدون الحاجة لكتابة حرف JavaScript!</p><pre class="html ipsCode prettyprint">&lt;p&gt;{{ data.length &gt; 0 &amp;&amp; 'My data' || 'No data' }}&lt;/p&gt;</pre><p>سيقوم هذا بتحديث الصفحة تلقائيًا دون استدعاءات عند وصول البيانات أو ما شابه. إن لم تتوفر البيانات، سيظهر هذا واضحًا، وإن وجدت فسيظهر كذلك. هناك حالات كثيرة جدًا يُمكن فيها لـAngular أن يتولاها عبر ربطه ثنائي الجانب للبيانات الذي يعمل بشكل رائع.</p><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/XCwcr/light/">النتيجة</a></p><h3>طرق العرض الديناميكية والتوجيه (Routing)</h3><p>هي ما تقوم عليه فلسفة تطبيقات الويب (والمواقع) أحادية الصفحة: لديك قسم الترويسة وقسم التذييل وشريط جانبي ثم المحتوى الذي يُحدث تلقائيًا بناءً على الرابط الحالي.</p><p>يجعل Angular إعداد هذا الأمر في منتهى السهولة. تحقن طرق العرض الديناميكة دوالا مُعينة بناء على الرابط، عبر استخدام <code>$routeProvider</code>. فيما يلي إعداد بسيط:</p><pre class="javascript ipsCode prettyprint">myApp.config(['$routeProvider', function ($routeProvider) {

  /**
   * $routeProvider
   */
  $routeProvider
  .when('/', {
    templateUrl: 'views/main.html'
  })
  .otherwise({
    redirectTo: '/'
  });

}]);</pre><p>لاحظ أنه عندما (<code>when</code>) يكون الرابط <code>/</code> فقط (الصفحة الرئيسية)، ستعرض الصفحة <code>main.html</code>. من المفيد تسمية طريقة العرض الأساسية <code>main.html</code> وليس <code>index.html</code> لأنه سيكون لدينا مسبقاً الصفحة <code>index.html</code> وهي الصفحة التي تحوي طرق العرض الديناميكية وبقية الأجزاء.<br>يمكن ببساطة إضافة المزيد من طرق العرض:</p><pre class="javascript ipsCode prettyprint">myApp.config(['$routeProvider', function ($routeProvider) {

  /**
   * $routeProvider
   */
  $routeProvider
  .when('/', {
    templateUrl: 'views/main.html'
  })
  .when('/emails', {
    templateUrl: 'views/emails.html'
  })
  .otherwise({
    redirectTo: '/'
  });

}]);</pre><p>بإمكاننا الآن تحميل الصفحة <code>emails.html</code> ببساطة لتقوم بعرض قائمة الرسائل الإلكترونية. الخلاصة أننا استطعنا أن نبني تطبيقًا معقدًا للغاية بجهد ضئيل جدًا.<br>توفر الخدمة <code>$routerProvider</code> المزيد من الخيارات، لكن ما تعلمناه عنها كافٍ في البداية. هناك أيضًا أمور أخرى مثل مُعترِضات <code>$http</code> التي تبدأ أحداثًا خلال مسير طلب AJAX، فتتيح لنا عرض مقدار التقدم على سبيل المثال أثناء جلب البيانات.</p><h3>البيانات الثابتة العامة</h3><p>في تطبيق Gmail للويب، تُكتب بيانات كثيرة بصيغة JSON ضمن الصفحة (انقر باليمين واختر عرض المصدر في صفحة Gmail). إن قمنا بخطوة مشابهة، أي كتابة البيانات ضمن الصفحة، فهذا سيجعل وقت عرضها أقل وسيبدو التطبيق أسرع.</p><p>عندما أطور تطبيقات مؤسستنا، تُدرج وسوم Java ضمن الصفحة وعندما تُعرض، تُرسل البيانات من الخادوم (لا خبرة لدي في Java لذا سأكتب فيما يلي تصريحات وهمية، يمكنك استخدام أي لغة على الخادوم إن أحببت). النصوص التالية توضح كيف يمكنك كتابة JSON ضمن الصفحة ثم تمريرها إلى المتحكم لربطها مباشرة:</p><pre class="html ipsCode prettyprint">&lt;!-- ضمن index.html (في نهاية الصفحة بالطبع) --&gt;
&lt;script&gt;
window.globalData = {};
globalData.emails = &lt;javaTagHereToGenerateMessages&gt;;
&lt;/script&gt;</pre><p>سيُنشئ وسم Java الذي اختلقته البينات بينما سيعالج Angular الرسائل فورًا. كل ما عليك هو إعطاؤه البيانات عبر المتحكم:</p><pre class="javascript ipsCode prettyprint">myApp.controller('EmailsCtrl', ['$scope', function ($scope) {

    $scope.emails = {};

    // Assign the initial data!
    $scope.emails.messages = globalData.emails;

}]);</pre><h3>تقليص الملفات (Minification)</h3><p>سنتحدث قليلاً عن تقليص حجم الشفرات البرمجية التي كتبناها. ربما تكون قد جربت تقليص شفراتك البرمجية التي كتبتها لـAngular وصادفت خطأ.<br>ليس هناك أمور خاصة يتطلبها تقليص حجم هذه الملفات، باستثناء الحاجة لإدراج أسماء المتطلبات ضمن مصفوفة قبل الدالة المُصرّح عنها، لنوضح أكثر:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl',
['$scope', 'Dependency', 'Service', 'Factory',
function ($scope, Dependency, Service, Factory) {

  // code

}]);</pre><p>بعد التقليص:</p><pre class="javascript ipsCode prettyprint">myApp.controller('MainCtrl',
['$scope', 'Dependency', 'Service', 'Factory',
function (a,b,c,d) {

  // a = $scope
  // b = Dependency
  // c = Service
  // d = Factory

  // $scope alias usage
  a.someFunction = function () {...};

}]);</pre><p>عليك أن تحافظ على ترتيب المتطلبات المحقونة في المصفوفة <code>['_one', '_two']</code> وضمن مُعاملات الدالة <code>function(_one, _two)</code>، وإلا فإنك ستسبب لنفسك ولفريق العمل معك مشاكل كثيرة!</p><h3>الاختلافات بين MVC وMVVM</h3><p>سننهي مقالتنا العملاقة الآن بشرح سريع يشمل الفروق بين MVC وMVVM:</p><ul><li dir="rtl"><strong>MVC</strong>: التواصل يعتمد على المتحكم (Controller)، لذلك نقول Model-View-Controller</li><li dir="rtl"><strong>MVVM</strong>: يشمل ربط البيانات التصريحي الذي يتواصل، بالمفهوم التقني، مع نفسه؛ أي Model-View-View-Model. يتواصل النموذج مع طريقة العرض، وتتواصل هذه الأخيرة مع النموذج ثانية. يسمح هذا للبيانات بأن تبقى محدّثة على الجانبين دون الحاجة لفعل أي شيء. لا داعي هنا للمتحكم.<br>مثال على ذلك: إنشاء حلقة <code>ng-repeat</code> دون أن نعتمد على بيانات يُرسلها متحكم:</li></ul><pre class="html ipsCode prettyprint">&lt;li ng-repeat="number in [1,2,3,4,5,6,7,8,9]"&gt;
  {{ number }}
&lt;/li&gt;</pre><p>يبدو هذا مناسبًا للتجارب السريعة، ولكنني أنصح دومًا باستخدام متحكم للحفاظ على تنظيم النص البرمجي.</p><p><a rel="external nofollow" href="http://jsfiddle.net/toddmotto/C9GHF/light/">مثال</a></p><h3>مكونات الويب في HTML5</h3><p>قد تبدو هذه الفكرة مُكررّة، ولكنني سأعيدها هنا لنتحدث عن مكونات الويب.<br>يسمح Angular بإنشاء عناصر (elements) مخصصة مثل: <code>&lt;myCustomElement&gt;&lt;/myCustomElement&gt;</code></p><p>في الحقيقة هذا أشبه ما يكون بمستقبل HTML5 التي تقدم فكرة جديدة تُسمى مكونّات الويب (<strong>Web Components</strong>)، والتي تتركب من عناصر مخصصة ضمن HTML مترافقة مع نص JavaScript ديناميكي، وهذا أمر مثيرٌ للغاية - والأكثر إثارة أنه أمر ممكن اليوم باستخدام Angular. فريق Angular بعيد النظر - شكرًا لكم!</p><h3>تعليقات المجال (Scope)</h3><p>أعتقد أن تعليقات المجال إضافة جميلة لسياق العمل، فبدل الحاجة لكتابة التعليقات ضمن HTML بالطريقة التالية:</p><pre class="html ipsCode prettyprint">&lt;!-- header --&gt;
&lt;header&gt;
  Stuff.
&lt;/header&gt;
&lt;!-- /header --&gt;</pre><p>أصبحنا نتحدث عن طرق العرض والمجالات بدل الصفحة، البيانات ضمن مجال ما لا تُشارك مع مجالات أخرى إلا إن قمت بفعل ذلك عن عمدٍ. لنستغل هذا في تحسين كتابة النص البرمجي بتقسيمه إلى مناطق تسبقها تعليقات:</p><pre class="html ipsCode prettyprint">!-- scope: MainCtrl --&gt;
&lt;div class="content" ng-controller="MainCtrl"&gt;

&lt;/div&gt;
&lt;!-- /scope: MainCtrl --&gt;</pre><h3>تصحيح العلل في Angular</h3><p>تتوفر إضافة جميلة للغاية لمتصفح Chrome ينصح بها فريق Angular، وتسمى <a rel="external nofollow" href="https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk">Batarang</a>.</p><p>برمجة سعيدة!</p><p>ترجمة -وبتصرف- للمقال:  <a rel="external nofollow" href="http://toddmotto.com/ultimate-guide-to-learning-angular-js-in-one-day/">Ultimate guide to learning AngularJS in one day</a>  لصاحبه Todd Motto (الذي -بطبيعة الحال- يعود عليه ضمير المُتكلم في هذا المقال).</p>
]]></description><guid isPermaLink="false">11</guid><pubDate>Mon, 31 Mar 2014 23:00:00 +0000</pubDate></item></channel></rss>
