CGriffin
CGriffin

Reputation: 1476

Can I return a Vue JS component in a callback method?

Assume I have a method in a Vue.js component that returns a string to be rendered onto the page:

display: (arg) => {
    return arg.name
}

And in the relevant HTML:

<div html="component.display(arg)">
</div>

This has worked fine for me until now, but now I want to return HTML with some Vue-bound data on it:

display: (arg) => {
    return '<button @click="myMethod(arg)">Click</button>'
}

Obviously, the above doesn't work. My research has led me to believe that the correct approach here would be to create a component and return it, but I just can't seem to get it working. How would I approach this problem?

Upvotes: 2

Views: 9503

Answers (3)

Shinwi
Shinwi

Reputation: 139

If you want to write a function that will return a component and be able to use vue-bound data but do not want to make that into a separate file, then you can look into render functions in vue

Upvotes: 1

Phil
Phil

Reputation: 164812

I think what you're after is a dynamic component.

I would use a computed property to return the component definition to take advantage of Vue's reactivity (methods run all the time, computed properties only when required)

<component :is="display" :arg="arg" @click="myMethod"></component>

and...

computed: {
  display () {
    // you weren't clear on the conditions
    // that should cause this to return something different
    // but here is where you would put them
    return {
      props: ['arg'],
      template: `<button @click="$emit('click', arg)">Click</button>`
    }
  }
}

I'm assuming here that myMethod is defined in the parent, hence adding the @click handler on <component> and $emit in the child.


I suppose you could use a method to return the component definition but that feels like it would be quite inefficient and there's probably a better way to do it.

Upvotes: 5

t56k
t56k

Reputation: 6981

Seems like you could make that button its own component.

// New component
Vue.component('arg-button', {
  props: ['arg'],
  data: function () {
    return {
      arg: null
    }
  },
  myMethod: function(arg) {
    console.log(arg)
  },
  template: `
    <button 
      @click="myMethod(arg)">
        Click
    </button>`
})

// Old component
Vue.component('parent', {
  data: function () {
    return {
      arg: null,
      displayIfArg: true
    }
  },
  template: `
    <arg-button 
      v-show="displayIfArg"
      :arg="arg">
    </arg-button>`

})

Your overall approach is what Vue solves without returning functions-as-strings like that. There's a couple of ways to do it The Vue Way, but it roughly involves conditional instantiation/display of components—which should be readily reusable anyway, so thinking you need to base your return on arg itself is likely more hassle than it's worth.

Components should above all be reusable and atomic. Read their docs, esp. on components, it'll shed a lot of light.

Upvotes: 2

Related Questions