البرمجة

المتحكمات في AngularJS: شرح مفصل

المتحكمات (Controllers) في AngularJS: العمود الفقري لتفاعل المستخدم في تطبيقات الويب

تُعد المتحكمات (Controllers) في AngularJS أحد الركائز الأساسية التي بُني عليها هذا الإطار البرمجي الشهير المخصص لتطوير واجهات المستخدم الديناميكية في تطبيقات الويب. حيث توفر المتحكمات بيئة منطقية لربط البيانات (Data) مع واجهة المستخدم (View) وإدارتها بكفاءة. من خلال هذا المفهوم، يتم فصل منطق التطبيق عن العرض، مما يعزز القابلية لإعادة الاستخدام، والاختبار، والتوسعة المستقبلية.

إن فهم آلية عمل المتحكمات في AngularJS يُعد جوهرياً لأي مطوّر يسعى لبناء تطبيقات تعتمد على بنية MVC (Model-View-Controller) أو ما يشابهها، حيث يكون المتحكم هو الجسر الذي يربط بين النموذج (Model) والعرض (View).


تعريف المتحكم (Controller) في AngularJS

المتحكم هو ببساطة دالة JavaScript يتم تعريفها داخل نطاق التطبيق AngularJS، وتُستخدم لإدارة نطاق البيانات $scope وتوفير الوظائف (Functions) التي يتم ربطها بواجهة المستخدم. عندما يتم تحميل الصفحة، يقوم AngularJS بربط هذا المتحكم بعنصر HTML محدد باستخدام التوجيه ng-controller.

ويُستخدم المتحكم في الغالب لتعريف:

  • البيانات الأولية التي ستظهر في العرض.

  • العمليات التي يتم تنفيذها كرد فعل لتفاعل المستخدم.

  • التحكم في منطق الواجهة.

  • التعامل مع الأحداث والتفاعلات.


دور المتحكم في بنية MVC الخاصة بـ AngularJS

في بنية AngularJS، يُشبه المتحكم في دوره طبقة “Controller” في نموذج MVC التقليدي. حيث يعمل كوسيط بين العرض (View) والنموذج (Model). أي أن:

  • العرض (View) يمثل واجهة المستخدم المبنية بـ HTML/CSS.

  • النموذج (Model) يمثل البيانات والمعلومات التي يتم عرضها أو تعديلها.

  • المتحكم (Controller) هو المنسق الذي يربط بين الاثنين ويستجيب للأحداث ويُحدث التعديلات على النموذج.


إنشاء متحكم في AngularJS

يتم إنشاء المتحكم في AngularJS باستخدام الدالة controller الخاصة بوحدة Angular. فيما يلي مثال على إنشاء متحكم بسيط:

javascript
var app = angular.module('myApp', []); app.controller('MainController', function($scope) { $scope.message = "مرحباً بك في AngularJS!"; });

وفي جانب HTML:

html
<div ng-app="myApp" ng-controller="MainController"> <h1>{{ message }}h1> div>

في هذا المثال، يتم عرض القيمة “مرحباً بك في AngularJS!” داخل العنصر

من خلال ربط البيانات مع خاصية $scope.message.


مفهوم $scope في المتحكمات

يُعد كائن $scope الجسر الحيوي بين المتحكم والعرض. حيث تُخزّن فيه جميع البيانات والوظائف التي سيتم استخدامها في واجهة المستخدم. عند تغيير قيمة أحد الخصائص في $scope، يتم تحديث العرض تلقائيًا (two-way data binding)، مما يجعل تجربة المستخدم ديناميكية وفورية.

بعض خصائص $scope الأساسية التي تُستخدم بشكل متكرر:

الخاصية الوصف
$scope.message تُخزن رسالة نصية تُعرض في واجهة المستخدم
$scope.items تُخزن مصفوفة من العناصر تُستخدم في التكرار مع ng-repeat
$scope.addItem() تُستخدم كدالة تضيف عنصرًا جديدًا إلى المصفوفة

تقسيم المتحكمات إلى وحدات منطقية

في التطبيقات الكبيرة، من الأفضل تقسيم المتحكمات إلى أقسام ووحدات منطقية صغيرة تتعامل مع أجزاء معينة من التطبيق. وهذا يسمح بفصل الاهتمامات (Separation of Concerns) وزيادة قابلية الصيانة.

فمثلاً يمكن إنشاء متحكم للمنتجات، وآخر للمستخدمين، وآخر لتسجيل الدخول، وهكذا. كل متحكم يدير منطقة معينة من التطبيق ويمتلك بياناته ودواله الخاصة.


استخدام الخدمات (Services) داخل المتحكمات

غالباً ما يحتاج المتحكم إلى التواصل مع مصادر بيانات خارجية أو تنفيذ منطق تجاري معقد، وهنا يأتي دور الخدمات (Services) في AngularJS. يُمكن حقن الخدمة داخل المتحكم باستخدام نظام الحقن التلقائي (Dependency Injection).

مثال:

javascript
app.controller('ProductController', function($scope, ProductService) { $scope.products = []; ProductService.getAll().then(function(response) { $scope.products = response.data; }); });

في هذا المثال، يتولى ProductService مهمة جلب البيانات من API خارجي، بينما يركز المتحكم على عرض البيانات للمستخدم فقط.


نطاق المتحكم (Controller Scope)

يُربط المتحكم دائمًا بعنصر HTML معين أو جزء معين من الواجهة، ويكون نطاق $scope الخاص به مقصورًا على ذلك الجزء فقط. هذا يعني أنه إذا تم تعريف متحكم داخل عنصر

، فلن تتاح خصائص $scope الخاصة به إلا داخل ذلك العنصر وما يحتويه.

يساعد ذلك على عزل البيانات والوظائف، ومنع تداخلها مع مكونات أخرى في الصفحة.


الممارسات الجيدة في كتابة المتحكمات

لضمان جودة الكود وسهولة اختباره وصيانته، يُفضل اتباع الممارسات التالية:

  • الحفاظ على بساطة المتحكم: يجب ألا يحتوي المتحكم على منطق تجاري معقد، بل يُفضّل نقل هذا المنطق إلى الخدمات.

  • استخدام السلاسل الزمنية Promises: عند التعامل مع بيانات غير متزامنة (Asynchronous)، يُفضل استخدام Promise بدلاً من تنفيذ العمليات مباشرة داخل المتحكم.

  • الاعتماد على التوجيهات (Directives) للعرض: لا يجب أن يحتوي المتحكم على تعليمات خاصة بكيفية عرض البيانات. يقتصر دوره على إعداد البيانات فقط.

  • التقليل من الاعتماد على $scope: في الإصدارات الحديثة، يُفضل استخدام النموذج القائم على controllerAs والذي يستخدم الكائن this بدلاً من $scope.


استخدام controllerAs بدلاً من $scope

من التحسينات التي أُدخلت على AngularJS دعم نمط “Controller As”، وهو أسلوب أكثر تنظيماً واستقراراً في إدارة البيانات داخل المتحكمات. بدلاً من استخدام $scope، يتم ربط المتحكم بواجهة العرض باستخدام الكلمة المفتاحية this.

مثال:

javascript
app.controller('MainController', function() { this.message = "مرحباً بك في نموذج Controller As!"; });

وفي جانب HTML:

html
<div ng-controller="MainController as main"> <h1>{{ main.message }}h1> div>

هذا النمط يُقلل من التعقيدات المتعلقة بـ $scope ويُسهل عملية اختبار المتحكمات.


العلاقة بين المتحكمات والتوجيهات (Directives)

في AngularJS، غالبًا ما يتم استخدام التوجيهات (مثل ng-click, ng-model, ng-repeat) للتفاعل مع المتحكمات. على سبيل المثال، عند الضغط على زر يمكن استدعاء دالة داخل المتحكم:

html
<button ng-click="addProduct()">إضافة منتجbutton>

وهذه الدالة تكون معرفة داخل المتحكم على النحو التالي:

javascript
$scope.addProduct = function() { // منطق إضافة منتج };

تُعتبر هذه التوجيهات واجهة الربط الأساسية بين العرض والمتغيرات والوظائف المعرفة داخل المتحكم.


مقارنة بين متحكمات AngularJS و Angular (الإصدارات الأحدث)

مع تطور Angular إلى Angular 2 وما بعده، تم إلغاء مفهوم المتحكمات تماماً لصالح مكونات (Components) أكثر شمولاً وتنظيماً. ومع ذلك، في AngularJS، تبقى المتحكمات هي الطريقة الأساسية لتنظيم منطق التطبيق وربط البيانات.

الجدول التالي يوضح الفرق الأساسي:

الجانب AngularJS Angular 2+
الوحدة الأساسية المتحكم + العرض المكون (Component)
إدارة البيانات $scope أو controllerAs استخدام @Input و @Output
الربط بالعرض توجيهات مثل ng-model خاصيات في القالب (template bindings)
تنظيم المشروع غير صارم بنية صارمة باستخدام TypeScript

حالات استخدام عملية للمتحكمات

1. إدارة المهام في قائمة ToDo

javascript
app.controller('TodoController', function($scope) { $scope.todos = []; $scope.addTodo = function() { $scope.todos.push({ text: $scope.todoText, done: false }); $scope.todoText = ''; }; });

2. إدارة بيانات النماذج

javascript
app.controller('FormController', function($scope) { $scope.user = { name: '', email: '' }; $scope.submitForm = function() { console.log('تم إرسال النموذج:', $scope.user); }; });

خاتمة تنظيمية

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


المراجع:

  1. AngularJS Official Documentation

  2. W3Schools AngularJS Controllers