0

I have a data structure of elements like:

[
  {
    type: 'text',
    content: 'some text'
  },
  {
    type: 'image',
    content: {
      name: 'filename.jpg',
      url: 'http://example.com/filename.jpg'
    }
  }
]

and in my template i do v-for with if's inside to render different components based on the type:

<div v-for="element in elements">
  <div v-if="element.type === 'text'">
    <p>{{ element.content }}</p>
  </div>
  <div v-if="element.type === 'image'">
    <some-component :image="element.content"></some-component>
  </div>
</div>

my question is, is there any "cleaner", better way of doing this?

1 Answer 1

1

I think I would make a component swapper based on the <component> tag - like:

//  template swapper based on the <component> tag
//  :is     - string value pointing to the component to be used
//  :value  - data to be used in the selected component 
Vue.component('vue-html-tag', {
  props: ['value'],
  template: `<component :is="'vue-' + value.tag + '-tag'" :value="value"></component>`
});


//  tag components 
Vue.component('vue-p-tag', {
  props: ['value'],
  template: `<p :class="value.class">
        {{ value.text }}
        <vue-html-tag v-for="item in value.content" :key="item.id" :value="item"></vue-html-tag>
    </p>`
});

Vue.component('vue-img-tag', {
  props: ['value'],
  template: `<img :src="value.src" />`
});

Vue.component('vue-a-tag', {
  props: ['value'],
  template: `<a :href="value.href" :target="value.target">{{ value.text}}</a>`
});

Vue.component('vue-span-tag', {
  props: ['value'],
  template: `<span :class="value.class">
        {{ value.text }}
        <vue-html-tag v-for="item in value.content" :key="item.id" :value="item"></vue-html-tag>
    </span>`
});



//  app instance
new Vue({
  el: '#app',
  data: {
    html: [
      { id: 1, tag: 'p', text: 'Lorem ipsum', class: 'foo',
        content: [
          { id: 11, tag: 'span', text: 'Nested span:', class: 'foo-span',
            content: [
              { id: 111, tag: 'a', text: 'Link 1 inside span inside p', href: 'http://example.com' },
              { id: 112, tag: 'a', text: 'Link 2 inside span inside p', href: 'http://example.com' },
          ]
        }]
      },
      { id: 2, tag: 'img', src: 'http://via.placeholder.com/350x150' },
      { id: 3, tag: 'a', text: 'Link', href: 'http://example.com' }
    ]
  }
})
.foo {
  padding: 10px;
  border: 1px solid olive
}

.foo-span {
  padding: 20px;
  display: block;
  border: 1px solid orange
}

.foo-span a {
  display: block;
  padding: 10px;
  margin-bottom: 5px;
  border: 1px solid tomato
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>

<div id="app">
  <vue-html-tag v-for="item in html" :key="item.id" :value="item"></vue-html-tag>
</div>

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

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.