moses toh
moses toh

Reputation: 13192

How can I reset data in child component from parent component on vue.js 2?

My parent component like this :

<template> 
    <div ref="modal" class="modal" tabindex="-1" role="dialog">
        <div class="modal-dialog" role="document">
            <div class="modal-content modal-content-data">
                <form id="form-data">
                    ...
                    <location-select .../>
                    ...
                </form>
            </div>
        </div>
    </div>
</template>
<script>
    import LocationSelect from './LocationSelect.vue'
    export default{
        name: 'CartModal',
        components:{
            LocationSelect,
        },
        mounted(){
            $(this.$refs.modal).on('hidden.bs.modal', () => {
                Object.assign(this.$data, this.$options.data())
            })
        }
    }
</script>

If modal hidden, it will reset data in parent component and it works

I want to reset data also in child component

I try like this :

<template>
    <select class="form-control" v-model="selected" ...>
        ...
    </select>
</template>
<script>
    export default{
        name: 'LocationSelect',
        ...
        created() {
            $(this.$parent.$refs.modal).on('hidden.bs.modal', () => {
                Object.assign(this.$data, this.$options.data())
            })
        }
    };
</script>

But it does not work

The child component no reset the data

How can I solve this problem?

Upvotes: 3

Views: 8583

Answers (1)

Bert
Bert

Reputation: 82499

The main problem with this code is the handler in LocationSelect is being added before this.$parent.$refs.modal exists. A ref does not exist until the component is mounted.

The easiest way to solve this would be to move the code to mounted.

mounted() {
  $(this.$parent.$refs.modal).on('hidden.bs.modal', () => {
    Object.assign(this.$data, this.$options.data())
  })
}

Or you could leave it in created and use nextTick.

created() {
  this.$nextTick(() => {
    $(this.$parent.$refs.modal).on('hidden.bs.modal', () => {
      Object.assign(this.$data, this.$options.data())
    })
  })
}

Another way to handle this would be to add a ref to the LocationSelect component and add a method that clears it that can be called from the parent. In LocationSelect add this method:

methods:{
  clear(){
    Object.assign(this.$data, this.$options.data())
  }
}

In the parent template add a ref:

<location-select ref="locationSelect" ... />

And in your parent's mounted:

mounted(){
  $(this.$refs.modal).on('hidden.bs.modal', () => {
    Object.assign(this.$data, this.$options.data())
    this.$refs.locationSelect.clear()
  })
}

However, the most idiomatic way to handle this with Vue would be to modify the component to support v-model and then it would be automatically cleared when the parent is cleared.

<template>
    <select class="form-control" v-model="selected" ...>
        ...
    </select>
</template>
<script>
    export default {
        props: ["value"],
        name: 'LocationSelect',
        computed:{
          selected:{
            get(){ return this.value },
            set(v) { this.$emit('input', v) }
          }
        },
    };
</script>

And then in the parent template:

<location-select v-model="someDataValue" ... />

If you did this, then when the parent is clear, the child is automatically cleared as well.

Upvotes: 2

Related Questions