RSS

Upgrading the $controllerProvider

27 ספט

אחד הדברים המציקים לי באנגולר זה העבודה המסיבית סביב ה-this לדברים שלא אמורים להיות עליו.

כתבתי כמה טריקים איך לשפר את המצב (AngularJS Tip 5: AngularJS Arguments , AngularJS Tip 4: Dynamic Prototype Pattern ). למעשה הבעיה קיימת רק שמגדירים controller. כאשר עובדים עם factory אני כותב את הקוד בסגנון הבא:

var mi = angular.module('myApp', ['ngRoute'])            
.
factory('User'
, UserTypeFactory);

 

function UserTypeFactory($log,$http){
// constructor
function User
(name){
this.name
= name;
}

// methods
User.prototype.setName = function
(newName){
this.name
= newName;
};

return User;
}

 

עכשיו כל מי שרוצה לעבוד עם Class מסוג User רק צריך לבקש וה-$injector יתן לו אותו. שימו לב שאם אני רוצה לעשות ירושה אני יכול לבקש שיזריקו לפונקציה UserTypeFactory  את BaseUser ואז בתוך הפונקציה אני בונה את הירושה. המתודה UserTypeFactory רצה רק פעם אחת בלבד, כך אנגולר עובד.

אם אני מחזיר new User() בפונקציה UserTypeFactory במקום רק User קבלתי את האפקט של פונקציה service אך עם היתרון שהצלחתי ליצור private static משתנים ( הכוונה ל- $ log ו- $http ).

ומה עם Controllers?

כאן יש בעיה קשה כי ה- controllers מקבלים גם שרותים כמו $log ו- $http אך גם $scope. ה-$scope הוא לא singleton ואחרים כן. ( אישית אני חושב שזה תכנון רע מאוד מה שהצוות של אנגולר עשה כאן)

פתרון פשוט:

function UserCtrlFactory($scope,userBL,$log,$q){
   function UserCtrl
($scope) {
      this.id = $scope.$id
;
      this.name = userBL.name;       

   
}
   UserCtrl.
prototype.update = function
(name) {
     $log.
debug('update'
);
     name +=
'!'
;
     userBL.
update.call(this
, name);

    };
  angular.extend( UserCtrlFactory.
prototype
,
  UserCtrl.
prototype
);
  UserCtrl.
apply(this, arguments
);
}

 

צורת כתיבה זו מאפשרת לי לכתוב controller שבתוכו כתוב ה-controller כמחלקה. בנוסף הצלחתי להגדיר את $log ו- $http כ- private static ואילו ה- $scope יעבור ל-controller הפנימי דרך ה- constructor.

יש פה הרבה טריקים של JavaScript בשתי השורות האחרונות, אך כאן לא המקום להסביר אותם.

הפתרון הזה פשוט אך לא טוב לביצועים כי כל פעם שיוצרים את ה-controller (למשל מעבר בין דפים ) ה- controller הפנימי גם נוצר וכל הפונקציות שמוגדרות ב- prototype שלו. זה בדיוק אותה הבעיה שעובדים עם $scope ולכן מומלץ מאוד לא להגדיר מתודות על ה-$scope.

מכאן הגעתי להחלטה שאין ברירה או שכותבים ng-controller חדש שיטפל בבעיה או פתרון יותר תשתיתי זה לשדרג את $controllerProvider.

אחרי השדרוג אפשר לכתוב controller בצורה הבאה:

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

                .controller('UserCtrl',UserCtrlFactory);

 

UserCtrlFactory.isFactory = true;
function UserCtrlFactory(userBL,$log,$q){
  function UserCtrl
($scope) {
    this.id = $scope.$id
;
    this.name = userBL.name;       

    }
  UserCtrl.
prototype.update = function
(name, address) {
    $log.
debug('update'
);
    name +=
'!'
;
    userBL.
update.call(this
, name);
  };
  return UserCtrl
;
}

 

הערות:

על מנת שאנגולר ידע שהפונקציה UserCtrlFactory היא מיצרת controller ולא ה- controller עצמו, אני מוסיף לה שדה isFactory עם ערך true.

התיקון שעשיתי בקוד של אנגולר זה להוסיף את השורות הבאות כאן.

// Start : Eyal Vardi
if(expression.isFactory){

  expression = $injector.invoke(expression);
 
controllers[constructor
] = expression; } // End : Eyal Vardi

הסבר:

כאשר אנגולר מוצא את שם ה- controller הוא מאחסן אותו במשתנה בשם expression. אני בודק אם זה באמת הקונטרולר או הפונקציה שעוטפת את הקונטרולר, אם זה מעטפת אני מריץ אותה ומאחסן את ה-controller האמיתי ב- expression וגם ב- controllers[constructor] כדי שפעם הבאה נקבל רק את הקונטרולר האמיתי ולא את העטיפה.

שיקולים בעד:

הכתיבה עכשיו של controllers הרבה יותר אלגנטית ויהיה קל יותר להפוך את הקוד ל- ES6 או לאנגולר 2.

שיקולים נגד:

שינויים בקוד של אנגולר יכולים ליצור בעיות בעתיד. ע"פ דעתי זה שינוי קטן שעושה נפלאות לקוד.

 

מה אתם חושבים?

רוצים להכיר עוד טריקים מהסוג הזה, בואו ליום של Angular Hacking.

 

 

 

מודעות פרסומת
 
השארת תגובה

פורסם ע"י ב- ספטמבר 27, 2015 ב- AngularJS

 

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s

 
%d בלוגרים אהבו את זה: