Vue.js中的模型和计算属性交互

时间:2017-08-09 09:13:05

标签: javascript vue.js

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

当用户点击"完成"复选框我想要发生两件事:

  1. 如果"显示所有任务"未经检查,隐藏任务。
  2. 向服务器发送ajax请求,将任务标记为完成/打开。
  3. 无效部分如下所示:

    <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)
          }
        }
    
      }
    
    })
    

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

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

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

3 个答案:

答案 0 :(得分: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)

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

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

答案 2 :(得分: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完成时才更新它。

  3. &#13;
    &#13;
    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)
          }
          */
        }
    
      }
    
    })
    &#13;
    <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>
    &#13;
    &#13;
    &#13;