CHAPTER 10 การเพิ่ม, แก้ไข, ลบ, คน้ หาและแสดงขอ้ มลู (CRUD) สคริปต์ JavaScript ท่ี 10-1 การเพิ่ม, แกไ้ ข, ลบและแสดงข้อมลู หนงั สือ (CRUD) (app.js) ScJraivpat 195 17 app.use(bodyParser.json()); 18 app.use(bodyParser.urlencoded({ extended: false })); 19 app.use(cookieParser()); 20 app.use(express.static(path.join(__dirname, ‘public’))); 21 22 app.use(‘/’, routes); 23 app.use(‘/users’, users); 24 app.use(‘/books’, books); 25 26 app.use(function (req, res, next) { 27 var err = new Error(‘Not Found’); 28 err.status = 404; 29 next(err); 30 }); 31 32 if (app.get(‘env’) === ‘development’) { 33 app.use(function (err, req, res, next) { 34 res.status(err.status || 500); 35 res.render(‘error’, { 36 message: err.message, 37 error: err 38 }); 39 }); 40 } 41 42 app.use(function (err, req, res, next) { 43 res.status(err.status || 500); 44 res.render(‘error’, { 45 message: err.message, 46 error: {} 47 }); 48 }); 49 50 app.set(‘port’, process.env.PORT || 3000); 51 52 var server = app.listen(app.get(‘port’), function () { 53 debug(‘Express server listening on port ‘ + server.address().port); 54 });
2. ข้ันตอนการเพ่ิม, แก้ไข, ลบและแสดงข้อมูลหนังสือทั้งหมด อยู่ในไฟล์ books.js ท่ีอยู่ในโฟลเดอร์ routes ดังสคริปต์ตอ่ ไปน้ี สคริปต์ JavaScript ท่ี 10-1 การเพิม่ , แกไ้ ข, ลบและแสดงข้อมูลหนงั สอื (CRUD) (\\routes\\books.js) 1 var express = require(‘express’); 2 var router = express.Router(); 3 4 var mongoose = require(‘mongoose’); 5 var books = mongoose.model(‘books’); 6 7 router.get(‘/’, function (req, res) { 8 books.find(function (err, dbBooks) { 9 res.render( 10 ‘books’, 11 { title: ‘รายการหนังสือ’, data: dbBooks } 12 ); 13 }); 14 }); 15 16 router.post(‘/search’, function (req, res) { 17 books.find({ ‘title’: { $regex: req.body.q } }, function (err, dbBooks) { 18 res.render( 19 ‘books’, 20 { title: ‘รายการหนังสือ’, data: dbBooks } 21 ); 22 }); 23 }); 24 25 router.get(‘/add’, function (req, res) { 26 res.render( 27 ‘add’, 28 { title: ‘เพิ่มหนังสอื ใหม่’ } 29 ); 30 }); 31 32 router.post(‘/add’, function (req, res) { 33 new books({ 34 isbn: req.body.isbn, 35 title: req.body.title, 196
CHAPTER 10 การเพิม่ , แก้ไข, ลบ, คน้ หาและแสดงขอ้ มลู (CRUD) สคริปต์ JavaScript ท่ี 10-1 การเพิม่ , แกไ้ ข, ลบและแสดงข้อมูลหนังสือ (CRUD) (\\routes\\books.js) 36 price: req.body.price 37 }).save(function (err) { 38 if (err) { 39 res.json(err); 40 } else { 41 res.redirect(‘/books’); 42 } 43 }); 44 }); 45 46 router.param(‘id’, function (req, res, next, id) { 47 books.findById(id, function (err, dbBooks) { 48 if (err) { 49 res.json(err); 50 } else { 51 req.booksId = dbBooks; 52 next(); 53 } 54 }); 55 }); 56 57 router.get(‘/:id’, function (req, res) { 58 res.render(‘detail’, { bookData: req.booksId }); 59 }); 60 61 router.get(‘/:id/edit’, function (req, res) { 62 res.render(‘edit’, { bookData: req.booksId }); 63 }); 64 ScJraivpat 65 router.post(‘/:id’, function (req, res) { 66 books.findByIdAndUpdate({ _id: req.params.id }, 67 { 68 isbn: req.body.isbn, 69 title: req.body.title, 70 price: req.body.price 71 }, function (err, dbBooks) { 72 if (err) { 73 res.json(err); 197
สคริปต์ JavaScript ท่ี 10-1 การเพ่ิม, แกไ้ ข, ลบและแสดงขอ้ มลู หนังสอื (CRUD) (\\routes\\books.js) 74 } else { 75 res.redirect(‘/books’); 76 } 77 }); 78 }); 79 80 router.post(‘/deletebook/:id’, function (req, res) { 81 books.findByIdAndRemove({ _id: req.params.id }, 82 function (err, dbBooks) { 83 if (err) { 84 res.json(err); 85 } else { 86 res.redirect(‘/books’); 87 } 88 }); 89 }); 90 91 module.exports = router; 3. ตอ่ มา แถบคน้ หาขอ้ มลู ตอ้ งปรากฎในบราวเซอรเ์ สมอ ไมว่ า่ ผใู้ ชง้ านจะเลอื กเมนใู ด กต็ าม จงึ สรา้ งชอ่ งคน้ หาขอ้ มลู ไวใ้ นไฟล์mainmenu.pug รว่ มกบั แถบเมนหู ลกั เดมิ ดังสคริปตต์ อ่ ไปนี้ สครปิ ต์ Pug ท่ี 10-1 การเพิม่ , แก้ไข, ลบและแสดงข้อมูลหนงั สอื (CRUD) (\\views\\mainmenu.pug) 1 div#navmain 2 nav 3 a(href=’/’) หน้าแรก | 4 a(href=’/books’) หนงั สือ | 5 a(href=’/users’) สมาชิก | 6 form(action=’/books/search’, method=’post’) 7 input(type=’text’, name=’q’, size=’80’, placeholder=’ค้นหาข้อมูล...’) 8 input(type=’submit’, value=’ค้นหา’) 4. ต่อมา หน้าจอสำ�หรับแสดงรายการหนังสือท้ังหมดแบบไม่มีเงื่อนไข อยู่ในไฟล์ books.pug อยู่ในฐานะเป็นหนา้ แรก ดงั สครปิ ต์ตอ่ ไปน้ี สคริปต์ Pug ที่ 10-1 การเพิม่ , แก้ไข, ลบและแสดงขอ้ มูลหนังสอื (CRUD) (\\views\\books.pug) 1 extends layout 2 3 block content 4 a(href=’/books/add’ style=’float: right;’) เพมิ่ ขอ้ มูล 5 h1 #{title} 6 table(border = 1) 198
CHAPTER 10 การเพ่ิม, แก้ไข, ลบ, ค้นหาและแสดงข้อมลู (CRUD) สครปิ ต์ Pug ที่ 10-1 การเพ่ิม, แกไ้ ข, ลบและแสดงข้อมลู หนงั สือ (CRUD) (\\views\\books.pug) 7 th รหัส 8 th ช่ือหนงั สือ 9 th ราคา 10 th 11 for item in data 12 tr 13 td #{item.isbn} 14 td #{item.title} 15 td #{item.price} 16 td 17 a(href=’/books/’ + item._id) รายละเอียด 5. ต่อมา แบบฟอร์มสำ�หรับเพิ่มข้อมูลหนังสือใหม่ อยู่ในไฟล์ add.pug ดังสคริปต์ ตอ่ ไปนี้ สคริปต์ Pug ท่ี 10-1 การเพ่มิ , แกไ้ ข, ลบและแสดงข้อมูลหนงั สือ (CRUD) (\\views\\add.pug) 1 extends layout 2 3 block content 4 h1 #{title} 5 form(action=’/books/add’, method=’post’) 6 label(for=’isbn’) ISBN : 7 input(type=’text’, name=’isbn’, size=’30’, placeholder=’รหัส ISBN’) 8 label(for=’title’) ช่ือหนงั สือ : 9 input(type=’text’, name=’title’, size=’50’, placeholder=’ชือ่ หนังสอื ’) 10 label(for=’price’) ราคา : 11 input(type=’number’, name=’price’, size=’30’, placeholder=’ราคา’) 12 hr 13 input(type=’submit’, value=’บันทึก’) 6. ต่อมา หน้าจอสำ�หรับแสดงข้อมูลหนังสือท่ีถูกคลิกเลือก อยู่ในไฟล์ detail.pug ดงั สคริปต์ตอ่ ไปน้ี สครปิ ต์ Pug ที่ 10-1 การเพมิ่ , แก้ไข, ลบและแสดงขอ้ มูลหนงั สอื (CRUD) (\\views\\detail.pug) 1 extends layout 2 3 block content 4 <h1>#{bookData.title}</h1> 5 ul 6 li รหสั ISBN : #{bookData.isbn} ScJraivpat 199
สคริปต์ Pug ท่ี 10-1 การเพ่มิ , แกไ้ ข, ลบและแสดงข้อมลู หนังสอื (CRUD) (\\views\\detail.pug) 7 li ชื่อหนังสอื : #{bookData.title} 8 li ราคา : #{bookData.price} 9 ul 10 li 11 a(href=’/books/’ + bookData._id + ‘/edit’) แก้ไข 12 li 13 form(action=’/books/deletebook/’ + bookData._id, 14 method=’post’) 15 button(type=’submit’) ลบขอ้ มูล 7. ตอ่ มา หน้าจอทเี่ ปน็ แบบฟอร์มส�ำ หรบั แกไ้ ขข้อมูลหนังสอื แตล่ ะเล่ม อยูใ่ นไฟลท์ ่ีชื่อ วา่ edit.pug ดังสครปิ ต์ต่อไปน้ี สครปิ ต์ Pug ท่ี 10-1 การเพ่ิม, แก้ไข, ลบและแสดงข้อมลู หนงั สือ (CRUD) (\\views\\edit.pug) 1 <h1>แก้ไขขอ้ มูลของหนงั สอื : #{bookData.title}</h1> 2 form(action=’/books/’ + bookData._id, method=’post’) 3 p ISBN : 4 input(type=’text’, name=’isbn’ value = bookData.isbn) 5 p ช่อื หนงั สือ : 6 input(type=’text’, name=’title’ size=’60’ value = bookData.title) 7 p ราคา : 8 input(type=’number’, name=’price’ value = bookData.price) 9 p 10 input(type=’submit’, value=’แกไ้ ข’) อธบิ ายการทำ�งานของสคริปต์ การท�ำ งานทัง้ หมด (CRUD) ถอื เป็นงานของหนังสอื โดยเฉพาะ ขอใหย้ ึดถอื ไว้ในข้นั ต้น กอ่ นเลยวา่ อยภู่ ายใต้พาธ /books เกบ็ อยใู่ นไฟลท์ ีช่ อื่ วา่ books.js ในโฟลเดอร์ \\routes 1. เมอื่ มกี ารร้องขอแบบ Get มาทีพ่ าธ /books เป็นการสง่ั ใหไ้ ฟล์ books.js ทำ�งาน app.js 1 var books = require(‘./routes/books’); 2 var app = express(); 3 ... 4 ... 5 ... 6 app.use(‘/books’, books); 200
CHAPTER 10 การเพิม่ , แก้ไข, ลบ, ค้นหาและแสดงข้อมูล (CRUD) 2. ทไ่ี ฟล์ books.js ในโฟลเดอร์ \\routes เมือ่ มีการรอ้ งขอข้อมูลแบบ Get มาท่พี าธ / books ส่ังให้แสดงข้อมลู หนังสือท้งั หมดแบบไม่มเี งอื่ นไข ผลการค้นหาท่ไี ดเ้ กบ็ ไว้ ในพารามเิ ตอร์ทช่ี ือ่ ว่า dbBooks \\routes\\books.js 1 router.get(‘/’, function (req, res) { 2 books.find(function (err, dbBooks) { 3. ต่อมา สงั่ ใหแ้ สดงข้อมูลหนังสอื ทไี่ ดโ้ ดยอาศยั องค์ประกอบ 2 สว่ น คือ ÂÂ สว่ นแสดงผล ใช้ไฟลท์ ชี่ ่ือวา่ books.pug ÂÂ สว่ นของข้อมลู สง่ ข้อมูลหนงั สือท่เี กบ็ อย่ใู นพารามเิ ตอร์ dbBooks ไปสู่ตวั แปรท่ชี ื่อ ว่า data เพือ่ แสดงขอ้ มลู ในสว่ นแสดงผล book.pug \\routes\\books.js 1 res.render( 2 ‘books’, 3 { title: ‘รายการหนังสอื ’, data: dbBooks } 4. ท่ไี ฟลส์ ่วนแสดงผล books.pug ผู้เขียนสร้างส่วนแสดงผล 2 สว่ น ÂÂ สร้างลิงก์สำ�หรับเพ่ิมข้อมูล ผู้เขียนกำ�หนดให้เพ่ิมข้อมูลด้วยพาธ /books/add (อธิบายรายละเอยี ดอีกครั้งในภายหลงั ) \\views\\books.pug 1 extends layout 2 3 block content 4 a(href=’/books/add’ style=’float: right;’) เพ่มิ ข้อมลู 5 h1 #{title} ÂÂ แสดงข้อมูลหนังสือที่ได้มา อ่านข้อมูลหนังสือได้จากตัวแปร data โดยใช้รูปแบบ ตาราง 4 คอลัมน์ ประกอบด้วย รหัส ISBN (td #{item.isbn}), ชื่อหนังสือ (td #{item.title}) และราคาหนงั สอื (td #{item.price}) \\views\\books.pug 1 table(border = 1) 2 th รหัส 3 th ชือ่ หนังสือ ScJraivpat 201
\\views\\books.pug 4 th ราคา 5 th 6 for item in data 7 tr 8 td #{item.isbn} 9 td #{item.title} 10 td #{item.price} คอลัมน์สุดท้ายมีความพิเศษตรงที่ผู้เขียนกำ�หนดให้แสดงเน้ือหาด้วยข้อความ “ราย ละเอยี ด” ทุกแถว สัง่ ใหล้ งิ กไ์ ปท่ีพาธ /books + รหัส _id ของหนังสอื เพื่อแก้ไขหรอื ลบข้อมลู หนังสอื เฉพาะเล่มปัจจบุ นั น่ันเอง \\views\\books.pug 1 td 2 a(href=’/books/’ + item._id) รายละเอยี ด เมอื่ เราเลอื กหนงั สอื เลม่ ใดกต็ ามลงิ กด์ า้ นลา่ งจะแสดงพาธในรปู แบบ /books + รหสั _id พบวา่ รหสั _id ทป่ี รากฎขึ้นมากค็ ือ รหัส _id ของหนงั สือแตล่ ะเลม่ รูปท ี่ 10-12 แสดงขอ้ มลู ทเ่ี กบ็ อยใู่ นฟลิ ด์ _id รหัส _id ที่ส่งให้กับพาธ /books เพ่ือนำ�ไปใช้แก้ไขหรือลบข้อมูลเฉพาะเล่มที่ถูกคลิก เลอื กนั่นเอง 5. การคน้ หาขอ้ มลู ผเู้ ขยี นสรา้ งชอ่ งคน้ หาไวท้ ไ่ี ฟล์mainmenu.pug เพราะวา่ ตอ้ งการ ให้ปรากฎในบราวเซอรเ์ สมอ ไมว่ า่ ผู้ใชง้ านจะเปล่ยี นไปหน้าใดก็ตาม ถอื เปน็ แบบ ฟอรม์ ประเภทหน่งึ ประกอบด้วย 2 สว่ น ดังน้ี 202
CHAPTER 10 การเพม่ิ , แก้ไข, ลบ, คน้ หาและแสดงข้อมูล (CRUD) hh ช่องรับเงื่อนไขในการค้นหา สร้างช่องรับเง่ือนไขที่ชื่อว่า q (name=’q’) ช่ือท่ี ตง้ั จะน�ำ ไปใช้อ้างอิงในการเขียนสคริปต์คน้ หาข้อมูล hh พาธท่ีสั่งให้ค้นหาข้อมูล เม่ือผู้ใช้คลิกท่ีปุ่มค้นหาข้อมูล... ผู้เขียนกำ�หนดให้ ร้องขอข้อมลู (action=’/books/search’) ด้วยวธิ ี Post (method=’post’) ไป ทพ่ี าธ /books/search \\views\\mainmenu.pug 1 div#navmain 2 nav 3 a(href=’/’) หน้าแรก | 4 a(href=’/books’) หนงั สือ | 5 a(href=’/users’) สมาชกิ | 6 form(action=’/books/search’, method=’post’) 7 input(type=’text’, name=’q’, size=’80’, placeholder=’ค้นหาขอ้ มูล...’) 8 input(type=’submit’, value=’คน้ หา’) 6. ท่ีไฟล์ books.js เมอื่ มกี ารร้องขอข้อมลู มาท่ีพาธ /books/search ดว้ ยวิธี Post ก็จะ สั่งให้คน้ หาขอ้ มูลหนงั สือแบบมเี งื่อนไข กล่าวคือ ÂÂ ค้นหาขอ้ มูลตามเง่อื นไขด้วยช่ือหนงั สือ (ฟลิ ด์ title) ตามขอ้ ความที่ผู้ใช้ป้อนเข้ามา ทีต่ วั แปร q อา่ นคา่ ไดจ้ ากแบบฟอร์ม mainmenu.pug ({ $regex: req.body.q }) ÂÂ ข้อมลู หนงั สือที่ได้ตามเง่ือนไข เกบ็ ไว้ในพารามเิ ตอร์ท่ชี ่ือวา่ dbBooks \\routes\\books.js 1 router.post(‘/search’, function (req, res) { 2 books.find({ ‘title’: { $regex: req.body.q } }, function (err, dbBooks) { 7. ต่อมา ส่งั ให้แสดงรายการหนงั สือที่ค้นหาไดด้ ้วยองคป์ ระกอบเดิม คอื ÂÂ สว่ นแสดงผลทีช่ ่อื ว่า books.pug ÂÂ สง่ ขอ้ มูลหนังสอื ที่ไดม้ า (dbBooks) ให้กับตวั แปร data เพื่อแสดงรายการหนังสอื ในไฟล์ books.pug การทำ�งานท้ัง 2 สว่ นข้างตน้ กเ็ พือ่ การแสดงขอ้ มลู ตามผลค้นหาทีไ่ ดน้ น่ั เอง ScJraivpat 203
\\routes\\books.js 1 res.render( 2 ‘books’, 3 { title: ‘รายการหนงั สอื ’, data: dbBooks } 8. การเพมิ่ ขอ้ มลู เกดิ จากผใู้ ชง้ านคลกิ ทลี่ งิ ก์ “เพม่ิ ขอ้ มลู ” ทอ่ี ยใู่ นไฟล์books.pug พบ วา่ เป็นการรอ้ งขอขอ้ มูลไปทพี่ าธ /books/add \\views\\books.pug 1 block content 2 a(href=’/books/add’ style=’float: right;’) เพ่มิ ขอ้ มลู 9. ตอ่ มา เมอ่ื มกี ารรอ้ งขอขอ้ มลู แบบGet มาทพ่ี าธ/books/add กจ็ ะสง่ั ใหส้ ว่ นแสดงผล ท่ีช่ือว่า add.pug ปรากฎขึน้ มา เพื่อเป็นแบบฟอร์มส�ำ หรบั เพ่ิมข้อมลู หนังสือใหม่ \\routes\\books.js 1 router.get(‘/add’, function (req, res) { 2 res.render( 3 ‘add’, 4 { title: ‘เพ่มิ หนังสอื ใหม่’ } 10. ตอ่ มา ทไ่ี ฟลส์ ว่ นแสดงผลadd.pug ท�ำ หนา้ ทเ่ี ปน็ แบบฟอรม์ เพมิ่ ขอ้ มลู หนงั สอื ใหม่ ให้เราสรา้ งชอ่ งรบั ข้อมลู ตามทต่ี อ้ งการ ในกรณีน้คี อื ÂÂ รหสั ISBN กำ�หนดให้ช่องรับขอ้ มูลชอ่ื ว่า isbn (name=’isbn’) ÂÂ ชือ่ หนงั สือ ก�ำ หนดให้ช่องรับขอ้ มลู ชือ่ ว่า title (name=’title’) ÂÂ ราคาหนังสอื ก�ำ หนดให้ช่องรบั ขอ้ มูลช่อื วา่ price (name=’price’) ทั้ง 3 ชือ่ ข้างต้น จะน�ำ ไปใชอ้ า้ งองิ เวลาส่งข้อมลู หนังสอื ใหม่ \\views\\add.pug 1 extends layout 2 3 block content 4 h1 #{title} 5 form(action=’/books/add’, method=’post’) 6 label(for=’isbn’) ISBN : 204
CHAPTER 10 การเพม่ิ , แก้ไข, ลบ, คน้ หาและแสดงข้อมูล (CRUD) \\views\\add.pug 7 input(type=’text’, name=’isbn’, size=’30’, placeholder=’รหัส ISBN’) 8 label(for=’title’) ชอื่ หนังสือ : 9 input(type=’text’, name=’title’, size=’50’, placeholder=’ชอ่ื หนงั สอื ’) 10 label(for=’price’) ราคา : 11 input(type=’number’, name=’price’, size=’30’, placeholder=’ราคา’) 12 hr 13 input(type=’submit’, value=’บนั ทกึ ’) แบบฟอร์มรับข้อมูลหนังสือใหม่ ผู้เขียนกำ�หนดให้ส่งข้อมูลไปท่ีพาธ /books/add (action=’/books/add’) ด้วยวิธี Post (method=’post’) 11. ท่ีไฟล์ books.js เมื่อมีการส่งข้อมูลด้วยวิธี Post มาที่พาธ /books/add เพ่ือเพ่ิม ขอ้ มูลหนังสือใหม่ มกี ารทำ�งาน 2 ข้ันตอนยอ่ ย กลา่ วคือ hh อา่ นขอ้ มลู หนงั สอื ใหม่ จากแบบฟอรม์ เพมิ่ ขอ้ มลู หนงั สอื โดยการอา่ นขอ้ มลู ออก มาจากช่องรับข้อมูลท่ีช่ือว่า isbn, title และ price ตามโครงสร้างของตัวแปร books (new books) \\routes\\books.js 1 router.post(‘/add’, function (req, res) { 2 new books({ 3 isbn: req.body.isbn, 4 title: req.body.title, 5 price: req.body.price hh บนั ทกึ ข้อมลู หนังสอื ใหม่ โดยอาศยั ฟังก์ชัน save() \\routes\\books.js 1 }).save(function (err) { ถา้ การบนั ทกึ ขอ้ มลู หนงั สอื ใหมเ่ สรจ็ สมบรู ณแ์ ลว้ กจ็ ะสงั่ ใหแ้ สดงรายการหนงั สอื ทงั้ หมด โดยการรอ้ งขอข้อมูลไปทพี่ าธ /books แบบ Get ซ่งึ กค็ อื การแสดงข้อมลู หนงั สือทัง้ หมดเท่า ที่มอี ยแู่ บบไมม่ เี งือ่ นไขนนั่ เอง \\routes\\books.js 1 } else { 2 res.redirect(‘/books’); ScJraivpat 205
12. ในหนา้ จอแสดงรายการหนงั สอื ทง้ั หมด(หนา้ จอbooks.pug) ทค่ี อลมั นร์ ายละเอยี ด ผู้เขยี นกำ�หนดให้แสดงเฉพาะขอ้ มลู หนังสือเลม่ ทถ่ี ูกคลกิ เลอื ก ดงั รูปท่ี 10-13 รูปท ่ี 10-13 รูปแบบการร้องขอ ขอ้ มูลเฉพาะหนงั สือท่ถี กู คลกิ เลอื ก จากรปู ท่ี 10-13 รปู แบบการรอ้ งขอขอ้ มลู เฉพาะเลม่ ทถี่ กู คลกิ เลอื ก ประกอบดว้ ย 2 สว่ น คือ พาธ + รหัส _id ÂÂ พาธ คอื พาธ /books ÂÂ รหัส _id คือ การอา่ นคา่ ออกมาจากฟลิ ด์ _id ของแถวปัจจุบนั ท่ถี ูกคลกิ เลือก \\views\\books.pug 1 for item in data 2 tr 3 td #{item.isbn} 4 td #{item.title} 5 td #{item.price} 6 td 7 a(href=’/books/’ + item._id) รายละเอียด การสรา้ งลงิ กข์ า้ งตน้ เมอ่ื ผใู้ ชง้ านคลกิ เลอื กรายละเอยี ดของหนงั สอื เลม่ ใดกต็ าม กจ็ ะได้ รหัส _id ของหนังสอื เล่มนัน้ ติดไปด้วยเสมอ 13. ต่อมา เป็นการจัดการเก่ียวกับรหัส _id ที่ถูกส่งเข้ามา กำ�หนดให้ทำ�ผ่านทาง พารามเิ ตอรท์ ชี่ อ่ื วา่ id กจ็ ะสง่ั ใหค้ น้ หาขอ้ มลู ตามรหสั id ปจั จบุ นั โดยอาศยั ฟงั กช์ นั findById() ผลการคน้ หาท่ไี ด้เก็บไว้ในพารามเิ ตอรท์ ชี่ ือ่ ว่า dbBooks \\routes\\books.js 1 router.param(‘id’, function (req, res, next, id) { 2 books.findById(id, function (err, dbBooks) { 14. ต่อมา ถ้าไมเ่ กิดข้อผิดพลาดใดๆ ขอ้ มูลหนงั สือทไ่ี ด้ ตงั้ ช่อื ว่า booksId \\routes\\books.js 1 } else { 2 req.booksId = dbBooks; 3 next(); 206
CHAPTER 10 การเพม่ิ , แกไ้ ข, ลบ, คน้ หาและแสดงขอ้ มูล (CRUD) 15. ตอ่ มา การคลกิ เลอื กหนงั สอื ทคี่ อลมั นร์ ายละเอยี ดเปน็ การรอ้ งขอขอ้ มลู เขา้ มาทพ่ี าธ /books แบบ Get ที่มีรหัส _id ตดิ มาด้วย (อยใู่ นชอ่ื id) กจ็ ะสง่ั ใหส้ ว่ นแสดงผลที่ ช่ือว่า detail ปรากฎขึน้ มาท�ำ หน้าท่ีแสดงขอ้ มูลหนังสอื เฉพาะเลม่ ทถ่ี ูกคลิกเลอื ก จากนนั้ สง่ ขอ้ มลู หนงั สอื เลม่ ปจั จบุ นั (req.booksId) ใหก้ บั ตวั แปร bookData เพอื่ แสดง ขอ้ มูลหนงั สอื ในไฟล์ detail.pug ในลำ�ดบั ถดั ไป \\routes\\books.js 1 router.get(‘/:id’, function (req, res) { 2 res.render(‘detail’, { bookData: req.booksId }); 3 }); 16. ตอ่ มา ที่ไฟล์สว่ นแสดงผล detail.pug มีหนา้ ที่อยู่ 3 อย่างดังนี้ ÂÂ แสดงขอ้ มลู หนงั สอื เลม่ ทถ่ี กู คลกิ เลอื ก ถอื เปน็ หนา้ ทห่ี ลกั ของหนา้ จอน้ี ผา่ นทางตวั แปร bookData ทร่ี บั ขอ้ มลู หนงั สอื เขา้ มากค็ อื รหสั ISBN, ชอ่ื และราคาหนงั สอื ตามล�ำ ดบั \\views\\detail.pug 1 extends layout 2 3 block content 4 <h1>#{bookData.title}</h1> 5 ul 6 li รหัส ISBN : #{bookData.isbn} 7 li ชื่อหนงั สอื : #{bookData.title} 8 li ราคา : #{bookData.price} ÂÂ แก้ไขข้อมูล ในกรณีท่ีผู้ใช้งานต้องการแก้ไขข้อมูล ก็จะสร้างลิงก์สำ�หรับแก้ไข ขอ้ มูลของหนังสือเล่มปัจจุบนั โดยการรอ้ งขอขอ้ มูลในรูปแบบ พาธ + รหสั _id + ขอ้ ความ edit \\views\\detail.pug 1 ul 2 li 3 a(href=’/books/’ + bookData._id + ‘/edit’) แก้ไข รูปที่ 10-14 กรณีตอ้ งการแกไ้ ขข้อมลู ScJraivpat 207
ÂÂ ลบข้อมูล ในกรณที ี่ผู้ใช้งานต้องการลบข้อมูลหนังสือเล่มปัจจบุ นั ผู้เขียนก�ำ หนดให้ ลบได้ทันที ถือวา่ ส่วนแสดงผลปัจจบุ ัน (detail.pug) เป็นฟอร์มแสดงข้อมูลหนังสือ อยแู่ ลว้ กจ็ ะสง่ั ใหร้ อ้ งขอขอ้ มลู ไปทพ่ี าธ/books/deletebook+ รหสั _id(action=’/ books/deletebook/’+bookData._id) เลม่ ปจั จบุ นั ดว้ ยวธิ ีPost(method=’post’) \\views\\detail.pug 1 li 2 form(action=’/books/deletebook/’ + bookData._id, method=’post’) 3 button(type=’submit’) ลบข้อมูล รปู ท่ ี 10-15 กรณีตอ้ งการลบข้อมูล 17. การแกไ้ ขขอ้ มลู ใชห้ ลกั การวา่ ใหส้ รา้ งแบบฟอรม์ แสดงขอ้ มลู หนงั สอื เฉพาะเลม่ ทถ่ี กู คลิกเลือกข้ึนมาก่อน เกิดจากการร้องขอข้อมูลมาจากพาธ /books/รหัส _id/edit แบบ Get จากน้ันส่ังให้ส่วนแสดงผลท่ีชื่อว่า edit.pug ปรากฎขึ้นมา พร้อมกับส่งข้อมูลหนังสือ เลม่ ปจั จุบัน (req.booksId) ให้กบั ตวั แปร bookData ดว้ ย เพ่อื แสดงผลในแบบฟอร์มรอการ แกไ้ ขขอ้ มลู \\routes\\books.js 1 router.get(‘/:id/edit’, function (req, res) { 2 res.render(‘edit’, { bookData: req.booksId }); 3 }); 18. ต่อมา ที่ฟอร์ม edit.pug ทำ�หน้าท่ีแก้ไขข้อมูลหนังสือเล่มปัจจุบันท่ีถูกคลิกเลือก เราสามารถอา่ นข้อมลู หนงั สอื ได้จากตัวแปร bookData ที่ถกู ส่งเขา้ มาดว้ ย โดยท่ี ÂÂ รหัส ISBN สั่งให้แสดงรหัส (value = bookData.isbn) ใน text ที่ช่ือว่า isbn (name=’isbn’) ÂÂ ชอ่ื หนังสือ ส่งั ใหแ้ สดงชือ่ หนังสอื (value = bookData.title) ใน text ที่ชอ่ื ว่า title (name=’title’) 208
CHAPTER 10 การเพมิ่ , แก้ไข, ลบ, ค้นหาและแสดงขอ้ มูล (CRUD) ÂÂ ราคาหนงั สอื สง่ั ใหแ้ สดงราคาหนังสือ (value = bookData.price) ใน text ทช่ี ่อื วา่ price (name=’price’) \\views\\edit.pug 1 <h1>แกไ้ ขข้อมลู ของหนังสือ : #{bookData.title}</h1> 2 form(action=’/books/’ + bookData._id, method=’post’) 3 p ISBN : 4 input(type=’text’, name=’isbn’ value = bookData.isbn) 5 p ชือ่ หนงั สอื : 6 input(type=’text’, name=’title’ size=’60’ value = bookData.title) 7 p ราคา : 8 input(type=’number’, name=’price’ value = bookData.price) 9 p 10 input(type=’submit’, value=’แก้ไข’) การส่งข้อมูลหนังสือเล่มปัจจุบันท่ีถูกแก้ไข (หรือไม่แก้ไขก็ได้) กลับไป เพ่ือบันทึกการ แก้ไข เกดิ ขน้ึ เม่ือมีการกดทปี่ มุ่ แก้ไข ผู้เขยี นก�ำ หนดให้ ÂÂ ส่งข้อมูลแบบ Post (method=’post’) ÂÂ ไปทพ่ี าธ /books + รหัส _id ปัจจุบนั (action=’/books/’ + bookData._id) 19. ตอ่ มา การรับขอ้ มูลหนังสือทถี่ กู แกไ้ ข อย่ทู พ่ี าธ /books/รหสั _id (อย่ใู นชือ่ id) ให้ ทำ�ดังน้ี hh ค้นหารหัสหนังสือเล่มปัจจุบัน ({ _id: req.params.id }) โดยอาศัยฟังก์ชัน findByIdAndUpdate() และ \\routes\\books.js 1 router.post(‘/:id’, function (req, res) { 2 books.findByIdAndUpdate({ _id: req.params.id }, 3{ hh อัพเดตข้อมูลหนังสือเล่มปัจจุบัน ด้วยข้อมูลล่าสุดที่แสดงอยู่ในแบบฟอร์ม ปัจจุบัน อ่านข้อมูลหนังสือล่าสุดทีละส่วนได้จาก isbn(req.body.isbn), title (req.body.title) และ price (req.body.price) \\routes\\books.js 1 isbn: req.body.isbn, 2 title: req.body.title, 3 price: req.body.price ScJraivpat 209
20. ต่อมา ในกรณีที่เกิดข้อผิดพลาด ให้แสดงข้อผิดพลาดดังกล่าวออกมาผ่านทาง พารามิเตอร์ err \\routes\\books.js 1 }, function (err, dbBooks) { 2 if (err) { 3 res.json(err); 21. ในกรณที อี่ พั เดตขอ้ มลู ถกู ตอ้ ง กจ็ ะสง่ั ใหแ้ สดงรายการหนงั สอื ทงั้ หมดโดยการสงั่ ให้ ไปทพ่ี าธ /books น่นั เอง \\routes\\books.js 1 } else { 2 res.redirect(‘/books’); 22. ในกรณีทต่ี อ้ งการลบขอ้ มูล เกดิ จากการร้องขอมาทีพ่ าธ /deletebook + รหสั _id ปัจจบุ นั แบบ Post ให้ทำ� ÂÂ คน้ หาและลบขอ้ มูลหนงั สือรหัสปจั จบุ ัน โดยอาศยั ฟงั ก์ชัน findByIdAndRemove() กอ่ น \\routes\\books.js 1 router.post(‘/deletebook/:id’, function (req, res) { 2 books.findByIdAndRemove({ _id: req.params.id }, ÂÂ แสดงรายการหนังสือล่าสุดเท่าท่ีมีอยู่ ถ้าการลบข้อมูลถูกต้อง ก็จะส่ังให้แสดง รายการหนังสอื ท้ังหมดเทา่ ทม่ี ีอย่โู ดยการสงั่ ให้ไปทีพ่ าธ /books \\routes\\books.js 1 } else { 2 res.redirect(‘/books’); สรุปทา้ ยบท การเพม่ิ , แกไ้ ข, ลบ และแสดงข้อมลู (CRUD) ถอื เป็นการทำ�งานท่ีตอ้ งทราบ ไมว่ า่ เราจะพฒั นาWebApps ดว้ ยภาษาใดกต็ าม ตวั อยา่ งทน่ี �ำ เสนอในบทน้ี เปน็ การ ทำ�งานแบบพ้ืนฐานไม่มีความซบั ซ้อนใดๆ ทัง้ ส้นิ 210
Java script 11CHAPTER เตรยี มความพรอ้ มกอ่ นเขา้ สโู่ ลกของ Angular เน้ือหาทผ่ี า่ นมาเป็นการพัฒนา Web Apps ท่ีเกดิ จากการใช้งาน 3 ส่วน คือ M (Mongo), E (Express) และ N (Node) ขาดตวั อักษร A (Angular) ก็คอื เนอื้ หาตง้ั แต่บทน้เี ป็นต้นไป โดยมี ขอบเขตเนอื้ หานำ� เสนอการใช้งาน Angular ในข้ันต้นเทา่ น้นั ก่อนท่ีจะน�ำ Angular เขา้ ไปใช้งานร่วมกบั Mongo, Express และ Node ผู้เขยี นขอ แยกเน้อื หาการใช้งาน Angular เพียงอย่างเดยี วออกมากอ่ นเพื่อให้ผอู้ า่ นรูจ้ กั กับ Angular ใน ขัน้ ตน้ เพราะวา่ Angular มีรายละเอยี ดโลกของตัวเองท่ีมีขนาดใหญ่มาก Angular คอื อะไร Angular (ในช่วงเวลาที่แต่งต้นฉบับหนังสือเล่มน้ี คือ Angular เวอร์ชัน 6) คือ JavaScript Framework ตวั หนง่ึ ท�ำหนา้ ที่สรา้ งสว่ นแสดงผลปรากฎในบราวเซอร์ โดยใชห้ ลัก การแบง่ แยกส่วนแสดงผลออกเปน็ พ้ืนท่ยี อ่ ย เรียกว่า คอมโปเนนท์ (Component) แล้วน�ำ พื้นท่ยี อ่ ยดังกล่าวมาแสดงผลต่อๆ กัน การเขยี น Angular เราไม่ไดใ้ ชภ้ าษา JavaScript โดยตรง แตใ่ ช้ภาษา TypeScript เข้า มาทำ� หนา้ ทส่ี ร้างคอมโปเนนท์ (หรือสว่ นอนื่ ๆ) กอ่ น แล้วจึงค่อยแปล (Compile) เปน็ ภาษา JavaScript HTML .Net HTML
ทำ�ไมตอ้ งสร้างส่วนแสดงผลดว้ ย Angular ส่วนแสดงผลของ Web Apps ไม่ว่าเราจะพฒั นาด้วยภาษาใดกต็ าม เกดิ จากการใช้ อลิ เี มนตพ์ ื้นฐานต่างๆ ตามมาตรฐาน HTML เชน่ ต้องการแสดงขอ้ ความ “สวัสดคี รับ” ดว้ ย ตัวอักษรขนาดใหญ่แบบ Header 1 ดังรูปที่ 11-1 index.html 1 <!DOCTYPE html> 2 <html lang=“th”> 3 <head> 4 <meta charset=“utf-8” /> 5 <title>หนา้ แรก</title> 6 </head> 7 <body> 8 <h1>สวัสดีครบั </h1> 9 </body> 10 </html> รปู ท ่ี 11-1 ส่วนแสดงผลทเี่ กดิ จาก HTML โดยตรง จากรปู ที่ 11-1 ส่วนแสดงผลข้างต้นท่ปี รากฎในบราวเซอร์ เกดิ จากองค์ประกอบ 2 ส่วน 1. ข้อมลู ในกรณนี ี้ คือ ขอ้ ความธรรมดา “สวสั ดีครับ” 2. วธิ แี สดงผล ในกรณนี ผ้ี เู้ ขยี นตอ้ งการแสดงขอ้ ความดว้ ยตวั อกั ษรใหญร่ ะดบั Header 1 เป็นหนา้ ท่ีของอลิ ีเมนต์ <h1>…</h1> ของภาษา HTML กล่าวได้อีกนัยหนึ่งว่าเราน�ำข้อมูลและวิธีแสดงผลมาอยู่ด้วยกัน ส่งผลให้หน้าเว็บเพจ ทเ่ี กดิ จาก HTML ถอื เปน็ เวบ็ เพจประเภท Static File กลา่ วคอื เปลย่ี นแปลงไม่ได้ ก�ำหนดให้ แสดงผลอยา่ งไรกต็ อ้ งเป็นแบบนั้น หน้าเวบ็ เพจทเี่ กดิ จาก HTML แทๆ้ ไม่รองรบั การเปล่ียนแปลงขอ้ มูล หรอื เปลยี่ นแปลง วิธแี สดงผลด้วยตวั เอง ต้องใช้ภาษาสคริปตอ์ ื่นๆ เข้ามาช่วย เชน่ ภาษา JavaScript, ASP. NET, PHP เปน็ ตน้ 212
CHAPTER 11 เตรียมความพรอ้ มกอ่ นเข้าส่โู ลกของ Angular ส่วนแสดงผลที่เกิดจาก Angular รองรับการเปลี่ยนแปลงข้อมูลได้ทั้งในพื้นท่ีของ ตัวเอง และการเปลี่ยนแปลงในพื้นที่อื่นๆ จึงเป็นเหตุผลที่ว่าท�ำไมเราต้องสร้างส่วนแสดงผล ด้วย Angular การติดตงั้ ส่วน Extension ใหก้ ับ Visual Studio Code ก่อนทีเ่ ข้าสู่ขั้นตอนการใชง้ าน Angular ผู้เขยี นเลือกใช้โปรแกรม Visual Studio Code เป็นตวั editor หลักส�ำหรับเขยี นสครปิ ต์ มขี อ้ แนะนำ� ให้ลงสว่ นขยาย (Extensions) เพิม่ เติม เพื่อชว่ ยใหก้ ารเขยี นสคริปต์ Angular ง่ายขึน้ 2 รายการ มีข้นั ตอนดงั นี้ 1. ให้เปดิ โปรแกรม Visual Studio Code ข้นึ มากอ่ น คลกิ ท่ี ปุ่ม เพือ่ ดาวน์โหลดและตดิ ตง้ั Extensions ที่ต้องการ ดังรปู ที่ 11-2 รปู ที ่ 11-2 แสดงการเปดิ สว่ น Extensions ของ Visual Studio Code 2. ตอ่ มา ให้คน้ หา Extensions ท่ชี อื่ ว่า “Angular 6 Snippets” (หรือเวอร์ชันใหมก่ ว่า ตามช่วงเวลาปัจจุบัน) คลิกที่ปุ่ม เพ่ือดาวน์โหลดและติดต้ัง ให้เปิด-ปิด โปรแกรม Visual Studio Code 1 คร้งั ด้วยเสมอ ดงั รปู ที่ 11-3 รปู ท่ี 11-3 แสดงการดาวนโ์ หลดและติดตั้ง Angular 6 Snippets ScJraivpat 213
3. ตอ่ มา ใหค้ น้ หาดว้ ยคำ�วา่ “AngularEssentials” ใหด้ าวนโ์ หลดและตดิ ตงั้ ใหเ้ รยี บรอ้ ย เชน่ กัน ดังรปู ท่ี 11-4 รูปท่ี 11-4 แสดงการดาวน์โหลดและติดตัง้ Angular Essentials Extensions ทง้ั 2 ตัวข้างตน้ ชว่ ยท�ำใหก้ ารเขยี นสคริปต์ Angular ใน Visual Studio Code สะดวกและรวดเร็วยิ่งขึ้น ผเู้ ขยี นขอไม่แนะนำ� วิธีการใช้งาน สามารถดรู ายละเอยี ดได้ ดว้ ยตัวเองมวี ธิ ีใช้งานคอ่ นขา้ งงา่ ย ในวันขา้ งหนา้ อาจจะมี Extensions ตวั อน่ื ๆ ท่ีดีกว่านี้ ขอให้ติดตามความคบื หนา้ ได้ จากแฟนเพจผเู้ ขียนท่ี https://www.facebook.com/thaivb.net/ การสรา้ งโปรเจ็กต์ Angular ด้วย Angular CLI จากทีผ่ เู้ ขยี นได้กลา่ วไวใ้ นตอนตน้ ที่ว่า Angular มโี ลกของตวั เอง ดังนัน้ เราจงึ ตอ้ งหา ผู้สร้างโปรเจ็กต์ Angular ก่อน ผู้เขียนเลือกใช้ Angular CLI เข้ามาท�ำหน้าท่ีเป็นผู้สร้าง โปรเจ็กต์ Angular ให้กับเรา การใช้งาน Angular CLI จะต้องดาวน์โหลดและตดิ ต้งั ในเคร่ืองของเรากอ่ น มขี นั้ ตอน ดงั น้ี 1. ให้เปิดหน้าต่าง Command Prompt ด้วยสิทธิ์ของ admin ของระบบก่อน จากนั้นพิมพ์คำ�ส่ังต่อไปน้ี เพื่อดาวน์โหลดและติดต้ัง Angular CLI ลงในเครื่อง ดังรปู ที่ 11-5 Angular CLI Command Prompt 1 npm install -g @angular/cli 214
CHAPTER 11 เตรยี มความพรอ้ มก่อนเขา้ ส่โู ลกของ Angular รปู ท ่ี 11-5 แสดงการดาวนโ์ หลดและตดิ ตงั้ Angular CLI เสรจ็ สมบรู ณ์ จากรปู ที่11-5 ใหร้ อดาวนโ์ หลดและตดิ ตง้ั จนกระทงั่ ขนึ้ CommandPrompt บรรทดั ใหม่ 2. สามารถตรวจสอบว่าการติดต้ัง Angular CLI เสร็จสมบูรณ์หรือไม่ ใหพิมพ์คำ�ส่ัง ตอ่ ไปน้ี เพือ่ ตรวจสอบเวอรช์ นั ของ Angular CLI ดงั รปู ที่ 11-6 Angular CLI Command Prompt 1 ng -v รูปท่ ี 11-6 แสดงเวอรช์ นั ของ Angular CL จากรูปท่ี 11-6 ถา้ มีตวั เลขเวอร์ชนั ปรากฎขน้ึ มาถอื วา่ การตดิ ต้งั Angular CLI ในเครื่อง เสรจ็ สมบูรณแ์ ลว้ พรอ้ มทจ่ี ะสร้างโปรเจก็ ต์ Angular ด้วย Angular CLI แล้ว การสร้างโปรเจก็ ต์ Angular ดว้ ย Angular CLI หลงั จากทตี่ ดิ ตง้ั AngularCLI ในเครอื่ งแลว้ กจ็ ะเขา้ สขู่ น้ั ตอนการสรา้ งโปรเจก็ ต์Angular ดงั ข้นั ตอนต่อไปนี้ 1. ให้เปิด Command Prompt ด้วยสิทธิ์ของ admin ผู้เขียนต้องการสร้าง โปรเจก็ ต์ Angular ไวท้ ่พี าธ E:\\Projects (หรือพาธตามทีต่ ้องการ) ตัง้ ชอื่ โปรเจ็กต์ วา่ usingangular โดยการพิมพ์คำ�สั่งตอ่ ไปน้ี แล้วกดปมุ่ Enter ดงั รปู ท่ี 11-7 ScJraivpat 215
Angular CLI Command Prompt 1 C:\\Windows\\system32>E: 2 E:\\>cd Projects 3 E:\\Projects>ng new usingangular ค�ำสง่ั ของ Angular CLI ขนึ้ ตน้ ด้วยคำ� ว่า ng รูปท่ ี 11-7 แสดงการสรา้ งโปรเจก็ ตท์ ชี่ อ่ื วา่ usingangular ถา้ ไปดทู พี่ าธE:\\Projects พบวา่ รายการไฟลต์ า่ งๆ ของ โปรเจก็ ต์ Angular ที่ดาวน์โหลดมาจะถกู เกบ็ อยูใ่ นโฟลเดอร์ ย่อย usingangular อีกช้ันตามช่ือโปรเจ็กต์ของเรา ตามรูป ที่ 11-8 รูปท่ ี 11-8 แสดงรายการไฟลข์ องโปรเจก็ ต์ Angular 2. ต่อมา เราตอ้ งการเปิดโปรเจ็กต์ usingangular ดว้ ย Visual Studio Code ใหท้ ำ� ดังน้ี hh ค�ำ สงั่ cd usingangular เพ่ือเข้าไปในโฟลเดอร์โปรเจ็กตป์ จั จบุ ันกอ่ น hh ค�ำ สงั่ code . เพอื่ เปิดโปรเจ็กต์ปจั จุบันด้วย Visual Studio Code Angular CLI Command Prompt 1 cd usingangular 2 code . 216
CHAPTER 11 เตรียมความพร้อมก่อนเขา้ สโู่ ลกของ Angular รูปท่ี 11-9 แสดงรายการ dependencies ของ Angular จากรูปที่ 11-9 โปรเจก็ ต์ Angular มรี ายการไฟล์ตา่ งๆ มากมาย ใหด้ ูทีไ่ ฟล์ package. json พบว่า Angular ก็มีการใชง้ านช้นิ สว่ น (dependencies) ของตัวเองเช่นกนั 3. ต่อมา ใหล้ องเปดิ โฟลเดอร์ node_modules พบว่ามีรายการไฟล์ส่วนหน่ึงถูกดาวน์โหลด มาด้วยเช่นกัน ดังรูปที่ 11-10 รปู ท่ี 11-10 แสดงรายการไฟล์ในโฟลเดอร์ node_modules การรันและหยดุ โปรเจ็กต์ Angular ท่ีได้จาก Angular CLI โปรเจก็ ต์ Angular ทไี่ ดม้ าจาก Angular CLI มคี วามสมบรู ณใ์ นระดบั หนง่ึ พรอ้ มที่ จะพฒั นาในล�ำดบั ต่อไป แต่ในขนั้ ตน้ นเ้ี รายงั ไม่สนใจหนา้ ที่ของแตล่ ะไฟล์ และไมม่ กี ารเขียน สครปิ ตใ์ ดๆ เพมิ่ เตมิ ทง้ั สน้ิ เราอยากดหู นา้ ตาของเวบ็ เพจทไ่ี ดจ้ ากAngular กอ่ น มขี นั้ ตอนดงั น้ี 1. ใหเ้ ลอื กเมนู View > Integrated Terminal เพอ่ื เปดิ หนา้ ตา่ งปอ้ นคำ�สงั่ ของโปรเจก็ ต์ ปจั จุบันใน Visual Studio Code ข้ึนมาก่อน จากนน้ั ให้พิมพค์ �ำสง่ั ตอ่ ไปนี้ เพ่ือสงั่ ให้รนั โปรเจก็ ตป์ จั จุบนั ดงั รปู ที่ 11-11 Angular CLI Command Prompt 1 ng serve ScJraivpat 217
รูปท่ ี 11-11 แสดงการรนั โปรเจก็ ตป์ จั จบุ นั จากรูปที่ 11-11 สามารถเปดิ ดูโปรเจ็กตป์ จั จบุ นั ได้ 2 วธิ ี ดังนี้ ÂÂ เปดิ บราวเซอรข์ ้นึ มา ไปที่พาธ http://localhost:4200/ ÂÂ กดปุม่ Ctrl ที่คยี บ์ อร์ดค้างไว้กอ่ น จากน้ันคลิกทีล่ ิงก์ http://localhost:4200/ 2. ต่อมา ถ้าเห็นสว่ นแสดงผลตอ่ ไปนี้ ถอื ว่า โปรเจก็ ต์Angular ของเราทำ�งานสมบรู ณ์ แล้ว ดงั รปู ท่ี 11-12 รูปที ่ 11-12 แสดงหนา้ ตาโปรเจก็ ตท์ เี่ กดิ จาก Angular จากรูปท่ี 11-12 หน้าเว็บเพจท่ีปรากฎข้ึนมา เรายังไม่ได้เขียนสคริปต์ใดๆ ท้ังสิ้น เกดิ จาก Angular CLI สร้างให้เราท้ังหมด 3. ในกรณที ่ีเราต้องการหยุดรนั โปรเจ็กต์ Angular ใหก้ ดปมุ่ Ctrl + C ทคี่ ีย์บอรด์ แล้ว ตอบ y เพือ่ หยดุ รันโปรเจ็กต์ปจั จบุ นั ดงั รูปที่ 11-13 รปู ท ่ี 11-13 กรณตี อ้ งการหยดุ รนั โปรเจก็ ต์ Angular สรปุ ทา้ ยบท เน้ือหาในบทน้ีเป็นเพียงการเตรียมความพร้อม เพ่ือให้เคร่ืองของเราสามารถ สร้างและรนั โปรเจ็กต์ Angular ได้เท่านน้ั เนอื้ หาในบทต่อไปกจ็ ะเขา้ สรู่ ายละเอียด ของ Angular อย่างแท้จริง 218
Java script 12CHAPTER พน้ื ฐานการใชง้ าน Angular เนอ้ื หาในบททีแ่ ล้วเปน็ การสร้างโปรเจ็กต์ Angular ข้นึ มาด้วย Angular CLI ผลลัพธท์ ไ่ี ด้ คอื ส่วนแสดงผลท่ีเกิดมาจาก Angular โดยท่ีเราไม่ทราบว่าส่วนแสดงผลดังกล่าวมีที่มาอย่างไร เกิดจากหลกั การท�ำ งานอะไร เราจะมาเร่ิมท�ำ ความรูจ้ ักกับหลักการทำ�งานของ Angular รายละเอยี ดข้นั ตน้ ของ Angular จุดเริม่ ต้นของโปรเจ็กต์ Angular ให้ไปทโ่ี ฟลเดอร์ \\src\\app\\app.module.ts ดงั รูป ที่ 12-1 OTE ค�ำ วา่ Angular ไม่ใชต่ วั ภาษา แตเ่ ปน็ ชอื่ เรยี ก Framework โดยใชภ้ าษา TypeScript มนี ามสกลุ .ts รูปท ่ี 12-1 แสดงสคริปต์ภาษา TypeScript ของไฟล์ app.module.ts จากรปู ที่12-1 ทไ่ี ฟล์app.module.ts ก�ำ หนดใหค้ อมโปเนนทท์ ชี่ อื่ วา่ AppComponent ท�ำ หน้าท่ีเป็นคอมโปเนนทล์ ำ�ดับแรก เกดิ จาก HTML .Net HTML
ÂÂ import { AppComponent } from ‘./app.component’ ทำ�หน้าที่อ้างอิง ไฟล์ที่ช่ือว่า app.component.ts (from ‘./app.component’) และต้ังชื่อว่า AppComponent (import { AppComponent }) ÂÂ declarations : [AppComponent] ทำ�หน้าท่ีบอกว่าโมดูลปัจจุบันประกอบด้วย คอมโปเนนท์ทชี่ ื่อว่า AppComponent ÂÂ bootstrap: [AppComponent] ทำ�หน้าท่กี ำ�หนดให้ AppComponent แสดงผล เปน็ ล�ำ ดับแรก กล่าวไดอ้ กี นยั หนึง่ วา่ ก�ำ หนดใหไ้ ฟล์ app.component.ts ท�ำ งาน เปน็ ลำ�ดบั แรกน่นั เอง \\src\\app\\app.module.ts 1 import { AppComponent } from ‘./app.component’; 2 3 @NgModule({ 4 declarations: [ 5 AppComponent 6 ], 7… 8… 9… 10 bootstrap: [AppComponent] 11 }) ส่วนแสดงย่อยท่ีเกดิ จากคอมโปเนนท์ ประกอบด้วย 3 ไฟล์หลักน้เี สมอ คือ 1. app.component.ts สำ�หรบั เขยี นสครปิ ต์ภาษา TypeScript เพอ่ื ก�ำ หนดวา่ ในสว่ น แสดงผลย่อย (หรือพื้นท่ีย่อย) AppComponent แห่งน้ีเก็บข้อมูลอะไร แสดงผล อย่างไร เรียกใชด้ ว้ ยช่ือวา่ อะไร 2. app.component.html ทำ�หนา้ ที่แสดงผล โดยใชโ้ ครงสร้างของภาษา HTML 3. app.component.css ท�ำ หนา้ ทต่ี กแตง่ สว่ นแสดงผล โดยใชโ้ ครงสรา้ งของภาษา CSS รูปท ่ี 12-2 แสดงรายการไฟล์ท่ีทำ�หน้าที่แสดงผลเป็น ล�ำ ดบั แรก 220
CHAPTER 12 พ้นื ฐานการใช้งาน Angular หลกั การสรา้ งสว่ นแสดงผลย่อยโดยอาศยั คอมโปเนนท์ ไฟล์ล�ำ ดับแรกทเ่ี ราตอ้ งร้จู ักกค็ อื ไฟล์ app.component.ts ดงั รปู ท่ี 12-3 รูปท ่ี 12-3 แสดงสครปิ ตใ์ นไฟล์ app.component.ts \\src\\app\\app.component.ts 1 import { Component } from ‘@angular/core’; 2 3 @Component({ 4 selector: ‘app-root’, 5 templateUrl: ‘./app.component.html’, 6 styleUrls: [‘./app.component.css’] 7 }) 8 export class AppComponent { 9 title = ‘app’; 10 } คอมโปเนนทข์ อง Angular ใชค้ ลาส (Class) ของภาษา TypeScript เขา้ มาท�ำ หน้าทนี่ ้ี ประกอบด้วย 2 สว่ น ดงั นี้ 1. ส่วนของคลาส สร้างคลาสทีช่ ่อื วา่ AppComponent ข้ึนมา การทำ�งานของคลาส นมี้ ีเพียงอยา่ งเดียว นัน่ คอื สร้างตวั แปรทช่ี อ่ื ว่า title ทำ�หนา้ ทเี่ ก็บข้อความ “app” เราถือว่าตัวแปร title เป็นหน่วยจัดเก็บข้อมูลช่ัวคราวภายในคลาส AppComponent ของเรา \\src\\app\\app.component.ts 1 export class AppComponent { 2 title = ‘app’; 3} ScJraivpat 221
2. ส่วนของการนำ�คลาสไปใช้งาน เราต้องบอกว่าข้อมูลชั่วคราวท่ีเก็บอยู่ในคลาส AppComponent มีวิธกี ารใช้งานอยา่ งไร กลา่ วคือ ใหอ้ า้ งองิ @angular/core (from ‘@angular/core’) ก่อนเสมอ ตงั้ ช่ือว่า Component (import { Component }) \\src\\app\\app.component.ts 1 import { Component } from ‘@angular/core’; ตอ้ งบอกวิธกี ารน�ำ ข้อมลู ดงั กลา่ วไปใช้งาน ประกอบดว้ ย 3 ส่วน ดังน้ี ÂÂ selector ถ้าตอ้ งการใชง้ าน app.component.ts นี้ ใหเ้ รียกด้วยช่ือ app-root (จ�ำ ชื่อนไ้ี ว้เปน็ หลกั ) ÂÂ templateUrl ใหใ้ ช้สว่ นแสดงผลดว้ ยไฟลท์ ่ีชอ่ื ว่า app.component.html ÂÂ styleUrls ตกแตง่ สว่ นแสดงผลดว้ ยไฟลท์ ี่ชอ่ื วา่ app.component.css \\src\\app\\app.component.ts 1 @Component({ 2 selector: ‘app-root’, 3 templateUrl: ‘./app.component.html’, 4 styleUrls: [‘./app.component.css’] 5 }) HTML ในโลกของ Angular ไฟล์ app.component.ts กำ�หนดให้ใช้ส่วนแสดงผลท่ีชื่อว่า app.component.html (เป็นไฟล์นามสกุล .html) น่ันคือ ไฟล์ท่ีเราใช้ออกแบบหน้าตาส่วนแสดงผลด้วยภาษา HTML นั่นเอง แต่ HTML ในโลกของ Angular แตกตา่ งจาก HTML ปกตติ รงท่ี เราจะแยกสว่ นของขอ้ มลู ออกจากวิธแี สดงผลอยา่ งเด็ดขาด กลา่ วคือ 1. ส่วนของข้อมูล เก็บข้อความ “app” ไว้ในตัวแปรที่ชื่อว่า title (title = ‘app’) กำ�หนดไว้อย่างชัดเจนว่าใช้ส่วนแสดงผลของไฟล์ท่ีชื่อว่า app.component.html (templateUrl: ‘./app.component.html’) 222
CHAPTER 12 พืน้ ฐานการใชง้ าน Angular \\src\\app\\app.component.ts 1 import { Component } from ‘@angular/core’; 2 3 @Component({ 4 selector: ‘app-root’, 5 templateUrl: ‘./app.component.html’, 6 styleUrls: [‘./app.component.css’] 7 }) 8 export class AppComponent { 9 title = ‘app’; 10 } 2. วธิ แี สดงผล เปน็ หนา้ ทขี่ องไฟล์ app.component.html ขอ้ ความทป่ี รากฏขน้ึ มาใน บราวเซอร์ เกิดจาก 2 สว่ น ดงั นี้ ÂÂ ข้อความ “Welcome to” เป็นข้อความในไฟล์ HTML ธรรมดาทั่วไป กำ�หนดให้ แสดงดว้ ยขอ้ ความขนาด h1 ÂÂ ข้อความ “app” เป็นข้อความท่ีอ่านออกมาจากตัวแปรที่ชื่อว่า title (ในคลาส AppComponent) เหน็ ไดว้ ่าเป็นการแยกสว่ นของข้อมลู ออกมาจากวิธีการแสดงผลอย่างเด็ดขาด \\src\\app\\app.component.html 1 <div style=”text-align:center”> 2 <h1> 3 Welcome to {{title}}! 4 </h1> รปู ที ่ 12-4 ทม่ี าของขอ้ ความ “Welcome to app!” ผู้เขียนลองแก้ไขเฉพาะส่วนของข้อมูล จากข้อความเดิม “app” เป็นข้อความใหม่ “Angular World!!!” ในคลาส AppComponent สว่ นวธิ กี ารแสดงผล ยงั คงเดิม ScJraivpat 223
\\src\\app\\app.component.ts 1 import { Component } from ‘@angular/core’; 2 3 @Component({ 4 selector: ‘app-root’, 5 templateUrl: ‘./app.component.html’, 6 styleUrls: [‘./app.component.css’] 7 }) 8 export class AppComponent { 9 title = ‘Angular World!!!’; 10 } รปู ท่ี 12-5 แสดงขอ้ ความใหมท่ ไี่ ดม้ า วธิ ีการเรียกใช้คอมโปเนนท์ จากทผี่ เู้ ขยี นกลา่ วไวก้ อ่ นหนา้ นวี้ า่ สว่ นแสดงผลของ Angular เกดิ จากการน�ำ พน้ื ทย่ี อ่ ย หรอื คอมโปเนนทต์ า่ งๆ มาประกอบเขา้ ดว้ ยกนั เปน็ สว่ นแสดงผลทงั้ หมด ปรากฎในบราวเซอร์ ค�ำ ถามก็คอื เราเรียกใชค้ อมโปเนนทต์ อนไหน มีวธิ ีการอยา่ งไร ในโปรเจก็ ตป์ จั จบุ นั มคี อมโปเนนทเ์ พยี ง1 ตวั ชอ่ื วา่ app-root ประกอบดว้ ย3 ไฟล์ ดงั น้ี 1. app.component.ts รบั ผิดชอบส่วนของข้อมลู 2. app.component.html รับผดิ ชอบวธิ ีแสดงผลด้วยภาษา HTML 3. app.component.css รับผิดชอบการตกแตง่ ด้วยภาษา CSS เราเรยี กใช้คอมโปเนนท์ app-root ในไฟล์ index.html ดังรูปที่ 12-6 รปู ที่ 12-6 แสดงสครปิ ต์ในไฟล์ index.htm 224
CHAPTER 12 พื้นฐานการใชง้ าน Angular \\src\\index.html 1 <!doctype html> 2 <html lang=”en”> 3 <head> 4 <meta charset=”utf-8”> 5 <title>Usingangular</title> 6 <base href=”/”> 7 8 <meta name=”viewport” content=”width=device-width, initial-scale=1”> 9 <link rel=”icon” type=”image/x-icon” href=”favicon.ico”> 10 </head> 11 <body> 12 <app-root></app-root> 13 </body> 14 </html> ชอ่ื ทต่ี ง้ั ใหก้ บั คอมโปเนนท์ (selector: ‘app-root’) สามารถเรยี กใชใ้ นฐานะเปน็ อลิ เี มนต์ หน่งึ ของภาษา HTML ได้เลย นนั่ คือ ระบุอิลีเมนต์ <app-root></app-root> การเพ่ิมสว่ นแสดงผล (หรอื คอมโปเนนท์) ใหม่ โปรเจก็ ต์ Angular ท่ีเราได้มาจาก Angular CLI มีส่วนแสดงผลมาให้ 1 คอมโปเนนท์ ช่อื ว่า app-root เกบ็ อยู่ในโฟลเดอร์ \\src\\app ดงั รปู ท่ี 12-7 รูปท่ี 12-7 แสดงรายการไฟล์ของคอมโปเนนท์ app-root ในกรณีที่เราต้องการสร้างคอมโปเนนท์ใหม่เพ่ิมเติม สามารถทำ�ได้เช่นกัน Angular CLI มีคำ�สงั่ เพิม่ รายการไฟลค์ อมโปเนนทค์ รบทั้งชุด โดยที่ไมต่ ้องเพม่ิ ทลี ะไฟล์ มีขั้นตอนดังน้ี 1. ที่หน้าต่าง TERMINAL ดา้ นล่าง ในพาธโปรเจก็ ต์ปัจจุบัน ใหพ้ ิมพ์คำ�ส่งั ต่อไปน้ีเพอื่ สร้างคอมโปเนนทใ์ หม่ เกบ็ อยใู่ นโฟลเดอรย์ อ่ ย \\components\\book อีกช้นั หนึ่ง ดงั รูปที่ 12-8 ScJraivpat 225
Angular CLI Command Prompt 1 ng g component components/book รปู ที ่ 12-8 แสดงการสรา้ งคอมโปเนนทใ์ หม่ จากรูปที่ 12-8 ให้รอจนคำ�ส่ัง Command Prompt ข้ึนบรรทัดใหม่ ถือว่าการสร้าง เสร็จสมบูรณ์ 2. ต่อมา ผู้เขียนต้องการจัดระเบียบโปรเจ็กต์ในเวลาเดียวกันด้วย คำ�สั่งการสร้าง คอมโปเนนท์ข้างต้น กำ�หนดให้คอมโปเนนท์ใหม่ เก็บอยู่ในโฟลเดอร์ย่อยลงไปอีก 2 ระดบั คือ \\src\\app\\components\\book เหตุผลท่ีต้องสร้างโฟลเดอร์ย่อยลงปอีกระดับก็เพ่ือในภายภาคหน้า โปรเจ็กต์ของเรา ต้องประกอบไปด้วยคอมโปเนนท์ต่างๆ มากมาย ผู้เขียนกำ�หนดให้คอมโปเนนท์ใหม่อยู่ใน โฟลเดอร์ย่อย book เพราะว่าคอมโปเนนท์ตัวน้ีท�ำ หน้าท่ีแสดงข้อมูลหนังสือเพียงอย่างเดียว สง่ ผลให้รายการไฟล์ต่างๆ ของคอมโปเนนท์ book จงึ ควรอยูใ่ นโฟลเดอรย์ อ่ ย book นัน่ เอง ดงั รูปที่ 12-9 รปู ที ่ 12-9 แสดงรายการไฟล์ของ คอมโปเนนทใ์ หม่ 3. ต่อมา รายการไฟล์ของคอมโปเนนท์ใหม่ท่ีถูกเพิ่มเข้ามา เราต้องบอกให้โปรเจ็กต์ ปจั จุบนั รับทราบด้วยเชน่ กนั จึงจะสามารถใช้งานได้ เราไม่ต้องทำ�เองเพราะว่าในขณะที่เพ่ิมคอมโปเนนท์ใหม่ด้วยคำ�ส่ังของ Angular CLI มกี ารกำ�หนดคอมโปเนนทใ์ หม่ในไฟล์ app.module.ts ใหโ้ ดยอัตโนมัตแิ ลว้ ดังรูปที่ 12-10 226
CHAPTER 12 พ้นื ฐานการใชง้ าน Angular รปู ท่ี 12-10 แสดงรายการคอมโปเนนท์ ท้ังหมดของโปรเจก็ ต์ปัจจุบัน จากรปู ที่ 12-10 มกี ารอา้ งองิ ไฟล์ book.component (.ts) และประกาศใช้งานในส่วน ของ declarations แล้ว 4. ตอ่ มา ผเู้ ขยี นอยากทราบวา่ คอมโปเนนทใ์ หมม่ ชี อื่ เรยี กวา่ อะไร จงึ เปดิ ทไี่ ฟล์ book. component.ts พบวา่ มีช่อื เรียกใช้งานวา่ app-book รูปท่ ี 12-11 คอมโปเนนท์ใหม่ชื่อว่า app-book จากรูปท่ี 12-11 คอมโปเนนท์ app-book กำ�หนดให้ใช้ส่วนแสดงผลด้วยไฟล์ที่ชื่อว่า book.component.html 5. ต่อมา ให้เปดิ ไฟล์ book.component.html พบว่าถกู ส่งั ใหแ้ สดงข้อความธรรมดา “book works!” รูปท่ี 12-12 ส่วนแสดงผลของ app-book ScJraivpat 227
การสัง่ ให้คอมโปเนนท์ท�ำ งาน โปรเจก็ ต์ปัจจุบันประกอบดว้ ยคอมโปเนนท์ 2 ตัวคือ 1. app-root ไดม้ าตอนสรา้ งโปรเจ็กต์ ถอื เปน็ คอมโปเนนทห์ ลกั ของโปรเจ็กต์ปจั จุบนั 2. app-book เปน็ คอมโปเนนทท์ เ่ี ราสรา้ งขน้ึ มาใชง้ านเอง มหี นา้ ทแ่ี สดงขอ้ มลู รายการ หนงั สือ ในกรณที ี่ตอ้ งการส่ังใหส้ ่วนแสดงผลของ app-book ท�ำ งาน มีขนั้ ตอนดังนี้ 1. ที่ไฟล์ app.component.html (ส่วนแสดงผลหลักของคอมโปเนนท์ app-root) ใหร้ ะบชุ อ่ื คอมโปเนนท์app-book ในรปู แบบอลิ เี มนต์<app-book></app-book> ตอ่ จากสว่ นแสดงผลเดิมทมี่ อี ยู่ ดงั รูปที่ 12-13 รปู ท่ ี 12-13 แสดงการสง่ั ให้คอมโปเนนท์ app-book ทำ�งาน \\src\\app\\app.component.html 1 <div style=”text-align:center”> 2 <h1> 3 Welcome to {{title}}! 4 </h1> 5 </div> 6 <app-book></app-book> 2. จากนนั้ ใหร้ นั โปรเจก็ ตด์ ว้ ยค�ำ สง่ั ng serve สว่ นแสดงผลทเ่ี หน็ ในบราวเซอรเ์ กดิ จาก การทำ�งานของคอมโปเนนท์ 2 ตัว คือ ÂÂ app-root ก�ำ หนดใหแ้ สดงข้อความ Welcome to app! ÂÂ app-book กำ�หนดให้แสดงขอ้ ความ book works! 228
CHAPTER 12 พืน้ ฐานการใชง้ าน Angular รูปท ่ี 12-14 ส่วนแสดงผลท่ีเกิดจากคอมโปเนนท์ app-root กับ app-boo 3. ผเู้ ขยี นคดิ วา่ เวบ็ ไซตท์ ว่ั ไปตอ้ งมสี ว่ นfooter ส�ำ หรบั แสดงขอ้ มลู อนื่ ๆ เชน่ ผพู้ ฒั นา, Contact Us, นโยบายความเป็นสว่ นตัว เป็นต้น จึงเพม่ิ คอมโปเนนท์ footer เก็บ ลงในพาธ \\components\\footer โดยการปอ้ นคำ�ส่ังตอ่ ไปน้ี Angular CLI Command Prompt 1 ng g component components/footer รปู ที่ 12-15 แสดงการเพ่ิมคอมโปเนนท์ สำ�หรบั ส่วน footer 4. ต่อมา ให้ไปดูรายการไฟล์ของโปรเจ็กต์ปัจจุบัน คอมโปเนนท์ที่เพ่ิมเข้ามาใหม่ ถกู เกบ็ แยกต่างหากอยใู่ นโฟลเดอร์ยอ่ ย footer เม่ือดทู ไ่ี ฟล์ footer.component.ts คอมโปเนนทน์ ถ้ี กู ตง้ั ชอื่ วา่ app-footer รูปท่ ี 12-16 แสดงรายการไฟลข์ องคอมโปเนนท์ app-footer 5. ตอ่ มา คอมโปเนนท์ app-footer ทส่ี รา้ งขน้ึ มาใหม่ ถกู อา้ งองิ ในไฟล์ app.module.ts พร้อมเรียกใชง้ านแล้วเช่นกนั ScJraivpat 229
รปู ท ่ี 12-17 แ ส ด ง ก า ร อ้ า ง อิ ง คอมโปเนนท์ app-footer ในไฟล์ app. module.ts 6. ตอ่ มา ทไ่ี ฟล์footer.component.html ซงึ่ เปน็ สว่ นแสดงผลของคอมโปเนนท์app- footer ก�ำ หนดใหแ้ สดงลิงก์ไปท่แี ฟนเพจของผูเ้ ขียนเพยี งอย่างเดยี ว ดังรปู ที่ 12-18 รูปที่ 12-18 สคริปต์ส่วนแสดงผล ของไฟล์ footer.component.html 7. ต่อมา ท่ีไฟล์ส่วนแสดงผลหลัก app.component.html ให้เรียกใช้คอมโปเนนท์ app-book และ app-footer ตามล�ำ ดบั ดงั รปู ท่ี 12-19 รูปท ่ี 12-19 แสดงการเรยี กใช้ งานคอมโปเนนท์ app-book กบั app-footer 8. ทา้ ยทส่ี ดุ ใหร้ ันโปรเจ็กต์ดว้ ยคำ�สัง่ ng serve ก็จะไดส้ ว่ นแสดงผลที่เกดิ จาก 3 คอม โปเนนท์ประกอบเข้าด้วยกัน คือ app-root, app-book และ app-footer ตาม ลำ�ดับ ดงั รปู ท่ี 12-20 230
CHAPTER 12 พนื้ ฐานการใชง้ าน Angular รูปที ่ 12-20 สว่ นแสดงผลทไี่ ดจ้ ากทงั้ 3 คอมโปเนนท์ ทำ�ความร้จู กั กบั คลาสในคอมโปเนนท์ สว่ นแสดงผลทเ่ี กดิ จากAngular เกดิ มาจากคอมโปเนนทต์ า่ งๆ ประกอบดว้ ย2 สว่ นดงั นี้ 1. สว่ นของข้อมลู เก็บอยใู่ นรปู แบบคลาสของภาษา TypeScript 2. สว่ นอธบิ ายการน�ำ ขอ้ มลู ไปใชง้ าน เปน็ การน�ำ ขอ้ มลู ไปแสดงรว่ มกบั ไฟล์ HTML เพอ่ื สรา้ งสว่ นแสดงผลตา่ งๆ ตามทเ่ี ราออกแบบ เราจะมาลองเร่ิมสร้างข้อมูลเองแบบง่ายๆ แล้วนำ� ขอ้ มลู ดงั กลา่ วไปแสดงผลในหนา้ เวบ็ เพจของเราโดยการใชง้ าน คอมโปเนนท์ app-book ดงั รูปท่ี 12-21 รปู ที่ 12-21 แสดงคอมโปเนนท์ app-book ตวั อย่างที่ 12-1 ทำ�ความร้จู ักกับคลาสในคอมโปเนนท์ เปา้ หมายของตัวอย่างนีก้ ็เพื่อสรา้ งข้อมลู หนงั สอื ขึ้นมา 1 เลม่ ใน book.component.ts แล้วน�ำ ขอ้ มลู ดงั กลา่ วไปแสดงในไฟล์ book.component.html มขี ัน้ ตอนดังน้ี 1. ทไี่ ฟล์ book.component.ts ในคลาส BookComponent ใหเ้ พม่ิ ขอ้ มลู หนังสือ 1 เลม่ ดงั สครปิ ต์ต่อไปน้ี ตวั อยา่ งท่ี 12-1 ท�ำ ความรู้จกั กบั คลาสในคอมโปเนนท์ (\\src\\app\\components\\book\\book.component.ts) 1 import { Component, OnInit } from ‘@angular/core’; 2 3 @Component({ 4 selector: ‘app-book’, 5 templateUrl: ‘./book.component.html’, ScJraivpat 231
ตวั อยา่ งท่ี 12-1 ท�ำ ความรูจ้ กั กบั คลาสในคอมโปเนนท์ (\\src\\app\\components\\book\\book.component.ts) 6 styleUrls: [‘./book.component.css’] 7 }) 8 export class BookComponent implements OnInit { 9 private isbn: string; 10 private title: string; 11 private price: number; 12 13 constructor() { } 14 15 ngOnInit() { 16 this.isbn = ‘1111’; 17 this.title = ‘พ้นื ฐานการใช้งาน C#’; 18 this.price = 399; 19 } 20 } รปู ท ่ี 12-22 แสดงสครปิ ตใ์ นไฟล์ book.component.ts 2. ต่อมา ที่ไฟล์ book.component.html ซ่ึงทำ�หน้าที่แสดงผลให้กับคอมโปเนนท์ app-book ให้เขยี นสคริปต์ตอ่ ไปนี้ ตวั อยา่ งท่ี 12-1 ท�ำ ความรจู้ กั กบั คลาสในคอมโปเนนท์ (\\src\\app\\components\\book\\book.component.html) 1 <h1>รายการหนังสอื </h1> 2 <ul> 3 <li><b>รหสั ISBN : </b> {{isbn}}</li> 4 <li><b>ชอื่ หนังสือ : </b> {{title}}</li> 5 <li><b>ราคา : </b> {{price}}</li> 6 </ul> 232
CHAPTER 12 พื้นฐานการใช้งาน Angular รปู ท ี่ 12-23 แสดงสครปิ ตใ์ นไฟล์ book.component.html 3. ท้ายท่ีสุด ใหร้ นั โปรเจก็ ตด์ ว้ ยค�ำ สั่ง ng serve ก็จะพบกบั ข้อมลู หนงั สือ 1 เล่ม ดัง รูปท่ี 12-24 รูปท ี่ 12-24 ผลการรนั ตวั อยา่ งที่ 12-1 อธบิ ายการทำ�งานของสครปิ ต์ 1. เรม่ิ ตน้ ภายในคลาส BookComponent สรา้ งคณุ สมบตั ขิ น้ึ มา 3 รายการ ท�ำ หนา้ ท่ี เปน็ หน่วยจดั เก็บข้อมูลชว่ั คราว โดยที่ hh คณุ สมบตั ิ isbn ก�ำ หนดใหม้ ชี นดิ ขอ้ มลู ขอ้ ความ string ท�ำ หนา้ ทเี่ กบ็ รหสั หนงั สอื ISBN hh คณุ สมบัติ title ก�ำ หนดให้มีชนดิ ข้อมลู ขอ้ ความ string ท�ำ หน้าท่ีเก็บช่อื หนังสอื hh คุณสมบัติ price กำ�หนดให้มีชนิดข้อมูลตัวเลข number ทำ�หน้าท่ีเก็บราคา หนังสือ \\src\\app\\components\\book\\book.component.ts 1 export class BookComponent implements OnInit { 2 private isbn: string; 3 private title: string; 4 private price: number; ScJraivpat 233
2. ต่อมา ในคลาส BookComponent มฟี งั กช์ นั พิเศษที่ช่อื ว่า constructor() ถกู สง่ั ให้ ทำ�งานโดยอตั โนมตั ิเมื่อมีการเรียกใชง้ านคลาสนี้ ในกรณนี เ้ี ราตอ้ งการน�ำ ขอ้ มลู หนงั สอื ไปแสดงในสว่ นแสดงผล เปน็ ความตอ้ งการขอ้ มลู ทต่ี ้องอยู่ในภาวะแน่นอน แต่ฟังกช์ ัน constructor() ไม่รับรองความแน่นอน จงึ ไมม่ กี ารเขียน สคริปต์ท�ำ งานใดๆ \\src\\app\\components\\book\\book.component.ts 1 constructor() { } 3. ต่อมา ผู้เขียนเลือกใช้ฟังก์ชัน ngOnInit() เป็นฟังก์ชันท่ีถูกสั่งให้ทำ�งานเม่ือคลาส BookComponent อยู่ในภาวะพร้อมใช้งานแล้ว จึงกำ�หนดค่าต่างๆ ให้กับทั้ง 3 คณุ สมบตั ิ กลายเปน็ ขอ้ มูลหนังสือ 1 เล่ม \\src\\app\\components\\book\\book.component.ts 1 ngOnInit() { 2 this.isbn = ‘1111’; 3 this.title = ‘พืน้ ฐานการใชง้ าน C#’; 4 this.price = 399; 5} OTE คำ�ส่ัง this (ท่ีกำ�กับอยู่ด้านหน้าคุณสมบัติท้ัง 3) ให้ใช้หลักที่ว่า คำ�ส่ัง this ทำ�หน้าท่ีแทนคลาส ปัจจุบันท่ีตัวเองอาศัยอยู่ ในกรณีน้ีคำ�ส่ัง this อยู่ภายในคลาส BookComponent จึงหมายถึง ตัวคลาส BookComponent น่ันเอง 4. ท้ายที่สุด ท่ีไฟล์ส่วนแสดงผล book.component.html ให้อ่านค่าจากคุณสมบัติ (หรอื ตวั แปร) ไดจ้ าก isbn, title และ price ตามล�ำ ดบั ก็จะไดข้ อ้ มลู หนังสอื ปรากฏ ในส่วนแสดงผล \\src\\app\\components\\book\\book.component.html 1 <h1>รายการหนงั สือ</h1> 2 <ul> 3 <li><b>รหัส ISBN : </b> {{isbn}}</li> 4 <li><b>ชื่อหนงั สือ : </b> {{title}}</li> 5 <li><b>ราคา : </b> {{price}}</li> 6 </ul> 234
CHAPTER 12 พ้นื ฐานการใชง้ าน Angular วิธีการเก็บโปรเจ็กต์ Angular ท่ีไดม้ าจาก Angular CLI โปรเจก็ ต์ Angular ทไ่ี ด้มาจาก Angular CLI มขี นาดคอ่ นขา้ งใหญม่ าก ถา้ เราพัฒนา หลายโปรเจก็ ตห์ ลายตวั อย่าง ต้องใช้พ้ืนท่ีจดั เก็บพอสมควร แม้วา่ จะบบี อดั เป็นไฟล์ ZIP หรอื RAR แล้วกต็ าม ให้ลองคลิกขวาที่โฟลเดอร์โปรเจ็กต์ เลือกคำ�ส่ัง Properties พบว่า โปรเจ็กต์ usingangular มขี นาดหลักรอ้ ยเม็ก ดังรปู ที่ 12-25 รูปท ี่ 12-25 แสดงขนาดของโปรเจก็ ต์ usingangular จากรูปที่ 12-25 ในขณะที่สร้างโปรเจ็กต์ Angular ด้วย Angular CLI ก็จะมีการ ดาวน์โหลดรายการไฟล์ต่างๆ เก็บไว้ในโฟลเดอร์ node_modules เพื่อให้โปรเจ็กต์ปัจจุบัน พรอ้ มใช้งาน สามารถลบโฟลเดอร์ node_modules และรายการไฟล์ ต่างๆ เหล่าน้ีออกได้เลย และสามารถจัดเก็บในรูปแบบ ZIP หรือ RAR ไดต้ ามปกติ รูปท่ ี 12-26 โปรเจ็กต์ usingangular ทล่ี บโฟลเดอร์ node_modules ออก ในกรณีที่เปิดโปรเจ็กต์ Angular ที่ไม่มีรายการไฟล์ในโฟลเดอร์ node_modules ส่ง ผลให้โปรเจ็กต์ปัจจุบันไม่สามารถรันได้ จึงต้องมีการส่ังให้ดาวน์โหลดรายการไฟล์ต่างๆ มา ใหมอ่ ีกครงั้ ScJraivpat 235
ท่หี น้าตา่ ง TERMINAL ให้พิมพ์ค�ำ สงั่ ตอ่ ไปนี้ แลว้ กดป่มุ Enter เพื่อดาวน์โหลดรายการ ไฟล์ตา่ งๆ ตามท่รี ะบไุ ว้ในไฟล์ package.json ดังรปู ท่ี 12-27 Command Prompt 1 npm install รูปท ่ี 12-27 กรณเี ปดิ โปรเจ็กต์ที่มีรายการไฟลใ์ นโฟลเดอร์ node_modules จากรูปที่ 12-27 เห็นได้ว่ามีการดาวน์โหลดรายการไฟล์ต่างๆ มาเก็บไว้ในโฟลเดอร์ node_modules แล้ว สง่ ผลให้โปรเจก็ ต์ Angular พร้อมใชง้ านตามปกตแิ ลว้ การสรา้ งแบบฟอรม์ และผกู ติดข้อมลู (Form & Data Binding) หน่ึงในหน้าจอพื้นฐานท่ีต้องทำ�ให้เป็น น่ันคือ การสร้างแบบฟอร์ม เช่น แบบฟอร์ม สมัครสมาชิก, แบบฟอร์มซอื้ สนิ คา้ , แบบฟอร์มต้งั กระทู้ เป็นตน้ ความสามารถพิเศษอกี อย่างหนึ่งของแบบฟอรม์ ในโลกของ Angular กค็ ือ เราสามารถ ผูกตดิ แบบฟอร์มเข้ากับข้อมลู ท่มี อี ยู่ได้อกี ดว้ ย ตัวอย่างที่ 12-2 การสร้างแบบฟอร์มและผกู ตดิ ข้อมูล (Form & Data Binding) เป้าหมายของตัวอย่างน้ีก็คือ ต้องการสร้างแบบฟอร์มทำ�หน้าท่ีแสดงข้อมูลหนังสือ 1 เลม่ มีขัน้ ตอนดังน้ี 236
CHAPTER 12 พนื้ ฐานการใชง้ าน Angular 1. การสร้างแบบฟอร์มใน Angular ต้องอ้างอิงโมดูลสำ�หรับสร้างแบบฟอร์มในไฟล์ app.module.ts ก่อนเสมอ ดงั รปู ที่ 12-28 รปู ที่ 12-28 แสดงการอา้ งองิ โมดลู ส�ำ หรบั สรา้ งแบบฟอรม์ 2. ต่อมา ผู้เขียนต้องการสร้างแบบฟอร์มในไฟล์ book.component.html ตาม โครงสรา้ งข้อมูลหนังสือเดิมท่ีมอี ยู่ คือ คุณสมบัติ isbn, title และ price ดงั สครปิ ต์ ตอ่ ไปน้ี ตัวอย่างที่ 12-2 การสรา้ งแบบฟอร์มและผูกตดิ ขอ้ มลู (Form & Data Binding) (\\src\\app\\components\\ book\\book.component.html) 1 <h1>รายการหนงั สอื </h1> 2 <ul> 3 <li><b>รหัส ISBN : </b> {{isbn}}</li> 4 <li><b>ชื่อหนังสอื : </b> {{title}}</li> 5 <li><b>ราคา : </b> {{price}}</li> 6 </ul> 7 8 <h1>แกไ้ ขข้อมูลหนังสือ</h1> 9 <form> 10 <div> 11 <label for=”isbn”><b>รหัส ISBN : </b></label> 12 <input type=”text” [(ngModel)] = “isbn” 13 name = “isbn” placeholder=”รหสั ISBN”> 14 </div> 15 16 <div> 17 <label for=”title”><b>ชือ่ หนงั สือ : </b></label> 18 <input type=”text” [(ngModel)] = “title” ScJraivpat 237
ตัวอย่างที่ 12-2 การสรา้ งแบบฟอร์มและผูกตดิ ขอ้ มลู (Form & Data Binding) (\\src\\app\\components\\ book\\book.component.html) 19 name = “title” placeholder=”ชื่อหนังสือ”> 20 </div> 21 22 <div> 23 <label for=”price”><b>ราคา : </b></label> 24 <input type=”text” [(ngModel)] = “price” 25 name = “price” placeholder=”ราคา”> 26 </div> 27 </form> รปู ที่ 12-29 แสดงสครปิ ตใ์ นไฟล์ book.component.html 3. ท้ายทสี่ ุด ให้รนั โปรเจก็ ตด์ ้วยค�ำ ส่ัง ng serve กจ็ ะพบกับ แบบฟอร์มและแสดงขอ้ มูลหนงั สืออยู่ด้วย ดงั รูปที่ 12-30 รปู ท ่ี 12-30 ผลการรนั ตวั อยา่ งท่ี 12-2 4. ตอ่ มา ใหท้ ดสอบแก้ไขข้อมลู หนังสอื ทป่ี รากฎขึ้นมา พบว่าข้อมลู หนงั สือทแ่ี สดงอยู่ ด้านบนเกิดการเปล่ียนแปลงด้วยเช่นกัน เกิดมาจากการผูกติดข้อมูลเข้ากับแบบ ฟอร์มทส่ี ร้างขึน้ มานั่นเอง ดังรูปที่ 12-31 238
CHAPTER 12 พน้ื ฐานการใชง้ าน Angular รูปที ่ 12-31 กรณขี อ้ มลู ในฟอรม์ เกดิ การเปลย่ี นแปลง อธบิ ายการท�ำ งานของสครปิ ต์ 1. การสร้างแบบฟอรม์ ให้ใช้อลิ เี มนต์ <form>…</form> ของภาษา HTML จากนน้ั ใช้ อลิ ีเมนต์ 2 ตัว ทำ�หนา้ ท่รี ว่ มกนั กล่าวคอื hh อิลีเมนต์ <label>…</label> ทำ�หน้าที่สร้างข้อความก�ำ กบั ช่องรับขอ้ มูล hh อิลีเมนต์ <input type=”text”>….</input> ทำ�หน้าท่ีสร้างช่องรับข้อมูล ที่ สำ�คัญคือ แอ็ตทริบิวต์ [(ngModel)] = “isbn” ทำ�หน้าที่ผูกติดช่องรับข้อมูล เข้ากบั คุณสมบตั ิ isbn \\src\\app\\components\\book\\book.component.html 1 <form> 2 <div> 3 <label for=”isbn”><b>รหสั ISBN : </b></label> 4 <input type=”text” [(ngModel)] = “isbn” 5 name = “isbn” placeholder=”รหสั ISBN”> 6 </div> 2. ตอ่ มา สว่ นช่องรบั ขอ้ มูลอีก 2 ชอ่ งที่เหลือ ก็จะผกู ติดเขา้ กบั คุณสมบตั ิ title และ price ตามลำ�ดับ \\src\\app\\components\\book\\book.component.html 1 <div> 2 <label for=”title”><b>ชือ่ หนงั สือ : </b></label> 3 <input type=”text” [(ngModel)] = “title” 4 name = “title” placeholder=”ชือ่ หนงั สือ”> 5 </div> 6 ScJraivpat 239
\\src\\app\\components\\book\\book.component.html 7 <div> 8 <label for=”price”><b>ราคา : </b></label> 9 <input type=”text” [(ngModel)] = “price” 10 name = “price” placeholder=”ราคา”> 11 </div> 12 </form> สรุปทา้ ยบท การใชง้ าน Angular ที่น�ำ เสนอในบทน้ี เปน็ เพียงหลกั การท�ำ งานขนั้ ตน้ เพอ่ื ให้เห็นภาพกว้างๆ เท่านั้น อาจจะไม่ได้ลงรายละเอียดมากเท่าใดนัก แต่ก็พอเป็น พ้ืนฐานสำ�หรบั ใช้งานในล�ำ ดับต่อไป 240
Java script 13CHAPTER การพฒั นา Web Apps แบบ MEAN Stack ขนั้ ตน้ เนอื้ หาตง้ั แตบ่ ทท่ี 2 ถงึ บทที่ 10 เปน็ การพฒั นา Web Apps โดยใชง้ าน 3 สว่ น คอื Mongo (M), Express (E) และ Node (N) ทำ�งานร่วมกนั ส่วนเนอื้ หาบทท่ี 11 ถึงบทที่ 12 เป็นการสรา้ งสว่ น แสดงผลโดยอาศัย Angular (A) แยกต่างหาก ไม่มคี วามเก่ยี วขอ้ งใดๆ กับบทที่ 2 ถงึ บทที่ 10 เป้าหมายสุดท้ายของเน้ือหาในหนังสือเลม่ น้กี ค็ ือ การพฒั นา Web App โดยใช้งานทง้ั 4 ส่วนเขา้ ด้วยกัน เรยี กวา่ MEAN Stack นั่นเอง จากท่ีผู้เขียนได้กล่าวไว้ในตอนต้นบทที่ 11 ว่า Angular มีโลกเป็นของตัวเอง และมี ขนาดใหญ่มาก ดังน้ัน ขอบเขตเน้ือหาในบทน้ีจึงเป็นการนำ� Angular เข้าไปใช้งานร่วมกับ Mongo (M), Express (E) และ Node (N) ในขน้ั ตน้ เทา่ น้นั เรมิ่ ตน้ Setup โปรเจก็ ต์ MEAN Stack หลกั การท�ำ งานข้ันตน้ ของ MEAN Stack สามารถแบ่งแยกหน้าที่ ดงั ต่อไปนี้ ÂÂ Express (Node) เหลือหน้าท่ีเพียงอย่างเดียวน่ันคือ ติดต่อกับฐานข้อมูล Mongo เพอื่ เปดิ ชอ่ งทางใหส้ ามารถท�ำ งานกบั ขอ้ มลู ทไ่ี ดม้ าจากฐานขอ้ มลู เราเรยี กชอ่ งทาง นวี้ า่ Web API ไม่ต้องมายงุ่ เกย่ี วกบั การจัดการส่วนแสดงผลดว้ ยชนิ้ สว่ น Pug (หรือ ชนิ้ ส่วนอื่นๆ) อกี ต่อไปแล้ว ÂÂ Angular ทำ�หน้าท่ีรับผดิ ชอบสว่ นแสดงผลทงั้ หมด และเรียกดขู ้อมูลจากฐานข้อมูล Mongo ผ่านทางช่องทาง Web API ทเ่ี ราก�ำ หนดไว้ HTML .Net HTML
ตวั อย่างที่ 13-1 การพฒั นา Web Apps แบบ MEAN Stack ขั้นต้น เป้าหมายของตัวอย่างน้ีก็คือ แสดงรายช่ือหนังสือท่ีอยู่ในคอลเล็กชัน books ผ่านทาง สว่ นแสดงผลที่เกดิ จาก Angular น�ำ เสนอสคริปต์เท่าท่ีเกย่ี วขอ้ ง เพือ่ ให้ได้สคริปตส์ ะอาดที่สุด ง่ายต่อการศกึ ษา มขี น้ั ตอนดงั นี้ รูปท่ ี 13-1 แสดงรายการหนงั สอื ท่ี เกบ็ อยใู่ นคอลเลก็ ชนั books 1. ผู้เขียนนำ�โปรเจ็กต์ Angular ของตัวอย่างที่แล้วมาทำ�ต่อ ต้องมีการเพ่ิมโฟลเดอร์ และไฟลเ์ ขา้ มาใหม่ และตอ้ งการจดั ระเบยี บโครงสรา้ งโปรเจก็ ตใ์ นคราวเดยี วกนั ดว้ ย ดังต่อไปน้ี hh ไฟล์ server.js ท�ำ หนา้ ท่ีรัน Express ท่เี ราคนุ้ เคยกันเป็นอยา่ งดี hh โฟลเดอร์ server ภายในมีไฟล์ท่ีช่ือว่า api.js ทำ�หน้าท่ีติดต่อกับหลังบ้าน นน่ั คอื Express + ฐานขอ้ มลู Mongo hh โฟลเดอร์ models ภายในมีไฟล์ที่ช่ือว่า book.js ทำ�หน้าท่ีกำ�หนดโครงสร้าง ขอ้ มูลหนังสอื ทเี่ ราก�ำ ลังสนใจอยู่ รปู ที ่ 13-2 แสดงการสรา้ งโฟลเดอรแ์ ละไฟลเ์ พม่ิ เตมิ 242
CHAPTER 13 การพัฒนา Web Apps แบบ MEAN Stack ขน้ั ต้น 2. ต่อมา ให้พิมพ์คำ�ส่ังต่อไปน้ี ดาวน์โหลดชิ้นส่วน express, body-parser และ mongoose เพ่ือให้โปรเจ็กต์ปัจจบุ ันสามารถส่ังใหฝ้ ่งั Server ทำ�งานได้ Command Prompt 1 npm install express - -save 2 npm install body-parser - - save 3 npm install mongoose - - save รูปท ่ี 13-3 แสดงการเพิ่มช้ินสว่ น Express, body-parser และ mongoose การกำ�หนดพารามิเตอร์ - -save ส่งผลไฟล์ package.json ของโปรเจ็กต์ Angular มีรายการช้นิ สว่ น express, body-parser และ mongoose เพ่ิมเข้ามาด้วย ScJraivpat 243
รูปท่ี 13-4 แสดงรายการ dependencies ในไฟล์ package. json 3. ตอ่ มา เราจะเรม่ิ ทำ�ส่วนของ express (ฝ่งั Server) กอ่ น ทีไ่ ฟล์ server.js ใหเ้ ขียน สครปิ ต์ต่อไปน้เี พ่อื ทดสอบโปรเจ็กต์ในข้ันตน้ กอ่ นวา่ express สามารถท�ำ งานร่วม กับ Angular ไดห้ รอื ไม่ server.js 1 var express = require(‘express’); 2 var path = require(‘path’); 3 var bodyParser = require(‘body-parser’); 4 5 var app = express(); 6 app.use(express.static(path.join(__dirname, ‘dist’))); 7 8 app.use(‘*’, function(req, res){ 9 res.sendFile(path.join(__dirname, ‘index.html’)); 10 }) 11 12 var server = app.listen(3000, function() { 13 var port = server.address().port; 14 console.log(‘Server is running... %s’, port); 15 }) จากสคริปต์ข้างตน้ ส่วนทแ่ี ตกต่างไปจากเดมิ คือ ÂÂ สงั่ ใหใ้ ช้ไฟลส์ ่วนแสดงผลทอี่ ยู่ในโฟลเดอร์ dist server.js 1 app.use(express.static(path.join(__dirname, ‘dist’))); 244
Search
Read the Text Version
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296