نحن مع غزة
الـرئـيـسـيـة الـمـنـتـدى سـؤال & اجـابـة الـتـبـرع بـالـدم الاسـتـضـافـة هـلال لـيـنـكـس الـقـرآن الـكـريـم Dz-SeC team


التسجيل في المنتدى غير متاح حاليا, اذا كنت ترغب في الحصول على عضوية ارجو مراسلتي على البريد الالكتروني "[email protected]"


مطلوب مشرفين على كامل اقسام المنتدى


أخي / أختي , إن تسجيل عضوية جديدة في منتدى شبكة الجزائر للجميع لا يهدف إلى زيادة الأعضاء مطلقا
فلا خير في عضوية عدد مشاركاتها صفرا فنحن نرفض يوميا الكثير من العضويات المشكوك في أمرها
سواء كان هدفها الإعلانات الغير شرعية أو تخريب الموضوعات الخ , كل هذا حتى يبقى المنتدى
ساحة جادة عطرة تجود بالخير لكل زوارها وأعضائها
وصدقة جارية لكل من يشارك في كتابة معلومة تفيد غيره سوف يشكر الله عليها وهو في جوف الأرض ...

لذلك نطلب منك التسجيل بل ونلح عليك إن كان هدفك هو أن تصنع صدقة جارية لا تنقطع إلى يوم الدين بمساعدة إخوانك في نشر الخير .

للتسجيل اضغط هنا وأملأ البينات المطلوبة بشكل صحيح ومن ثم انتظر حتى نقوم بتفعيل حسابك وابدأ رحلتك في صناعة صدقة جارية .

وتذكر قول سيد الخلق " إذا مات ابن آدم انقطع عمله إلا من ثلاث صدقة جارية أو علم ينتفع به أو ولدٍ صالح يدعو له "

   

[ مـنـتـدي لـــغــات الـــبرمجـــه | Programming Language ] قسم مختص بالبرمجة التفسيرية مثل : PHP, java, perl, Python, Bash, Shell script, JPython, AutoIt, Z shell, AWK, VB Script

إضافة رد
 
أدوات الموضوع انواع عرض الموضوع
قديم 24/12/2014, 17:38   المشاركة رقم: 1
المعلومات
الكاتب:
 xtrojn  
اللقب:
عضــــو جديــــد
الصورة الرمزية
 
الصورة الرمزية xtrojn

البيانات
التسجيل : Dec 2014
العضوية : 6471
الاهتمامات :
الإقامة :
المواضيع : 2
الردود : 0
المجموع : 2
بمعدل : 0.00 يوميا
الاختراقات : [ليس لدي حساب]
مجتمعنا : [لم اسجل]
الصنف : Not Hacker
آخر تواجد : 27/12/2014/16:59
سبب الغياب : حاظر
معدل التقييم: 0
نقاط التقييم: 10
xtrojn is on a distinguished road
شكراً: 0
تم شكره 0 مرة في 0 مشاركة

 Morocco


الإتصالات
الحالة:
xtrojn غير متواجد حالياً
وسائل الإتصال:

Arrow الدليل الكامل لتعلم إطار عمل JavaScript في يوم واحد " Angular JS"




ما هو AngularJS؟


AngularJS هو إطار عمل JavaScript لطرف العميل يتبع بنية Model-View-Controller/Model-View-View-Model، ويعتبر اليوم مُهمًا لبناء تطبيقات ويب وحيدة الصفحة (SAP) أو حتى المواقع العادية. يُعتبر Angular JS قفزة كبيرة نحو مستقبل HTML وما يجلبه الإصدار الخامس منها (مع التطورات على صعيد JavaScript بالطبع!)، ويبعث الحياة من جديد في تعاملنا مع الويب الحديث. هذا المقال جولة شاملة في Angular JS مستخلصة من تجاربي ونصائح وممارسات تعلمتها خلال استخدامي.
[]
المُصطلحات

ليس عليك أن تبذل جهداً كبيراً لتعلم Angular، وأهم ما يجب معرفته هو معاني المُصطلحات وتبني نمط MVC، وMVC هو اختصار لـModel-View-Controller، أي نموذج-طريقة عرض-مُتحكِّم. فيما يلي بعض المصطلحات والواجهات البرمجية الأساسية التي تزوّدنا بها Angular.
MVC

ربما سمعت بهذا الاختصار من قبل، وهو مستخدم في لغات برمجة عديدة كوسيلة لبناء هيكل التطبيقات أو البرامج. وهاك تلخيص سريع لمعناه:
  • النموذج (Model): بنية البيانات التي تقوم عليها أجزاء التطبيقات، غالبًا ما تُمثل بصيغة JSON. يفضل أن تكون لديك معرفة مسبقة بـJSON قبل تعلم Angular، لأنها ضرورية للتواصل بين الخادوم وطريقة العرض (سنأتي على شرحها في النقطة التالية). على سبيل المثال، لنفترض أنه لدينا مجموعة من المستخدمين، يمكن تمثيل بيانات تعريفهم كما يلي:
  • { "users" : [{ "name": "أحمد", "id": "82047392" },{ "name": "سامر", "id": "65198013" }] }
    1
    2
    3
    4
    5
    6
    7
    8
    9

    {
    "users" : [{
    "name": "أحمد",
    "id": "82047392"
    },{
    "name": "سامر",
    "id": "65198013"
    }]
    }
عادة ما تُجلب هذه المعلومات من خادوم بطلب XMLHttpRequest، ويقابله في jQuery الإجراء $.ajax، وفي Angular الكائن $http. وقد تكون هذه المعلومات مكتوبة ضمن النص البرمجي أثناء تفسير الصفحة (من قاعدة بيانات أو مخزن بيانات). بعد ذلك يكون بإمكانك تعديل هذه المعلومات وإعادة إرسالها.
  • طريقة العرض (View): وهو أمر سهل التفسير، فهي ببساطة المُخرج النهائي أو صفحة HTML التي تعرض البيانات (النموذج) على المستخدم مثلاً. باستخدام إطار عمل MVC، تُجلب البيانات من النموذج وتُعرض المعلومات المناسبة في صفحة HTML.
  • المُتحكِّم (Controller): وله من اسمه نصيب، فهو يتحكم بالأشياء، ولكن أية أشياء؟ البيانات. المُتحكمات هي الطريقة التي تصل من خلالها بين الخادوم وطريقة العرض، فتسمح بتحديث البيانات سريعًا من خلال التواصل مع كلا الخادوم والعميل.
إعداد مشروع Angular JS (الأساسيات)

يجب أولاً تهيئة الأساسيات التي يقوم عليها مشروعنا. يجب أن نبدأ بتطبيق (ng-app) الذي يُعرِّف التطبيق (وng هي بادئة تعني Angular وتسبق عادة كل مكونات Angular JS)، ثم متحكم (Controller) ليتواصل مع طريقة العرض، ثم ربط DOM ولا ننسى تضمين Angular بالطبع. إليك الأساسيات:
نص HTML مع تصريحات ng-*:

<div ng-app="myApp"> <div ng-controller="MainCtrl"> <!-- محتويات المتحكم --> </div> </div>
1
2
3
4
5

<div ng-app="myApp">
<div ng-controller="MainCtrl">
<!-- محتويات المتحكم -->
</div>
</div>



وحدة Angular مع متحكم:

var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) { // أوامر المتحكم }]);
1
2
3
4
5

var myApp = angular.module('myApp', []);

myApp.controller('MainCtrl', ['$scope', function ($scope) {
// أوامر المتحكم
}]);



قبل أن نستبق الأمور، نحتاج لإنشاء وحدة Angular (أو Angular module)، التي ستتضمن كل النص البرمجي المُتعلق بالمشروع. هناك أكثر من طريقة للتصريح عن الوحدات، إحداها سَلسَلة كل النص البرمجي معًا (لا أفضل هذه الطريقة):
angular.module('myApp', []) .controller('MainCtrl', ['$scope', function ($scope) {...}]) .controller('NavCtrl', ['$scope', function ($scope) {...}]) .controller('UserCtrl', ['$scope', function ($scope) {...}]);
1
2
3
4

angular.module('myApp', [])
.controller('MainCtrl', ['$scope', function ($scope) {...}])
.controller('NavCtrl', ['$scope', function ($scope) {...}])
.controller('UserCtrl', ['$scope', function ($scope) {...}]);



ولكن الطريقة التي أفضلها، والتي أثبتت أنها الأفضل لكل مشاريع Angular التي صمّمتها هي تعريف الوحدة العامة بشكل منفصل. الطريقة التي تعتمد على تسلسل التصريحات قد تجعلك تنسى إغلاق بعض الأقواس وتجعل قراءة النص البرمجي وتصحيحه أكثر تعقيدًا. لذا أُفضّل هذا الأسلوب:
var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) {...}]); myApp.controller('NavCtrl', ['$scope', function ($scope) {...}]); myApp.controller('UserCtrl', ['$scope', function ($scope) {...}]);
1
2
3
4

var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope', function ($scope) {...}]);
myApp.controller('NavCtrl', ['$scope', function ($scope) {...}]);
myApp.controller('UserCtrl', ['$scope', function ($scope) {...}]);



بهذه الطريقة أُقسّم النص البرمجي على عدة ملفات، وفي كل ملف أربط مكوّناً من المكونات مع فضاء الأسماء myApp فيصبح تلقائيًا جزءًا من تطبيقي. نعم، الأمر كما فهمت، أفضل أن أنشئ ملفًا مستقلًا لكل متحكم ومُرشِد (directive) ومعمل (factory) وأي شيء آخر (ستشكرني على هذا). فيما بعد يمكنك دمجها معًا وتقليصها لتصبح ملفًا واحدًا (مستخدمًا مُدير مهام مثل Grunt أو Gulp) فتدفعَه إلى DOM.
المُتحكّمات (Controllers)

أصبحت تعرف الآن مفهوم MVC وتعلمت طريقة إعداد مشروع جديد، فلنطّلع الآن على الكيفية التي يُطبِّق فيها Angular JS العمل بالمتحكّمات.
بناء على المثال السابق، بإمكاننا الآن أن نخطو خطوة بسيطة نحو عرض بعض البيانات ضمن طريقة العرض مستخدمين مُتحكّمًا. يستخدم Angular تركيب ” handlebars” لقولبة HTML. ببساطة يعني هذا أنه بإمكان المتحكمات أن تعرض البيانات في صفحة HTML بأن تستبدل كل عبارة فيها مكتوبة ضمن الأقواس المزدوجة هكذا: {{ data }} قيمة يُعيّنها المُتحكم. في الحالة المثالية يجب أن لا تحوي صفحة HTML نصًا حقيقيًا أو قيمًا مُدرجة مسبقًا، ويجب أن تترك هذه المهمة لمتحكمات Angular. فيما يلي مثال يُبيّن كيف يمكن عرض نص أو سلسلة حروف String بسيطة ضمن الصفحة:

<div ng-app="myApp"> <div ng-controller="MainCtrl"> {{ text }} </div> </div>
1
2
3
4
5

<div ng-app="myApp">
<div ng-controller="MainCtrl">
{{ text }}
</div>
</div>



في ملف JavaScript:
var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.text = 'مرحباً بمعجبي Angular!'; }]);
1
2
3
4
5
6
7

var myApp = angular.module('myApp', []);

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

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

}]);



والناتج النهائي: []
أهم مفهوم هنا هو مفهوم النطاق ($scope) والذي ستربطه بكل الوظائف ضمن متُحكّم مُعيّن. يُشير $scope إلى العُنصر أو المنطقة الحالية في DOM (فهو لا يُساوي this ضمن النص البرمجي) وبهذا يخلق نطاقًا يُحيط بكل البيانات والوظائف ضمن العناصر (DOM elements)، ويعزلها عن العناصر الأخرى، فيبدو وكأنه ينقل مجالات JavaScript العامة/الخاصة إلى DOM، وهذا شيء رائع.
قد يبدو مفهوم النطاق مخيفًا للوهلة الأولى، لكنه طريقك الواصل بين الخادوم (أو حتى البيانات المحلية) من جهة وDOM من الجهة الأخرى. يعطيك [] فكرة عن الطريقة التي “تُدفع” بها البيانات إلى DOM.

لنٌلقِ نظرة على بيانات حقيقية نفترض أننا جلبناها من خادوم لنعرض تفاصيل تسجيل دخول المستخدم، سنكتفي في هذه المرحلة باستخدام بيانات جاهزة، وسنتعلم كيفية جلبها من الخادوم على هيئة JSON لاحقًا.
أولاً سنكتب شفرة JavaScript:
var myApp = angular.module('myApp', []); myApp.controller('UserCtrl', ['$scope', function ($scope) { // لنجعل معلومات المستخدم ضمن عنصر فرعي $scope.user = {}; $scope.user.details = { "username": "Todd Motto", "id": "89101112" }; }]);
1
2
3
4
5
6
7
8
9
10
11
12

var myApp = angular.module('myApp', []);

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

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

}]);



ثم ننتقل إلى DOM لعرض هذه البيانات
<div ng-app="myApp"> <div ng-controller="UserCtrl"> <p class="username"> Welcome, {{ user.details.username }}</p> <p class="id"> User ID: {{ user.details.id }}</p> </div> </div>
1
2
3
4
5
6

<div ng-app="myApp">
<div ng-controller="UserCtrl">
<p class="username">Welcome, {{ user.details.username }}</p>
<p class="id">User ID: {{ user.details.id }}</p>
</div>
</div>



[]
من المهمّ أن تتذكر أن المتحكمات تستخدم فقط للبيانات ولإنشاء وظائف تتواصل مع الخادوم وتجلب أو ترسل بيانات JSON. لا تستخدم المتحكمات لمعالجة DOM (كأن تنقل عنصرًا ضمن الصفحة أو تخفيه أو تظهره…)، فمعالجة DOM مهمة المُرشِدات (directives)، وهي ما سنشرحه لاحقًا، المهم أن تتذكر أن موضع jQuery وغيرها من المكتبات التي تتعامل مع DOM ليس ضمن المتحكّمات.
تنويه: خلال اطلاعك على وثائق Angular الرسمية، ستلاحظ أن الأمثلة المقدمة تعتمد الأسلوب التالي لإنشاء المتحكمات:
var myApp = angular.module('myApp', []); function MainCtrl ($scope) { //... };
1
2
3
4
5

var myApp = angular.module('myApp', []);

function MainCtrl ($scope) {
//...
};



لا تفعل ذلك. هذا سيجعل كل الوظائف المُصرّحة تابعةً للنطاق العامّ (global scope) ولا يربطها بشكل جيد مع التطبيق. هذا يعني كذلك أن عمليات التقليص للنص البرمجي والتجارب ستكون أكثر صعوبة. لا تلوّث فضاء الأسماء العام، بل اجعل المتحكمات ضمن التطبيق.
المُرشِدات (Directives)

الُمرشد في أبسط صوره هو نص HTML مٌقولَب، يفضل أن يكون استخدامه متكررًا ضمن التطبيق. توفر المرشدات طريقة سهلة لإدخال أجزاء DOM ضمن التطبيق دون عناء. تعلم استخدام المرشدات ليس أمرًا سهلًا على الإطلاق، وإتقانها يتطلب جهدًا، ولكن الفقرات التالية ستضعك على الطريق الصحيح.
إذن، ما فائدة المُرشدات؟ إنها مفيدة في عدة أمور، منها إنشاء عناصر DOM، مثل علامات التبويب (tabs) وقوائم التصفح – ففائدتها تعتمد على ما يفعله تطبيقك في الواجهة. لتسهيل الشرح، سأقول ببساطة: إن كنت استعملت ng-show وng-hide من قبل، فقد استعملت المرشدات (حتى وإن كان هذان لا يُدرجان أية عناصر DOM).
على سبيل التمرين، سنُنشئ نوعًا خاصًّا من الأزرار ونُسميه customButton، يُدرج هذا العنصر بعض العناصر الفرعية التي لا نريد كتابتها في كل مرة. تتنوع طرق التصريح عن المرشدات في DOM، وهي مبينة في النص البرمجي التالي:

<!-- 1: تصريح عن مُرشد كخاصّة (attribute) --> <a custom-button>انقرني</a> <!-- 2: كعنصر مخصص (custom elements) --> <custom-button>انقرني</custom-button> <!-- 3: كصنف (class) (للتوافق مع النسخ القديمة من IE) --> <a class="custom-button">انقرني</a> <!-- 4: كتعليق (comment) (ليس ملائماً لهذا التمرين) --> <!-- directive: custom-button -->
1
2
3
4
5
6
7
8
9
10
11

<!-- 1: تصريح عن مُرشد كخاصّة (attribute) -->
<a custom-button>انقرني</a>

<!-- 2: كعنصر مخصص (custom elements) -->
<custom-button>انقرني</custom-button>

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

<!-- 4: كتعليق (comment) (ليس ملائماً لهذا التمرين) -->
<!-- directive: custom-button -->




أفضّل استخدام المرشدات كخواصّ (attributes)، أما العناصر المُخصصة (custom elements) فقادمة في النسخ المستقبلية من HTML باسم Web Components، يوفر Angular ما يشبهها، ولكنها قد تنطوي على بعض العيوب والعلل في المتصفحات القديمة.
الآن نعرف كيف نصرح عن المرشدات ضمن الصفحة، سننتقل إلى إنشائها ضمن JavaScript. لاحظ أنني سأربطه مع فضاء الأسماء العام myApp؛ في صيغته الأبسط يُكتب المرشد كما يلي:

myApp.directive('customButton', function () { return { link: function (scope, element, attrs) { // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه } }; });
1
2
3
4
5
6
7

myApp.directive('customButton', function () {
return {
link: function (scope, element, attrs) {
// هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه
}
};
});



عرّفنا المرشد باستخدام الدالة .directive()، ومررنا إليها اسم المرشد 'customButton'. عندما تكتب حرفًا كبيرًا بالإنجليزية في اسم المُرشد، فإنه ينبغي استخدام اسم المرشد ضمن DOM بصيغته التي يُفصل بها باستخدام الشرطة (-) بين الحروف الكبيرة (كما في المثال السابق: استخدمنا 'customElement' في JavaScript و"custom-button" في HTML).
يُرجع المُرشد كائنًا (Object) له عدد من الخصائص. أهم ما يجب تعلّمه منها: restrict وreplace وtransclude وtemplate وtemplateUrl وأخيرًا link. لنُضف بعضها إلى شفرتنا البرمجية:

myApp.directive('customButton', function () { return { restrict: 'A', replace: true, transclude: true, template: '<a href="" class="myawesomebutton" ng-transclude>' + '<i class="icon-ok-sign"></i>' + '</a>', link: function (scope, element, attrs) { // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه } }; });
1
2
3
4
5
6
7
8
9
10
11
12
13

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 أو تتعامل مع أحداثه
}
};
});



[]
تأكد من فحص العنصر (من الأمر Inspect element في المُتصفح) لرؤية العناصر الجديدة التي أُدخلت في الصفحة. اعلم أن الرمز لم يظهر ضمن العنصر الجديد، ببساطة لأنني لم أُضمّن Font Awesome ضمن المشروع، ولكن يمكنك فهم كيف تعمل المرشدات. لنتعرف الآن ما تعنيه كل واحدة من خصائص المرشد السابقة الذكر: الخاصية restrict: تُقيّد هذه الخاصة كيفية استخدام المُرشد، كيف نريد أن نستخدمه؟ إن كنت تبني مشروعًا يتطلب دعم النسخ القديمة من IE، فعليك استخدامه كخاصّة (attribute) أو صنف (class). القيمة 'A' تعني حصر استخدام المرشد بالخواص (attributes) فقط. 'E' تعني Element و'C' صنف و'M' تعليق. القيمة الافتراضية هي 'EA' (أي عنصر وخاصة). الخاصية replace: تعني استبدال HTML العنصر المصرّح عن المُرشد ضمن الصفحة بالقالب (template) الذي يُحدد في الخاصة template (مشروحة أدناه). الخاصةtransclude: تسمح بنسخ المحتوى الأصلي للعنصر المُصرّح عن المُرشد في الصفحة ودمجه ضمن المرشد (عند التنفيذ، ستلاحظ أن العبارة “انقرني” انتقلت إلى المُرشد). الخاصية template: قالب (كذلك المستخدم في المثال) يُدخل إلى الصفحة. يفضّل استخدام القوالب الصغيرة فقط. تُعالج القوالب وتبنى من قبل Angular مما يسمح باستخدام صيغة handlebars ضمنها. الخاصة templateUrl: مشابهة للسابقة، ولكنها تُجلب من ملف أو من وسم <script> بدل كتابتها ضمن تعريف المُرشد. كل ما عليك هو تعيين مسار الملف الذي يحوي القالب. يكون هذا الخيار مناسبًا عندما تريد الاحتفاظ بالقوالب خارج النص البرمجي لملفات JavaScript:
myApp.directive('customButton', function () { return { templateUrl: 'templates/customButton.html' // directive stuff... });
1
2
3
4
5
6

myApp.directive('customButton', function () {
return {
templateUrl: 'templates/customButton.html'
// directive stuff...

});



وضمن الملف، نكتب:
<!-- inside customButton.html --> <a href="" class="myawesomebutton" ng-transclude> <i class="icon-ok-sign"></i> </a>
1
2
3
4

<!-- inside customButton.html -->
<a href="" class="myawesomebutton" ng-transclude>
<i class="icon-ok-sign"></i>
</a>



ملاحظة: لا يخضع اسم الملف إلى أية قاعدة، وليس من الضروري أن يوافق اسمَ المُرشد.
عند استخدام الأسلوب السابق، سيحتفظ المتصفح بنسخة مُخبأة (cached) من ملف HTML، وهو أمر رائع، الخيار البديل هو استخدام قالب ضمن وسم <script> وهنا لا تُخبأ نسخة منه في المتصفح:

<script type="text/ng-template" id="customButton.html"> <a href="" class="myawesomebutton" ng-transclude> <i class="icon-ok-sign"></i> </a> </script>
1
2
3
4
5

<script type="text/ng-template" id="customButton.html">
<a href="" class="myawesomebutton" ng-transclude>
<i class="icon-ok-sign"></i>
</a>
</script>



هنا أخبرنا Angular بأن وسم <script> هذا هو قالب (ng-template) وأعطيناه المُعرف. سيبحث Angular عن القالب أو عن ملف html، فاستخدم ما تراه مناسبًا. شخصيًا، أفضّل إنشاء ملفات html لسهولة تنظيمها ولتحسين الأداء وإبقاء DOM نظيفًا، فقد يستخدم مشروعك مع الوقت عشرات المُرشدات، وترتيبها في ملفات مستقلة يجعل مراجعتها أسهل.
الخدمات (Services)

كثيرًا ما تثير الخدمات في Angular ارتباك المطورين، ومن خبرتي وأبحاثي، أعتقد أن الخدمات وُضعت كنمط وأسلوب للتصميم أكثر من اختلافها بالوظيفة التي تؤديها. بعد التنقيب في مصدر Angular، وجدت أنها تُعالج وتبنى باستخدام المُجمّع (compiler) ذاته، وكذلك فهي تقدم العديد من الوظائف المشابهة. أنصح باستخدام الخدمات لبناء الكائنات المُتفرِّدة (singletons)، واستخدام المعامل (Factories) لبناء وظائف أكثر تعقيدًا كالكائنات الحرفيّة (Object Literals).
فيما يلي مثال لاستخدام خدمة توجد ناتج الضرب لعددين:

myApp.service('Math', function () { this.multiply = function (x, y) { return x * y; }; });
1
2
3
4
5

myApp.service('Math', function () {
this.multiply = function (x, y) {
return x * y;
};
});



يمكنك بعد هذا استخدامها ضمن مُتحكم كما يلي:
myApp.controller('MainCtrl', ['$scope', function ($scope) { var a = 12; var b = 24; // الناتج: 288 var result = Math.multiply(a, b); }]);
1
2
3
4
5
6
7

myApp.controller('MainCtrl', ['$scope', function ($scope) {
var a = 12;
var b = 24;

// الناتج: 288
var result = Math.multiply(a, b);
}]);



نعم بالطبع إيجاد ناتج الضرب سهل ولا يحتاج خدمة، لكننا نستخدمه لإيصال الفكرة فحسب.
عندما ننشئ خدمة (أو معملاً) نحتاج إلى إخبار Angular عن متطلبات هذه الخدمة، وهو ما يسمى “حقن المتطلبات Dependency Injection” – إن لم تُصرّح عن المتطلبات فلن يعمل المتحكم المعتمد على الخدمة، وسيحدث خطأ عند التجميع. ربما لاحظت الجزء function ($scope) ضمن التصريح عن المتحكم أعلاه، وهذا هو ببساطة حقن المتطلبات. ستُلاحظ أيضًا [$scope] قبل الجزء function ($scope)، وهو ما سأشرحه لاحقًا. فيما يلي طريقة استخدام حقن المتطلبات لإخبار Angular أنك تحتاج إلى الخدمة التي أنشأتها للتو:

// مرر الخدمة Math myApp.controller('MainCtrl', ['$scope', 'Math', function ($scope, Math) { var a = 12; var b = 24; // يُعطي 288 var result = Math.multiply(a, b); }]);
1
2
3
4
5
6
7
8

// مرر الخدمة Math
myApp.controller('MainCtrl', ['$scope', 'Math', function ($scope, Math) {
var a = 12;
var b = 24;

// يُعطي 288
var result = Math.multiply(a, b);
}]);



المعامل (Factories)

إيضاح فكرة المعامل سهل إذا كنت قد استوعبت فكرة الخدمات، بإمكاننا إنشاء كائن حرفي (Object Literal) ضمن المعمل أو عبر طرق أكثر تعقيدًا:
function ($http) { return { get: function(url) { return $http.get(url); }, post: function(url) { return $http.post(url); }, }; }]);
1
2
3
4
5
6
7
8
9
10

function ($http) {
return {
get: function(url) {
return $http.get(url);
},
post: function(url) {
return $http.post(url);
},
};
}]);



هنا أنشأنا مُغلفات (wrappers) مخصصة لخدمة $http في Angular المسؤولة عن طلبات XHR. بعد حقن المتطلبات ضمن المتحكم يمكننا استخدام هذا المعمل بسهولة:
myApp.controller('MainCtrl', ['$scope', 'Server', function ($scope, Server) { var jsonGet = 'http://myserver/getURL'; var jsonPost = 'http://myserver/postURL'; Server.get(jsonGet); Server.post(jsonPost); }]);
1
2
3
4
5
6

myApp.controller('MainCtrl', ['$scope', 'Server', function ($scope, Server) {
var jsonGet = 'http://myserver/getURL';
var jsonPost = 'http://myserver/postURL';
Server.get(jsonGet);
Server.post(jsonPost);
}]);



إذا أرت طلب التحديثات من الخادوم، بإمكانك إنشاء دالة Server.poll أو إن كنت تستخدم مقبسًا (ٍSocket)، فربما سترغب في إنشاء دالة Server.socket وهكذا… المعامل تسمح لك بتنظيم نصك البرمجي ضمن وحدات يمكن إدراجها ضمن المتحكمات منعًا لتكرار النص البرمجي فيها والحاجة المتكررة لصيانته.
المُرشّحات

تستخدم المرشحات مع مصفوفات (arrays) من البيانات وخارج الحلقات (loops). إن احتجت للمرور على عناصر من مصفوفة بيانات والحصول على بعض منها فقط، فأنت في المكان الصحيح، يمكنك أيضًا استخدام المرشحات لتصفية ما يكتبه المستخدم ضمن حقل إدخال <input> مثلًا. هناك عدة طرق لاستخدام المُرشحات: ضمن متحكم أو دالة مُعرفة. فيما يلي الطريقة الأخيرة:
myApp.filter('reverse', function () { return function (input, uppercase) { var out = ''; for (var i = 0; i < 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'; }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

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';
}]);



وفي HTML:
<div ng-app="myApp"> <div ng-controller="MainCtrl"> <p> No filter: {{ greeting }}</p> <p> Reverse: {{ greeting | reverse }}</p> </div> </div>
1
2
3
4
5
6

<div ng-app="myApp">
<div ng-controller="MainCtrl">
<p>No filter: {{ greeting }}</p>
<p>Reverse: {{ greeting | reverse }}</p>
</div>
</div>



[]
وهنا نستخدم المُرشح ضمن حلقة ng-repeat:
<ul> <li ng-repeat="number in myNumbers |filterddNumbers">{{ number }}</li> </ul>
1
2
3

<ul>
<li ng-repeat="number in myNumbers |filterddNumbers">{{ number }}</li>
</ul>



مثال عن مُرشح ضمن متحكم:
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 > $scope.lowerBound; }; }]);
1
2
3
4
5
6
7
8
9
10
11
12

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;
};

}]);



واستخدامه حلقة ng-repeat:
<li ng-repeat="number in numbers | filter:greaterThanNum"> {{ number }} </li>
1
2
3

<li ng-repeat="number in numbers | filter:greaterThanNum">
{{ number }}
</li>



[]
كان هذا القسم الأكبر مما تحتاج لمعرفته عن AngularJS وواجهاتها البرمجية، ومع أن ما تعلمناه كافٍ لبناء تطبيق Angular، ولكننا إلى الآن لم نسكتشف أغوراها بعد.
ربط البيانات ثنائي الاتجاه

عندما سمعت للمرة الأولى عن ربط البيانات ثنائي الاتجاه لم أفهم ما يعنيه. باختصار يمكن القول إنه حلقة متصلة من البيانات المُزامنة: حدّث النموذج (Model) لتُحدَّث طريقة العرض (View)، أو حدّث طريقة العرض ليُحدَّث النموذج (Model). هذا يعني أن البيانات تبقى محدثة دومًا دون عناء. إن ربطت نموذج ng-model مع حقل إدخال <input> وكتبت فيه، فهذا يُنشئ (أو يُحدِّث) نموذجاً في الوقت ذاته.
فيما يلي نقوم بإنشاء حقل <input> ونربطه بنموذج نسميه myModel، يمكنني الآن استخدام صياغة handlebars لعكس هذا النموذج وما يطرأ عليه من تحديثات في طريقة العرض في الوقت ذاته:

<div ng-app="myApp"> <div ng-controller="MainCtrl"> <input type="text" ng-model="myModel" placeholder="Start typing..." /> <p> My model data: {{ myModel }}</p> </div> </div>
1
2
3
4
5
6

<div ng-app="myApp">
<div ng-controller="MainCtrl">
<input type="text" ng-model="myModel" placeholder="Start typing..." />
<p>My model data: {{ myModel }}</p>
</div>
</div>




myApp.controller('MainCtrl', ['$scope', function ($scope) { // Capture the model data // and/or initialise it with an existing string $scope.myModel = ''; }]);
1
2
3
4
5

myApp.controller('MainCtrl', ['$scope', function ($scope) {
// Capture the model data
// and/or initialise it with an existing string
$scope.myModel = '';
}]);



[]
طلبات XHR/Ajax/$http وربط JSON

نعرف الآن كيف نرسل بيانات بسيطة ضمن المجال ($scope)، ونعرف ما يكفي عن كيفية عمل النماذج وربط البيانات ثنائي الجانب، والآن حان الوقت لمحاكاة طلبات XHR حقيقية للخادوم. ليس هذا ضروريًا لمواقع الويب العادية، لكنه مناسب جدًا لجلب البيانات في تطبيقات الويب.
عندما تطور تطبيقك على جهازك المحلي، فغالبًا ما ستستخدم لغة مثل Java أو ASP.NET أو PHP أو غيرها لتشغيل خادوم محلي. وسواء كنا نتصل بقاعدة بيانات محلية أم بخادوم بعيد كواجهة برمجية، فإننا نتبع نفس الخطوات بالضبط.

هنا يأتي دور $http، صديقك المخلص من اليوم فصاعدًا. الدالة $http هي مُغلّف wrapper تقدمه Angular للوصول إلى البيانات من الخادوم، وهو سهل الاستخدام للغاية ولا يحتاج لأية خبرة. فيما يلي مثال عن طلب GET لجلب البيانات من الخادوم. الصياغة مشابهة جدًا لصياغة jQuery، وهذا يُسهل الانتقال من الأخيرة إلى Angular:
myApp.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) { $http({ method: 'GET', url: '//localhost:9000/someUrl' }); }]);
1
2
3
4
5
6

myApp.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
$http({
method: 'GET',
url: '//localhost:9000/someUrl'
});
}]);



يُعيد Angular إلينا أمرًا يُصطلح على تسميته الوعد (Promise) ، وهو بديل أسهل استخدامًا من الاستدعاءات الراجعة (callbacks). يمكن تركيب الوعود في سلسلة باستخدام النقطة، ويمكننا ربطها مع مستقبلات النجاح والفشل:
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 }); }]);
1
2
3
4
5
6
7
8
9
10
11
12

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
});
}]);



سهلة الاستخدام والقراءة. هنا نربط طريقة العرض والخادوم بربط نموذج أو تحديثه. لنفترض أنه لدينا خادومًا مُعدًّا ولنقم بدفع اسم المستخدم إلى طريقة العرض عن طريق طلب AJAX.
علينا –لو كنا حريصين على المثالية– أن نصمم بيانات JSON التي نريدها أولاً. دعونا الآن نُبسط الأمور، ولندع هذا الأمر ليتولاه من يفهم في أمور النهاية الخلفية (backend)، ولكن لنقل أننا تفترض أن نستقبل بيانات مثل هذه:
{ "user": { "name": "Todd Motto", "id": "80138731" } }
1
2
3
4
5
6

{
"user": {
"name": "Todd Motto",
"id": "80138731"
}
}



هذا يعني أننا سنحصل على كائن Object من الخادوم (سنسميه data، وسترى أنه يُمرر إلى مستقبلات الوعد الذي أنشأناه).
علينا الآن أن نربط هذا الكائن بالخاصة data.user، وضمنها لدينا name وid.
يمكن ببساطة الوصول إلى هذه القيم باستخدام data.user.name للحصول على “Todd Motto” مثلاً.

فيما يلي الشفرة البرمجية (اطلع على التعليقات المضمنة):
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) { // وقع خطأ ما! }); }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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) {
// وقع خطأ ما!
});
}]);



الآن ضمن الصفحة يمكننا ببساطة كتابة:
<div ng-controller="UserCtrl"> <p> {{ user.username }}</p> </div>
1
2
3

<div ng-controller="UserCtrl">
<p>{{ user.username }}</p>
</div>



هذا سيعرض اسم المستخدم. لننتقل الآن إلى خطوة أبعد بفهم ربط البيانات التصريحي (Declarative data-binding) حيث تصبح الأمور أكثر إثارة.
ربط البيانات التصريحي

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

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" }]; }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

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"
}];

}]);



علينا الآن دفعها ضمن الصفحة. هنا نستخدم الربط التصريحي لنُعلن عما سيفعله تطبيقنا: إنشاء أول جزء من عناصر HTML الحيوية. سنستخدم مُرشد ng-repeat المبني ضمن Angular، والذي سوف يمر على البيانات ويعرض الناتج دون عناء الاستدعاءات الرجعية أو تغيير الحالة، بهذه السهولة:
<ul> <li ng-repeat="message in emails.messages"> <p> From: {{ message.from }}</p> <p> Subject: {{ message.subject }}</p> <p> {{ message.sent | date:'MMM d, y h:mm:ss a' }}</p> </li> </ul>
1
2
3
4
5
6
7

<ul>
<li ng-repeat="message in emails.messages">
<p>From: {{ message.from }}</p>
<p>Subject: {{ message.subject }}</p>
<p>{{ message.sent | date:'MMM d, y h:mm:ss a' }}</p>
</li>
</ul>



[]
قمت أيضًا باستخدام مُرشّح التاريخ لأبين لك كيف يمكن أن تعرض تواريخ UTC.
اطلع على المُرشدات التي توفرها Angular لتتعرف على القدرات الكاملة للربط التصريحي. بهذا نكون قد عرفنا كيف نصل البيانات بين الخادوم وطريقة العرض.
وظائف المجال (Scope functions)

تعتبر وظائف المجال الخطوة التالية في بناء وظائف التطبيق واستكمالاً للربط التصريحي. فيما يلي وظيفة بسيطة تحذف إحدى الرسائل:
myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.deleteEmail = function (index) { $scope.emails.messages.splice(index, 1) }; }]);
1
2
3
4
5
6
7

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

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

}]);



تنويه: من المهم أن تفكر في حذف البيانات من النموذج، لا تحذف العناصر أو أي شيئ من الصفحة، دع Angular يتولى هذا بربطه ثنائي الجانب للبيانات، فقط فكر بذكاء واكتب شفرة برمجية تستجيب لبياناتك.
ربط الوظائف مع طريقة العرض يمر عبر المُرشدات، هذه المرة نستخدم مُرشد ng-click:
<a ng-click="deleteEmail($index)">Delete email</a>
1

<a ng-click="deleteEmail($index)">Delete email</a>



هذا يختلف تمامًا عن مستقبلات النقر التقليدية في JavaScript، لأسباب عديدة سنشرحها لاحقًا.
لاحظ أنني أيضًا أمرر فهرس العنصر $index، إذ يعرف Angualr ما العنصر المُراد حذفه (كم يوفر هذا من العناء؟)

[]
دوال DOM التصريحية

ننتقل الآن لدوال DOM، وهي أيضًا مُرشدات تؤدي وظيفة ضمن الصفحة بدونها كنا سنكتب شفرات برمجية طويلة. أحد الأمثلة المناسبة لإيضاح الفكرة هنا هو إظهار أو إخفاء قسم التنقل ضمن الصفحة باستخدام ng-show وng-click، لنرَ بساطة هذا:
<a href="" ng-click="toggle = !toggle">Toggle nav</a> <ul ng-show="toggle"> <li>Link 1</li> <li>Link 2</li> <li>Link 3</li> </ul>
1
2
3
4
5
6

<a href="" ng-click="toggle = !toggle">Toggle nav</a>
<ul ng-show="toggle">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>



هنا ندخل عالم MVVM (اختصار Model-View-View-Model)، لاحظ أننا لم نستخدم متحكمًا، وسنشرح فكرة MVVM بعد قليل.
الناتج (جرب الإظهار والإخفاء):
[]
التعابير (Expressions)

من أفضل ما يقدمه Angular، يقدم بديلاً عن الحاجة لكتابة الكثير من JavaScript والنصوص المكررة.
هل قمت يومًا ما بكتابة شيء كهذا؟
elem.onclick = function (data) { if (data.length === 0) { otherElem.innerHTML = 'No data'; } else { otherElem.innerHTML = 'My data'; } };
1
2
3
4
5
6
7

elem.onclick = function (data) {
if (data.length === 0) {
otherElem.innerHTML = 'No data';
} else {
otherElem.innerHTML = 'My data';
}
};



ربما يكون هذا استدعاءً راجعًا عن طلب GET، ونحتاج لنغير محتوى في الصفحة بناء على البيانات، يقدم Angular هذا بدون الحاجة لكتابة حرف JavaScript!
<p> {{ data.length > 0 && 'My data' || 'No data' }}</p>
1

<p>{{ data.length > 0 && 'My data' || 'No data' }}</p>



سيقوم هذا بتحديث الصفحة تلقائيًا دون استدعاءات عند وصول البيانات أو ما شابه. إن لم تتوفر البيانات، سيظهر هذا واضحًا، وإن وجدت فسيظهر كذلك. هناك حالات كثيرة جدًا يُمكن فيها لـAngular أن يتولاها عبر ربطه ثنائي الجانب للبيانات الذي يعمل بشكل رائع.
[]
طرق العرض الديناميكية والتوجيه (Routing)

هي ما تقوم عليه فلسفة تطبيقات الويب (والمواقع) أحادية الصفحة: لديك قسم الترويسة وقسم التذييل وشريط جانبي ثم المحتوى الذي يُحدث تلقائيًا بناءً على الرابط الحالي.
يجعل Angular إعداد هذا الأمر في منتهى السهولة. تحقن طرق العرض الديناميكة دوالا مُعينة بناء على الرابط، عبر استخدام $routeProvider. فيما يلي إعداد بسيط:
myApp.config(['$routeProvider', function ($routeProvider) { /** * $routeProvider */ $routeProvider .when('/', { templateUrl: 'views/main.html' }) .otherwise({ redirectTo: '/' }); }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

myApp.config(['$routeProvider', function ($routeProvider) {

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

}]);



لاحظ أنه عندما (when) يكون الرابط / فقط (الصفحة الرئيسية)، ستعرض الصفحة main.html. من المفيد تسمية طريقة العرض الأساسية main.html وليس index.html لأنه سيكون لدينا مسبقاً الصفحة index.html وهي الصفحة التي تحوي طرق العرض الديناميكية وبقية الأجزاء.
يمكن ببساطة إضافة المزيد من طرق العرض:

myApp.config(['$routeProvider', function ($routeProvider) { /** * $routeProvider */ $routeProvider .when('/', { templateUrl: 'views/main.html' }) .when('/emails', { templateUrl: 'views/emails.html' }) .otherwise({ redirectTo: '/' }); }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

myApp.config(['$routeProvider', function ($routeProvider) {

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

}]);



بإمكاننا الآن تحميل الصفحة emails.html ببساطة لتقوم بعرض قائمة الرسائل الإلكترونية. الخلاصة أننا استطعنا أن نبني تطبيقًا معقدًا للغاية بجهد ضئيل جدًا.
توفر الخدمة $routerProvider المزيد من الخيارات، لكن ما تعلمناه عنها كافٍ في البداية. هناك أيضًا أمور أخرى مثل مُعترِضات $http التي تبدأ أحداثًا خلال مسير طلب AJAX، فتتيح لنا عرض مقدار التقدم على سبيل المثال أثناء جلب البيانات.

البيانات الثابتة العامة

في تطبيق Gmail للويب، تُكتب بيانات كثيرة بصيغة JSON ضمن الصفحة (انقر باليمين واختر عرض المصدر في صفحة Gmail). إن قمنا بخطوة مشابهة، أي كتابة البيانات ضمن الصفحة، فهذا سيجعل وقت عرضها أقل وسيبدو التطبيق أسرع.
عندما أطور تطبيقات مؤسستنا، تُدرج وسوم Java ضمن الصفحة وعندما تُعرض، تُرسل البيانات من الخادوم (لا خبرة لدي في Java لذا سأكتب فيما يلي تصريحات وهمية، يمكنك استخدام أي لغة على الخادوم إن أحببت). النصوص التالية توضح كيف يمكنك كتابة JSON ضمن الصفحة ثم تمريرها إلى المتحكم لربطها مباشرة:
<!-- ضمن index.html (في نهاية الصفحة بالطبع) --> <script> window.globalData = {}; globalData.emails = <javatagheretogeneratemessages>; </script>
1
2
3
4
5

<!-- ضمن index.html (في نهاية الصفحة بالطبع) -->
<script>
window.globalData = {};
globalData.emails = <javaTagHereToGenerateMessages>;
</script>



سيُنشئ وسم Java الذي اختلقته البينات بينما سيعالج Angular الرسائل فورًا. كل ما عليك هو إعطاؤه البيانات عبر المتحكم:
myApp.controller('EmailsCtrl', ['$scope', function ($scope) { $scope.emails = {}; // Assign the initial data! $scope.emails.messages = globalData.emails; }]);
1
2
3
4
5
6
7
8

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

$scope.emails = {};

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

}]);



تقليص الملفات (Minification)

سنتحدث قليلاً عن تقليص حجم الشفرات البرمجية التي كتبناها. ربما تكون قد جربت تقليص شفراتك البرمجية التي كتبتها لـAngular وصادفت خطأ.
ليس هناك أمور خاصة يتطلبها تقليص حجم هذه الملفات، باستثناء الحاجة لإدراج أسماء المتطلبات ضمن مصفوفة قبل الدالة المُصرّح عنها، لنوضح أكثر:

myApp.controller('MainCtrl', ['$scope', 'Dependency', 'Service', 'Factory', function ($scope, Dependency, Service, Factory) { // code }]);
1
2
3
4
5
6
7

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

// code

}]);



بعد التقليص:
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 () {...}; }]);
1
2
3
4
5
6
7
8
9
10
11
12
13

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 () {...};

}]);



عليك أن تحافظ على ترتيب المتطلبات المحقونة في المصفوفة ['_one', '_two'] وضمن مُعاملات الدالة function(_one, _two)، وإلا فإنك ستسبب لنفسك ولفريق العمل معك مشاكل كثيرة!
الاختلافات بين MVC وMVVM

سننهي مقالتنا العملاقة الآن بشرح سريع يشمل الفروق بين MVC وMVVM:
  • MVC: التواصل يعتمد على المتحكم (Controller)، لذلك نقول Model-View-Controller
  • MVVM: يشمل ربط البيانات التصريحي الذي يتواصل، بالمفهوم التقني، مع نفسه؛ أي Model-View-View-Model. يتواصل النموذج مع طريقة العرض، وتتواصل هذه الأخيرة مع النموذج ثانية. يسمح هذا للبيانات بأن تبقى محدّثة على الجانبين دون الحاجة لفعل أي شيء. لا داعي هنا للمتحكم.
    مثال على ذلك: إنشاء حلقة ng-repeat دون أن نعتمد على بيانات يُرسلها متحكم:
  • <li ng-repeat="number in [1,2,3,4,5,6,7,8,9]"> {{ number }} </li>
    1
    2
    3

    <li ng-repeat="number in [1,2,3,4,5,6,7,8,9]">
    {{ number }}
    </li>
يبدو هذا مناسبًا للتجارب السريعة، ولكنني أنصح دومًا باستخدام متحكم للحفاظ على تنظيم النص البرمجي.
[]
مكونات الويب في HTML5

قد تبدو هذه الفكرة مُكررّة، ولكنني سأعيدها هنا لنتحدث عن مكونات الويب.
يسمح Angular بإنشاء عناصر (elements) مخصصة مثل: <myCustomElement></myCustomElement>

في الحقيقة هذا أشبه ما يكون بمستقبل HTML5 التي تقدم فكرة جديدة تُسمى مكونّات الويب (Web Components)، والتي تتركب من عناصر مخصصة ضمن HTML مترافقة مع نص JavaScript ديناميكي، وهذا أمر مثيرٌ للغاية – والأكثر إثارة أنه أمر ممكن اليوم باستخدام Angular. فريق Angular بعيد النظر – شكرًا لكم!
تعليقات المجال (Scope)

أعتقد أن تعليقات المجال إضافة جميلة لسياق العمل، فبدل الحاجة لكتابة التعليقات ضمن HTML بالطريقة التالية:
<!-- header --> <header> Stuff. </header> <!-- /header -->
1
2
3
4
5

<!-- header -->
<header>
Stuff.
</header>
<!-- /header -->



أصبحنا نتحدث عن طرق العرض والمجالات بدل الصفحة، البيانات ضمن مجال ما لا تُشارك مع مجالات أخرى إلا إن قمت بفعل ذلك عن عمدٍ. لنستغل هذا في تحسين كتابة النص البرمجي بتقسيمه إلى مناطق تسبقها تعليقات:
!-- scope: MainCtrl --> <div class="content" ng-controller="MainCtrl"> </div> <!-- /scope: MainCtrl -->
1
2
3
4
5

!-- scope: MainCtrl -->
<div class="content" ng-controller="MainCtrl">

</div>
<!-- /scope: MainCtrl -->



تصحيح العلل في Angular

تتوفر إضافة جميلة للغاية لمتصفح Chrome ينصح بها فريق Angular، وتسمى [].
برمجة سعيدة!

للاشارة الموضوع منقول من [] و تم نقله بعد اخد الاذن من صاحب المدونة



آخر مواضيع » xtrojn

عرض البوم صور xtrojn   رد مع اقتباس
إضافة رد

مواقع النشر (المفضلة)

الكلمات الدلالية (Tags)
مدرسة , النت , البرمجة , تعلم , java


حالياً الأعضاء النشيطين الذين يشاهدون هذا الموضوع : 1 (0 عضو و 1 ضيف)
 

(أظهر الكل الأعضاء الذين قاموا بمشاهدة هذا الموضوع : 3
loun , S1LV3rS3rf3r , xtrojn

تعليمات المشاركة
لا تستطيع إضافة مواضيع جديدة
لا تستطيع الرد على المواضيع
لا تستطيع إرفاق ملفات
لا تستطيع تعديل مشاركاتك

كود [IMG] متاحة
كود HTML معطلة

الانتقال السريع

المواضيع المتشابهه
الموضوع كاتب الموضوع المنتدى مشاركات آخر مشاركة
تعرف على أفضل 8 برامج لصناعة الرسوم المتحركة "2d" و "3d" ADMINISTRATOR [ منتدى اخبــــار الشبكـــة] 0 02/12/2013 12:53
[ شرح ] : الفهرس الكامل للعملاق "Driver Genius12 "في جلب وتحديث التعريفات للجهاز"خاص ADMINISTRATOR [ منتدى البرامج الكاملة والمشروحة ] 0 07/09/2013 12:22
لعيونكم "/"احلى واجمل وافضل موقع بالعالم.."/" Dr.Black_ID [ مـنتدى حمايه المواقع والسيرفرات | Hacking Site's & Servers ] 2 07/05/2011 16:50
"عرب نت ???? -التحول الرقمي" يفتتح الأربعاء في "الحبتور" برعاية الرئيس سليمان ADMINISTRATOR [ منتدى اخبــــار الشبكـــة] 0 21/03/2011 20:21
مؤتمر"عرب نت" يعلن اسماء المتأهلين الى نهائيات مسابقتي "ماراثون الأفكار" ADMINISTRATOR [ منتدى اخبــــار الشبكـــة] 0 16/03/2011 20:22

الساعة معتمدة بتوقيت جرينتش +1 . الساعة الآن : 15:06.
Copy Right Des 2010 - 2014 To is|sec Organization, Des By  yasMouh 
Powered By vBulletin Special Edition, Secured By Dz-SeC team
Support by Dz-SeC team




RSS RSS 2.0 XML MAP HTML



 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115