2014年9月6日 星期六

AngularJS:Custom Directive Dualbox、Factory



未被選擇人員
已被選擇人員
{{PerMembers|json}}

Source Code:http://plnkr.co/edit/riXlgw?p=preview

一、由於Html原本並無提供Dualbox功能,故範例中利用自訂Directive製作Dualbox,並使用Factory來處理運算或一些邏輯判斷,如此更可實現關注點分離的概念

        (一)關注點分離:主要目的是將業務邏輯及View分離,如此一來開發人員可以將注意力  集中於業務邏輯的開發,將與業務邏輯無關的功能分開處理,簡化開發複雜度及方便日 後維護。
        (二)Directive:所謂Directive就如html中的<div>、<table>等標籤,在AngularJS中不僅可以使用預設的Directive之外,也能自訂Directive,通常使用方式:
app.directive("test1",function(){  
    return {  
        restrict: "E",  
        template: "<div>test</div>"  
    };  
});  
        屬性說明如下:
restrict 說明該directive要以何種方式宣告,像是元素、屬性、註解
A’ – Attribute (You want to use your directive as <div rating>)
‘E’ – Element (Use it as <rating>)
‘C’ – Class. (Use it like <div class=”rating”>)
‘M’ – Comment (Use it like <!– directive: rating –>)
priority 說明該directive和其他在同個元素的directive的優先度為何,數字越小優先度越高
template 用字串的方式編寫HTML碼,使用該directive的元素將會替換為這裡指定的HTML
templateUrl 同template,但是是指定template的url
replace 若為true則會用template取代原本的Html元素,若為false則將元素insert到元本的Html裡面
transclude 設為true可以將原本的HTML的元素內容移到template定義的HTML元素裡
scope 若給一物件則會建立一個新的scope,若指定為true則繼成自父scope
controller 為directive定義一個controller(大部分的目的是為了和其他directive互動)
require 指定該directive需要和哪些directive互動
link 可以在該方法內增加監聽事件($scope.$watch),或初始化一些資訊
compile 在link執行之前會先被執行,用於用程式動態修改template

           自訂Directive的好處在於html所提供的控件有限且能做到的功能不多,但當我們可以自 訂Directive後便能創造專屬控件,並賦予特殊功能,就相當於Asp.Net中的WebControl,且都在前端進行處理,不需要每次操作都回到後端。
           (三)Factory:Angularjs中重要概念Service,可以將Controller中共用的邏輯收納成一個Service,而該Service提供了三種方式,以複雜度來區分為:Service<Factory<Provider,各使用時機大致如下:
           1.Service:當外部已經寫好某服務的Constructor時,可透過service直接用Constructor來註冊服務。
myApp.service('myService', function(){
   
});
          2.Factory:自行製作服務時。
myApp.factory('myFactory', function(){

  return {
    
  };
});
           3.Provider:希望服務能夠客制化,在注入時做一些設定和調整。
myApp.provider('myProvider', function(){  
  
  
  return {  
    
  };  
  
  $get: function(){
      
    
  
    return{  
      
    };  
  };   
});  

二、首先我們設計出DefaultView並使用自訂標籤<dual-box></dual-box>

<html>
    <head>

<link href="//da7xgjtj801h2.cloudfront.net/2014.2.716/styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
<link href="//da7xgjtj801h2.cloudfront.net/2014.2.716/styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
<link href="Option.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<script src="//code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="//da7xgjtj801h2.cloudfront.net/2014.2.716/js/kendo.ui.core.min.js"></script>
      
<script src="listApp.js"></script>
<script src="listFactory.js"></script>
<script src="listDirective.js"></script>      
                <meta charset="utf-8">
        <title>JS Bin</title>
    </head>
    <body ng-app="listAppModule">

    <dual-box>
        <div>{{PerMembers|json}}</div>
    </dual-box>

</body>
</html>

三、再來設計dualBox.htm獨立成一個UI,並套入一些model、function來顯示資料及進行異動,於此我們只是先大致上定義model name、function可傳入的值,而實作部分則置於Factory。

<div>
    <table class="ifo" cellpadding="0" cellspacing="0" border="0" height="144px;" width="300px;">
       
        <tr>
        <td>
            未被選擇人員
            <select class="options" id="listView" size="10" id="myselection" multiple ng-multiple="true" ng-model="NonPermissions" ng-options="id as id for (id, ifo) in NonPerMembers" ng-dblclick="move(NonPerMembers, PerMembers, NonPermissions);"></select>

        </td>
        <td valign="center">
            <button class="btn btn-default" ng-click="move(NonPerMembers, PerMembers, NonPermissions);">></button>
            <br />
            <button class="btn btn-default" ng-click="move(PerMembers, NonPerMembers, Permissions);"><</button>
        </td>
        <td>
            已被選擇人員
            <select class="options" size="10" multiple="" ng-model="Permissions" ng-options="id as id for (id, ifo) in PerMembers"  ng-dblclick="move(PerMembers, NonPerMembers, Permissions);"></select>
        </td>
        </tr>
        <tr><td colspan="3" align="right"><button class="btn btn-info">確定</button><button class="btn btn-info" data-dismiss="modal">取消</button></td></tr>
    </table>
</div>
<div  ng-transclude></div><!--可讓外部擴充控件等-->

四、撰寫listApp.js,定義出Angularjs的module並將有引用到的directive引入。

var listboxConstractor = function(){

    var listApp = angular.module('listAppModule',['listFactoryModule','listDirectiveModule',"kendo.directives"]);
}();

五、建構出listFactory.js定義出要實作之功能,如載入初始資料、兩個listbox間的移動。

var listFactoryConstruct = function(){
    var app = angular.module('listFactoryModule',[])
        .factory('listFactoryService',function($http,$q){
            return{
                getData: function(jsonUrl){
                    var deferred = $q.defer();
                    
                    var data = {
                    'J': {
                        name: 'Jack',
                        age: 20
                    }
                    , 'A': {
                        name: 'Abe',
                        age: 19
                    }
                    , 'B': {
                        name: 'Ben',
                        age: 18
                    }
                    , 'C': {
                        name: 'Cilly',
                        age: 22
                    }
                    , 'Z': {
                        name: 'Zeny',
                        age: 29
                    }
                  };
                   deferred.resolve(data);
                   return deferred.promise;
                },
                move: function(src,desc,selectedItems){
                    if (src.length <= 0) return;
                     selectedItems.forEach(
                      function(value){
                        desc[value]={"name":src[value].name,"age":src[value].age};
                        delete src[value];
                      });
                }
            }
        });
}();

六、設計listDirective.js,設計自訂標籤,並使用dualBox.html為樣板,而Controller則扮演著業務邏輯與view的溝通。

var  listDirectiveConstruct = function() {
    var app = angular.module('listDirectiveModule',['listFactoryModule']);
    app.directive('dualBox', function (listFactoryService)
    {
        return{
            restrict: 'E',
            templateUrl: "dualBox.html",
            transclude: true,
            controller: function ($scope) {
                $scope.NonPerMembers = {};
                $scope.PerMembers={};
                    listFactoryService.getData('json/listArray.json').then(
                    function(data){//success
                        $scope.NonPerMembers = data;
                    }
                );
                $scope.move = function(src,desc,selectedItems){
                    listFactoryService.move(src,desc,selectedItems);
                    
                }



            }
        }
    })
}();

七、最後則處理頁面的美化部分可自訂CSS或引用套件。

.ifo{
    border: 1px solid;
 background-repeat: no-repeat;
 background-position: 10px center;
 -moz-border-radius:.5em;
 -webkit-border-radius:.5em;
 border-radius:.5em;
 color: #202020;
 
 margin-top: 10px;
 margin-right: 0px;
 margin-bottom: 10px;
 margin-left: 25%;
 text-align: center;
 
 padding: 0%;           
 }
.options {         
    width: 200px;
   -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 5px;
    margin-top: 10px;
    margin-right: 10px;
    margin-bottom: 10px;
    margin-left: 10px;
 }
.k-autocomplete
{
    width: 92%;
    vertical-align: middle;
    margin-top: 10px;
    margin-right: 10px;
    margin-bottom: 10px;
}
.btn-info{
    margin-top: 5px;
    margin-right: 5px;
    margin-bottom: 5px;
    margin-left: 5px;
}

沒有留言:

張貼留言