Gotts
Gotts

Reputation: 2454

Switch template on same component in Vue

I am migrating from angularjs to Vue. Angularjs was nice in the sense that a single controller could be applied on different templates. So using the same controller I could display it via a list.html template or a table.html template and easily switch between a list view or table view of the same data.

In vue I need to create a component that uses a fixed template. That component might have lots of business logic but I want the ability to easily switch between a list view or a table view. What is the correct way to achieve this with Vue?

Thanks

UPDATE

Just to add some detail. What I am currently doing is just including both views into a single template into the component with some logic to determine which one of the two to display. This keeps it simpler as I dont have to duplicate all the logic or methods were I to separate these into two components. At the same time its very messy. Here is a rough example of what I am doing:

<template>
<div>
<div v-if="showTable">
<table>
<tr><td>Name</td><td>Type</td><td>Actions</td></tr>
<tr v-for="item in items">
<td @click="loadObject(item.Uid)>{{item.Name}}</td>
<td @click="viewType(item.Uid)>{{item.Type}}</td>
<td><span @click="expandOptions(item.Uid)">Expand</span><span @click="analyze(item.Uid)"></span></td>
</tr>
</table>
</div>

<div v-if="showList">
<div v-for="item in items">
  <div class="list" @click="loadObject(item.Uid)>{{item.Name}}</div>
  <div@click="viewType(item.Uid)>{{item.Type}}</div>
  <div><span @click="expandOptions(item.Uid)">Expand</span><span @click="analyze(item.Uid)"></span></div>
</div>
</div>
</div>
</template>

That is a highly simplified version of what I need which ultimately has a lot of logic and methods. With this approach I can now just have all these methods and logic in one component. But managing the above template becomes very messy.

Any suggestions?

Upvotes: 0

Views: 932

Answers (1)

Terry
Terry

Reputation: 66228

What you're looking for is a dynamic component loaded using the is binding, in the form of:

<component :is="componentView" />

...where componentView can be in the data or a computed prop that returns a Vue component. This allows you to dictate which component to load in the <component> tag. Essentially, every Vue component has only one template, but you can always switch between different components.

Here is a proof-of-concept example:

const listComponent = Vue.component('list-component', {
  template: '#list-component-template',
  props: {
    items: {
      type: Array,
      required: true
    }
  }
});

const tableComponent = Vue.component('table-component', {
  template: '#table-component-template',
  props: {
    items: {
      type: Array,
      required: true
    }
  }
});

new Vue({
  el: '#app',
  data: {
    view: 'list',
    items: ['Lorem', 'Ipsum', 'Dolor', 'Sit', 'Amet']
  },
  methods: {
    switchView: function() {
      if (this.view === 'list') {
        this.view = 'table';
      } else {
        this.view = 'list';
      }
    }
  },
  computed: {
    componentView: function() {
      if (this.view === 'list') {
        return listComponent;
      } else {
        return tableComponent;
      }
    }
  }
})
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

.grid .cell {
  border: 1px solid #000;
  padding: 1rem;
  margin: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button type="button" @click="switchView">Switch view</button>
  <component :is="componentView" :items="items" />
</div>

<script type="text/x-template" id="list-component-template">
  <ul>
    <li v-for="(item, i) in items" :key="i">
      {{ item }}
    </li>
  </ul>
</script>

<script type="text/x-template" id="table-component-template">
  <div class="grid">
    <div v-for="(item, i) in items" :key="i" class="cell" >
      {{ item }}
    </div>
  </div>
</script>

Upvotes: 2

Related Questions