AppsTab.vue
<script>
export default {
props: {
tabList: {
type: Array,
required: true,
},
variant: {
type: String,
required: false,
default: () => "vertical",
},
},
data() {
return {
activeTab: 1,
};
},
};
</script>
<template>
<div
:class="{
'flex space-x-4': variant === 'horizontal',
}"
>
<ul
class="list-none bg-blue-900 bg-opacity-30 p-1.5 rounded-lg text-center overflow-auto whitespace-nowrap"
:class="{
'flex items-center mb-6': variant === 'vertical',
}"
>
<li
v-for="(tab, index) in tabList"
:key="index"
class="w-full px-4 py-1.5 rounded-lg"
:class="{
'text-blue-600 bg-white shadow-xl': index + 1 === activeTab,
'text-white': index + 1 !== activeTab,
}"
>
<label
:for="`${_uid}${index}`"
v-text="tab"
class="cursor-pointer block"
/>
<input
:id="`${_uid}${index}`"
type="radio"
:name="`${_uid}-tab`"
:value="index + 1"
v-model="activeTab"
class="hidden"
/>
</li>
</ul>
<template v-for="(tab, index) in tabList">
<div
:key="index"
v-if="index + 1 === activeTab"
class="flex-grow bg-white rounded-lg shadow-xl p-4"
>
<!-- <slot :name="`tabPanel-${index + 1}`" /> --> want to get data using loop inside tab
</div>
</template>
</div>
</template>
App.vue
< script >
import AppTabs from "./components/AppTabs";
export default {
components: {
AppTabs,
},
data() {
return {
tabList: ["Tab 1", "Tab 2", "Tab 3", "Tab 4"],
};
},
}; <
/script>
<template>
<div class="bg-gradient-to-r from-blue-300 to-blue-500 min-h-screen">
<app-tabs
class="w-11/12 lg:w-10/12 mx-auto"
:tabList="tabList"
variant="horizontal"
>
{{value}} // want to bind data inside tab
</app-tabs>
</div>
</template>
Expected Output
I am working on vertical tabs. Where the functionality is working fine. Here is the complete working code with static mock data https://codesandbox.io/s/vue-js-tabs-forked-we2cx?file=/src/App.vue
Now i want to create some mockdata inside of my data like 'tabList' and then, i want to display data dynamically when user clicked on tabs(including content -->tabs)
How to remove static data, which is inside slots and then only use data dynamically
To start with that, i am not sure, Where to start the looping to display data inside tabs dynamically with mock data?
You can set dynamic slot name using :slot="slotName" where slotName is a dynamic value
This can be achieved using a v-for aswell like below.
<template v-for="content in contentList" :slot="content.slot">
{{ content.content }}
</template>
Where contentList is your array something like below.
contentList: [
{ id: 1, slot: "tabPanel-1", content: "Content 1" },
{ id: 2, slot: "tabPanel-2", content: "Content 2" },
{ id: 3, slot: "tabPanel-3", content: "Content 3" },
{ id: 4, slot: "tabPanel-4", content: "Content 4" },
]
Working Fiddle
Related
I want to simply loop through several props object data in my component, so for example:
I have created a card component and passing as props objects:
<template>
<div class="container">
<div v-for="(title, index) in titles" :key="index" class="counter">
<div class="title ">
<span>{{ title }}</span>
</div>
<div class="content">
<span>{{ values.value1 }}</span>
</div>
<div>
<Button :prop1="moreActions.prop1" :prop2="moreActions.prop2"
:prop3="moreActions.prop3" />
</div>
</div>
<!-- <div class="counter">
<div class="title">
<span>{{ titles.usersA }}</span>
</div>
<div class="content">
<span>{{ values.values2 }}</span>
</div>
<div>
<Button :prop1="moreActions.prop1" :prop2="moreActions.prop2"
:prop3="moreActions.prop3" />
</div>
</div> -->
// more div here.....
</div>
</template>
<script>
import Button from "../test/testButton";
export Test {
name: "Card",
components: {
Button,
},
**//Comment: I want to loop through each objects ( titles, values, moreActions)**
props: {
titles: {
type: Object,
default: () => ({}),
},
values: {
type: Object,
default: () => ({}),
},
moreActions: {
type: Object,
default: () => ({}),
},
},
};
</script>
and in app.vue , i am passing the data something like this:
export const test = createTest ({
.........
props: // I can say 'data' too
{
titles: {
testA: "testA",
usersA: "TestB",
testc: "test3",
textd: "Test4",
},
values: {
value1: "9000",
value2: "600",
value3: "100",
value4: "2",
ofTotal: " of 9",
},
moreActions: {
prop1: "Test",
prop2: "testIcon",
prop3: "test",
},
}
});
in the second div I can loop through like this and so on:
<div v-for="(value, index) in values" :key="index" class="content">
<span>{{ value }}</span>
</div>
but then it doesnot look goods, I want to loop through every props objects in one v-for loop instead giving v-for loop to each div. how can I do that in efficient way.
Thanks in advance!
I have two components: Toggle.vue which is basically a button and a TestToggle.vue which has two Toggle components inside. I want to be able for the toggle elements to serve as a radio button of sorts: only one can be selected at a time.
It is supposed to look like this (only one button is active at a time):
However I can select two buttons:
which isn't right.
Toggle.vue:
<template>
<div class="rounded-full m-5 w-40
flex justify-center
p-2 cursor-pointer"
:class = "status ? 'bg-green-700
hover:bg-green-600' :
'bg-red-700
hover:bg-red-600'"
v-on:click="status = true">
<p>{{text}} : {{status}}</p>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
},
status: {
type: Boolean,
default: false
}
}
}
</script>
TestToggle.vue:
<template>
<div>
<p>Active: {{activeTab}}</p>
<Toggle v-on:click = "activeTab = 1"
text="Toggle 1 "/>
<Toggle v-on:click = "activeTab = 2"
text = "Toggle 2"/>
</div>
</template>
<script>
import Toggle from '../test/Toggle.vue';
export default {
components: {Toggle},
data: function () {
return {
activeTab: 1
}
},
methods: {
}
}
</script>
I think I need to set status = false from TestToggle to Toggle when another Toggle is clicked? How do I do that? Or should I do it completely differently?
Another problem is that I can't update activeTab data property inside TestToggle component: it always shows 1...
EDIT:
I tried this code (as suggested in the answer), but it just doesn't work: the buttons don't react to clicks:
Toggle.vue:
<template>
<div class="rounded-full m-5 w-40
flex justify-center
p-2 cursor-pointer"
:class = "status ? 'bg-green-700 hover:bg-green-600' :
'bg-red-700 hover:bg-red-600'">
<p>{{text}} : {{status}}</p>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
},
status: {
type: Boolean,
default: false
}
}
}
</script>
TestToggle.vue:
<template>
<div>
<p>Active: {{activeTab}}</p>
<Toggle v-on:click = "activeTab = 1"
text="Toggle 1 "
v-bind:status="activeTab === 1"/>
<Toggle v-on:click = "activeTab = 2"
text = "Toggle 2"
v-bind:status="activeTab === 2"/>
</div>
</template>
<script>
import Toggle from '.././toggle-so/Toggle.vue';
export default {
components: {Toggle},
data: function () {
return {
activeTab: 1
}
},
methods: {
}
}
</script>
In Toggle.vue, status is declared as a prop, so you should not modify it:
<template>
<div class="rounded-full m-5 w-40
flex justify-center
p-2 cursor-pointer"
:class = "status ? 'bg-green-700
hover:bg-green-600' :
'bg-red-700
hover:bg-red-600'"
<p>{{text}} : {{status}}</p>
</div>
</template>
but pass it to Toggle.vue from TestToggle.vue:
<template>
<div>
<p>Active: {{activeTab}}</p>
<Toggle v-on:click.native = "activeTab = 1"
text="Toggle 1 "
v-bind:status="activeTab === 1"/>
<Toggle v-on:click.native = "activeTab = 2"
text = "Toggle 2"
v-bind:status="activeTab === 2"/>
</div>
</template>
If you change the status in Toggle.vue, you make it independent of every other Toggle, but if you want a radio button behavior, each status is dependent of other statuses. That's why you need to manage if from the parent component.
You also need to use the native event modifier to listen to the div click of the children.
I made a simple JSFiddle to show a working example.
I encountered some troubles creating an accordion table. I created an Accordion component and a Table component. While independant from each other it works perfectly fine but I can't get any table appear into accordion.
//js part of accordion component
import Table from "../Table/index.vue"
export default {
name: 'accordion',
components: { Table },
mounted () {
},
data(){
return {
items: [
{ id: "mc", title: "Medical Checkup", text: this.components.Table },
{ id: "ac", title: "Application connected", text:
this.components.Table },
{ id: "p", title: "Programs", text: this.components.Table },
{ id: "pl", title: "Pain list", text: this.components.Table }
]
}
}
}
//html part of accordion component
<div>
<div ref="list" class="list">
<transition-group class="flip-list" name="flip-list" ref="tg1"
tag="div">
<div v-for="(item,index) in items" :key="item.id" class="item">
<slot name="item" :class="{active:item.isOpen}" :item="item"
:index="index">
<v-expansion-panel id="exp1">
<v-expansion-panel-content>
<div slot="header" class="drop-target handle2">
<span>{{item.title}}</span>
</div>
<v-card>
<v-card-text>
<div slot="item">{{Table}}</div>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</slot>
</div>
</transition-group>
</div>
</div>
So, the point is : how can I make it so that a datatable appears into accordion ? Like when you click aon one of the titles and it appears instead of some text ?
Thanks a lot
Resolved!
In case of (if people encounter the same problem as I had), here is the code (html / js).
//html goes here
<div id="app">
<v-app id="inspire">
<v-data-table :headers="mainHeaders"
:items="mainItems"
item-key="title"
hide-actions
expand
class="elevation-1">
<template slot="items" scope="props">
<tr #click="props.expanded = !props.expanded">
<td class="text-xs">{{ props.item.title }}</td>
</tr>
</template>
<template slot="expand" scope="props">
<v-data-table :headers="subHeaders"
:items="subItems"
item-key="pain"
hide-actions
class="elevation-10">
<template slot="items" scope="props">
<td class="text-xs">{{ props.item.pain }}</td>
<td class="text-xs">{{ props.item.type }}</td>
</template>
</v-data-table>
</template>
</v-data-table> </v-app>
</div>
//js goes here
export default {
name: 'accordion-table',
mounted () {
},
data () {
return {
mainHeaders: [
{ text: 'Medical informations', value: 'title' }
],
mainItems: [
{ title: 'Medical Checkup' },
{ title: 'Application connected' },
{ title: 'Programs' },
{ title: 'Pain List' }
],
subHeaders: [
{ text: 'Pain', value: 'pain' },
{ text: 'Type', value: 'type' }
],
subItems: [
{ pain: 'Knee', type: '1' },
{ pain: 'Ankle', type: '2' },
{ pain: 'Back', type: '3' },
{ pain: 'Neck', type: '4' }
]
}
}
}
(I used random values)
Hope it helps some of you
I am working with Bootstrap Vue JS table component to create a datatable:
https://bootstrap-vue.js.org/docs/components/table
I am new to VueJS and am uncertain on how to approach this problem which makes searching for a solution even more complicated.
I use an API endpoint to return JSON data:
{
"options":{
"filter":false
},
"fields":[
{
"key":"id",
"label":"Id",
"editLink":false,
"display":true,
"sortable":true,
"class":"shrink"
},
{
"key":"name",
"label":"Name",
"editLink":true,
"display":true,
"sortable":true
}
],
"data":[ ]
}
Here is my table template:
<b-table striped hover bordered foot-clone class="table-sm"
:items="users" :fields="displayedFields" :per-page="perPage" :current-page="currentPage" :filter="filter"
#filtered="onFiltered"
>
<template v-for="(field, index) in fields">
<template slot="{{field.key}}" slot-scope="row" v-if="field.editLink">
<router-link :to="'/user/' + row.item.id" v-bind:key="index"></router-link>
</template>
</template>
<template slot="status" slot-scope="row">
<toggle-button :width="36" :height="18" v-model="row.status" :labels="false" :colors="{checked: '#00FF00', unchecked: '#FF0000', disabled: '#CCCCCC'}"/>
</template>
</b-table>
The first template tag is an attempt from a wild guess. I want to be able to conditionally select a table for a column from the fields config. You can see in my attempt that I want to put a RouterLink when the field's config editLink is true.
How can I get this done?
If you're using version 2.0.0 or newer of bootstrap-vue you need to change the slot names as
they've changed, and the old vue slot has also been deprecated in favor for v-slot.
I changed the accepted answers fiddle to work with the new naming and v-slot
new Vue({
el: "#app",
data: {
fields: [{
key: "id",
label: "Id",
colType: "span"
}, {
key: "name",
label: "Name",
colType: "button"
}, {
key: "uhh",
label: "uhh..",
colType: "idk"
}],
items: [{
id: 0,
name: "Test 0"
}, {
id: 1,
name: "Test 1"
}, {
id: 2,
name: "Test 2"
}]
}
});
<link href="https://unpkg.com/bootstrap#4.3.1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.0.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.0.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-table :items="items" :fields="fields">
<template v-for="(field, index) in fields" v-slot:[`cell(${field.key})`]="data">
<div v-if="field.colType === 'button'">
<h5>{{data.item.name}}</h5>
<b-button>Am Button</b-button>
</div>
<div v-else-if="field.colType === 'span'">
<h5>{{data.item.name}}</h5>
<span>Am Span</span>
</div>
<div v-else>
<h5>{{data.item.name}}</h5>
Am Confused
</div>
</template>
</b-table>
</div>
Here's a jsfiddle showing dynamic columns with a b-table:
https://jsfiddle.net/nardnob/wvk6fxgt/
new Vue({
el: "#app",
data: {
fields: [{
key: "id",
label: "Id",
colType: "span"
}, {
key: "name",
label: "Name",
colType: "button"
}, {
key: "uhh",
label: "uhh..",
colType: "idk"
}],
items: [{
id: 0,
name: "Test 0"
}, {
id: 1,
name: "Test 1"
}, {
id: 2,
name: "Test 2"
}]
}
});
<div id="app">
<b-table :items="items" :fields="fields">
<template v-for="(field, index) in fields" :slot="field.key" slot-scope="data">
<div v-if="field.colType === 'button'">
<h5>{{data.item.name}}</h5>
<b-button>Am Button</b-button>
</div>
<div v-else-if="field.colType === 'span'">
<h5>{{data.item.name}}</h5>
<span>Am Span</span>
</div>
<div v-else>
<h5>{{data.item.name}}</h5>
Am Confused
</div>
</template>
</b-table>
</div>
I'm trying to make a list item clickable. When the item is clicked the checkbox within the list item should be enabled or disabled. However it's not working the way I expect.
I've made an example:
var app = new Vue({
el: '#app',
data: {
showNav: false,
categories: [{name: 'test' }]
},
mounted() {
this.categories.forEach((category) => {
category.active = true;
});
}
})
<div id="app">
<nav class="navbar-dropdown w-full">
<ul class="list-reset">
<li class="flex justify-between items-center hover:bg-grey hover:text-white text-grey uppercase cursor-pointer p-3" v-for="category in categories" #click="category.active = !category.active">
{{ category.name }}
<input type="checkbox" class="shadow" v-model="category.active" #click="category.active = !category.active"/>
</li>
</ul>
</nav>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" rel="stylesheet"/>
When I change this:
categories: [{name: 'test' }]
to this:
categories: [{name: 'test', active: true }]
It's working. But in my application I fetch the application with an ajax and receive the category objects without an active property.
That's why I'm doing this:
this.categories.forEach((category) => {
category.active = true;
});
But that's obviously not working. How could I fix this?
As #ohgodwhy mentioned in his comment there's an issue with the way you define a property for a category. I'm having a hard time explaining why exactly this doesn't work, although this is how you could do this:
var app = new Vue({
el: '#app',
data: {
showNav: false,
categories: [{
name: 'test'
}],
},
mounted() {
this.categories = this.categories.map((category) => {
return {
name: 'test',
active: true,
};
});
},
});
<div id="app">
<ul class="list-reset">
<li class="flex justify-between items-center hover:bg-grey hover:text-white text-grey uppercase cursor-pointer p-3" v-for="category in categories" #click="category.active = !category.active">
{{ category.name }}
<input type="checkbox" class="shadow" v-model="category.active" #click="category.active = !category.active" />
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
I would appreciate any additions or expansions on the reason why OP has this issue.