最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Auto fill input based on select dropdown in Vue JS - Stack Overflow

programmeradmin2浏览0评论

I'm looking solution for how to auto fill input in vue js. I have a form which include of input type text, select dropdown, quantity, etc. I want when the select dropdown is selected, then the quantity of vCPU, vRAM, and Storage Capacity will be automatically filled with the value according to the selected Server Flavor.

I tried to choose Flavor Server with Flavor 1 options, vCPU should immediately be filled with a value 4, vRAM should be filled with a value 2, and storage capacity should be filled with a value 10. But the quantity does not appear.

But in the price estimation the numbers are correct, namely vCPU (4), vRAM (2), Storage Capacity (10)

I'm confused, to put the if conditional in the <base-quantity> at the @updateQuantity custom event or in v-if attribute. Is there anyone here that can help me solve this problem?

The full source code is in this codesandbox =>

Lite.vue

<template>
  <div class="container">
    <h2 class="font-size-26 txt-secondary">Deka Flexi</h2>
    <div class="row">
      <div class="col-12">
        <form @submit.prevent="submitFormLite">
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Commitment Type</label>
            <select name="mitment" id="" class="select-custom" v-model="selectedCommitTypeLite">
                <option v-for="ctl in mitTypeLite" :key="ctl.name" :value="ctl.value">{{ ctl.name }}</option>
            </select>
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Name</label>
            <input type="text" name="name" class="custom-input" v-model="serverNameLite" />
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Flavor</label>
              <select name="storage-type" id="" class="select-custom" v-model="selectedServerFlavorLite">
                <option v-for="sfl in serverFlavorLite" :key="sfl.name" :value="sfl.value">{{ sfl.name }}</option>
              </select>
          </div>
          <h6 class="font-size-22 txt-secondary txt-semibold">
              Components
          </h6>
          <div class="row form-group--border">
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vCPU (GHz)</div>
                <base-quantity @updateQuantity="updateCpuLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vRAM (GB)</div>
                <base-quantity @updateQuantity="updateRamLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Storage Type</label>
                <select name="storage-type" id="" class="select-custom" v-model="selectedStorageTypeLite">
                   <option v-for="stl in storageTypeLite" :key="stl.name" :value="stl.value">{{ stl.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Storage Capacity (GB)</div>
                <base-quantity @updateQuantity="updateCapacityLite" v-model="updateCapacityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="row pt-4">
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Public IP</label>
                <select name="public-ip" id="" class="select-custom" v-model="selectedPublicIpLite">
                   <option v-for="pil in publicIpLite" :key="pil.name" :value="pil.value">{{ pil.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">OS Type</label>
                <select name="os-lite" id="" class="select-custom" v-model="selectedOsLite">
                   <option v-for="ol in osLite" :key="ol.name" :value="ol.value">{{ ol.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Quantity</div>
                <base-quantity @updateQuantity="updateQuantityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="form-group mt-4 text-center">
            <button class="button button__add" @click="addToCart">Submit</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import BaseQuantity from "../base/BaseQuantity.vue";
export default {
  ponents: {
    BaseQuantity,
  },
  data() {
    return {
      serverNameLite: '',
      storageTypeLite: [
        {
          name: "Storage Type 1",
          value: 100
        },
        {
          name: "Storage Type 2",
          value: 120
        }
      ],
      publicIpLite: [
        {
          name: "Yes",
          value: 120
        },
        {
          name: "No",
          value: 20
        }
      ],
      osLite: [
        {
          name: "OS 1",
          value: 80
        },
        {
          name: "OS 2",
          value: 100
        },
        {
          name: "OS 3",
          value: 120
        }
      ],
      serverFlavorLite: [
        {
          name: "Flavor 1",
          value: "flavor-1"
        },
        {
          name: "Flavor 2",
          value: "flavor-2"
        },
        {
          name: "Flavor 3",
          value: "flavor-3"
        }
      ],
      mitTypeLite: [
        {
          name: "Commitment Type 1",
          value: 80
        },
        {
          name: "Commitment Type 2",
          value: 100
        },
        {
          name: "Commitment Type 3",
          value: 120
        }
      ],
      selectedStorageTypeLite: "",
      selectedPublicIpLite: "",
      selectedOsLite: "",
      selectedCommitTypeLite: "",
      selectedServerFlavorLite:""
    };
  },
  watch: {
    serverNameLite: function() {
      this.$storemit('setServerNameLite', this.serverNameLite);
    },
    selectedStorageTypeLite: function() {
      let storageTypeLite = this.storageTypeLite.find((storageTypeLite) => storageTypeLite.value == this.selectedStorageTypeLite);
      this.$storemit('setStorageTypeLite', storageTypeLite);
    },
    selectedPublicIpLite: function() {
      let publicIpLite = this.publicIpLite.find((publicIpLite) => publicIpLite.value == this.selectedPublicIpLite);
      this.$storemit('setPublicIpLite', publicIpLite);
      console.log(publicIpLite);
    },
    selectedOsLite: function() {
      let osLite = this.osLite.find((osLite) => osLite.value == this.selectedOsLite);
      this.$storemit('setOsLite', osLite);
    },
    selectedCommitTypeLite: function() {
      let mitTypeLite = thismitTypeLite.find((mitTypeLite) => mitTypeLite.value == this.selectedCommitTypeLite);
      this.$storemit('setCommitTypeLite', mitTypeLite);
    },
    selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$storemit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },
  },
  methods: {
    async addToCart() {
        let isLiteEmpty = await this.$store.dispatch('isLiteEmpty');
      if(!isLiteEmpty) {
        this.$storemit('calculateLiteCost');
        this.$storemit('setLite', this.$store.getters.getLiteState);
        this.$storemit('calculatePrice');
      }
    },
    updateCpuLite(val) {
      this.$storemit('setCpuLite', {qty: val, value: 100});
      console.log(val);
    },
    updateRamLite(val) {
      this.$storemit('setRamLite', {qty: val, value: 100});
       console.log(val);
    },
    updateCapacityLite(val) {
      this.$storemit('setCapacityLite', {qty: val, value: 100});
       console.log(val);
    },
    updateQuantityLite(val) {
      this.$storemit('setQuantityLite', {qty: val, value: 100});
       console.log(val);
    },
  },
};
</script>

selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$storemit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },

BaseQuantity.vue

<template>
    <div class="quantity" :class="disabled ? 'quantity__untoggle' : 'quantity__toggle'">
        <button type="button" @click="decrement" class="btn quantity__decrement" :disabled="disabled">-</button>
        <input type="text" class="quantity__value" :value="quantity" :disabled="disabled" readonly>
        <button type="button" @click="increment" class="btn quantity__increment" :disabled="disabled">+</button>
    </div>
</template>

<script>
export default {
    props : ['disabled'],
    data(){
        return{
            quantity: null
        }
    },
    watch:{
        quantity :function(val){
            this.$emit('updateQuantity',val);
        }
    },
    methods :{
        increment () {
            this.quantity++
        },
        decrement () {
            if(this.quantity === 0) {
                alert('Negative quantity not allowed')
            } else {
                this.quantity--
            }
        }
    }
}
</script>

I'm looking solution for how to auto fill input in vue js. I have a form which include of input type text, select dropdown, quantity, etc. I want when the select dropdown is selected, then the quantity of vCPU, vRAM, and Storage Capacity will be automatically filled with the value according to the selected Server Flavor.

I tried to choose Flavor Server with Flavor 1 options, vCPU should immediately be filled with a value 4, vRAM should be filled with a value 2, and storage capacity should be filled with a value 10. But the quantity does not appear.

But in the price estimation the numbers are correct, namely vCPU (4), vRAM (2), Storage Capacity (10)

I'm confused, to put the if conditional in the <base-quantity> at the @updateQuantity custom event or in v-if attribute. Is there anyone here that can help me solve this problem?

The full source code is in this codesandbox => https://codesandbox.io/s/suspicious-almeida-rjyy9

Lite.vue

<template>
  <div class="container">
    <h2 class="font-size-26 txt-secondary">Deka Flexi</h2>
    <div class="row">
      <div class="col-12">
        <form @submit.prevent="submitFormLite">
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Commitment Type</label>
            <select name="mitment" id="" class="select-custom" v-model="selectedCommitTypeLite">
                <option v-for="ctl in mitTypeLite" :key="ctl.name" :value="ctl.value">{{ ctl.name }}</option>
            </select>
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Name</label>
            <input type="text" name="name" class="custom-input" v-model="serverNameLite" />
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Flavor</label>
              <select name="storage-type" id="" class="select-custom" v-model="selectedServerFlavorLite">
                <option v-for="sfl in serverFlavorLite" :key="sfl.name" :value="sfl.value">{{ sfl.name }}</option>
              </select>
          </div>
          <h6 class="font-size-22 txt-secondary txt-semibold">
              Components
          </h6>
          <div class="row form-group--border">
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vCPU (GHz)</div>
                <base-quantity @updateQuantity="updateCpuLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vRAM (GB)</div>
                <base-quantity @updateQuantity="updateRamLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Storage Type</label>
                <select name="storage-type" id="" class="select-custom" v-model="selectedStorageTypeLite">
                   <option v-for="stl in storageTypeLite" :key="stl.name" :value="stl.value">{{ stl.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Storage Capacity (GB)</div>
                <base-quantity @updateQuantity="updateCapacityLite" v-model="updateCapacityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="row pt-4">
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Public IP</label>
                <select name="public-ip" id="" class="select-custom" v-model="selectedPublicIpLite">
                   <option v-for="pil in publicIpLite" :key="pil.name" :value="pil.value">{{ pil.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">OS Type</label>
                <select name="os-lite" id="" class="select-custom" v-model="selectedOsLite">
                   <option v-for="ol in osLite" :key="ol.name" :value="ol.value">{{ ol.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Quantity</div>
                <base-quantity @updateQuantity="updateQuantityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="form-group mt-4 text-center">
            <button class="button button__add" @click="addToCart">Submit</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import BaseQuantity from "../base/BaseQuantity.vue";
export default {
  ponents: {
    BaseQuantity,
  },
  data() {
    return {
      serverNameLite: '',
      storageTypeLite: [
        {
          name: "Storage Type 1",
          value: 100
        },
        {
          name: "Storage Type 2",
          value: 120
        }
      ],
      publicIpLite: [
        {
          name: "Yes",
          value: 120
        },
        {
          name: "No",
          value: 20
        }
      ],
      osLite: [
        {
          name: "OS 1",
          value: 80
        },
        {
          name: "OS 2",
          value: 100
        },
        {
          name: "OS 3",
          value: 120
        }
      ],
      serverFlavorLite: [
        {
          name: "Flavor 1",
          value: "flavor-1"
        },
        {
          name: "Flavor 2",
          value: "flavor-2"
        },
        {
          name: "Flavor 3",
          value: "flavor-3"
        }
      ],
      mitTypeLite: [
        {
          name: "Commitment Type 1",
          value: 80
        },
        {
          name: "Commitment Type 2",
          value: 100
        },
        {
          name: "Commitment Type 3",
          value: 120
        }
      ],
      selectedStorageTypeLite: "",
      selectedPublicIpLite: "",
      selectedOsLite: "",
      selectedCommitTypeLite: "",
      selectedServerFlavorLite:""
    };
  },
  watch: {
    serverNameLite: function() {
      this.$store.mit('setServerNameLite', this.serverNameLite);
    },
    selectedStorageTypeLite: function() {
      let storageTypeLite = this.storageTypeLite.find((storageTypeLite) => storageTypeLite.value == this.selectedStorageTypeLite);
      this.$store.mit('setStorageTypeLite', storageTypeLite);
    },
    selectedPublicIpLite: function() {
      let publicIpLite = this.publicIpLite.find((publicIpLite) => publicIpLite.value == this.selectedPublicIpLite);
      this.$store.mit('setPublicIpLite', publicIpLite);
      console.log(publicIpLite);
    },
    selectedOsLite: function() {
      let osLite = this.osLite.find((osLite) => osLite.value == this.selectedOsLite);
      this.$store.mit('setOsLite', osLite);
    },
    selectedCommitTypeLite: function() {
      let mitTypeLite = this.mitTypeLite.find((mitTypeLite) => mitTypeLite.value == this.selectedCommitTypeLite);
      this.$store.mit('setCommitTypeLite', mitTypeLite);
    },
    selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$store.mit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },
  },
  methods: {
    async addToCart() {
        let isLiteEmpty = await this.$store.dispatch('isLiteEmpty');
      if(!isLiteEmpty) {
        this.$store.mit('calculateLiteCost');
        this.$store.mit('setLite', this.$store.getters.getLiteState);
        this.$store.mit('calculatePrice');
      }
    },
    updateCpuLite(val) {
      this.$store.mit('setCpuLite', {qty: val, value: 100});
      console.log(val);
    },
    updateRamLite(val) {
      this.$store.mit('setRamLite', {qty: val, value: 100});
       console.log(val);
    },
    updateCapacityLite(val) {
      this.$store.mit('setCapacityLite', {qty: val, value: 100});
       console.log(val);
    },
    updateQuantityLite(val) {
      this.$store.mit('setQuantityLite', {qty: val, value: 100});
       console.log(val);
    },
  },
};
</script>

selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$store.mit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },

BaseQuantity.vue

<template>
    <div class="quantity" :class="disabled ? 'quantity__untoggle' : 'quantity__toggle'">
        <button type="button" @click="decrement" class="btn quantity__decrement" :disabled="disabled">-</button>
        <input type="text" class="quantity__value" :value="quantity" :disabled="disabled" readonly>
        <button type="button" @click="increment" class="btn quantity__increment" :disabled="disabled">+</button>
    </div>
</template>

<script>
export default {
    props : ['disabled'],
    data(){
        return{
            quantity: null
        }
    },
    watch:{
        quantity :function(val){
            this.$emit('updateQuantity',val);
        }
    },
    methods :{
        increment () {
            this.quantity++
        },
        decrement () {
            if(this.quantity === 0) {
                alert('Negative quantity not allowed')
            } else {
                this.quantity--
            }
        }
    }
}
</script>

Share Improve this question edited May 19, 2021 at 5:53 frankfurt asked May 16, 2021 at 5:43 frankfurtfrankfurt 1531 gold badge7 silver badges25 bronze badges 2
  • Hi, Try using v-model on the input field. – Yash Maheshwari Commented May 16, 2021 at 6:01
  • input field in <base-quantity>? – frankfurt Commented May 16, 2021 at 14:44
Add a ment  | 

2 Answers 2

Reset to default 5

There are multiple ways, but it's all based on how your data is stored and connected through ponents.

Let's start from BaseQuantity.vue:

data() {
  return {
    quantity: 0 // you have a local saved state of the quantity
  }
},
methods: {
  increment() {
    this.quantity++ // when user hits something, you increment the LOCAL state
  },
}
watch: {
  quantity: function(val) { // when the LOCAL value updates
    this.$emit('updateQuantity', val); // you emit event it has been updated
  }
}

Basically each of your Base Quantity ponents defines its state (starting from 0), and then tracks its own actions that update that state.

You use those ponents like

<base-quantity @updateQuantity="updateServer"

And the method calls Vuex to store the new value (gotten from the ponent, equals to it's internal state):

updateServer(val) {
  this.$store.mit('setServer', {qty: val, value: 100});
}

  1. Your first issue is that each of those Base Quantity ponents define their own initial state, which is internal and separate. Currently, there's no real way to tell any of those "your value is X", it's quite the opposite - they tell the parent "I've updated my value".

    In order to do so, you must somehow set the initial value. The very basic approach would be to pass the initial value to the ponent:

    props : ['disabled', 'initialValue'],
    data(){
      return {
        quantity: this.initialValue
      }
    },
    
  2. Problem two now is that you don't only need an initial value, you need to set the value from outside, whenever the user selects a dropdown option. But you would also like to keep track of manual updates on the ponent. So you need a two-directional binding of the values (set and update). That's where the v-model es in handy. Here's a good article explaining how it worked before, and how it works now: https://v3-migration.vuejs/breaking-changes/v-model.html#overview Basically you'll use it like that:

    <base-quantity v-model="serverQuantity" />
    
    <!-- would be shorthand for: -->
    
    <base-quantity
      :modelValue="serverQuantity"
      @update:modelValue="serverQuantity= $event"
    />
    
  3. You don't store the data in your Calculator ponent - you store it in Vuex. Now this is the part where you have a lot of solutions and you need to be careful how you design your data flow. I would go with the simplest one:

    • Use store getters to instruct Base Quantity what its value is: <base-quantity :value="$store.getters.serverQuantity" />. This is a reactive property that would be updated when the store updates its value for server quantity. If you don't have getters you could use the state instead, but that's not suggested.
    • Remove local variable for quantity, and just use the passed property: <input :value="value" />
    • Upon update (clicking on a button), emit an event with the new value without updating it locally: increment() { this.$emit('updateQuantity', this.value + 1)
    • In your handler, mit the update as of now

  1. In order to handle dropdown selection, if you use the approach described above, you just need to wait for the user input (dropdown selection) and populate the store with all the needed fields. Since they are passed to each ponent, the value would be automatically populated:

    watch: {
      selectedPackage: function() {
        let pack = this.storagePackage.find((pack) => pack.value == this.selectedPackage);
        this.$store.mit('setPackage', pack);
        // here you should somehow map the pack to the values you'd like to populate
        // let's say package "One" (value: 30) means you'd have 8 vRAM, then:
        this.updateRam(package.ram);
        // this would call this.$store.mit('setRam', { qty: 8, value: 100 });
    
        this.updateCapacity(100);
        this.updateCpu(5);
        // all the other fields you'd like to update, with the specific values this PACK has (I haven't seen any map for plan -> values)
      },
    }
    

    p.s. I'm not entirely sure why you store qty: val, value: 100 everywhere, but probably you have some reason about it.

With this approach you'll have a single source of truth about the data. And separate ponents that just say "I want this value (whatever it is) to be either incremented or decremented". So the ponent is pletely isolated of any knowing of the real business logic of modification and storage, as well as the property name. The parent is the one that handles data both ways - first it sends it to each ponent, and second - it handles the user actions, which are then mited to a Vuex store (single point of truth).

You can set values using the v-model but this is a different scenario where the values are based on the selected events. So I reached this solution where you can create a function that sets the values in custom mode

Try using this:

setValues: function () {
      this.specifications === this.specifications[1]
        ? (this.os = this.os[0].name)
        : (this.os = '');

You can pass in other Databases, StorageType, Firewall values as well.

发布评论

评论列表(0)

  1. 暂无评论