Des Albert
Des Albert

Reputation: 331

Object assignment in Vue.js method

I have a Vue component in which I select a specific value from an array of objects then attempt to copy some fields from that value into Vue data

  <div class="container">
    <h4>Add Item</h4>
    <form @submit.prevent="addItem(item.Code)">
      <div class="row">
        <div class="col-md-6">
          <div class="form-group">
            <label for="ItemCode">Code</label>&nbsp;
            <select
              id="ItemCode"
              v-model="item.Code"
            >
              <input
                v-model="item.Code"
                type="hidden"
              >
              <option
                v-for="part in PartCodes"
                :key="part"
              >
                {{ part }}
              </option>
            </select>
   .
   .
   .
    </form>
  </div>

where the data is

  data() {
    return {
      item: {},
      parts: [],
    };
  },
  computed: {
    PartCodes: function () {
      return [...new Set(this.parts.map(p => p.Code))];
    },
  },
  created() {
    let uri = '/parts';
    if (process.env.NODE_ENV !== 'production') {
      uri = 'http://localhost:4000/parts';
    }
    this.axios.get(uri).then(response => {
      this.parts = response.data;
    });
  },
  methods: {
    addItem(selectCode) {
      let uri = '/items/create';
      if (process.env.NODE_ENV !== 'production') {
        uri = 'http://localhost:4000/items/create';
      }
      let selectPart = this.parts.filter( obj => {
        return obj.Code === selectCode;
      });

      this.item.Description = selectPart.Description;
      this.item.Cost = selectPart.Cost;
      this.item.Price = selectPart.Price);

      this.axios.post(uri, this.item)
        .then(() => {
          this.$router.push({name: 'QuoteIndex'});
        });
    }
  }
};

When I log the object 'selectPart' it has the correct fields but assigning these fields into the object 'items' results in 'undefined' values

I must be doing something wrong with scope but I don't know what is wrong.

Please suggest how I can copy fields with this Component

Thanks enter image description here

Upvotes: 4

Views: 12026

Answers (2)

Daniel Elkington
Daniel Elkington

Reputation: 3637

In Vue 2.x, properties added to objects are not reactive. You have declared the item data item without the properties Description and Price, and have later assigned these properties using simple object assignment, which Vue will not be able to track.

There are two ways to solve this:

1. Declare all reactive properties upfront

Change data to

data() {
    return {
      item: {
        Description: null,
        Price: null
      },
      parts: [],
    };
  },

2. Use Vue.set()

Change

this.item.Description = selectPart.Description;
this.item.Price = selectPart.Price;

to

this.$set(this.item, 'Description', selectPart.Description);
this.$set(this.item, 'Price', selectPart.Price);

Thankfully in Vue 3.x this caveat will be eliminated and all properties added to reactive objects will themselves become reactive.

Upvotes: 4

Des Albert
Des Albert

Reputation: 331

Here is a more elegant solution to the problem.

Replace .filter() with .find()

  <div class="container">
    <h4>Add Item</h4>
    <form @submit.prevent="addItem(item.Code)">
      <div class="row">
        <div class="col-md-6">
          <div class="form-group">
            <label for="ItemCode">Code</label>&nbsp;
            <select
              id="ItemCode"
              v-model="item.Code"
            >
              <input
                v-model="item.Code"
                type="hidden"
              >
              <option
                v-for="part in PartCodes"
                :key="part"
              >
                {{ part }}
              </option>
            </select>
   .
   .
   .
    </form>
  </div>

where the data is

  data() {
    return {
      item: {          
          Code: null,
          Description: null,
          Group: null,
          GroupCount: null,
          Quantity: null,
          ExtQuantity: null,
          Cost: null,
          Price: null,
          QuoteNumber: null},
      parts: [],
    };
  },
  computed: {
    PartCodes: function () {
      return [...new Set(this.parts.map(p => p.Code))];
    },
  },
  created() {
    let uri = '/parts';
    if (process.env.NODE_ENV !== 'production') {
      uri = 'http://localhost:4000/parts';
    }
    this.axios.get(uri).then(response => {
      this.parts = response.data;
    });
  },
  methods: {
    addItem(selectCode) {
      let uri = '/items/create';
      if (process.env.NODE_ENV !== 'production') {
        uri = 'http://localhost:4000/items/create';
      }
      let selectPart = this.parts.find( obj => {
        return obj.Code === selectCode;
      });

      this.item.Description = selectPart.Description;
      this.item.Cost = selectPart.Cost;
      this.item.Price = selectPar.Price;

      this.axios.post(uri, this.item)
        .then(() => {
          this.$router.push({name: 'QuoteIndex'});
        });
    }
  }
};

Upvotes: 0

Related Questions