5

I have 3 select boxes, and I would like them to reset a certain field on select. How can I make it dynamic, so that it is reusable?

Here's an excerpt of my code:

v-on:select="getDate('{{ route('api.v1.get.date') }}', 'input1', ['form.company.input2', 'form.company.input3'], $event)"

getDate(url, obj, obj2, event){

     let current = this

     current[obj] = ''
     current[obj2[0]] = ''
     current[obj2[1]] = ''

}

When obj is at the root level of the Vue instance (i.e., current[obj]), it sets the property correctly; but not when obj is a nested object.

1

4 Answers 4

6

In JavaScript, property accessors do not allow nested object paths, which is what you have in the dot-separated string. By using that string, you're actually creating a property on the root Vue instance instead of setting a nested property, similar to this:

this['form.company.input2'] = ''  // XXX: creates `form.company.input2` prop
this.form.company.input2 = ''     // sets `input2`

To set the object value by path, you could create a method that uses the object path to navigate the current Vue instance's data properties via this:

methods: {
  getDate(url, obj, obj2, event) {
    this.setValue(obj, '')
    this.setValue(obj2[0], '')
    this.setValue(obj2[1], '')
  },
  setValue(path, value) {
    let obj = this
    const parts = path.split('.')
    while (parts.length > 1 && obj.hasOwnProperty(parts[0])) {
      obj = obj[parts.shift()]
    }
    obj[parts[0]] = value
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      input1: 'input1',
      form: {
        company: {
          input2: 'input2',
          input3: 'input3'
        }
      }
    }
  },
  methods: {
    getDate(url, obj, obj2, event) {
      this.setValue(obj, '')
      this.setValue(obj2[0], '')
      this.setValue(obj2[1], '')
    },
    setValue(path, value) {
      let obj = this
      const parts = path.split('.')
      while (parts.length > 1 && obj.hasOwnProperty(parts[0])) {
        obj = obj[parts.shift()]
      }
      obj[parts[0]] = value
    },
    route(prop) {
      return prop
    }
  }
})
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <input v-model="input1">
  <input v-model="form.company.input2">
  <input v-model="form.company.input3">

  <button @click="getDate(route('api.v1.get.date'), 'input1', ['form.company.input2', 'form.company.input3'], $event)">
    Reset data
  </button>
</div>

Alternatively, you could use a library (such as lodash's _.set):

methods: {
  getDate(url, obj, obj2, event) {
    _.set(this, obj, '')
    _.set(this, obj2[0], '')
    _.set(this, obj2[1], '')
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      input1: 'input1',
      form: {
        company: {
          input2: 'input2',
          input3: 'input3'
        }
      }
    }
  },
  methods: {
    getDate(url, obj, obj2, event) {
      _.set(this, obj, '')
      _.set(this, obj2[0], '')
      _.set(this, obj2[1], '')
    },
    route(prop) {
      return prop
    }
  }
})
<script src="https://unpkg.com/[email protected]/lodash.js"></script>
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <input v-model="input1">
  <input v-model="form.company.input2">
  <input v-model="form.company.input3">

  <button @click="getDate(route('api.v1.get.date'), 'input1', ['form.company.input2', 'form.company.input3'], $event)">
    Reset data
  </button>
</div>

Sign up to request clarification or add additional context in comments.

Comments

2

Try to use this.$set function as follows:

  this.$set(current,obj,'');
 this.$set(current,obj2[0],'');
 this.$set(current,obj2[1],'');

learn more about that function here

3 Comments

Seems i'm encountering this error when using set method, the data has already been set yet i still get this error "[Vue warn]: Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option."
current[obj] is passed via props?
the function is in the same instance, i passed it on v-select "form.compay.input2"
0

This library allows you to use nested object paths.

https://www.npmjs.com/package/vue-data-object-path

Your excerpt would look like this:

v-on:select="getDate('{{ route('api.v1.get.date') }}', 'input1', ['form.company.input2', 'form.company.input3'], $event)"

getDate(url, obj, obj2, event){

     let current = this

     current.$op.set(obj, '')
     current.$op.set(obj2[0], '')
     current.$op.set(obj2[1], '')

}

Comments

0

For getting or setting nested values inside an object having the path as string

function getNestedValue(obj, path){
    return path.split('.').reduce((o,i)=> o[i] || '', obj)
}

function setNestedValue(obj, path, value) {
    let i;
    path = path.split('.');
    for (i=0;i<path.length-1;i++) obj = obj[path[i]];
    obj[path[i]] = value
}

const obj = { a:{ b: [{c: 1 },{ d: 2 }] }}

setNestedValue(obj,'a.b.0.c',3)
console.log(getNestedValue(obj, 'a.b.0.c'))  // 3

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.