El Mac
El Mac

Reputation: 3418

v-bind v-model or v-bind.sync?

I dont understand what is the difference between v-bind, v-modeland v-bind.sync?

Maybe it's too late, but I can't tell the difference between v-bind.syncand v-model after reading the documentation.

Sync modifier

Passing Data to Child Components with Props

v-model

Example

I have the following component written in Typescript, using "vue-property-decorator". I don't know how I can manage to update the date object passed into the component without having to write the event handling myself. If you ask me, it should work with the v-model and with the v-bind.sync bindings (and respective changes in the markup and decorator).

HTML

<Datepicker v-model="date"/>

Typescript

import { Component, Prop, Vue, Model } from "vue-property-decorator";

@Component({})
export default class Datepicker extends Vue {
    @Prop()
    private label!: string;
    @Model()
    private date!: Date;
    private internalDate = new Date().toISOString().substr(0, 10);
    private menu = false;

    private onDateChanged() {
        const isoDate = this.date.toISOString();
        const newDate =
            this.internalDate + this.date.toISOString().substring(10);
        this.date = new Date(newDate);
    }
}

Every time I change the this.date object, I get the warning:

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "date"

Upvotes: 4

Views: 3640

Answers (1)

Harshal Patil
Harshal Patil

Reputation: 21030

In Vue.js, you should not mutate the input prop that is passed to you by the component. For example in your case, consider label prop. Within your DatePicker, you should not have any statement that does something like this.label = 'Hello! Change Prop!';.

TLDR: Do not mutate the prop within your component. Let parent mutate it.

Coming back to your component, you should have a component like this:

import { Component, Prop, Vue, Watch } from 'vue-property-decorator';

@Component({})
export default class Datepicker extends Vue {

    @Prop()
    private label!: string;

    @Prop()
    private value!: Date;

    private internalDate = new Date().toISOString().substr(0, 10);

    private previouslyEmittedDate: Date;

    private menu = false;

    @Watch('value')
    public onDatePropChange() {

        // Break infinite one-way recursion
        if (this.value !== this.previouslyEmittedDate) {
            const newDate = new Date(this.internalDate + this.value.toISOString().substring(10));

            this.previouslyEmittedDate = newDate;

            // input events created a sugar coated v-model binding
            this.$emit('input', newDate);
        }
    }
}

As a side note: I notice some sort of code smell here. On every date change, you are adding some internal date. It will cause infinite one-way binding recursion. v-model is to be used for input changed by the user and not programatically. v-model is just a sugar-coated syntax for the following:

<Datepicker :value="date" @input="this.date = $event"/>

Finally, avoid .sync modifier. It has a different purpose and should be used sparingly.

Upvotes: 1

Related Questions