提醒:由於看到這系列鐵人訂閱人數漸漸變多,標記一下這些內容是在「非常萌新時期」所寫,更多技術內容請參考我的 Github,歡迎跟我一起討論 ^ ^
今天藉由昨天學習的方法,建立各種 form,用以更新 database,達到可以更改網站的呈現內容。(此範例將完成三個功能:新增、刪除、更新)
以新增Genre的頁面為例
POST
提交 form。placeholder
:可在輸入框顯示你想提示的文字。value
,讓第一次傳送 空白form,而當被 validator 擋住時,回傳的頁面能保留已輸入的內容。extends layout
block content
h1 #{title}
form(method='POST' action='')
div.form-group
label(for='name') Genre:
input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name))
button.btn.btn-primary(type='submit') Submit
if errors
ul
for error in errors
li!= error.msg
exports.genre_create_get = function (req, res, next) {
res.render('genre_form', { title: 'Create Genre' })
}
const validator = require('express-validator')
validator.body('name', 'Genre name required').isLength({ min: 1 }).trim(),
validator.sanitizeBody('name').escape(),
(req, res, next) => {
const errors = validator.validationResult(req)
const genre = new Genre({ name: req.body.name })
if (!errors.isEmpty()) {
res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()})
return
} else {... <save the result/> ...}}
Genre.findOne({ 'name': req.body.name })
.exec( function(err, foundGenre) {
if (err) { return next(err) }
if (foundGenre) {
res.redirect(foundGenre.url)
}
else {
genre.save(function (err) {
if (err) { return next(err) }
res.redirect(genre.url)
})}})
exports.genre_create_post = [
validator.body( ... ),
validator.sanitizeBody( ... ),
(req, res, next) => { ... }
]
const { body,validationResult } = require('express-validator/check')
const { sanitizeBody } = require('express-validator/filter')
(...)
body('name', 'Genre name required').isLength({ min: 1 }).trim(),
sanitizeBody('name').escape(),
sanitizeBody('*').escape()
:也可使用*
代替所有資料,一次清理。genre.*
來清理所有 genre array 裡面的資料。(例如只選擇 0 或 1 個 genre 時,就不會是 array)(req, res, next) => {
if (!(req.body.genre instanceof Array)) {
if (typeof req.body.genre === 'undefined') { req.body.genre = [] } else { req.body.genre = new Array(req.body.genre) }
}
next()
},
( ... )
sanitizeBody('genre.*').escape(),
select
替代,並將 type 設定為 select
selected
:回傳錯誤時,可以將已選擇選項保留。author._id
不是 string,所以要先轉換過去) for author in authors
if book
option(value=author._id selected=(author._id.toString()===book.author ? 'selected' : false) ) #{author.name}
else
option(value=author._id) #{author.name}
checkbox
div
for genre in genres
div(style='display: inline;')
input(type='checkbox', name='genre', id=genre._id, value=genre._id, checked=genre.checked )
label(for=genre._id) #{genre.name}
sanitizeBody('*').escape()
,將會把 array 清到只剩一個項目,因此我改成一個一個分別 sanitizeBody。for (let i = 0; i < results.genres.length; i++) {
if (book.genre.indexOf(results.genres[i]._id) > -1) {
results.genres[i].checked = 'true'
}
}