Reputation: 2454
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
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
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