iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 27
0
Modern Web

「VR 」前端後端交響曲 - 30天開發 Vue.js feat. Ruby on Rails即時互動網站系列 第 27

[VR 前後端交響曲Day27] Rails專案開發 - 編輯ticket (使用vuex狀態管理)

前情提要:
前天我們完成了新增ticket昨天也順便介紹了v-if語法;
今天就延續著前兩天的tempo~~,介紹以Vue.js實作CRUD裡的編輯功能!

Step 1. UI: 設計編輯區塊

首先設計按下編輯那枝筆的icon,會出現更新的小區塊,如下圖所示:

我們先用昨天的v-if語法來現學現賣,
編輯icon會綁一個v-on語法,設計按下後出現的toggle開關editTickettrue
如果是true的話,再讓v-if="editTicket"的編輯區塊全部秀出來:

<template>
  <div class="ticket">
    {{ ticket.name }}
    <div>
      <button class="edit-btn" @click="editTicket=true"><i class="fas fa-edit text-gray-400"></i></button>

      <div v-if="editTicket" class="edit-area">
        <i class="far fa-window-close edit-cancel" @click="cancelUpdate"></i> 
        <textarea type="text" class="edit-input" v-model="ticket.name"></textarea>
        <button class="update-ticket-btn" @click="updateTicket">更新</button>
      </div>

    </div>
  </div>
</template>

editTickettrue時,edit-area有兩個部分的按鈕也需要設計:

  • 一個是關閉視窗 far fa-window-close的按鈕,按下時綁定cancelUpdate method,
  • 另一個是更新按鈕時,綁定updateTicket method;

兩者都會觸發editTicket = false,也就是回到原來沒有編輯輸入框的畫面;

<script>
  import Rails from '@rails/ujs';
  export default {              
    name: 'Ticket',
    props: ["ticket"],
    data: function () {
      return {
        column: this.ticket.column,
        editTicket: false
      }
    },    
    methods: {
      cancelUpdate(evt){
        evt.preventDefault();
        this.editTicket = false;
      },
      updateTicket(evt){
        evt.preventDefault();
        this.editTicket = false;
      },
      deleteTicket(evt){
        //略
      }
    }  
</script>

綁上v-model後,只要我們一在輸入欄位更新資料,畫面上就會跟著連動~太神奇了傑克

Step2. Vue觸發Vuex this.$store.dispatch

還記得Vuex的這張流程圖嗎?今天我們要實作的方式是怎麼由component觸發Vuex:

在這裡我們為了要把ticket component裡面的ticket idticket name送到Vuex的同名action裡運用,
使用了this.$store.dispatch()的方式。

dispatch這個英文字的中譯有調度分發的意思,它實際上是一個觸發的方法。
this.$store.dispatch(actionType, payload)會傳兩個參數,一個是要觸發Vuex的action的類型,另一個是攜帶的資料(payload),

所以我們在Vue method可以這樣寫:

updateTicket(evt){
  evt.preventDefault();
  this.$store.dispatch("updateTicket", {id: this.ticket.id, name: this.ticket.name})
  this.editTicket = false;
},

Step3. Vuex actions 把資料往後端送

首先確定更新ticket的路徑及動詞,再請Rails打ajax到後端。

Helper HTTP Verb Path Controller#Action
kanban_ticket_path PUT /kanbans/:kanban_id/tickets/:id(.:format) tickets#update

剛剛從Component接來的ticket idticket name在這裡就可以派上用場了:

  actions: {
    updateTicket({ commit }, {id, name}){
      let data = new FormData();
      let el = document.querySelector("#column");        
      data.append("ticket[name]", name);
      Rails.ajax({
        url: `/kanbans/${el.dataset.kanbanid}/tickets/${id}`,
        type: 'PUT',
        data,
        dataType: 'json',
        success: result => {
          // Step 5.會提到!
          commit("UPDATE_TICKET", result);
          console.log(result);
        },
        error: error => {
          console.log(error);            
        }
      });      
    },

    dragColumn({ commit, state }, evt) {
      //略
    },
    fetchColumn({ commit }, kanbanid){
      //略
    }
  }

Step 4. Rails MVC: controller 更新資料庫

因為ticket的內容已經更新,我們透過rails controller render新的show.json

tickets_controller.rb

def update
  respond_to do |format|
    if @ticket.update(ticket_params)
      format.json { render :show, status: :ok}
    else
      format.json { render json: @ticket.errors, status: :unprocessable_entity }
    end
  end
end

Step 5. Vuex: 送出commit請Mutation更新state

ajax回傳結果為成功(也就是資料庫更新成功)之後,畫面上也要請mutations進行變更。
所以我們在Vuex的store裡 commit("UPDATE_TICKET", result);,會觸發UPDATE_TICKET變更state。

更新ticket的方式,是透過state.columns的findIndex,比對傳進來的ticket的idcolumn_id,找到這張ticket在哪一欄位、哪一個序號,並且透過splice把ticket更新過後的name換上去。

  mutations: {
    UPDATE_COLUMNS(state, columns){
      state.columns = columns;
    },

    UPDATE_TICKET(state, ticket){
      let column_index = state.columns.findIndex(col => col.id == ticket.column_id)
      let ticket_index = state.columns[column_index].tickets.findIndex(tkt => tkt.id == ticket.id)

      state.columns[column_index].tickets.splice(ticket_index, 1, ticket)
    }
  },

編輯ticket,完成!而且重新refresh仍然是更新後的ticket

小感言:
Rails的CRUD果然是強項呀!相比之下Rails可以20分鐘搞定;
前端+Vue.js新手,我用js刻功能的話連簡單的CRUD都要做好幾天...

再三天就鐵人賽結尾了,不屈不撓堅持到底!


上一篇
[VR 前後端交響曲Day26] Rails專案開發 - 新增ticket(v-if語法介紹)
下一篇
[VR 前後端交響曲Day28] Rails專案開發 - 刪除ticket (使用vuex狀態管理)
系列文
「VR 」前端後端交響曲 - 30天開發 Vue.js feat. Ruby on Rails即時互動網站30

尚未有邦友留言

立即登入留言