【问题标题】:Model and Computed Property interaction in Vue.jsVue.js 中的模型和计算属性交互
【发布时间】:2018-01-17 02:07:24
【问题描述】:

使用 vue.js 我正在尝试构建一个简单的任务管理器。

当用户点击“完成”复选框时,我希望发生两件事:

  1. 如果未选中“显示所有任务”,则隐藏该任务。
  2. 向服务器发送 ajax 请求以将任务标记为完成/打开。

阳痿部分如下图:

<div id="tasks-app">
<input type="checkbox" id="checkbox" v-model="show_all">
<label for="checkbox">Show all tasks</label><br>

<table class="table">
  <tr><th v-for="column in table_columns" v-text="column"></th><tr>
  <tr v-for="row in visibleTasks" :class="{danger: !row.daily_task.complete && row.daily_task.delayed, success: row.daily_task.complete}">
    <td v-text="row.task.name"></td>
    <td v-text="row.task.deadline"></td>
    <td v-text="row.daily_task.status"></td>
    <td v-text="row.daily_task.task_user"></td>
    <td>
      <input type="checkbox" v-on:change="updateStatus(row)" v-model="row.daily_task.complete" >Complete</input>
    </td>
    <td><input v-model="row.daily_task.delay_reason"></input></td>
</table>
</div>

还有 VUE.js 代码:

app = new Vue({
  el: '#tasks-app',

  data: {
    table_columns: ['Task','Deadline','Status','User','Actions','Reason'],
    tasks: [],
    filter_string: '',
    show_all: false
  },

  computed: {
    visibleTasks() {

      show_all = this.show_all

      if(show_all){
         search_filter = this.tasks         
      }else{
         search_filter = _.filter(this.tasks,function(task){
            return !task.daily_task.complete;
         })
      }
      return search_filter
    }
  },

  methods: {
    updateStatus(row){
      var id = row.daily_task.id
      var complete = row.daily_task.complete
      if(complete){
        axios.get('set_task_complete/' + id)
      }else{
        axios.get('set_task_open/' + id)
      }
    }

  }

})

如果选中显示全部复选框,则按预期工作。数据发生变化,然后调用updateStatus函数。

如果未选中显示全部复选框,则可见任务将触发并且updateStatus 的逻辑将失败,因为该行将被隐藏并且发送到服务器的 ID 将被关闭。如果在调用updateStatus 之前隐藏了行,则将错误的行传递给updateStatus 函数。

我可以通过在updateStatus 函数的末尾添加过滤器更新来解决这个问题,但这似乎没有利用 Vue.js 库。有人可以帮我解决这个问题的 Vue 组件吗?

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    您的问题是同时使用更改事件句柄和模型。实际上,两者都是在您单击复选框时同时触发的。

    <input type="checkbox" v-on:change="updateStatus(row)" v-model="row.daily_task.complete" >Complete</input>
    

    您应该只使用v-on:change="updateStatus(row)" 编辑您的代码。在 updateStatus 完成 ajax 调用后切换 row.daily_task.complete 以触发 visibleTasks 更新您的视图。

    updateStatus(row){
          var id = row.daily_task.id
          var complete = !row.daily_task.complete
          var p;
          if(complete){
            p = axios.get('set_task_complete/' + id)
          }else{
            p = axios.get('set_task_open/' + id)
          }
          p.then(() => row.daily_task.complete = complete)
        }
    

    【讨论】:

      【解决方案2】:

      如果你把逻辑分开,你可以简化很多:

      1. 遍历每个任务(已完成或未完成)以显示它们(不考虑 show_all
      2. 使用v-on:click="updateStatus(row)" 更新任务
      3. 在每个tr 上,添加v-show="show_all || !row.status.complete"

      【讨论】:

        【解决方案3】:

        我已经对您的代码进行了一些重构,它似乎可以正常工作:

        1. 您不应使用v-on:change,而应使用&lt;input type="checkbox" v-on:click="updateStatus(row)" v-bind:checked="row.daily_task.complete"&gt;

        2. 不要马上更新row.daily_task.complete,等异步axios完成后再更新。

        const fakeUpdateComplete = (id) => {
          return new Promise((resolve, reject) => { resolve(true); });
        };
        
        const fakeUpdateIncomplete = (id) => {
          return new Promise((resolve, reject) => { resolve(true); });
        };
        
        const app = new Vue({
          el: '#tasks-app',
        
          data: {
            history: [],
            table_columns: ['Task','Deadline','Status','User','Actions','Reason'],
            tasks: [
              {
                task: {
                  name: 'A',
                  deadline: '2017-01-01',
                },
                daily_task: {
                  id: 1,
                  status: '',
                  task_user: '',
                  complete: true,
                  delayed: false,
                  delay_reason: ''
                }
              },
              {
                task: {
                  name: 'B',
                  deadline: '2017-01-02',
                },
                daily_task: {
                  id: 2,
                  status: '',
                  task_user: '',
                  complete: false,
                  delayed: false,
                  delay_reason: ''
                }
              },
              {
                task: {
                  name: 'C',
                  deadline: '2017-01-03',
                },
                daily_task: {
                  id: 3,
                  status: '',
                  task_user: '',
                  complete: false,
                  delayed: false,
                  delay_reason: ''
                }
              },
              {
                task: {
                  name: 'D',
                  deadline: '2017-01-03',
                },
                daily_task: {
                  id: 4,
                  status: '',
                  task_user: '',
                  complete: true,
                  delayed: false,
                  delay_reason: ''
                }
              },
              {
                task: {
                  name: 'E',
                  deadline: '2017-01-03',
                },
                daily_task: {
                  id: 5,
                  status: '',
                  task_user: '',
                  complete: false,
                  delayed: false,
                  delay_reason: ''
                }
              }
            ],
            filter_string: '',
            show_all: true
          },
        
          computed: {
            visibleTasks() {
              const show_all = this.show_all
              let search_filter;
              if(show_all){
                 search_filter = this.tasks         
              }else{
                console.log(this.tasks);
                search_filter = this.tasks.filter(task => {
                  return !task.daily_task.complete
                });
              }
              return search_filter
            }
          },
        
          methods: {
            updateStatus(row){
              const id = row.daily_task.id;
              const complete = !row.daily_task.complete;
               
              if (complete) {
                
                fakeUpdateComplete(id).then(() => {
                   this.history.push(`Task ${row.task.name} with id ${row.daily_task.id} is marked as complete`);
                   row.daily_task.complete = !row.daily_task.complete;
                });
              } else {
                fakeUpdateIncomplete(id).then(() => {
                   this.history.push(`Task ${row.task.name} with id ${row.daily_task.id} is marked as incomplete`);
                   row.daily_task.complete = !row.daily_task.complete;
                });
              }
              /*
              if(complete){
                axios.get('set_task_complete/' + id)
              }else{
                axios.get('set_task_open/' + id)
              }
              */
            }
        
          }
        
        })
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
        <div id="tasks-app">
        <input type="checkbox" id="checkbox" v-model="show_all">
        <label for="checkbox">Show all tasks</label><br>
        
        <table class="table">
          <tr><th v-for="column in table_columns" v-text="column"></th><tr>
          <tr 
            v-for="row in visibleTasks" 
            :class="{danger: !row.daily_task.complete && row.daily_task.delayed, success: row.daily_task.complete}"
          >
            <td>{{row.task.name}}</td>
            <td>{{row.task.deadline}}</td>
            <td>{{row.daily_task.status}}</td>
            <td>{{row.daily_task.task_user}}</td>
            <td>
              <input type="checkbox" v-on:click="updateStatus(row)" v-bind:checked="row.daily_task.complete">
              <label for="complete">Complete</label>
            </td>
            <td><input v-model="row.daily_task.delay_reason" /></td>
          </tr>
        </table>
          <div>
            <div><b>Data:</b></div>
            <div>{{this.tasks}}</div>
          </div>
           <div>
            <div><b>History:</b></div>
            <div v-for="item in history">
              {{item}}
            </div>
          </div>
        </div>

        【讨论】:

          猜你喜欢
          • 2017-08-26
          • 2017-12-22
          • 2017-08-31
          • 1970-01-01
          • 2019-08-08
          • 2017-10-06
          • 2017-10-07
          • 2016-09-17
          • 2018-01-09
          相关资源
          最近更新 更多