תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

מדריך אנגולר: custom directives וסרטים

מחבר:
בתאריך:

 

 

משתמשים ב- Custom directivesבשביל להחליף אלמנטים פשוטים בדף אינטרנט בתוכן מורכב יותר. השימוש בהם מועיל במיוחד כשרוצים לחזור על אותו אלמנט שוב ושוב. לדוגמה, אם נרצה להחליף את שלושת הדיבים הבאים בתוכן עשיר הכולל את שם הסרט, שנה ותמונה.


<div movie-result></div>
<div movie-result></div>
<div movie-result></div>

 

נתחיל לפתח את האפליקציה...

האפליקציה כוללת את 5 המרכיבים הבאים:

  1. תבנית ה-HTML העיקרית שבה נגדיר את האלמנט שאנחנו מעוניינים להחליף.
  2. קוד ה-angular הבסיסי שכולל את הקונטרולר.
  3. קוד ה-custom directive
  4. הטמפלייט שמחליף את האלמנט
  5. אפשרות לטמפלייט לגשת למידע בקונטרולר

 

1. תבנית ה-HTML העיקרית

נתחיל מיצירת תבנית ה-HTML הבסיסית, שכוללת:

  • הגדרת ng-app על כל דף ה-HTML.
  • הגדרת ng-controller על div מסוים שבתוכו יתבצע תהליך החלפת האלמנטים בתוכן של custom directive.
  • בתוך הקונטרולר, נגדיר אלמנט עם attribute מיוחד movie-result, שיוחלף בהמשך בתוכן מלא ששייך לסרט.
<div movie-result></div>


<html lang="en" ng-app="myApp">
<head>
    <title>Custom directives</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
</head>
<body dir="ltr">
    <div ng-controller="mainCtrl">
        <h3>Movies</h3>
        <div movie-result></div>
    </div>
</div>
</body>
</html>

הגדרנו על האלמנט שאנחנו מעוניינים להחליף את השדה movie-result. שם שמתאר האלמנט, ומציית לכללים שאנגולר מכתיב לנו הכוללים שם שמכיל אותיות קטנות בלבד, ומילים שמופרדות בקו מפריד.

* זכרו את שם השדה movie-result כי נתייחס אליו בהמשך כשניתן שם ל-directive.

 

2. קוד ה-angular הבסיסי שכולל את הקונטרולר

קוד האנגולר הבסיסי מחזיק אובייקט movie הכולל מידע אודות הסרט. קוד האנגולר כולל 3 מרכיבים:

  • הגדרת האפליקציה ששמה myApp.
  • הגדרת הקונטרולר ששייך לאפליקציה.
  • בתוך הקונטרולר נגדיר אובייקט movie ששייך ל-scope, וכולל את שם הסרט והשנה בה נוצר.


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

myApp.controller("mainCtrl",function($scope){
    $scope.movie = {
        name: 'Captain America',
        year: '2016'
    }
});

 

3. קוד ה-custom directive

נוסיף לקוד האנגולר גם קוד של directive, שיקבל את השם movieResult. שם זה נגזר מה-custom attribute שהגדרתי על האלמנט שאני רוצה להחליף: movie-result. כדי ליצור את שם ה-directive מוחקים את כל הקווים המפרידים, ומתחילים כל מילה מלבד המילה הראשונה באות גדולה (lower camel case).

קוד ה-directive מחזיר אובייקט שכולל את השדות הבאים:

  • templateUrl, שמגדיר את המקום שבו נמצא ההטמ"ל שיהווה את הטמפלייט של ה-custom directive.
  • scope שמגדיר את מקור המידע שיהיה נגיש לטמפלייט (ועל זה עוד נרחיב בהמשך).


myApp.directive("movieResult",function(){
    return {
        templateUrl: 'directives/movieresult.html',
        scope: {
            
        }
    }
});

 

4. הטמפלייט שמחליף את האלמנט

הטמפלייט שמחליף את האלמנט נמצא בקובץ 'directives/movieresult.html'. הטמפלייט כולל את השדות שאנחנו מעוניינים שיוחלפו בתוכן אמיתי.


<div>
	<h4>{{ movieName }}</h4>
	<p>{{ movieYear }}</p>	
</div>
<hr />

אם נריץ את מה שכתבנו עד כה, לא נראה כלום מפני שאין לטמפלייט גישה למידע באובייקט שנמצא ב-scope הקונטרולר בעוד ל-directive יש scope משלה.

 

5. נאפשר לטמפלייט לקבל מידע מהאובייקט שנמצא בתוך הקונטרולר

כדי לאפשר לטמפלייט לקבל מידע מהקונטרולר אנחנו צריכים להגדיר באמצעות custom attribute את המידע שאנחנו מעוניינים להעביר.

בטמפלייט הראשי (index.html), נגדיר את המידע שאנחנו רוצים להעביר באמצעות custom attribute, שכולל את השם שאנחנו רוצים לתת למידע שאנו רוצים להעביר (לדוגמה, movie-name), וגם את המידע הקונקרטי שאנו מעוניינים שיעבור (לדוגמה, "{{ movie.name }}").


<div ng-controller="mainCtrl">
    <h3>Movies</h3>
    <div movie-result 
             movie-name="{{ movie.name }}" 
             movie-year="{{ movie.year }}"></div>
</div>

המידע הקונקרטי שאנו מעוניינים להעביר מוגדר בין זוג שפמים ({{}}) מפני שמדובר במחרוזת.

נגדיר ב-scope של ה-directive שה-custom attribute שהגדרנו מקבל ערך של טקסט מהקונטרולר באמצעות הסמל @. (למה? ככה!)

המשמעות של @ זה קשירה חד-כיוונית של טקסט. כך שהמידע זורם מהקונטרולר לטמפלייט, ולא להיפך.


myApp.directive("movieResult", function(){
  return {
    templateUrl: 'directives/movieresult.html',
    scope : {
      movieName: "@",
      movieYear: "@"
    }
  }
});

 

הקוד המלא

index.html


<html lang="en" ng-app="myApp">
<head>
    <title>Custom directives</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
</head>
<body dir="ltr">
    <div ng-controller="mainCtrl">
        <h3>Movies</h3>
        <div movie-result 
             movie-name="{{ movie.name }}" 
             movie-year="{{ movie.year }}">
        </div>
    </div>
</div>
<script>
var myApp = angular.module("myApp",[]);

myApp.controller("mainCtrl",function($scope){
    $scope.movie = {
        name: 'Captain America',
        year: '2016'
    }
});

myApp.directive("movieResult", function(){
  return {
    templateUrl: 'directives/movieresult.html',
    scope : {
      movieName: "@",
      movieYear: "@"
    }
  }
});
</script>
</body>
</html>

 

directives/movieresult.html


<div>
	<h4>{{ movieName }}</h4>
	<p>{{ movieYear }}</p>	
</div>
<hr />

 

 

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

 

כיצד להעביר אובייקט?

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

1. נגדיר את האובייקט שרוצים להעביר בטמפלייט הראשי. movie-object="movie"


<div ng-controller="mainCtrl">
    <h3>Movies</h3>
    <div movie-result movie-object="movie"></div>
</div>

 

2. נגדיר ב-scope של ה-directive שה-custom attribute שהגדרנו מקבל אובייקט מהקונטרולר.

המשמעות של "=" היא קשירה דו-כיוונית של האובייקט.


myApp.directive("movieResult", function(){
    return {
        templateUrl: 'directives/movieresult.html',
        scope : {
            movieObject: "="
        }
    }
});

צריך לשים לב שקשירה של אובייקט באנגולר היא קשירה דו-כיוונית, ולכן המידע יזרום מהקונטרולר לטמפלייט, וגם חזרה מהטמפלייט לקונטרולר, מה שעלול לגרום בעיית אבטחה. לכן, צריך להיזהר כשמשתמשים באופציה של קשירת אובייקט.

 

3. נשנה את הדירייקטיב, כך שידע להציג את המידע שמתקבל מהאובייקט.


<div>
	<h4>{{ movieObject.name }}</h4>
	<p>{{ movieObject.year }}</p>
</div>
<hr />

 

כיצד להעביר את הסוג הבוליאני?

שימו לב שאת הסוג בוליאני (true/false) מעבירים כמו אובייקט.

 

כיצד להעביר פונקציה?

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

1. נוסיף את הפונקציה לקונטרולר.


myApp.controller("mainCtrl", function($scope){
    $scope.movie = {
            name: 'Captain America',
            year: '2016'
    }
    
    $scope.formatMovieTitle = function(movie){
        return movie.name + ', ' + movie.year;
    }
});

2. נגדיר את הפונקציה שרוצים להעביר בטמפלייט הראשי.


< div movie-result 
         movie-object="movie" 
         format-movie-title-function="formatMovieTitle(movie)"> </div>

3. נגדיר בקוד ה-directive שאחנו מעבירים פונקציה באמצעות &.


myApp.directive("movieResult", function(){
    return {
        templateUrl: 'directives/movieresult.html',
        scope : {
            movieObject: "=",
            formatMovieTitleFunction: "&"
        }
    }
});

4. בטמפלייט של ה-directive, נשלב את המחרוזת שמחזירה הפונקציה. נעביר לפונקציה מפת אובייקטים שממפה על הפרמטר שאנו מצפים לו בפונקציה (movie) את האובייקט שכבר קיים בטמפלייט (movieObject).


< div>
  <h4>{{ movieObject.name }}< /h4>
  <p>{{ formatMovieTitleFunction({movie: movieObject}) }}</p>
< /div>
< hr />

 

כיצד להציג מספר תוצאות במקום רק אחת?

עד כה למדנו כיצד להחליף את האלמנט רק פעם אחת, אבל מה קורה כשרוצים להציג מספר אובייקטים ולא רק אחד (בדוגמה זו, נרצה להציג מספר סרטים במקום סרט אחד).

1. נגדיר בקונטרולר, מערך של אובייקטים ששמו movies, והוא כולל מידע על מספר סרטים.


myApp.controller("mainCtrl", function($scope){
    $scope.movies = [
        {
            name: 'Captain America',
            year: '2016'
        },
        {
            name: 'Mad Max',
            year: '2015'
        },
        {
            name: 'Godzilla',
            year: '2014'
        }
    ]
    
    $scope.formatMovieTitle = function(movie){
        return movie.name + ', ' + movie.year;
    }
});

2. בטמפלייט הראשי נשתמש בng-repeat כדי להציג את האלמנט כמה פעמים שצריך.


< div ng-repeat="movie in movies">
    < div movie-result 
		 movie-object="movie" 
		 format-movie-title-function="formatMovieTitle(movie)"> < /div>
< /div>

 

כיצד לשנות את הטמפלייט של הדיירקטיב לאחר הקשירה?

שום מדריך על custom directives באנגולר אינו יכול להיות שלם בלי ללמד על link כי הפונקציה link רצה על כל האלמנטים שבתוך ה-custom directive. שינויים הכוללים העברת מידע באמצעות משתנים והרצת פונקציות.

את הפונקציה link מעבירים כאופציה לקוד ה-directive, ובתוך ה-link ניתן לבצע פעולות שונות.

בדוגמה זו, נריץ בתוך הפונקציה link קוד שמוסיף קלאס לאלמנט רק במידה ושם הסרט הוא Mad Max.


myApp.directive("movieResult", function(){
    return {
        templateUrl: 'directives/movieresult.html',
        scope : {
            movieObject: "=",
            formatMovieTitleFunction: "&"
        },
        link: function(scope, elements, attrs){
            
            if(scope.movieObject.name == 'Mad Max'){
                elements.addClass("red");
            }
        }
    }
});

 

מה זה transclusion וכיצד להשתמש בזה?

transclusion זו חתיכת מילה, אבל המשמעות היא פשוטה למדי, והיא שניתן לכלול טמפלייט אחד בתוך טמפלייט אחר.

בדוגמה הבאה, נוסיף לתצוגה אלמנט נוסף באמצעות transclusion.

נתחיל מזה שנוסיף טקסט ישירות לתוך הטמפלייט הראשי שנמצא ב-index.php. למרות שהוספנו את הטקסט לטמפלייט לא נראה אותו מפני שכל האלמנט מוחלף ב-custom directive על ידי אנגולר.


<div ng-repeat="movie in movies">
	<div movie-result 
		 movie-object="movie" 
		 format-movie-title-function="formatMovieTitle(movie)">

	* Not comprehensive.

	</div>
</div>

כדי שנוכל לצפות באלמנט שהוספנו, עלינו לבצע את שתי הפעולות הבאות:

1. ב-directive נגדיר transclude: true


myApp.directive("movieResult",function(){
    return {
        templateUrl: 'directives/movieresult.html',
        scope : {
            movieObject: "=",
            formatMovieTitleFunction: "&"
        },
        link: function(scope,elements,attrs){
            
            if(scope.movieObject.name == 'Mad Max'){
                elements.addClass("red");
            }
        },
        transclude: true
    }
});

2. בטמפלייט של ה-directive ניצור אלמנט שיכיל את ה-transclusion.


<div>
	<h4>{{ movieObject.name }}</h4>
	<p>{{ formatMovieTitleFunction({movie: movieObject}) }}</p>
	<p><ng-transclude></ng-transclude></p>
</div>
<hr />

מדריכי AngularJS

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

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

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

שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.

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

השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.

הוסף תגובה חדשה

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

איך קוראים בעברית לצ`ופצ`יק של הקומקום?

 

תמונת המגיב

ריבקה בתאריך: 19.10.2017

נושא שהתקשתי להבין מוסבר באופן מאוד ברור ופשוט

תמונת המגיב

יוסי בן הרוש בתאריך: 19.10.2017

שמח שאני יכול לעזור.

תמונת המגיב

שני בתאריך: 18.05.2020

מוסבר מעולה! תודה! אני צריכה לעשות גרף עם custom directive וd3 זה שונה לגמרי? או שזה אותו דבר כמו כאן רק להוסיף על זה את הd3?

תמונת המגיב

שני בתאריך: 19.05.2020

מוסבר מעולה! תודה! אני צריכה לעשות גרף עם custom directive וd3 זה שונה לגמרי? או שזה אותו דבר כמו כאן רק להוסיף על זה את הd3?