Alex Gusev
Alex Gusev

Reputation: 1854

Vue 3: set dynamic component from other component

I have a display component (app-display) with dynamic component inside (by default: app-empty):

    app.component('appDisplay', {
        template: `<component :is="currentComponent"></component>`,
        data() {
            return {currentComponent: 'appEmpty'}
        }
    });

I need to create new instance of app-message, to set property message for this instance and to set the instance as current component for app-display on button click.

This is a browser code for the question:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue component reference</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app"></div>
<script>
    // main application with button & display panel
    const app = self.Vue.createApp({
        template: `
          <app-btn></app-btn>
          <app-display></app-display>
        `
    });

    // button component to fire action
    app.component('appBtn', {
        template: `
          <button v-on:click="setDisplay">Display message</button>`,
        methods: {
            setDisplay() {
                console.log('I need to set "appMessage" (with some "message" param) as inner component to "app-display" here.');
            }
        }
    });

    // component with dynamic component inside
    app.component('appDisplay', {
        template: `<component :is="currentComponent"></component>`,
        data() {
            return {currentComponent: 'appEmpty'}
        }
    });

    // default component to display
    app.component('appEmpty', {
        template: `<div>I'm empty.</div>`
    });

    // this component with custom message should be displayed on button click
    app.component('appMessage', {
        template: `
          <div>{{ message }}</div>
        `,
        props: {
            message: String
        }
    });
    // mount main app to the page
    app.mount('#app');
</script>
</body>
</html>

How can I access app-display from app-btn?

Upvotes: 1

Views: 2312

Answers (1)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You should emit an event from button component to main component with component name to display and the message and in the main component you should define a message and current component name which will be updated by the handler of the emitted event and passed as props to the component that displays them:

   // main application with button & display panel
    const app = self.Vue.createApp({
        template: `
          <app-btn @change-content="changeContent"></app-btn>
          <app-display :currentComponent="componentName" :message="msg"></app-display>
        `,
        data(){
         return{
            componentName:'appEmpty',
            msg:''
         }
        },
        methods:{
           changeContent(compName,msg){
           console.log(compName,msg)
             this.componentName=compName
             this.msg=msg
           }
        }
    });

    // button component to fire action
    app.component('appBtn', {
        template: `
          <button v-on:click="setDisplay">Display message</button>`,
        methods: {
            setDisplay() {
            this.$emit('change-content','appMessage','Hello message :)')
            
            }
        }
    });

    // component with dynamic component inside
    app.component('appDisplay', {
        props:{
        currentComponent:{
             type:String,
             default:'appEmpty'
           }
        },
        template: `<component :is="currentComponent"></component>`,
      
    });

    // default component to display
    app.component('appEmpty', {
        template: `<div>I'm empty.</div>`
    });

    // this component with custom message should be displayed on button click
    app.component('appMessage', {
        template: `
          <div>{{ message }}</div>
        `,
        props: {
            message: String
        }
    });
    // mount main app to the page
    app.mount('#app');
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue component reference</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app"></div>

</body>
</html>

Upvotes: 1

Related Questions