การพัฒนาโปรแกรมไม่ควรต้องเขียนงานซ้ำๆ แต่ควรเป็นการใช้ module หรือ function กลางที่สามารถนำกลับมาใช้ใหม่ได้ ฉะนั้น การแยกองค์ประกอบให้เป็นอิสระต่อกันจึงเป็นสิ่งที่สำคัญมาก
คราวนี้เรามาลองดูว่า AngularJS ทำแบบนั้นได้หรือไม่
file: testAngularJS.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="../../angular-1.8.0/angular.js"></script>
</head>
<body>
<div id="myApp">
<form id='f1'>
<div data-ng-controller="myCtrl">
<my-directive></my-directive>
</div>
<div data-ng-controller="myCtrl">
<my-directive data-ng-init='alldatas = [
{ type: "text", show:"text 2", id:"id3", value:"1", ref:"ref3" },
{ type: "number", show:"text 3", id:"id4", value:2, ref:"ref4" },
];'></my-directive>
</div>
<my-directive-submit data-ng-init='formID="f1";'></my-directive-submit>
</form>
</div>
</body>
</html>
<script>
function myCtrl($scope) {
//$scope.init = function(){}; //ระวังเรื่องตำแหน่งการส่งค่า data-ng-init
};
function myDirective() {
return {
template:
'<div data-ng-repeat="(mainKey,datas) in alldatas" data-ng-switch on="datas.type">'+
'<label for="{{datas.id}}">{{datas.show}}</label>'+
'<input data-ng-switch-when="number" type="number" id="{{datas.id}}" name="{{datas.id}}" data-ng-model="datas.value" data-ng-value="datas.value" refA="{{datas.ref}}" />'+
'<textarea data-ng-switch-when="textarea" id="{{datas.id}}" name="{{datas.id}}" data-ng-model="datas.value" refA="{{datas.ref}}">{{datas.value}}</textarea>'+
'<input data-ng-switch-default type="text" id="{{datas.id}}" name="{{datas.id}}" data-ng-model="datas.value" data-ng-value="datas.value" refA="{{datas.ref}}" data-ng-click="functionB($event)" style="border: 2px solid red;" />'+
'</div>'
,
controller: function($scope, $element) {
$scope.alldatas = [
{ type: 'text', show:'text 1', id:'id1', value:1, ref:'ref1' },
{ type: 'textarea', show:'text area 1', id:'id2', value:'abc', ref:'ref2' },
];
//
$scope.functionB = function(event){
const val1 = angular.element(event.target).attr('refA');
//event.target.getAttribute('refA'); //ok
//angular.element(event).attr('refA'); //error
console.log( val1 );
};
}
};
};
function myDirectiveSubmit() {
return {
template: '<input type="button" value="submit" data-ng-click="funcSubmit()" {(cont)?true:false} />',
link: {
pre: function(scope, element, attrs, ctrl) {
//scope.init here //call right before render.
},
},
controller: function($scope, $element) {
//
$scope.funcSubmit = function() {
const myFormData = document.getElementById( $scope.formID ) ;
const postdata = new FormData( myFormData );
// ajax
$http({
method: 'POST',
url: "" ,
data: postdata,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
})
.then(function(response) {
//success
}, function(response) {
//error
});
};
//
}
};
};
var myapp = angular.module('myApp', []);
myapp.controller('myCtrl', myCtrl);
myapp.directive('myDirective', myDirective);
myapp.directive('myDirectiveSubmit', myDirectiveSubmit);
//bootstrap
angular.element(document).ready(function() {
if( document.getElementById('myApp') ) {
angular.bootstrap(document.getElementById('myApp'),['myApp']);
}
});
</script>
- ผมเปลี่ยน data-ng-app เป็น id เพื่อผมจะได้ใช้ angular.bootstrap ในส่วน script ตอนท้าย เพื่อผมจะสามารถใช้งานได้มากกว่า 1app ทำให้ผมสามารถเอา app การแสดงผลแบบตาราง(ข้อมูลทั้งหมด) และ form(การกรอกข้อมูลเพิ่ม) ที่ผมเขียนแยก app ไว้ มาอยู่ในหน้าเดียวกันได้ เป็นต้น
- ผมแยก directive ออกเป็น function (ซึ่งทำให้ผมเขียนเป็น file.js แยกออกไปได้) โดยให้ส่วน return มี controller รวมอยู่ด้วย การทำเช่นนี้ ทำให้ผมสามารถแยก event.function ทีสัมพันธ์กับ directive นั้นๆ รวมอยู่ในที่เดียวกันและสามารถยกไปใช้ได้พร้อมกัน (อย่าง myDirectiveSubmit ผมมีปุ่ม submit พร้อม function ติดไปด้วย โดยผมแยก $scope.formID ออกมาเพื่อสามารถระบุ formID ได้)
- การส่งค่า json ผ่าน data-ng-init ทำได้โดยการใส่ค่า json ลงไปดื้อๆ โดยให้ระวังเรื่อง quote (‘,”) แต่ไม่สามารถส่งค่าผ่านตัวแปรได้(อันนี้ไม่รู้เหมือนกันว่าเพราะอะไร เพราะ พอไปใช้ $scope ใน controller กลับทำได้ )
สิ่งที่น่าสนใจ
ภายใน directive return มีอะไรบ้าง ใน document หลัก ผมอ่านแล้วไม่เข้าใจ ตัวอย่างก็ไม่ชัดเจน (ทั้งหมดนี้ผมได้จากการค้น web stack overflow) แต่เท่าที่เห็น นอกจาก template, link, controller ยังมี templateUrl ซึ่งเป็นการเรียกใช้ template จาก file ข้างนอก (เข้าใจว่า จะใช้ร่วมกับ template ไม่ได้)
document: https://docs.angularjs.org/guide/directive