vue.jsvuejs2interpolationtwo-way-binding

Interpolation doesn't rerender in parent component after custom event from child


I have select displayed in v-for loop:

<div v-for="(n, key) in selectedLanguages">
    <select class="input input__col"
            v-model="currentLang[key]"
            @change="changeLanguage(currentLang[key], key)"
            id="lang_select">
        <option value="pl">Polski</option>
        <option value="en">Angielski</option>
        <option value="es">Hiszpański</option>
    </select>
</div>

To each select I'm adding changeLanguage method which is:

<script>
    export default {
        data() {
            return {
                currentLang: []
            }
        },
        methods: {
            changeLanguage(value, key) {
                let data = { value, key };
                this.$nuxt.$emit('change::language', data);
            }
        },
        props: ['selectedLanguages']
    }
</script>

and it is in child component. In parent I'm listening for this change::language event:

this.$nuxt.$on('change::language', res => {
    console.log(res);
    this.selectedLanguages[res.key] = res.value;
    console.log(this.selectedLanguages);

Although it's working correctly and it's updating selectedLanguages array just fine it doesn't rerender interpolation {{ selectedLanguages }} in parent. However it's correctly rerendering interpolation {{ selectedLanguages }} in child where it's passed by props. Why?


It seems like vue doesn't "catch" that selectedLanguages array have been changed. It only see when I .push or .pop this array. Is there something like apply method in vue?

I found this link in documentation: https://v2.vuejs.org/v2/guide/list.html#Caveats and added this.$set(this.selectedLanguages, res.value, res.key); in parent below my assignment but it didn't fix.


Solution

  • I found solution in Vue docs:

    Due to limitations in JavaScript, Vue cannot detect the following changes to an array: When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue

    I was doing exacly like above.

    The solution is instead

    this.selectedLanguages[res.key] = res.value;
    

    use

    this.$set(this.selectedLanguages, res.key, res.value);
    

    which is basically a bit weird but it works.