เนื้อหาในตอนที่ 2 จะยากขึ้นมาหน่อย แต่จะได้ศึกษา ส่วนใช้งาน
เพิ่มขึ้น todo app คือ การทำ ลิสรายการที่ต้องทำ ก็จะอ้างอิง ตัวอย่าง
จากเว็บไซต์ https://angularjs.org/ เช่นดิม
เนื้อหาก่อนหน้า
เรียนรู้ angularjs javascript framework ตอนที่ 1
https://www.ninenik.com/content.php?arti_id=514 via @ninenik
เริ่มต้น ไฟล์ ทดสอบครั้งนี้ มีด้วยกัน 3 ไฟล์ คือ
index.html สำหรับทดสอบ แสดงผล
todo.js สำหรับเขียน javascript
todo.css สำหรับจัดรูปแบบ html
มีอะไรเพิ่มมา ในไฟล์ index.html
<!DOCTYPE html>
<html ng-app="todoApp">
<head>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js"></script>
<script src="todo.js"></script>
<link rel="stylesheet" href="todo.css">
<title>My Learn AngularJs 2</title>
</head>
<body>
<h2>Todo</h2>
<div ng-controller="TodoController">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form ng-submit="addTodo()">
<input type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
</body>
</html>
1. จะเห็นว่า ในบรรทัดที่ 2 จะมีการกำหนดค่าให้กับ attribute (directive ใน angularjs) ng-app ซึ่งปกติหาก
ไม่มีการกำหนดค่า ให้เข้าใจว่า angularjs จะทำงานกับทั้งหน้าเพจนั้น และการ
กำหนดค่า ให้กับ ng-app ก็เพื่อสำหรับอ้างอิงการเรียกใช้งาน
<html ng-app="todoApp">
ในการทำ todo app จึงมีการตั้งชื่อเป็น todoApp
กำหนดชื่อแบบ camelCase คือ คำตัวเล็กตัวใหญ่สลับกัน คล้ายหลังอูฐ)
2. บรรทัดที่ 6 โหลดไฟล์ javascirpt todo.js ไฟล์นี้เราจะสร้างขึ้นมา และก็ใช้สำหรับ
กำหนดการทำงานของ todo app
3. บรรทัดที่ 7 โหลดไฟล์ css ไฟล์นี้ สร้างขึ้นมา ไม่มีอะไรมาก เป้นแค่การกำหนด style
ให้กับ รายการที่ถูกเลือกแล้ว ให้มี เส้นขึดฆ่า และเป็นข้อความสีเทา
โฟล์ todo.css
.done-true { /* ชื่อ class สำหรับรายการที่ถูกติ้กเลือก */
text-decoration: line-through; /* แสดงเส้นขีดฆ่า */
color: grey; /* แสดงเป็นสีเทา */
}
ul.unstyled{ /* ชื่อ class สำหรับรายการ แสดงลิสรายการ */
margin: 0;
padding:5px;
list-style: none;
}
4. บรรทัดที่ 13 มี attribute (directive ใน angularjs) ใหม่ คือ ng-controller ให้เข้าใจว่า เป็นการกำหนดชื่อ
class ซึ่งจะมีการเรียกใช้งาน ในที่นี้เขากำหนดเป็นชื่อ TodoController
<div ng-controller="TodoController">
หลักการสำหรับใช้งานคือ การกระทำใดๆ ก็ตามที่เกิดขึ้นภายในส่วนนี้ จะถูกเรียกใช้ผ่าน
class ที่ชื่อ TodoController
5. บรรทัดที่ 14 เป็นการวาง template หรือจัดรูปแบบสำหรับการแสดงผล
โดยอย่าลืมว่า จะใช้ในลักษณะ ปีกกาปิดปิดอย่างละสองอัน {{}}
ด้านในเป็นได้ทั้งชื่อฟังก์ชัน ค่า object หรือชื่อตัวแปร เป็นต้น สำหรับอ้างอิง
<span>{{remaining()}} of {{todos.length}} remaining</span>
จากโค้ดบรรทัดนี้ จะเห็นว่า
remaining() คือฟังก์ชั่น
todos.length คือค่าของ objext ชื่อ todos (ในไฟล์ todo.js จะอธิบายที่มาอีกที)
6. บรรทัดที่ 15 มี attribute (directive ใน angularjs) คือ ng-click ให้เข้าใจว่า ตัวนี้คล้าย กับ event onclick
หรือก็คือ เมื่อคลิก ก็จะเรียกใช้ฟังก์ชั่นด้านใน ชื่อ archive() โดยฟังก์ชั่นนี้ ก็คือการ
จัดเก็บรายการที่ถูกติ้กเลือกแล้ว ในตัวอย่างเป็นแค่การลบออกธรรมา
[ <a href="" ng-click="archive()">archive</a> ]
7. บรรทัดที่ 16-21 ก็จะเป็น แท็ก html คล้ายกับการวาง template การแสดงข้อมูล
เหตุที่ใช้แท็ก ul ก็เพื่อรองรับ การทำงานในลักษณะวนลูป หรือซ้ำการแสดงข้อมูล
แบบเป็นลิสรายการ
จะเห็นว่า บรรทัดที่ 17 จะมีการกำหนด ng-repeat ให้เข้าใจว่า จะมีการวนลูปแสดง หรือ
การแสดงข้อมูลแท็ก li นี้ซ้ำ ตามจำนวนลิสรายการ เช่นถ้ามีการเพิ่ม รายการเข้าไป ก็จะ
มีการแสดง li แทรกเข้ามา และหากมีการลบ ก็จะทำการลบแท็ก li ออกไป
<li ng-repeat="todo in todos">
สังเกตการกำหนดค่า ng-repeat เป็น "todo in todos"
todo คือค่า instnant หรือ object อ้างอิง ของ property ชื่อ todos อีกที
(todos จะมีอธิบายในไฟล์ todo.js)
บรรทัดที่ 18 บรรทัดนี้ เราจะพบ ng-model ซึ่งได้รู้จักคร่าวๆ มาแล้วในตอนที่ 1
<input type="checkbox" ng-model="todo.done">
ให้เข้าใจว่า ค่าของ checkbox นี้ มีค่าเท่ากับ ค่าของ todo.done
เช่น todo.done มีค่าเท่ากับ true แล้ว checkbox ก็จะถูกติ้กเลือก
แต่ถ้า todo.don มีค่าเท่ากับ false แล้ว checkbox ก็จะไม่ถุกเลือก เป็นต้น
บรรทัดที่ 19 ส่วนนี้ไม่มีอะไร จะเป็นแค่กำหนด template ของการแสดงข้อความ
ตามค่าที่ได้
<span class="done-{{todo.done}}">{{todo.text}}</span>
สังเกตแท็ก span นี้ ถ้า todo.done มีค่าเท่ากับ true ก็จะทำให้
class css ของ span ก็จะมีชื่อเป็น done-true ซึ่งก็คือ css ขัดฆ่าในไฟล์ todo.css นั่นเอง
สำหรับ todo.text ก็คือ ข้อความของรายการ ที่แสดงในแท็ก span
8. บรรทัดที่ 22-26 เป็นส่วนของ form สำหรับส่งข้อมูล ในที่นี้ คือการเพิ่ม
ลิ้สรายการ todo มี attibute สำหรับการ submit form คือ ng-submit คล้ายกับ
event submit หรือเหตุการเมื่อมีการกดปุ่มส่ง submit ข้อมูล ตามตัวอย่าง ก็จะไป
เรียกใช้ฟังก์ชั่น addTodo()
<form ng-submit="addTodo()">
บรรทัดที่ 23 input text สำหรับรับค่าลิ้สรายการ โดยใช้ ng-model กำหนดให้ค่าของ
input text นี้อยู่ในชื่อ todoText
บรรทัดที่ 25 ปุ่ม กำหนดให้เป็น type submit เพื่อให้ event submit ทำงาน
9 ส่วนสุดท้าย อันนี้ยากหน่อย มาลองๆ ดูกัน
ไฟล์ toto.js คือส่วนการของการคำสั่ง และการกำหนดให้ทำงานทั้งหมด
คำอธิบายแสดงใน โค้ด
โค้ดไฟล์ todo.js
angular.module('todoApp', []) /* angularjs จะเข้ามาจัดการในส่วนที่กำหนดนี้ <html ng-app="todoApp"> */
.controller('TodoController', ['$scope', function($scope)
{/* โดยเข้ามาจัดการเหตุการณ์ ต่างๆ ใน <div ng-controller="TodoController"> ผ่าน $scope object */
/* ส่วนนี้ จะเป็นการกำหนดรายการ todo สองรายการเริ่มต้น
โดย todos คือชื่อ property ของ object scope
ใน todos property ก็จะมี name และ value */
$scope.todos = [ /* todos นี้มี property type เป็นแบบ array มี name ชื่อ text และ done */
{text:'learn angular', done:true},
{text:'build an angular app', done:false}
];
/* เมื่อมีการโหลดหน้า app เพจ เริ่มต้น สอง รายการด้านบนนี้
จะถูกนำไปแสดงในแท็ก li ผ่าน ng-repeat ตาม html ด้านล่าง
todo จะไปเรียกใช้งาน property todos ของ object scope ผ่านค่า todo in todos
iรายการแรก จะถูกติ้กเลือก เพราะ มีค่า todo.done = todos.done = true
และรายการ ข้อความใน span จะถูกขีดฆ่า ด้วย css class
done-{{todo.done}} = done-{{todos.done}} = done-true
{{todo.text}} = todos.text
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li> */
/* object scope กำหนด method ขอเรียกเป็น ฟังก์ชั่นละกัน
ฟังก์ชั่น addTodo()
เนื่องจาก property todos เป็น array การเพิ่มข้อมูลเข้าไปจะใช้ คำสั่ง push เพื่อเพิ่ม array
<input type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
จะเห็นว่า object scope จะดึงค่า input text ด้วยชื่อ todoText โดยเรียกผ่าน $scope.todoText
การเพิ่มค่า จะเพิ่มเข้าไป สองค่า คือ text กับ done
ค่า text คือค่า จาก input text ส่วนค่า done จะเป็นค่าเริ่มต้น กำหนดให้เป็น false คือยังไม่ถูกติ้กเลือก */
$scope.addTodo = function() {
$scope.todos.push({text:$scope.todoText, done:false}); /* เพิ่มค่าเข้าไปใน array todos */
$scope.todoText = ''; /* หลังจากเพิ่มค่าแล้ว ให้ลบข้อความ ใน input text */
};
/* ส่วนของการแสดงค่า จำนวนรายการ ใน template
<span>{{remaining()}} of {{todos.length}} remaining</span>
โดย todos.length คือ จะนับค่า รายการใน array todos ทั้งหมด ส่งค่าไปแสดง
สำหรับรายการที่ยังไม่ติ้กเลือก หรือรายการคงเหลือ
จะใช้ฟังก์ชั่น remaining() */
$scope.remaining = function() {
var count = 0; // กำหนดตัวแปร ค่านับเริ่มต้น เป็น 0
angular.forEach($scope.todos, function(todo) { //คำสั่งของ angularjs วนลูปแสดง array todos
//ให้ตัวนับจำนวนทั้งหมด บวกค่า ตามเงือนไข
count += todo.done ? 0 : 1; // นับเฉพาะรายการ false หรือรายการยังไม่ติ้กเลือก ให้บวกเพิ่ม ทีละ 1
});
return count; // คืนค่า รายการที่ยังไม่ถูกติ้กเลือกทั้งหมด หรือรายการคงเหลือ
};
/* ส่วนสุดท้าย กับการใช้งานกับ event click เพื่อกำหนดรายการเป็น archive
ที่จริงก็คือรายการลิ้สที่ติ้กเลือกแล้ว และต้องการจัดเก็บ แต่คำสั่ง จะเป็นการลบออก เพื่อดูผลลัพธ์อย่างง่าย
[ <a href="" ng-click="archive()">archive</a> ]
จะใช้งาน ฟังก์ชั่น archive()
โดยในตัวอย่างนี้ เขาจะกำหนด property todos ที่เป็น array ของ object scope
ด้วย $scope.todos = []; กำหนดเป็น array ค่าว่าง
แล้วเพิ่มค่าไปใหม่ */
$scope.archive = function() {
var oldTodos = $scope.todos; // เก็บค่า todos array ทั้งหมดไว้กับตัวแปร array oldTodos แทนก่อน
$scope.todos = []; // ล้างค่าตัวเก่า โดย กำหนดเป็น array ค่าว่าง
angular.forEach(oldTodos, function(todo) { // นำค่าที่ถูกเก็บในตัวแปร oldTodos วนลูปแสดง
// จากนั้น เพิ่มค่าเข้าไปใหม่ ภายในเงื่อนไขว่า เอาเฉพาะ รายการที่ยังไม่ถูกเลือกเท่านั้นไว้
// ซื่อก็คือ รายการที่ todo.done=false ให้เอามาแสดง รายการที่ถูกเลือกแล้ว ไม่เอา
if (!todo.done) $scope.todos.push(todo); // รายการที่ todo.done=false ให้เอามาแสดง
});
};
}]);
แบบไม่มีคำอธิบาย โค้ดไฟล์ todo.js
angular.module('todoApp', [])
.controller('TodoController', ['$scope', function($scope) {
$scope.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
$scope.addTodo = function() {
$scope.todos.push({text:$scope.todoText, done:false});
$scope.todoText = '';
};
$scope.remaining = function() {
var count = 0;
angular.forEach($scope.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) $scope.todos.push(todo);
});
};
}]);
ตัวอย่าง
ตอนที่ 2 ยาว แต่ถ้าทำความเข้าใจ ก็จะเรียนรู้ได้เร็วขึ้น
ตอนนี้ได้รู้จัก ng-controller ng-click ng-submit ng-repeat
และรู้จัก object scope เพิ่มเข้ามา
ตอนหน้าจะมีอะไรใหม่ รอติดตาม