2017-08-09 73 views
0

使用vue.js我想建立一个简单的任务管理器。模型和计算属性相互作用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函数。

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

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

回答

1

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

  1. 遍历每个任务(完成与否)显示它们(不考虑show_all
  2. v-on:click="updateStatus(row)"
  3. 更新任务
  4. 对每个tr,添加v-show="show_all || !row.status.complete"
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) 
    } 
1

我已经重构你的代码了一下,似乎很好地工作:

  1. 你不应该使用v-on:change,而是使用<input type="checkbox" v-on:click="updateStatus(row)" v-bind:checked="row.daily_task.complete">

  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>