Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force vue.js to refresh prop when it's sub-property is changed

I have a component that binds on an object, and the parent component changes a property of its object. The subcomponent should react to the change.

Subcomponent:

import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from 'vue-property-decorator'

@Component({
    props: {
        value: Object,
    }
})
class ValidatedSummaryComponent extends Vue {
    value: any;
    field = "Name";
    v: any;

    created() {
        console.log("!", this.value);
        this.v = this.value;
    }

    state: string | null = null;
    error = "";

    @Watch('value')
    onValueChanged(val: any, oldVal: any) {
        console.log("Value called", val);
        this.v = val;
        this.onChanged();
        this.$forceUpdate();
    }

    private onChanged() {
        if (typeof this.v.validationErrors[this.field] == 'undefined') {
            this.state = null;
            this.error = "";
        } else {
            this.state = 'invalid';
            this.error = this.v.validationErrors[this.field].join();
        }
    }
}

export default ValidatedSummaryComponent;

Usage:

<ValidatedSummary v-bind:value="bindableObject"></ValidatedSummary>

Then I do:

bindableObject.Name = 'New name' 

and I need my component ValidatedSummaryComponent to react.

I probably could bind it as a separate property:

<ValidatedSummary v-bind:value="bindableObject.Name"></ValidatedSummary>

, but in the end design, the component should watch for all of the properties of BindableObject and there will be a few different BindableObjects with different set of properties, so I can't just bind it property by property.

The only way I managed to make it work is to force vue.js to update the whole object ensuring vue.js equality check does not pass:

this.bindableObject = Object.assign(new BindableObject(), this.bindableObject );

But this is very cumbersome as I will have to do this on every change so I'm looking for a better way to handle this. It would also be nice to remove this.$forceUpdate(); in the code above, but I can survive with it.

like image 707
Archeg Avatar asked Oct 22 '25 19:10

Archeg


1 Answers

Well just do a force update. It will make your life easier

vm.$forceUpdate();

As mentioned in docs

Force the Vue instance to re-render. Note it does not affect all child components, only the instance itself and child components with inserted slot content.

However it's only recommended when you have no other options left(Only as a last option).

So what other options can you use make it work.(depends on code design)

  1. Try using Vue.set(). or,
  2. Reassign the changed object.
like image 64
Ankit Kumar Ojha Avatar answered Oct 24 '25 14:10

Ankit Kumar Ojha