只有当人改变输入时才调用方法 - 而不是当方法改变Vue.js中的输入时

时间:2017-12-11 10:40:09

标签: javascript websocket vue.js vuejs2

我是Vue的新手并尝试构建一个在输入更改为动态构建和设置其他输入时调用API的表单。它的目的是选择一辆车。

当您选择make时,它会通过WebSocket从API填充带有适当值的模型和年份选择字段。这些字段可以从VIN(车辆识别号)自动填充,并且过程中的任何字段都可以更改其他字段。

这导致一个反馈循环,其中输入被另一个输入改变,而另一个输入又调用API,该API发回另一组数据并改变其他数据。

如何确保人类更改字段后仅设置一次数据?

我的车辆选择代码:

<template>
  <div id="vehicleSelection">
    <h1 class="title">{{ title }}</h1>
    <b-field label="Make">
      <b-select placeholder="Select a make" v-model="make" @input="setMake(make)" id="makeSelect">
        <option
                v-for="make in make_list"
                :value="make"
                :key="make">
          {{ make }}
        </option>
      </b-select>
    </b-field>
    <b-field label="Model">
      <b-select placeholder="Select a model" v-model="model" @input="setModel(model)" id="modelSelect">
        <option
                v-for="model in model_list"
                :value="model"
                :key="model">
          {{ model }}
        </option>
      </b-select>
    </b-field>
    <b-field label="Year">
      <b-select placeholder="Select a model year" v-model="year" @input="setYear(year)" id="yearSelect">
        <option
                v-for="year in year_list"
                :value="year"
                :key="year">
          {{ year }}
        </option>
      </b-select>
    </b-field>
  </div>
</template>

<script>
  import CommandClient from '../communication/command/CommandClient';
  import MessageHandler from '../communication/handler/MessageHandler';

  export default {
    name: 'VehicleSelection',
    methods: {
      setMake(make) {
        CommandClient.send(this.$socket, CommandClient.prepare('set_vehicle_make', ['make', make]));
      },
      setModel(model) {
        CommandClient.send(this.$socket, CommandClient.prepare('set_vehicle_model', ['model', model]));
      },
      setYear(year) {
        CommandClient.send(this.$socket, CommandClient.prepare('set_vehicle_year', ['year', year]));
      },
    },
    created() {
      this.$options.sockets.onmessage = (message) => {
        MessageHandler.handle(this, message);
      };
    },
    data() {
      return {
        title: 'Vehicle Selection',
        make_list: [],
        make: null,
        model_list: [],
        model: null,
        year_list: [],
        year: null,
      };
    },
  };
</script>

这里有一些重复,可能会被重构,但我想让它先工作。

对于上下文,如果API响应中存在密钥,则MessageHandler在此处获取Vue组件并为其设置数据:

const _ = require('lodash');

export default {
  /**
   * @param {Object} context
   * @param {MessageEvent} message
   * @return {void}
   */
  handle(context, message) {
    const messagePayload = JSON.parse(message.data);
    Object.entries(messagePayload).forEach((data) => {
      if (_.has(context.$data, data[0])) {
        context.$set(context, data[0], data[1]);
      }
    });
  },
};

1 个答案:

答案 0 :(得分:0)

我对你的代码做了一些假设,因为我不知道它的具体细节......

如果您正在调用API以响应通过watch对特定数据属性进行的任何更改,我认为您正在获得反馈循环;例如如果你有这样的代码:

data() {
  return {
    year: 2010,
  };
},
watch: {
  year() {
     // this.year changed either by user input or by any other means.
     // Calling API here...
     this.api();
  },
},

您在模板中合并了v-model@input;虽然它有点令人困惑,但这会有效(v-model只是:value@input的语法糖;两个@input会起作用吗?是的,事实证明,但我离题了)。

如果您只想响应用户输入调用API,请在要触发调用的UI元素的@input处理程序中调用API:

<b-select :value="make" @input="setMake">

<!-- For a native DOM element, do this instead -->
<select :value="make" @input="setMake($event.target.value)">
methods: {
  // This method is *only* called by @input
  setMake(make) {
    // Set this.make in response to user input
    this.make = make;

    // Call API here only; this.make can be changed by other means
    // but it won't trigger an API call in those cases
    this.api();
  },
},