Can Vue.js update a nested property?

Viewed 1336

I have a complicated component with lots of two way bound variables so in order to keep things clean im grouping variables in category objects.

settings: {
    setting1: true,
    setting2: false,
    setting3: true
},
viewMode: {
    option1: true,
    option2: false,
    options3: true
}

I am then passing the settings to my component like so

<some-component :settings.sync="settings" :viewmode.sync="viewMode"></some-component>

some-component then can transform these values and emit them back to the parent but this is where the problem lies. It appears

this.$emit('update:settings.setting1', newValue)

does NOT work in Vuejs. The only solution i can find to update these values from some-component is to overwrite the entire settings object like so

props: {
    settings: {
        type: Object,
        default: () => {
            return {
                setting1: true,
                setting2: false,
                setting3: true
             }
        }
    }
},
computed: {
    localSetting1: {
        get () {
            return this.settings.setting1
        },
        set (newValue) {
            // This does not work
            this.$emit('update:settings.setting1', newValue)

            // The only thing that does seem to work, is overwriting the entire object
            this.$emit('update:settings', {
                setting1: newValue,
                setting2: this.settings.setting2,
                setting3: this.settings.setting3
            }

            // or to be less verbose, but still update the entire object
            this.$emit('update:settings', Object.assign(this.settings, {settings1: newValue}))
        }
    }
}

This seems a bit messy. Is there not a way to update just a single nested property and emit it back to the parent? The most ideal way being something similar to this

this.$emit('update:settings.setting1', newValue)
1 Answers

Actually Vue can update nested props, we just need to overwrite the whole prop object, as Vue cannot track nested changes.

If we have a prop like this

props: {
  someValues: {
    'a': 1,
    'b': 2,
    'c': 3
  }
}

If we make a change like this one Vue will not react

this.someValues.a = 10

What we need to do

this.tmpSomeValues = { ...someValues, a: 10 }
this.someValues = this.tmpSomeValues
Related