iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 21
0
自我挑戰組

轉職道上的萌芽人生 − 自學程式開發ing系列 第 21

Day 21- 191007學習筆記 Express - 建立 Form - 更新、刪除

昨天完成了 新增 這個部分,今天繼續把 更新刪除 完成。


刪除

  • 如同前天文章所提,在此範例中,設計為:只能刪除未被其他 object 引用的 object
    (例如 想要刪除作者的資料,必須先確認沒有他的任何書籍資料存在)
  • 以刪除作者資料為例,首先我們希望在該作者頁面,設計一個刪除按鈕:
    • author_detail.pug 中加入:
      a(href=author.url+'/delete') Delete author
    • GET:點擊按鈕後的動作
      • 大致上與前面學過的很像,先抓出要的資料後帶入 templete 呈現頁面。
      • 這裡有一個情境是:當該作者已不存在,則直接導向作者列表。
        (可能你在刪除時,同時其他人先一步刪除了)
     (err, results) => {
        if (err) { return next(err) }
        if (results.author === null) { 
          res.redirect('/catalog/authors')
        }
    
  • 接著點擊刪除鍵後會導入一個刪除資訊頁面:
    /views/author_delete.pug
    • 頁面設計:
      • 這裡會列出一些作者資訊。
      • 若還有該作者的書在案,則會列出來告知。
      • 最後一個確認刪除作者的按鈕。
    • 要注意的是,這裡的刪除按鈕依然必須為一個 form,藉由 POST 傳送。
    • 另外,教材中 author.js 建立的 lifespan 屬性,為壽命,但他這邊想呈現的是 生卒年,因此需要更改一下,另外壽命也有一些 bug,需要稍微調整一下。
      • 首先生卒年就直接用前面建立過的屬性:
        p #{author.birthDay} - #{author.deathDay}
      • 壽命 則需要做調整:(因為有些作者沒有生卒年資訊,則會出錯)
    if author.date_of_birth && author.date_of_death
        p= `享年: ${author.lifespan}`
    
  • POST:接著點擊確認刪除按鈕後,會發出一個 POST。
    author_delete_post 為例:
    • 需要抓該 author & 他的 book 的資料,來做判斷是否可以刪除。
    • 若還有書籍,則把資料帶入 author_delete.pug 導向告知頁面。
    • 最後都確認沒問題,即可將此作者資料刪除(這裡作者的資訊是從 request 取得。而不是在為了判斷時,從 database 抓出來的。),並導向作者列表。
      • findByIdAndRemove:以參數1的ID搜尋並刪除該資料,並完成參數2 的 callback(這邊導回作者列表)。
      • req.body: 用以抓取 request 的提供的資訊。
    Author.findByIdAndRemove(req.body.authorid, (err) => {
      if (err) { return next(err) }
      res.redirect('/catalog/authors')
    })
    

更新

  • 以更新書本資料為例,與上面刪除相同,在該書本頁面,設計一個更新按鈕。
    • book_detail.pug 中加入:
      a(href=book.url+'/update') Update Book
    • GET:點擊按鈕後的動作
      • 更新要導向的 form 跟新增時一樣,但它需要預先填好已有資訊。
      • 一樣先抓出要的資料(這裡除了需要 form 的架構所需資料外,還需要該書本已有的資料)帶入 templete 呈現頁面。
      • 若該書本已不存在,則導向報錯頁面 404。
      • 此處一樣需將已選擇的 genre 設定為 checked,已將已有資訊附上。
    for (let i = 0; i < results.genres.length; i++) {
      for (let j = 0; j < results.book.genre.length; j++) {
        if (results.genres[i]._id.toString() === results.book.genre[j]._id.toString()) {
          results.genres[i].checked = 'true' } } }
    
  • 接著需更新 /views/book_form.pug,以讓 更新新增 可以使用同一個 form。
    (因為 book_update_get 中的 book.author 有些許差異。其回傳一個 object)
    for author in authors
      if book
        option(
          value=author._id
          selected=(
            author._id.toString()===book.author._id
            || author._id.toString()===book.author
          ) ? 'selected' : false
        ) #{author.name}
    
  • POST:更新新增 大致上的動作是相同的,主要的差別是:
    • 在創建 Instances 時,須多做一個動作:設定 ID
      (因為若沒有自己設定ID,創建時都會自動賦予一個ID,如此一來就跟原資料不同了,而是新增另一筆資料)
    const book = new Book({
     ( ... )
      _id: req.params.id 
    })
    
    • 最後將原本的 save() 改成 findByIdAndUpdate() 以更新特定 ID 的資料,就大功告成啦:
    Book.findByIdAndUpdate(req.params.id, book, {}, (err, thebook) => {
      if (err) { return next(err) }
      res.redirect(thebook.url)
    })
    
  • 另外當需要填入日期時,因為他填入的格式為'YYYY-MM-DD',因此需帶入該格式的日期給 templete,才不會錯誤。(可直接在 model 建一個 virtual 來達成)

上一篇
Day 20- 191006學習筆記 Express - 建立 Form - 新增
下一篇
Day 22- 191008學習筆記 Express - Deploying to production(上)
系列文
轉職道上的萌芽人生 − 自學程式開發ing30

尚未有邦友留言

立即登入留言