4

Hi i want to wrap the content of a component with some specific html tag let say button for this example.

i have a function which dynamically returns a value which i use as a prop, based on that i want to wrap the content of a component.

i know i could have achieved this way too <button><compA/></button> it does not solve my problem beacuse i need to change it in 100 places.

My expected result:

  1. <button><div>press me i'm button</div></button>
  2. <div>don't wrap me with button leave me as it is</div>

Note: :wrappwithbutton="" having true for 1st usage and false for 2nd usage

const localComponent = {
     name:'first-comp',
     template:`<div> {{text}}</div>`,
     props:['wrappwithbutton','text'],
}



const app = new Vue({
   el:'#app',
   name:'app',
  components:{'first-comp':localComponent},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>


  <div id="app">

    <first-comp :wrappwithbutton="true" text="press me i'm button"></first-comp>
    
    <br/>
    <hr/>
    <br/>
    
       <first-comp :wrappwithbutton="false" text="don't wrap me with button leave me as it is"></first-comp>

 </div>

2 Answers 2

3

This is a perfect example for render functions. Instead of using a template you can use a render function to render the template for you. Read more about render functions

const localComponent = {
 name:'first-comp',
 props:['wrappwithbutton', 'text'],
 methods: {
   btnClick() {
     if (this.wrappwithbutton) console.log('button')
   }
 },
 render(h) {
   return h(this.wrappwithbutton ? 'button' : 'div', [
     h('div', this.text)
   ])
 }
}

const app = new Vue({
  el:'#app',
  name:'app',
  components:{'first-comp':localComponent},
});

Vue.config.productionTip = false
Vue.config.devtools = false

You can even go a step further and make your localComponent to be more dynamic with the parent passing a prop with the tag that should be rendered:

const localComponent = {
 name:'first-comp',
 props:['tag', 'text'],
 methods: {
   btnClick() {
     if (this.wrappwithbutton) console.log('button')
   }
 },
 render(h) {
   return h(this.tag, [
     h('div', this.text)
   ])
 }
}

If you would like to have a single div and not two divs you can do:

render(h) {
   if (this.tag === 'div') {
     return ('div', this.text);
   }

   return h(this.tag ? 'button' : 'div', [
     h('div', this.text)
   ])
}
Sign up to request clarification or add additional context in comments.

5 Comments

Yeah, but in this case div will be wrapped by another div
@Radeanu Edited the answer to reflect the solution to your comment
yes that's perfect
this is what i was expecting great solution !! 1 doubt i have let say i don't want to do anything in render but render expect to return something in that case what would i return return h that would sufficient
@EaBengaluru I'm not currently on my computer but I think you can just return null. render(h) { return null; } and Vue will sort that out for oyu
0

This is my idea, but I think the template should have a more concise way of writing

const localComponent = {
  name: "first-comp",
  template: `
    <template v-if="wrappwithbutton">
      <button>
        <div> {{text}}</div>
      </button>
    </template>
    <template v-else>
      <div> {{text}}</div>
    </template>
  `,
  props: ["wrappwithbutton", "text"]
};

const app = new Vue({
  el: "#app",
  name: "app",
  components: { "first-comp": localComponent }
});

Comments

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.