I want to use breadcrumbs in my vuetify project but I'm stuck somewhere. The point I'm stuck with is that when I click on bredcrumbs, the ones that come after that are deleted from the breadcrumbs list. For this, I tried the code below, but I could only delete the next element from it. Also, I couldn't delete the dividers. How do you think I can overcome this situation? thanks.
template:
<v-breadcrumbs :items="items" divider=">">
<template v-slot:item="{ item }">
<v-breadcrumbs-item :href="item.href" #click="showSelectedRow2(item)">
{{ item.text }}
</v-breadcrumbs-item>
</template>
</v-breadcrumbs>
Data:
items: [
{
text: '',
disabled: false,
id: '',
},
],
Script:
showSelectedRow2(item) {
for (var i = 0; i < this.items.length; i++) {
if (this.items[i].id == item.id) {
const index = this.items.indexOf(this.items[i]);
this.items.splice(index, 1);
}
this.items.push({
text: item.name,
disabled: false,
id: item.id,
});
}
},
eg Technology>Computer>laptop>Apple when I click on technology, only technology should remain in the list. I don't use route or link, I fill the list with data I get from an api.
You can try to change your method like in the following snippet:
(you can disable items or you can remove them)
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
items: [{text: 'Technology', disabled: false, id: 0,}, {text: 'Computer', disabled: false, id: 1,}, {text: 'Laptop', disabled: false, id: 2,}, {text: 'Apple', disabled: false, id: 3,},],
}
},
methods: {
itemIdx(itm) {
return this.items.findIndex(i => i.id === itm.id)
},
showSelectedRow2(item) {
//this.items = this.items.map(el => this.itemIdx(el) > this.itemIdx(item) ? {...el, disabled: true} : el)
this.items = this.items.filter(el => this.itemIdx(el) <= this.itemIdx(item))
}
}
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#6.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<v-container>
<v-breadcrumbs :items="items" divider=">">
<template v-slot:item="{ item }">
<v-breadcrumbs-item :href="item.href" #click="showSelectedRow2(item)">
{{ item.text }}
</v-breadcrumbs-item>
</template>
</v-breadcrumbs>
</v-container>
</v-main>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
Related
Problem statement - I'm creating cards with vuetify that will loop in foreach, but I wanna each card has different color that I get from my generateColor() function, here's what I mean :
ProjectCard.vue :
<template>
<v-card :color="colorCard">
<v-row>{{ projectName }}</v-row>
<v-row>{{ projectDecs }}</v-row>
<v-row>{{ deadline }}</v-row>
</v-card>
</template>
<script>
export default {
props: {
projectName: String,
projectDecs: String,
deadline: String,
colorCard: String,
},
};
</script>
Project.vue :
<template>
<v-container>
<v-row>
<v-col v-for="(project, index) in projects" :key="index">
<project-card
:projectName="project.name"
:projectDesc="project.desc"
:deadline="project.date"
:colorCard="this.color"
></project-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
import ProjectCard from "#/components/ProjectCard.vue";
export default {
components: {
ProjectCard,
},
data() {
return {
color: "",
projects: [
{
name: "Learning laravel",
desc: "Finish video asap",
date: "28",
},
{
name: "Learning laravel",
desc: "Finish video asap",
date: "28",
},
],
};
},
mounted(){
this.generateColor()
},
methods: {
generateColor() {
const colors = ["#c07bc3", "#a6dcaf", "#ddddce"];
this.color = colors[Math.floor(Math.random() * colors.length)];
},
}
};
</script>
I know we can't define color as a prop :color="ColorCard", and I'm running out ideas, anybody can help?
You can try to call method for random color:
Vue.component('projectCard', {
template: `
<v-card :color="colorCard">
<v-row>{{ projectName }}</v-row>
<v-row>{{ projectDecs }}</v-row>
<v-row>{{ deadline }}</v-row>
</v-card>
`,
props: {
projectName: String,
projectDecs: String,
deadline: String,
colorCard: String,
},
})
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
colors: ["#c07bc3", "#a6dcaf", "#ddddce"],
projects: [
{name: "Learning laravel", desc: "Finish video asap", date: "28",},
{name: "Learning laravel", desc: "Finish video asap", date: "28",},
]
}
},
methods: {
setColor() {
return this.colors[Math.floor(Math.random() * this.colors.length)]
},
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#6.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<v-container>
<v-row>
<v-col v-for="(project, index) in projects" :key="index">
<project-card
:project-name="project.name"
:project-desc="project.desc"
:deadline="project.date"
:color-card="setColor()"
></project-card>
</v-col>
</v-row>
</v-container>
</v-main>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
What you are trying to do here is that you are assigning a single color for every card but it should be dynamic. So what you can try is that assign a color property in each object of projects array and then bind in the same way :color="colorCard".
I created this simple demo for your understanding :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
cardsDetails: [{
title: 'Card A'
}, {
title: 'Card B'
}, {
title: 'Card C'
}]
},
created() {
this.generateColor();
},
methods: {
generateColor() {
const colors = ["#c07bc3", "#a6dcaf", "#ddddce"];
this.cardsDetails.forEach(obj => {
const color = colors[Math.floor(Math.random() * colors.length)];
obj.colorCard = color;
});
}
}
})
.mx-auto {
margin: 5px
}
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.7/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.7/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-card
v-for="(card, index) in cardsDetails"
:key="index"
class="mx-auto"
max-width="344"
:color="card.colorCard"
>
<v-card-text>
<div>{{ card.title }}</div>
</v-card-text>
</v-card>
</v-app>
</div>
I'm using VueJs and Vuetify. I have Vuetify's table where I present the data. I'm trying to edit the header column of some of the columns so I could add a dropdown search bar to filter the table. Something like:
Where Select Item is actually the header (please see the sort symbol aside of it). I could add it the dropdown above the table, like it's shown in the official docs, but I'm trying to make the dropdown as the header column itself and not just above the table.
The current code:
<v-data-table
class="elevation-1"
:headers="headers"
:items="items"
:items-per-page="tableItemsPerPage"
:footer-props="tableFooterSettings"
:loading="tableLoading"
hide-default-footer
>
where headers is a simple array of the headers, for example:
{ text: 'data', value: 'pretty_data', align: 'center', sortable: true },
Of course I want the column to be still sortable (like it's shown in the image [the arrow]). How can I make it done?
Created this working Demo. Hope it will work as per your expectation.
new Vue({
el: '#app',
data: () => ({
selected: [],
headers: [
{
text: 'Name',
align: 'left',
value: 'name'
}
],
filters: {
name: []
},
desserts: [
{
name: 'Frozen Yogurt'
},
{
name: 'Ice cream sandwich'
},
{
name: 'Eclair'
},
{
name: 'Cupcake'
},
{
name: 'Gingerbread'
},
{
name: 'Jelly bean'
},
{
name: 'Lollipop'
},
{
name: 'Honeycomb'
},
{
name: 'Donut'
},
{
name: 'KitKat'
}
]
}),
computed: {
filteredDesserts() {
return this.desserts.filter(d => {
return Object.keys(this.filters).every(f => {
return this.filters[f].length < 1 || this.filters[f].includes(d[f])
})
})
}
},
methods: {
columnValueList(val) {
return this.desserts.map(d => d[val])
}
}
})
<script src="https://unpkg.com/vue#2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.1.10/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.1.10/dist/vuetify.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<div id="app">
<v-app id="inspire">
<v-data-table
v-model="selected"
:headers="headers"
:items="filteredDesserts"
item-key="name"
class="elevation-1"
>
<template slot="headers" slot-scope="props">
<tr class="grey lighten-3">
<th
v-for="header in props.headers"
:key="header.text"
>
<div v-if="filters.hasOwnProperty(header.value)">
<v-select flat hide-details small multiple clearable :items="columnValueList(header.value)" v-model="filters[header.value]">
</v-select>
</div>
</th>
</tr>
</template>
<template slot="items" slot-scope="props">
<tr>
<td>{{ props.item.name }}</td>
</tr>
</template>
</v-data-table>
</v-app>
</div>
i need to add an input field used to edit the title in the currently selected element component (selection was done by clicking). The problem is that there should be one input and work for each selected element. I couldn't find a similar task and solving on the Internet. Maybe someone will tell you how to do it?
ItemsList.vue component:
<template>
<input type="text" placeholder="Edit selected items"/>
<div class="items-col">
<ul class="items-list">
<Item v-for="item in items" :key="item" :title="item.title"/>
</ul>
</div>
</template>
<script>
import Item from '#/components/Item.vue'
export default {
data() {
return {
items: [
{ title: 'item 1' },
{ title: 'item 2' },
{ title: 'item 3' },
{ title: 'item 4' },
{ title: 'item 5' },
{ title: 'item 6' }
]
}
},
components: {
Item
}
}
</script>
Item.vue component:
<template>
<li class="item" #click="isActive = !isActive" :class="{ active: isActive }">{{ title }}</li>
</template>
<script>
export default {
name: 'ItemsList',
data() {
return {
isActive: false
}
},
props: {
title: String
}
}
</script>
<style>
.item.active {
color: red;
}
</style>
You might want to reconsider which component should be responsible of knowing which item is active at any point of time: hint: it should be the parent/consuming component. That is because you:
Have only a single input field, which means only one item can be edited at any point of time
You want to let the parent/consuming component to be the single source of truth of which item is actually active
Therefore, the first thing you should do is to ensure that isActive is a prop on the Item component, while the parent ItemList component keeps track of which is active at any point.
Then, it is simply a matter of:
Implementing a toggling logic for the isActive flag. The flag is updated when a native click event is fired from the Item component. For the toggling logic, we can simply toggle between a zero-based index of the click item, or -1, which we used to indicate that nothing is active.
Using v-bind:value and a computed property to reflect the value of the currently active item. We can simply retrieve it using this.items[this.activeIndex] on the parent component
Listening to the onInput event and then updating the correct item
See proof-of-concept below:
Vue.component('item-list', {
template: '#item-list-template',
data() {
return {
items: [{
title: 'item 1'
},
{
title: 'item 2'
},
{
title: 'item 3'
},
{
title: 'item 4'
},
{
title: 'item 5'
},
{
title: 'item 6'
}
],
activeIndex: -1,
}
},
methods: {
onItemClick(index) {
this.activeIndex = this.activeIndex === index ? -1 : index;
},
setActiveItemValue(event) {
const foundItem = this.items[this.activeIndex];
if (!foundItem) return;
return this.items[this.activeIndex].title = event.currentTarget.value;
}
},
computed: {
activeItemValue() {
return this.items[this.activeIndex]?.title ?? '';
}
}
});
Vue.component('item', {
template: '#item-template',
props: {
isActive: Boolean,
title: String
}
});
new Vue({
el: '#app'
});
li.active {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<item-list></item-list>
</div>
<script type="text/x-template" id="item-list-template">
<div>
<input type="text" placeholder="Edit selected items" :value="activeItemValue" #input="setActiveItemValue" />
<div class="items-col">
<ul class="items-list">
<item v-for="(item, i) in items" :key="i" :title="item.title" :isActive="activeIndex === i" #click.native="onItemClick(i)" />
</ul>
</div>
</div>
</script>
<script type="text/x-template" id="item-template">
<li class="item" :class="{ active: isActive }">{{ title }}</li>
</script>
If you want a solution with your current components (not the cleanest) , you can actually emit an event to the parent component when you activate an element that event should containe the index of the object in the items array
Then you can use the index to get and set the title variable , here is an example :
Item.vue
<template>
<li class="item" #click="activateItem" :class="{ active: isActive }">{{ title }}</li>
</template>
<script>
export default {
name: 'ItemsList',
data() {
return {
isActive: false
}
},
methods:{
activateItem() {
this.isActive = !this.isActive
this.$emit('activatedItem', this.isActive ? this.index : null)
}
},
props: {
title: String,
index: Number
}
}
</script>
<style>
.item.active {
color: red;
}
</style>
ItemList.vue
<template>
<div>
<input type="text" placeholder="Edit selected items" #input="inputChange" :value="inputValue"/>
<div class="items-col">
<ul class="items-list">
<Item v-for="(item, index) in items" :key="index" :title="item.title" :index="index" #activatedItem="itemSelected"/>
</ul>
</div>
</div>
</template>
<script>
import Item from '#/components/Item.vue'
export default {
data() {
return {
items: [
{ title: 'item 1' },
{ title: 'item 2' },
{ title: 'item 3' },
{ title: 'item 4' },
{ title: 'item 5' },
{ title: 'item 6' }
],
selectedIndex: null,
inputValue: ''
}
},
methods:{
itemSelected(index){
this.selectedIndex = index;
if(this.selectedIndex != null) {
this.inputValue = this.items[this.selectedIndex].title;
}
},
inputChange(event){
this.inputValue = event.target.value;
if(this.selectedIndex != null){
this.items[this.selectedIndex].title = this.inputValue
}
}
},
components: {
Item
}
}
</script>
You should also be aware that with the component Item you have given you can select more than one item !
I am using Bootstrap Vue to build a reusable Drowndown component. I would like to dynamically render different elements: item, title, and divider. How can I do this?
So what I want to achieve is the Dropdown component like this:
<template>
<b-dropdown>
<b-dropdown-{{option.element}}
v-bind:key="index"
v-for="option in data"
:value="option.id"
>{{ option.value }}</b-dropdown-{{option.element}}
>
</b-dropdown>
</template>
<script>
export default {
name: 'Dropdown',
props: {
data: data
}
}
</script>
So that it would render like
<b-dropdown-title>I am a title</b-dropdown-title>
<b-dropdown-item>And I am an item</b-dropdown-item>
<b-dropdown-item>I am another item</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
Then from the parent component, I could pass data like:
<Dropdown id="modules-dropdown" v-data="data"></Dropdown>
import Dropdown from './Dropdown'
const dropdownData = [{id: 1, value: 'I am a title', element: 'title'}, {id: 2, value: 'And I am an item', element: 'item'}, {id: 3, value: 'I am another item', element: 'item'}, {id: 4, element: 'divider'}]
export default {
name: 'ParentComponent',
components: {
Dropdown
},
data () {
return {
data: dropdownData,
}
},
}
What you want is a Dynamic Component, which allows you to define which component should be rendered using the is prop.
new Vue({
el: '#app',
data() {
return {
options: [
{ value: "Hello", element: 'header' },
{ value: "Item 1", element: 'item' },
{ value: "Item 2", element: 'item' },
{ value: null, element: 'divider' },
{ value: "Item 3", element: 'item' },
{ value: "Item 4", element: 'item' }
]
}
}
})
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.17.3/dist/bootstrap-vue.js"></script>
<link href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.17.3/dist/bootstrap-vue.css" rel="stylesheet" />
<div id="app">
<b-dropdown text="Dropdown">
<component
:is="`b-dropdown-${option.element}`"
v-for="(option, index) in options"
:key="index"
>
{{ option.value }}
</component>
</b-dropdown>
</div>
Using vue, I display my database in a table.
My table contains a lot of rows. Therefore, I use pagination.
Using the select function, I can select multiple rows and store them in an array.
The problem:
I select some rows in my table. The data from the row is stored in my array called selected. I let them appear next to my table.
Using pagination, I go to the next page. My data is still stored in this array. When I now select another row. My array is emptied,
my data from my section is gone.
How can I solve this? Why does this happen? Is there a way to store this data so it isn't lost?
Did I miss something?
Bellow, you find my code. Thanks for the help.
Vue code
<!-- Main table -->
<b-row align-v="start">
<b-col sm="8">
<b-table class="col-sm-12"
show-empty
striped hover
selectable
stacked="md"
:items="values"
:fields="fields"
:select-mode="selectMode"
:current-page="currentPage"
:filter="valueSearch"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:sort-direction="sortDirection"
#filtered="onFiltered"
#row-selected="rowSelected"
<template slot="name" slot-scope="row">
{{row.item.name}}
</template>
<template slot="id" slot-scope="row">
{{ row.item.id }}
</template>
<template slot="ref" slot-scope="row">
{{row.item.ref}}
</template>
<template slot="specific" slot-scope="row">
{{row.item.specific}}
</template>
<template slot="iso" slot-scope="row">
{{row.item.iso}}
</template>
<template slot="tax" slot-scope="row">
{{row.item.tax}}
</template>
<template slot="amount" slot-scope="row">
<span class='dot largerSize' :class="statusColor[range(row.item.amount)]"></span>
</template>
</b-table>
</b-col>
<b-col sm="4">
Here comes the value selected.
<div v-for="selectedvalue in selected" :key="selectedvalue.id">
{{ selectedvalue.id }} - {{selectedvalue.name}}
{{selected}}
</div>
</b-col>
</b-row>
<!-- How is sorted? & Pagnation -->
<b-row align-v="end" class="mb-2">
<b-col>
Sorting By: <b>{{ sortBy | capitalize }}</b>, Sort Direction:
<b>{{ sortDesc ? 'Descending' : 'Ascending' }}</b>
</b-col>
<b-col>
<b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage" class="my-0"></b-pagination>
</b-col>
<b-col>One of three columns</b-col>
</b-row>
Javascript
<script>
export default {
props: ['valuedata','minamount','maxamount'],
data() {
return {
values: this.valuedata,
statusColor: ["red","orange","green"],
totalRows: 1,
currentPage: 1,
perPage: 10,
pageOptions: [5, 10, 20, 50,100],
sortBy: "id",
sortDesc: false,
sortDirection: 'asc',
filter: null,
selectMode: 'multi',
fixed: true,
selected: [],
fields: {
id: {
label: "Id",
sortable: true
},
name: {
label: "Name",
sortable: true
},
ref: {
label: "Ref",
sortable: true
},
iso: {
label: "Iso",
sortable: true
},
tax: {
label: "Tax",
sortable: true
},
specific: {
label: "specific",
sortable: true
},
amount: {
label: "amount",
sortable: true
}
}
}
},
computed:{
hits: function(){
var hits = this.values.length
return hits
}
},
mounted () {
this.totalRows = this.values.length
},
methods: {
onFiltered(filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.totalRows = filteredItems.length
this.currentPage = 1
},
// Option: enables the storage of selected rows
rowSelected(items){
console.log(items[0].name)
this.selected = items
},
// Function: color code amount
range: function(x){
if (x < this.minamount){
return 0;
}else if(x >= this.minamount && x <= this.maxamount ){
return 1;
}else if(x >= this.maxamount ){
return 2;
}
}
},
filters: {
// Function: captitalize the first letter
capitalize: function (value) {
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
}
From my understanding, you replace all items in selected :
// Option: enables the storage of selected rows
rowSelected(items){
console.log(items[0].name)
this.selected = items
},
What you want to do is adding values, not replacing them, so IMHO what you should is something like :
// Option: enables the storage of selected rows
rowSelected(items){
console.log(items[0].name)
items.forEach(item => {
const selectedIds = this.selected.map(selectedItem => selectedItem.id);
// I guess you don't want twice the same item in your array
if (!selectedIds.includes(item.id) {
this.selected.push(item)
}
})
},