跳到主要內容

Angularjs:動態Render 控制項


當我們在設計表單頁面時,常常會發現許多控制項都是常見的,尤其是開發多個頁面時,那麼假設開發完第一頁之後勢必又要將寫過的程式碼搬移到第二頁,造成冗於的代碼,如果我們能將這些控制項進行預製設計,而後便由後端所提供的資料來動態產生控制項,如此一來前端不僅減少冗於代碼,重要的業務邏輯也能由後端控制,乾淨切割相關責任,更易於管理,那麼在Angularjs中我們可以將預設樣板設計於directive或者使用ng-include動態載入樣板,但其中會發現一個問題點是,我們必須要有一個可以判斷該資料依據,才能將資料套用到正確的樣板,那麼剩下的就只剩後端資料的解析,在下面的範例中簡單的預置三個樣板,分別為textbox、selection、textarea。

一、範例網址: http://plnkr.co/edit/GJeKuz?p=info


二、首先我們假設後端給出的json資料
     (一)render.json,在這邊只需要抓出"rel" = "section"的連結,再根據此連結去獲取render的資料內容

{
    "collection":{
        "version": "1.0",
        "href": "http://localhost/multiTemplate",
        "links": [
            {
                "rel": "section",
                "prompt": "RenderA",
                "href": "renderA.json"
            },
            {
                "rel": "section",
                "prompt": "RenderB",
                "href": "renderB.json"
            },
            {
                "rel": "section",
                "prompt": "RenderC",
                "href": "renderC.json"
            },
            {
                "rel": "creator",
                "href": ""
            }
        ],
        "items":[]
    }
}

   (二)分別假設renderA、B、C的片段資料為:
          1.renderA,textbox的資料結構:

{
    "collection": {
        "version": "1.0",
        "href": "",
        "links":[],
        "items": [
            {
                "data": [
                    {
                        "name": "名字",
                        "value": "王曉明",
                        "prompt": "textbox"
                    }
                ]
            }
        ]
    }
}

          2.renderB,selection的資料結構:

{
    "collection": {
        "version": "1.0",
        "href": "",
        "links":[],
        "items": [
            {
                "data": [
                    {
                        "name": "性別",
                        "array": [
                            {
                                "name": "男"
                            },
                            {
                                "name": "女"
                            }
                        ],
                        "prompt": "selection"
                    }
                ]
            }
        ]
    }
}

          3.renderC,textarea的資料結構

{
    "collection": {
        "version": "1.0",
        "href": "",
        "links":[],
        "items": [
            {
                "data": [
                    {
                        "name": "自我介紹",
                        "value": "............",
                        "prompt": "textarea"
                    }
                ]
            }
        ]
    }
}

三、利用Angularjs中的directive來設計預置樣板,並進行資料的綁定

(function(){
    angular.module("multiTemp")
        .directive("dynamicControl",["$compile",dynamicControl])
    function dynamicControl($compile){
        var textboxTemplate = "{{data.name}} : <input type='text' class='form-control' ng-model='data.value' />";
        var selectionTempate = "<label>{{data.name}}</label><select class='form-control'><option ng-repeat='sex in data.array'>{{sex.name}}</option></select>";
        var textareaTemplate = "<label>{{data.name}}</label><textarea class='form-control' row='5' ng-model='data.value'></textarea>"
        var templateMapping = {
            "textbox": textboxTemplate,
            "selection": selectionTempate,
            "textarea": textareaTemplate
        }
        function linker(scope, element, attrs){
            element.html(templateMapping[scope.data.prompt]).show();
            $compile(element.contents())(scope);
        }
        return{
            restrict: "E",
            link: linker,
            scope:{
                data: "="
            }

        }
    }
})()

四、設計取得json的http服務

(function(){
    angular.module('jsonMethodModule',[])
        .service('jsonMethodService',function($q,$http){
            var getJson = function(url){
                var deferred = $q.defer();
                $http.get(url).success(function(data,status, headers, config){
                    deferred.resolve(data);
                }).error(function (data, status, headers, config){
                    deferred.reject(data);
                });
                return deferred.promise;
            }
            return{
                getJson: getJson
            };
        })
})();

五、設計剖析json的服務

(function () {
    angular.module('jsonParseModule', [])
        .service('jsonParseService', jsonParseService)
   function DataClass(name, value,array, prompt, href) {
        this.name = name;
        this.value = value;
        this.array = array;
        this.prompt = prompt;
        this.href = href;
    }
    function jsonParseService() {
        function getDatasFromCollectionJson(collectionJson) {
            var datas = new Array()
            angular.forEach(collectionJson.collection.items, function (item) {
                angular.forEach(item.data, function (detailItem) {
                    var data = new DataClass(detailItem.name, detailItem.value,detailItem.array, detailItem.prompt, item.href)
                    datas.push(data);
                });
            })
            return datas;
        }
        function getRelTemplate(links,rel){
            var result = [];
            angular.forEach(links,function(link){
                if (link.rel == rel) result.push(link);
            })
            return result;
        }
        return{
            getDatasFromCollectionJson: getDatasFromCollectionJson,
            getRelTemplate: getRelTemplate
        };
    }
})();

六、設計controller,首先取得render.json後再篩選出links中rel = section的項目,再分別根據各個項目的的連結取得資料內容。

(function(){
    angular.module('multiTemp',['jsonParseModule','jsonMethodModule'])
        .controller('multiTempCtrl',['jsonMethodService','jsonParseService','$http',multiTempCtrl])
    function multiTempCtrl(jsonMethodService,jsonParseService,$http){
        var self = this;
        self.sections = [];
        setRenderData();

        function setRenderData(){
            jsonMethodService.getJson('json/render.json').then(function(collectionjson){
                self.sections = jsonParseService.getRelTemplate(collectionjson.collection.links,"section");
                angular.forEach( self.sections,function(section){
                    jsonMethodService.getJson('json/' + section.href).then(function(collectionjson){
                        var datas = jsonParseService.getDatasFromCollectionJson(collectionjson);
                        section.datas = datas;
                    })
                })
            })
        }
    }
})();

七、將資料綁定到index.html並使用directive進行動態控制項的產生:

<!DOCTYPE html>
<html ng-app="multiTemp">

  <head>
    <link data-require="bootstrap@3.3.2" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
    <script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
    <script data-require="bootstrap@3.3.2" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
    <script data-require="angular.js@1.4.0" data-semver="1.4.0" src="https://code.angularjs.org/1.4.0/angular.js"></script>
    <script src="controllers/app.js"></script>
    <script src="services/jsonMethod.js"></script>
    <script src="services/jsonParse.js"></script>
    <script src="directives/directive.js"></script>
  </head>

  <body ng-controller="multiTempCtrl as tempCtrl">
    <div ng-repeat="section in tempCtrl.sections">
        <div class="panel">
            <div class="panel-heading">{{section.prompt}}</div>
        </div>
        <div class="panel-body">
            <div ng-repeat="data in section.datas">
                <dynamic-control data="data"></dynamic-control>
            </div>

        </div>
    </div>
</body>
</html>

留言

這個網誌中的熱門文章

java西元民國轉換_各種不同格式

C#資料庫操作(新增、修改、刪除、查詢)