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