آموزش گام به گام AngularJS قسمت یازدهم : ساخت Custom Directive

بازدید کنندگان : 1598 دسته بندی برنامه نویسی , برنامه نویسی سمت کلاینت , شروع کار با AngularJS
درمقاله اول با Directive های خود AngularJS آشنا شدیم و در مقالات بعدی با آنها کار کردیم و به صورت عملیاتی از هرکدام استفاده نمودیم .
همانطور که در مقاله اول ذکر شد انگولار به ما امکان ساخت دیرکتیو های کاملا شخصی سازی شده را میدهد که میتوانیم از آنها به شکل کنترل یا کامپاننت استفاده نماییم .
فرمت کلی ساخت یک دیرکتیوبه شکل زیر است :
angular.module('moduleName')

    .directive('myDirective', function () {

        return {

            restrict: 'EA', //E = element, A = attribute, C = class, M = comment        

            scope: {

                //@ reads the attribute value, = provides two-way binding, & works with functions

                title: '@'

            },

            template: '<div>{{ myVal }}</div>',

            templateUrl: 'mytemplate.html',

            controller: controllerFunction, //Embed a custom controller in the directive

            link: function ($scope, element, attrs) { } //DOM manipulation

        }

    });
 و در ساده ترین حالت به شکل زیر خواهد بود :
app.directive("myDirective", function () { 
    return { 
        restrict: "EACM", 
        template: "<h1>Hello I Am A Directive</h1>" 
    }; 
و به 4 شکل قابل استفاده میباشد : 
1- به صورت یک Element:  بدین منظور کافیست حرف E را در پارامتر restrict اضافه نمایید  
<my-dirctive></my-directive> 
همانطور که میبینید در هنگام استفاده حرف بزرگ D در کلمه myDirective به کوچک تبدیل شده و یک - اضافه گردیده است 
این یکی از قوانین استفاده از custome directive مباشد 
2- به صورت یک Attribute : بدین منظور حرف A اضافه میشود 
<div my-directive></div> 
3- به صورت Class : حرف C را اضافه میکنیم 
<div class="my-directive"></div> 
4- به صورت Comment : حرف M را اضافه می کنیم 
<!-- directive: my-directive --> 
 
برای اینکه بتوانید یک یا چند روش را باهم استفاده کنیم میتوانید یک یا چند یا همه حروف را مشابه نمونه کد در restirct وارد نمایید 
پارامتر template دقیقا کدهای Html است که جایگزین تگ شما خواهد شد 
 
حال فرض کنید در پروژه قبلی بخواهیم فیلد جستجو و خود جدول نمایش اطلاعات را به یک کنترل تبدیل کنیم که در جاهای مختلف 
بتوانیم از آن استفاده نماییم و میخواهیم فقط به صورت یک المنت باشد :
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        template: '<p> Search : <input type="text" ng-model="search" /> </p>' 
    } 
}); 
و برای استفاده از آن خیلی ساده خواهیم داشت :
 <search-box></search-box>
ما میتوانیم برای دیرکتیو مقدار ورودی تعریف کنیم که به صورت Attribute تعریف میشوند ، برای اینکار ما از scope در داخل 
دیرکتیو استفاده می کنیم ، برای تعریف یک Attribute ابتدا نام دلخواه را در بخش اسکوپ نوشته و سپس نوع آن را تعیین میکنیم ، 
که به 3 نوع تقسیم میشود : 
@ : مقدار ورودی را مستقیما به داخل اسکوپ پاس میدهد  
= : به یک مدل بایند میشود 
& : به یک تابع متصل میشود 
 
اکنون اگر بخواهیم کلمه Search که در بخش Template نوشته شده است را پارامتریک کنیم یعنی بتوانیم مقدار را از داخل خود تگ 
به صورت attribute مقدار دهی کنیم یک متغیر در نظر گرفته (مثلا title )  و آن را در بخش scope با کاراکتر @ تعریف مینماییم:
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        scope: { 
            title: '@' 
        }, 
        template: '<p> {{title}} : <input type="text" ng-model="search"  /> </p>' 
    } 
و برای استفاده به سادگی خواهیم داشت :
    <search-box title="Filter" ></search-box> 
همانطور که ملاحظه میکنید کلمه Filter مستقیما جایگزین {{title}} خواهد شد ، حال اگر بخواهیم ورودی را به یک مدل بایند کنیم 
به جای @ باید از = استفاده کنیم : 
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        scope: { 
            title: '=', 
        }, 
        template: '<p> {{title}} : <input type="text" ng-model="search"  /> </p>' 
    } 
و داریم :
    <input type="text" ng-model="Filter" /> 
    <search-box title="Filter"></search-box>
البته در این پروژه این کار بی معنی است چرا که مقدار باید مستقیم وارد شود ( این مثال فقط جنبه آموزشی داشت ) 
و اگر بخواهیم مثلا یک event تعریف کنیم به نام clicked که وقتی روی باکس جستجو کلیک شد عمل کند به صورت زیر آن را 
تعریف خواهیم کرد :
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        scope: { 
            title: '@', 
            clicked: '&' 
        }, 
        template: '<p> {{title}} : <input type="text" ng-model="search" ng-click="clicked()"  /> </p>' 
    } 
}); 
و برای استفاده کافیست تابع دلخواه را در رویداد clicked بنویسیم :
 <search-box title="Filter" clicked="alertMe()"></search-box> 
دقت نمایید که تابع alertMe در کنترل مادر یعنی GridController تعریف شده است :
    $scope.alertMe = function () { 
        alert('Clicked!'); 
    } 
همچنین یک دیرکتیو میتواند خودش کنترلر مجزا داشته باشد ، به عنوان مثال میتوانیم تابع clicked را در کنترل به شکل زیر تعریف 
کنیم :
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        scope: { 
            title: '@', 
            clicked: '&' 
        }, 
        template: '<p> {{title}} : <input type="text" ng-model="search" ng-click="clicked()"/> </p>', 
        controller: function ($scope) { 
 
            $scope.clicked = function () { 
                alert('click!'); 
 
            } 
        } 
    } 
}); 
همانطور که ملاحظه میکنید دیگر تابع alertMe کار نخواهد کرد چرا که کنترل داخلی دیرکتیو تابع clicked را هندل میکند . 
 
نکته ای که در انتها باید به آن اشاره کرد این است که با شرایط فوق جستجو در جدول کار نمیکند ، مشکل از کجاست ؟ 
مشکل اینجاست که ما search را به ng-model تخصیص دادیم ولی این search هیچ جا تعریف نشده است ، بنابراین کافیست 
search را در اسکوپ با کاراکتر = ـعریف کرده ( چرا که قرار است به صورت یک مدل بایند شود ) و در تگ مربوط هم مدل را 
به آن معرفی میکنیم :
app.directive('searchBox', function () {

    return {

        restrict: 'E',

        scope: {

            title: '@',

            clicked: '&',

            search: '='

        },

        template: '<p> {{title}} : <input type="text" ng-model="search" ng-click="clicked()"/> </p>',

        controller: function ($scope) {

 

            $scope.clicked = function () {

                alert('click!');

 

            }

        }

    }

});
و خواهیم داشت :
 <search-box title="Filter" search="search" ></search-box> 
حتی میتوانیم برای واضح شدن کار مقدار مدل را به یک کلمه دیگر مثلا criteria تغییر دهیم :
   <search-box title="Filter" search="criteria" ></search-box> 
البته دقت کنید که مدل در بخش filter مربوط به ng-repeat هم باید تغییر کند :
   <tr ng-repeat="row in myData | filter:criteria | orderBy:sortOrder" ng-include="myTemplate"></tr> 
همانطور که میبینید دیگر به جای کلمه search کلمه criteria نوشته شده و سیستم به خوبی کار میکند
دقت کنید که دیگر چیزی به نام  ng-model نداشتیم تا مستقیما مدل را ایجاد کنیم چرا که در یک directive شخصی سازی شده به صورت پیشفرض هیچ کدام از ng- ها وجود ندارند و ما میبیست آنهارا خودمان ایجاد کنیم
مثلا اگر بخواهیم ng-model را ایجاد کنیم کافیست به جای خصیصه search یک خصیصه به نام ngModel ایجاد کنیم :
app.directive('searchBox', function () { 
    return { 
        restrict: 'E', 
        scope: { 
            title: '@', 
            clicked: '&', 
            ngModel: '=' 
        }, 
        template: '<p> {{title}} : <input type="text" ng-model="search" ng-click="clicked()"/> </p>', 
        controller: function ($scope) { 
 
            $scope.clicked = function () { 
                alert('click!'); 
 
            } 
        } 
    } 
}); 
و برای استفاده داریم :
<search-box title="Filter" ng-model="criteria" ></search-box>
دقت کنید که مشابه اسم گزاری خود دیرکتیو خصیصه ها هم به حرف بزرگ حساس هستند و حرف بزرگ میان اسم خصیصه به - تبدیل میشود ، در بالا کلمه ngModel در هنگام استفاده به ng-model تبدیل شده است .

در مقالات بعدی با کاربرد و امکانات پیشرفته تر Custom Directives آشنا خواهید شد
 
فایل پروژه را از اینجا دانلود نمایید 


منابع :

نظرات کاربران