Search code examples
javascriptvue.jsvuejs2vue-componentvue-dynamic-components

How do I inform the parent component that something has happened in a Vue dynamic component?


I have a Vue component that generates a dynamic component, and within that dynamic component is a click handler for a button that makes an Ajax call. Upon the Ajax call being successfully completed, I want to inform the component that generates the dynamic component that the Ajax call has finished. How do I do that?

The basic structure of the code in question is as follows:

<template>
    <div>
        <!-- Other markup here. -->
        <div class="contentPlaceholder">
        </div>
    </div>
</template>

<script>
    export default {
        // Props, etc.
        data: function () {
            return {
                // ...
                content: 'long-html-string-that-contains-Vue-components'
            };
        },
        mounted: function () {
            Vue.component(`content-component`, {
                template: `
                    <div class="content">
                        ${this.content}
                    </div>
                `,
                data: function () {
                    return {
                        // Local data here.
                    };
                }
                methods: {
                    // Button in this.content markup clicked.
                    btnCicked: function () {
                        ajax.post('url', {
                            // Params
                            success: () => {
                                // Want to report back to the parent component
                                // that we're here now.
                            }
                        });
                    }
                }
            });

            const res = Vue.compile(`
                <content-component>
                </content-component>
            `);

            new Vue({
                render: res.render,
                staticRenderFns: res.staticRenderFns
            }).$mount(`.contentPlaceholder`);
        }
    }
</script>

My initial thought was to do this.$emit('btnClicked', 'data-here') in the Ajax success callback, but when I try to attach an @btnClicked event handler to the content-component in either the template part of the Vue.component method call or the Vue.compile method call, I get a Vue error.

Basically, I have no clue what to do. The this context is definitely different in the dynamic component, so I can't just add a data property to the parent component and then set it in the Ajax callback of the dynamic component. I tried that and it doesn't work.

I trust there is a simple way to do this, but I'm honestly not sure how. Any help would be greatly appreciated. Thank you.


Edit: It's worth noting that I tried to treat the dynamic component as if it were just a regular child component of the parent component. As such, I added a this.$emit('btnClicked') call within the Ajax success callback and then added an @btnClicked handler to the content-component, but it didn't work.

Maybe I'm just doing it wrong, but I tried both of the following:

template: `
    <div class="content" @btnClicked="btnClicked">
        ${this.content}
    </div>
`,

// And

const res = Vue.compile(`
    <content-component @btnClicked="btnClicked">
    </content-component>
`);

But neither seem to work. Thanks.


Solution

  • btnCicked: () => { console.log(this) }.

    Try to use arrow function to save the context.

    Another option is to create a function that already has access to outer this, and invoke it in your method.

    const method = () => {
      console.log('I have access to outer this', this)
    }
    ...
    btnCicked: function () { method(); console.log('Local this', this) }
    ...