یادگیری Directive های سفارشی در AngularJS

یکشنبه 16 آبان 1395

در این مقاله، Directive های سفارشی در Angular Js را خواهیم آموخت و آن ها را در یک برنامه ساده پیاده سازی می کنیم تا بهتر بتوانید با نحوه کار آن ها آشنا شوید.

یادگیری Directive های سفارشی در AngularJS

directive ها

directive ها در Angular JS ، همان attribute های المان های HTML هستند که Angular JS به ما اجازه می دهد آن ها را توسعه بدهیم . Angular JS  بسیاری از directive  ها را به صورت تعبیه شده دارد مانند : ng-app, ng-controller, ng-repeat, ng-model, ng-bindو ... . بنابراین ، با استفاده از ng-app در تگ HTML ، ما شروع یک برنامه ی Angular Js را اعلام می کنیم.

چرا از Directive  ها استفاده می کنیم؟

Directive ها به ما کمک می کنند که کامپوننت هایی بسازیم که قابلیت استفاده مجدد داشته باشند.

ساختار  Directive ها

نحوه کلی تعریف یک Directive به صورت زیر است:

    angularModuleName.directive('directiveName', function() {  
        return {  
            restrict: String,  
            priority: Number,  
            terminal: Boolean,  
            template: String or Template Function,  
            templateUrl: String,  
            replace: Boolean or String,  
            scope: Boolean or Object,  
            transclude: Boolean,  
            controller: String or  
                function(scope, element, attrs, transclude, otherInjectables) { ... },  
            controllerAs: String,  
            require: String,  
            link: function(scope, iElement, iAttrs) { ... },  
            compile: return an Object OR  
                function(tElement, tAttrs, transclude) {  
                    return {  
                        pre: function(scope, iElement, iAttrs, controller) { ... },  
                        post: function(scope, iElement, iAttrs, controller) { ... }  
                    }  
                    // or  
                    return function postLink(...) { ... }  
                }  
          };  
    });  

اساسا، یک Directive ،یک شی تعریف شده با تعدادی جفت کلید- مقدار است. این جفت های کلید-مقدار چگونگی رفتار یک Directive  را مشخص می کنند. ممکن است در ابتدا این کلید ها کمی پیچیده به نظر برسند، اما کار با آن ها ساده است. بیایید به بررسی این کلید ها بپردازیم:

Restrict(محدودیت):

این directive برای مشخص کردن نحوه استفاده دایرکتیو در DOM استفاده می شود. این directive می تواند به عنوان یک صفت (A) ، یک المان (E) ، یک کلاس(C) و یا یک Comment (C) باشد. این موارد می تواند به تنهایی یا همگی با هم مورد استفاده قرار بگیرند. مقدار دهی به این موارد دلخواه است، به این معنی که اگر برای آن ها مقداری انتخاب نکنید، مقادیر پیش فرض در آن ها قرار خواهند گرفت.

مثال :

As an attribute <div custom-directive/>
As an element <custom-directive></custom-directive>
As a class <div class="custom-directive"/>
As a comment <!--custom-directive-->

Priority (اولویت):

ترتیب فراخوانی ها در Angular Js را مشخص می کند. دایرکتیوی که بیشترین اولویت را داشته باشد، سریع تر از بقیه دایرکتیو ها اجرا خواهد شد. مقدار پیش فرض این مورد، 0 می باشد.

Template(قالب):

قالب Inline HTML مربوط به دایرکتیو را مشخص می کند.

TemplateURL:

شما همچنین می توانید قالب directive را بارگذاری کنید، با استفاده از یک URL که شامل کدهای قالب باشد.

Replace (جایگزینی):

مقدار این مورد می تواند True و یا False  باشد. اگر این مقدار True  باشد، قالب به المان والد اضافه می شود.

Scope (قلمرو):

این مورد، قلمرو directive را مشخص می کند و یک گزینه بسیار مهم محسوب می شود، که باید با دقت و متناسب با نیاز دایرکتیو مشخص شود. سه راه برای مقدار دهی به این دایرکتیو وجود دارد:

1-قلمرو مشخص شده در DOM برای دایرکیتو : اگر scope  برابر با False باشد، مقدار پیش فرض چه خواهد بود؟ قلمرو دایرکتیو همان قلمرو المان DOM خواهد بود.

2-یک قلمرو جدید که از قلمرو Controller داخلی ارث بری می کند. اگر scope  بر روی true تنظیم شده باشد، یک قلمرو جدید برای دایرکتیو ایجاد می شود، که از همه Property  های المان والد ارث بری می کند.

3-به عنوان یک قلمرو ایزوله ، هیچ چیزی از والد به ارث نخواهد برد. این نوع از قلمرو برای ساخت کامپوننت های قابل استفاده مجدد به کار می رود.

Transclude(رسانایی):

همان طور که قبلا نیز گفتیم ، دایرکتیو می تواند به محتویات / قالب المان والد خودش اضافه شود و یا با آن جایگزین شود. با گزینه ی Transclude ، اگر مقدار آن بر روی True باشد، شما می توانید محتویات اصلی را درون قالب دایرکتیو نگهداری کنید.

Controller :

شما می توانید نام کنترلر و یا تابع کنترلر را مشخص کنید که بعدا در درون دایرکتیو از آن استفاده کنید.

ControllerAs :

با استفاده از این گزینه، یک نام جایگزین می تواند برای کنترلر مشخص شود .

Require :

این گزینه، نام سایر دایرکتیو هایی که می خواهیم از آن ها استفاده کنیم را در بر می گیرد. اگر یکی از دایرکتیو های شما به دایرکتیو دیگری وابسته باشذ، شما می توانید نام آن را در این قسمت مشخص کنید.

Link :

این گزینه، برای تعریف یک تابع استفاده می شود، که می تواند برای تعریف و ویرایش نمونه های شی های درون DOM استفاده شود. برخی از این موارد عبارتند از : اضافه کردن event listener ها و یا تنظیم data binding ها.

Compile :

با استفاده از این مورد، شما می توانید یک تابع تعریف کنید که قالب المان های DOM را با آن ویرایش کنید. این گزینه همچنین می تواند برای بازگرداندن یک link function  برای ویرایش نمونه های المان ها مورد استفاده قرار بگیرد.

مثال 1 : ایجاد اولین دایرکتیو

    var ngCustomDirectivesApp = angular.module('ngCustomDirectivesApp')  
    ngCustomDirectivesApp.directive('customLabel', function () {  
        return {  
      
            restrict: 'EA',  
            template: '<div class="jumbotron"><h2>My First Directive</h2><p>This is a simple example.</p></div>'  
        }  
    })  

توضیح:

مانند هر برنامه ی Angular ، ابتدا یک Angular module ایجاد کرده ایم. سپس ، یک تابع directive تعریف کرده ام که یک شی با دو صفت برمی گرداند که نام های آن ها ‘restrict' و ‘template'است.

همان طور که می بینید، برای محدود کردن یک Property ، ما از EA استفاده کرده ایم که به معنای این است که این دایرکتیو می تواند هم یک المان و هم یک صفت باشد. خاصیت Template شامل یک رشته است، که در آن ساختار دایرکتیو را تعریف می کنیم. این دایرکتیو یک div نمایش می دهد که یک عنوان و یک پاراگراف دارد. نکته مهمی که در اینجا باید در نظر گرفته شود، نامگذاری دایرکتیو ها است. همان طور که می بینید ما از قاعده ی camel-case استفاده کرده ایم. ما در اینجا از نام Custom-label استفاده کرده ایم. احتمالا تا به حال به این نکته توجه کرده اید که همه دایرکتیو های AngularJS با پیشوند ng- می آیند. در dom دایرکتیو ها مطابق شکل زیر خواهند بود:

<custom-label></custom-label>
یا
<div custom-label></div>

خروجی :

نکته : ما برای این div  از کلاس jumborton در bootstrap  استفاده کرده ایم.

مثال 2 استفاده از Link Function

در این مثال، ما یک دایرکتیو ساده ی 'like button' ، که با استفاده از خاصیت link function آن به رویداد کلیک دایرکتیو دسترسی پیدا کنیم.

تعریف یک دایرکتیو

    ngCustomDirectivesApp.directive('likeButton', function () {  
        return {  
            restrict: 'EA',  
            templateUrl: '../partials/likebutton.html',  
            replace: true,  
            link: function (scope, element, attrs) {  
                element.bind('click', function () {  
                    element.toggleClass('like');  
                })  
            }  
        }  
    })  

قالب

<button type="button" class="btn-sty">  
    <span class="glyphicon glyphicon-thumbs-up"></span>  
</button> 

CSS

    .like {  
    background-color: blue;  
    color: white;  
    }  
    .btn-sty {  
    border-radius: 12px;  
    }  

خروجی

توضیح:

تعریف دایرکتیو دقیقا مشابه مثال قبل انجام شده است، اما به جای نوشتن قالب به صورت inline ، قالب را در یک فایل جداگانه نوشته ایم. بیایید کمی در مورد مفهوم link function توضیح دهیم . می توانید ببینید که  Link function سه پارامتر دارد که اولی، تعیین کننده محدوده قلمرو دایرکتیو است. دومی ، پارامتری است که المان های قابل دسترسی را برای ما مشخص می کند. این گفته به این معنا است که در این مثال ما به دکمه به عنوان یک المان دسترسی پیدا کرده ایم. سومین پارامتر ، صفت دایرکتیو می باشد. در link function ما به رویداد کلیک دکمه دسترسی پیدا کرده ایم.

مثال 3 درک مفهوم قلمرو (scope)

در این مثال ، ما تلاش می کنیم مفهوم قلمرو را توضیح بدهیم. همه دایرکتیو ها یک قلمرو دارند که می توانند به متدها و داده های داخل قالب و link function های آن دسترسی پیدا کنند. دایرکتیو ها تا زمانی که یک قلمرو به صورت صریح برایشان تعریف نشود، هیچ گونه قلمرویی ندارند و از قلمرو والد خودشان استفاده می کنند. همان طور که قبلا گفتیم مقادیر داخل قلمرو، تعیین می کنند که دایرکتیو چه رفتاری داشته باشد. سه نوع مقدار می توانند داخل قلمرو ها استفاده شوند که عبارتند از : true و  false  و {};

قلمرو - false

زمانی که قلمرو بر روی false  تنظیم شده باشد، دایرکتیو از قلمرو والد خودش استفاده خواهد کرد که به این معنی است که می تواند به همه مقادیر قلمرو والدش دسترسی داشته باشد و آن ها را ویرایش کند. اگر والد ، داده های خودش را ویرایش کند، داده ها درون دایرکتیو ها نیز ویرایش خواهند شد. این مورد اگر دایرکتیو داده ها را تغییر بدهد، نیز اتفاق می افتد.(یعنی تغییرات به والد نیز انتقال داده خواهد شد.) تا زمانی که قلمرو والد و دایرکتیو فرزند یکی باشد، می توانند داده های یکدیگر را ویرایش کنند.

تعریف دایرکتیو

    ngCustomDirectivesApp.controller('dashboardController', function ($scope) {  
       
        $scope.dataFromParent = "Data from parent";  
      
    })  
    ngCustomDirectivesApp.directive('parentScope', function () {  
        return {  
            restrict: 'E',  
            scope: false,  
            template: '<input type="text" ng-model="dataFromParent" style="border:1px solid red;"/>'  
        }  
    })   
    <div ng-controller="dashboardController">  
        <input type="text" ng-model="dataFromParent" style="border:1px solid green" />  
        <parent-scope></parent-scope>  
    </div>  

خروجی :

توضیح:

ابتدا یک controller تعریف کرده ایم و یک متغیر dataFromParent درون قلمرو تعریف کرده ایم.

سپس ، یک دایرکتیو ایجاد کرده ایم و مقدار قلمرو را برابر با false تنظیم کرده ایم.

در قالب، یک input box قرار داده ایم، که به dataFormParent از طریق ng-model وصل شده است.

سپس ما یک div والد ایجاد کرده ایم که کنترلر آن مشابه کنترلری است که در مرحله اول ایجاد کردیم.

در این div ، یک input box قرار داده ایم که به datafromparent متصل شده است.

سپس ما کنترلر را در همان div  به کار گرفتیم که با اینکار ، قلمرو همان قلمرو والد خواهد بود.

حالا اگر ما ورودی هر یک از input box ها را تغییر بدهیم، این تغییر بر روی سایر بخش ها نیز اعمال خواهد شد زیرا همگی به یک Controller متصل هستند.

به صورت خلاصه، زمانی که قلمرو بر روی false باشد، controller  و directive از یک شی مشابه استفاده خواهند کرد. بنابراین تغییرات آن ها به صورت هماهنگ اعمال خواهد شد.

Scope - true

زمانی که قلمرو بر روی true تنظیم شده باشد، یک قلمرو جدید ایجاد می شود و به دایرکتیو اختصاص داده می شود که به صورت پیش فرض از والد خودش ارث بری کرده است، هر تغییری که به این قلمرو جدید اعمال شود ، بر روی قلمرو والد نیز تاثیر خواهد گذاشت.

    ngCustomDirectivesApp.controller('dashboardController', function ($scope) {  
       
        $scope.dataFromParent = "Data from parent";  
      
    })  
    ngCustomDirectivesApp.directive('inheritedScope', function () {  
        return {  
            restrict: 'E',  
            scope: true,  
            template: '<input type="text" ng-model="dataFromParent" style="border:1px solid red;"/>'  
        }  
    })  
    <div ng-controller="dashboardController">  
      
        <input type="text" ng-model="dataFromParent" style="border:1px solid green" />  
        <parent-scope></parent-scope>  
        <inherited-scope></inherited-scope>  
    </div>  

توضیح:

درست مانند دایرکتیو قبلی ، ما یک دایرکتیو ایجاد کرده ایم. اما در این دایرکتیو ، قلمرو را بر روی true تنظیم کرده ایم که به این معنی است که دایرکتیو دسترسی ای به شی والد خودش ندارد. در عوض، می تواند یک شی قلمرو جدید برای خودش ایجاد کند. که این قلمرو از قلمرو والد ارث بری خواهد کرد. بنابراین زمانی که text box اولی تغییری کند، همه ی text box های دیگر نیز به روز رسانی خواهند شد. اما اگر هر تغییر در text box سوم اتفاق بیفتد که دایرکتیو ما است، تغییرات بر روی دو text box دیگر اعمال نخواهند شد.

Scope - { }

زمانی که قلمرو بر روی {} تنظیم شده باشد، یک قلمرو جدید از دایرکتیو ایجاد می شود اما این بار، از قلمرو والد خودش ارث بری نمی کندو کاملا از قلمرو والد خودش جدا می شود. این قلمرو به عنوان قلمرو ایزوله (Isolated Scope) شناخته می شود.

    ngCustomDirectivesApp.controller('dashboardController', function ($scope) {  
       
        $scope.dataFromParent = "Data from parent";  
      
    })  
    ngCustomDirectivesApp.directive('isolatedScope', function () {  
        return {  
            restrict: 'E',  
            scope: {},  
            template: '<input type="text" ng-model="dataFromParent" style="border:1px solid red;"/>'  
        }  
    })  
    <div ng-controller="dashboardController">  
        <input type="text" ng-model="dataFromParent" style="border:1px solid green" />  
        <parent-scope></parent-scope>  
        <inherited-scope></inherited-scope>  
        <isolated-scope></isolated-scope>  
    </div>  

مثال 4 درک مفهوم Isolated Scope

همان طور که گفتیم اگر قلمرو بر روی {} تنظیم شده باشد، یک قلمرو ایزوله برای دایرکتیو ایجاد می شود که به این معنی است که دایرکتیو به متغیر ها / داده های قلمرو والد دسترسی ندارد. این ویژگی می تواند بسیار مفید باشد، به این خاطر که می توانید یک کامپوننت قابل استفاده مجدد ایجاد کنید. اما در اغلب مواردبه یک ارتباط میان دایرکتیو و قلمرو والد احتیاج داریم و همچنین نمی خواهیم که دایرکتیو به قلمرو والد خودش دسترسی داشته باشد. بنابراین یک قلمرو ایزوله ، تعدادی فیلتر برای تبادل داده بین قلمرو والد و شی قلمرو جدید ایجاد می کند. برای این که داده ها از قلمرو والد بتوانند به قلمرو دایرکتیو بروند، ما نیاز داریم تعدادی property تعریف کنیم تا بعدا آن ها را به قلمرو بفرستیم.

    scope: {  
    varibaleName1:'@attrName1',  
    varibaleName2:'=attrName2',  
    varibaleName3:'&attrName3'  
    }  

و یا

scope: {  
attrName1:'@',  
attrName2:'=',  
attrName3:'&'  
}

در قلمرو ایزوله، سه راه ارتباطی بین والد و دایرکتیو وجود دارد:

@Text binding و یا اتصال یک طرفه و یا دسترسی فقط خواندنی. این مورد یک ارتباط یک طرفه بین والد و دایرکتیو است.

= Model bindin و یا ارتباط دو طرفه. این مورد مقدار صفت را به عنوان یک نام مدل می شناسد و می پذیرد. تغییرات در این روش به صورت همزمان انجام می شوند.

& Method binding و یا ارتباط رفتاری ، برای اتصال متدها از قلمرو والد به قلمرو دایرکتیو استفاده می شود. بنابراین این امکان را به ما می دهد تا فراخوانی ها را در قلمرو والد اجرا کنیم.

مثال

بیایید یک دایرکتیو ایجاد کنیم تا کاربرد این موارد را ببینیم. ابتدا، یک controller ایجاد می کنیم، که به عنوان والد برای دایرکتیو عمل می کند. در کنترلر، یک متغیر تعریف می کنیم به نام dataFromParent و یک تابع به نام ChangeValue   نیز ایجاد می کنیم.

    ngCustomDirectivesApp.controller('dashboardController', function ($scope) {  
        $scope.dataFromParent = "Data from parent";  
        $scope.changeValue = function () {  
            $scope.dataFromParent = "Changed data from parent";  
        }  
      
    })  

حالا بیایید دایرکتیو را ایجاد کنیم.

    ngCustomDirectivesApp.directive('isolatedScopeWithFilters', function () {  
        return {  
            restrict: 'E',  
            scope: {  
                oneWayBindData: '@oneWayAttr',  
                twoWayBindData: '=twoWayAttr',  
                methodBind:'&parentMethodName'  
            },  
            template: '<input type="text" ng-model="oneWayBindData" style="border:1px solid red;"/><br/><input type="text" ng-model="twoWayBindData" style="border:1px solid red;"/><br/><button type="button" ng-click="methodBind()">Change Value</button>'  
        }  
    })  

می توانید ببینید که در قلمرو، سه Property تعریف کرده ایم. این property ها در دایرکتیو ما برای اتصال اطلاعات استفاده خواهند شد. ما دو text box  و یک button  ایجاد می کنیم. اولین text box به وسیله اتصال یک طرفه به قلمرو متصل است و دومی به وسیله اتصال دو طرفه و در رویداد کلیک دکمه ، عملی بر روی این دو انجام خواهد شد.

<div ng-controller="dashboardController">  
     
    <isolated-scope-with-filters one-way-attr="{{ dataFromParent}}" two-way-attr="dataFromParent" parent-method-name="changeValue()"></isolated-scope-with-filters>  
   <p>{{dataFromParent}}</p>  
</div>  
one-way- 

بنابراین در این زمان با اجرای این قطعه کد، دایرکتیو باید بتواند به وسیله اتصال یک طرفه و دو طرفه، اطلاعات را منتقل کرده و آن ها را نمایش بدهد.

مثال 5 کار با controller

در مثال زیر یک Controller  ایجاد می کنیم که برای ارتباط بین دایرکتیو های مختلف مورد استفاده قرار خواهد گرفت.

مرحله 1:

یک accordian directive والد ایجاد می کنیم که المان های زیر را در خودش نگهداری کند.

    ngCustomDirectivesApp.directive('accordion', function () {  
        return {  
            restrict: 'EA',  
            template: '<div ng-transclude></div>',  
            replace: true,  
            transclude: true,  
            controllerAs: 'accordionController',  
            controller: function () {  
                var children = [];  
                this.OpenMeHideAll = function (selectedchild) {  
                    angular.forEach(children, function (child) {  
                        if (selectedchild != child) {  
                            child.show = false;  
                        }  
                    });  
                };  
      
                this.addChild = function (child) {  
                    children.push(child);  
                }  
            }  
        }  
    })  

نکته مهمی که در تکه کد بالا باید به آن توجه شود، این است که ما از ng-transclude استفاده کرده ایم، که به div  اجازه می دهد تا المان هایی را در درون خودش نگهداری کند. به همین خاطر نیز گزینه transclude بر روی true تنظیم شده است. سپس یک کنترلر تعریف شده است که محل تمرکز این دایرکتیو است، یک تابع تعریف شده است که تا المان های فرزند را در یک آرایه قرار بدهد و سپس تابعی تعریف شده است تا در صورت انتخاب شدن یک فرزند، سایر فرزندان را hide (مخفی) کند.

مرحله 2

دایرکتیو مربوط به المان فرزند accordian را ایجاد می کنیم.

    ngCustomDirectivesApp.directive('accordionChild', function () {  
        return {  
            restrict: 'EA',  
            template: '<div><div class="heading" ng-click="toggle()">{{title}}</div><div class="content" ng-show="show" ng-transclude></div></div>',  
            replace: true,  
            transclude: true,  
            require: '^accordion',  
            scope: {  
                title:'@'  
            },  
            link: function (scope,element,attrs,accordionController) {  
                scope.show = false;  
                accordionController.addChild(scope);  
                scope.toggle = function () {  
                    scope.show = !scope.show;  
                    accordionController.OpenMeHideAll(scope);  
                }  
            }  
        }  
    })  

المان accordian یک عنوان و یک بدنه دارد تا داده ها و یا سایر المان ها را در خودش نگهداری کند. بنابراین ما یک div  را برای heading (عنوان) تعیین کرده ایم و رویداد کلیک دکمه را نیز به این المان اختصاص داده ایم. سپس به همین روش مجبوریم یک div برای بدنه تعریف کنیم تا بتواند محتویات را به صورت داینامیک در خودش نگهداری کند. ng-show برای این استفاده شده است که محتویات را در رویداد کلیک ، نمایش بدهد یا آن ها را مخفی کند. در link function نیاز داریم تا به show model دسترسی داشته باشیم که برای نمایش و مخفی سازی محتویات مورد استفاده قرار خواهد گرفت.

زمانی که کاربر بر روی عنوان یک المان accordian کلیک می کند، آدرس آن المان به تابع پاس داده می شود و تابع این طور عمل می کند که آن المان را نمایش می دهد و سایر المان ها را مخفی می کند.

مرحله 3

استفاده از directive  در view

<accordion>  
    <accordion-child title="Element 1">Data 1</accordion-child>  
    <accordion-child title="Element 2">Data 2</accordion-child>  
    <accordion-child title="Element 3">Data 3</accordion-child>  
</accordion>

خروجی

مثال 6 کار با Controller

بیایید یک مثال دیگر از نحوه استفاده از یک controller   در یک directive بیان کنیم. در این مثال ، ما یک لیست قابل مرتب شدن ایجاد می کنیم که محتویات آن می توانند بر اساس نیاز ما به روش های مختلف دسته بندی شوند.

مرحله 1

یک directive تعریف می کنیم تا لیستی شامل آرایه ای از مواردی که به آن پاس داده می شود را در خودش نگهداری کند.

    ngCustomDirectivesApp.directive('smartList', function () {  
        return {  
            restrict: 'EA',  
            templateUrl: '../partials/listdirective.html',  
            replace: true,  
            scope: {  
                items: '='  
            },  
            controller: function ($scope) {  
                $scope.source = null;  
            },  
            controllerAs:'listCTRL'  
        }  
    })  

قالب

    <ul class="ul-sty">  
        <li ng-repeat="item in items" class="li-sty" draggable>  
            {{item }}  
        </li>  
    </ul>  

این دایرکتیو بسیار ساده است. یک لیست نامرتب در درون آن وجود دارد که اعضای این لیست با استفاده از ng-repeat تولید شده اند. همچنین اعضای این لیست دارای خاصیتdraggable نیز هستند. ما دایرکتیو مربوط به این موضوع را در مراحل بعد ایجاد خواهیم کرد. این ایتم ها از خاصیت ارتباط دو طرفه بهره مند هستند که به این معنی است که ما می توانیم به مدل قلمرو والد در درون قلمرو directive دسترسی داشته باشیم. ما همچنین یک cobtroller تعریف کرده ایم که یک متغیر به نام source  را نگهداری می کند. 

مرحله 2

تغییر دایرکتیو draggable

    ngCustomDirectivesApp.directive('draggable', function () {  
        return {  
            require:'^smartList',  
            link: function (scope, element, attr, listCTRL) {  
                element.css({  
                    cursor: 'move',  
                });  
                attr.$set('draggable', true);  
      
                function isBefore(x, y) {  
                    if (x.parentNode == y.parentNode) {  
                        for (var i = x; i; i = i.previousSibling)  
                        {  
                            if (i == y)  
                                return true;  
                        }  
                    }  
                    return false;  
                }  
                element.on('dragenter', function (e) {  
                    if (e.target.parentNode != null) {  
                        if (isBefore(listCTRL.source, e.target)) {  
                            e.target.parentNode.insertBefore(listCTRL.source, e.target)  
                        }  
                        else {  
                            e.target.parentNode.insertBefore(listCTRL.source, e.target.nextSibling)  
                        }  
                    }  
                })  
                element.on('dragstart', function (e) {  
                    listCTRL.source = element[0];  
                    e.dataTransfer.effectAllowed = 'move';  
                })  
            }  
        }  
    })  

در بخش link function این دایرکتیو ، ما کنترلی که در مرحله 1 ایجاد کرده ایم را پاس داده ایم. رویداد drag زمانی فعال می شود که drag enter به المان وصل شود. ما المانی که کشیده شده است را ذخیره می کنیم تا بتوانیم آن را با المان والد مقایسه کنیم و سپس در مورد وضعیت آن تصمیم بگیریم. در ادامه کد که بسیار ساده است ما فقط داریم node  را در محل مناسب آن قرار می دهیم.

مرحله 3

کنترلر والد را تعریف می کنیم:

    ngCustomDirectivesApp.controller('dashboardController', function ($scope) {  
       
        $scope.itemsdata = ['Apple', 'Mango', 'Banana', 'PineApple', 'Grapes', 'Oranges'];  
      
    })  

مرحله 4 :

از دایرکتیو به صورتی که در زیر نشان داده شده است، استفاده می کنیم:

<div ng-controller="dashboardController">  
  
    <smart-list items="itemsdata" />  
  
</div> 

خروجی

آموزش angular

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

تاکنون هیچ کاربری از این پست تشکر نکرده است

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید