[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都要做好几天...

再三天就铁人赛结尾了,不屈不挠坚持到底!


<<:  (29) 试着学 Hexo - 奇淫技巧 - 快速上传你的图片到 imgur

>>:  谁温暖了资安部-26(资安事件与Log)

Day2 Develop Environment For Go

Preface 笔者将介绍自己所熟悉的Go开发环境如何设定,也就是MacOS(OS) + Golan...

Day01 - 【入门篇】Quick Start(1)

本系列文之後也会置於个人网站 开始之前~2?。开完笑的~ 但是想了许久,总觉的就这麽直接开始解释各...

初学者跪着学JavaScript Day20 : 原型毕露(中)

一日客语:中文:青色 客语:抢厶ㄟ ˋ 继续学习原型吧~ 学习内容: 1.Object.getPro...

[Day:30] 钥匙好多不知道选哪把(IOS凭证该如何管理?)

当年不懂事,看网路的教学就乱作一通,看看这可怕的凭证数量 以下解释关键的凭证申请与用途 01 登入 ...

Day 21: 人工智慧在音乐领域的应用 (AI作曲-基因演算法四 掌握生杀大权-Interactive Fitness Function)

昨天我们聊完了子代出生後所要面临的第一个挑战 - 突变。 我们接着来聊聊整个基因演算法里面最重要的一...