186

I've a dynamic view:

<div id="myview">
  <div :is="currentComponent"></div>
</div>

with an associated Vue instance:

new Vue ({
  data: function () {
    return {
      currentComponent: 'myComponent',
    }
  },
}).$mount('#myview');

This allows me to change my component dynamically.

In my case, I have three different components: myComponent, myComponent1, and myComponent2. And I switch between them like this:

Vue.component('myComponent', {
  template: "<button @click=\"$parent.currentComponent = 'myComponent1'\"></button>"
}

Now, I'd like to pass props to myComponent1.

How can I pass these props when I change the component type to myComponent1?

5
  • You pass props via attributes on the element propName="propValue". Is that your question? Commented Apr 27, 2017 at 13:05
  • I cannot because I never write <myComponent1 propName="propValue"> I change the component programmatically with $parent.currentComponent = componentName Commented Apr 27, 2017 at 13:07
  • Yeah but you write <div :is="currentComponent"></div>. That's where you'd add the attribute. Commented Apr 27, 2017 at 13:08
  • 8
    Yes but props depends of the component. For instance, myComponent1 take props and myComponent2 doesn't take props Commented Apr 27, 2017 at 13:10
  • Spent one hour trying to make this happen. Thank you so much! Commented Mar 1, 2022 at 23:49

6 Answers 6

333

To pass props dynamically, you can add the v-bind directive to your dynamic component and pass an object containing your prop names and values:

So your dynamic component would look like this:

<component :is="currentComponent" v-bind="currentProperties"></component>

And in your Vue instance, currentProperties can change based on the current component:

data: function () {
  return {
    currentComponent: 'myComponent',
  }
},
computed: {
  currentProperties: function() {
    if (this.currentComponent === 'myComponent') {
      return { foo: 'bar' }
    }
  }
}   

So now, when the currentComponent is myComponent, it will have a foo property equal to 'bar'. And when it isn't, no properties will be passed.

Sign up to request clarification or add additional context in comments.

11 Comments

Why this is not working for me? It works for the first component, but after i change the “currentComponent” i get a “e.currentProperties” is undefined on child component.
@RicardoVigatti, without seeing any of your code, it's pretty hard to know
@FelipeMorales, yep, you'd just need to define a default <slot> for each component you are dynamically rendering. vuejs.org/v2/guide/components-slots.html
The style guide says that prop names should be as detailed as possible. This way breaks the rule. This is also what I use, but I am looking for a better solution.
@KorayKüpe you are mis-quoting the style guide here. It says "prop definitions should always be as detailed as possible". The intent of a dynamic component inherently means that prop names and structure will almost certainly be different between components loaded into this structure.
|
30

You can also do without computed property and inline the object.

<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

Shown in the docs on V-Bind - https://v2.vuejs.org/v2/api/#v-bind

Comments

22

You could build it like...

comp: { component: 'ComponentName', props: { square: true, outlined: true, dense: true }, model: 'form.bar' }
     
<component :is="comp.component" v-bind="{...comp.props}" v-model="comp.model"/>

Comments

3

I have the same challenge, fixed by the following:

<component :is="currentComponent" v-bind="resetProps"> 
   {{ title }}
</component>

and the script is

export default { 
  …
  props:['title'],
  data() {
    return {
      currentComponent: 'component-name',
    }
  },
  computed: {
    resetProps() {
      return { ...this.$attrs };
    },
}
<div
    :color="'error'"
    :onClick="handleOnclick"
    :title="'Title'"
/>

I'm came from reactjs and I found this solve my issue

Comments

2

If you have imported you code through require

var patientDetailsEdit = require('../patient-profile/patient-profile-personal-details-edit')
and initalize the data instance as below

data: function () {
            return {
                currentView: patientDetailsEdit,
            }

you can also reference the component through the name property if you r component has it assigned

currentProperties: function() {
                if (this.currentView.name === 'Personal-Details-Edit') {
                    return { mode: 'create' }
                }
            }

1 Comment

why function was used?
1

When you use the <component> inside a v-for you can change the answer of thanksd as follow:

methods: {
  getCurrentProperties(component) {
    if (component === 'myComponent') {
      return {foo: baz};
    }
  }
},

usage

<div v-for="object in object.items" :key="object._your_id">
  <component :is="object.component" v-bind="getCurrentProperties(object.component)" />
</div>

Let me know if there is an easier way.

1 Comment

FYI, in a v-for (any list really), it's more performant to define a computed or data property that returns all the properties as an array and have your components select them by index. Like v-bind="currentProperties[object.component]". Methods are called much more frequently than computed properties. (in my testing...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.