Change the background color of a list item in Vuetify - vue.js

I have a dynamically created list that I want to be able to add a click event to. Clicking on a list item should turn the background color green. Clicking it again would remove the green.
The problem I am having is turning a individual list item green and not the whole list. I have tried adding a index to each item, which works in turning the list item green, but doesn't stay green once I click another list item.
Here is the code I have.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selected: -1,
isLoading: true,
bool: true,
isActive: false,
items: [
{
icon: "print",
iconClass: "grey lighten-1 white--text",
title: "Printers",
subtitle: "MHC PDF Pro",
subtitle2: "HP LaserJet P4015 UPD PCL 6",
subtitle3: "RICOH Africo MP C3001"
},
{
icon: "email",
iconClass: "grey lighten-1 white--text",
title: "Email",
subtitle: "s.miller#mhc.com",
subtitle2: "hr#mhc.com",
subtitle3: "payroll#mhc.com"
},
{
icon: "mdi-fax",
iconClass: "grey lighten-1 white--text",
title: "Fax",
subtitle: "612-555-5555",
subtitle2: "952-555-5555",
subtitle3: "763-555-5555"
},
{
icon: "mdi-inbox-arrow-up",
iconClass: "grey lighten-1 white--text",
title: "File Transfer",
subtitle: "Text",
subtitle2: "CSV"
},
{
icon: "mdi-file-pdf",
iconClass: "grey lighten-1 white--text",
title: "PDF Creation"
}
]
}),
methods: {
changeColor() {
this.isLoading = !this.isLoading;
},
one() {
this.bool = !this.bool;
this.isActive = true
console.log('one');
},
two() {
this.bool = !this.bool;
this.isActive = false
console.log('two');
}
},
})
.active {
background: rgb(17, 128, 17);
}
.is-green {
background: #4caf50 !important;
}
.is-gray {
background: #505050 !important;
}
<html>
<head>
<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#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-card>
<v-toolbar color="#1f497d" dark dense>
<v-toolbar-title>My processes</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-list two-line subheader>
<v-list-item v-for="(item ) in items" #click="bool ? one() : two()" v-bind:class="{ active: isActive}" :key="item.title">
<v-list-item-avatar>
<v-icon
dark
:class="{'is-gray': isLoading, 'is-green': !isLoading }"
v-text="item.icon"
></v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.title"></v-list-item-title>
<v-list-item-subtitle v-text="item.subtitle"></v-list-item-subtitle>
<v-list-item-subtitle v-text="item.subtitle2"></v-list-item-subtitle>
<v-list-item-subtitle v-text="item.subtitle3"></v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn #click="printWindow()">
Setup
<!-- <v-icon color="grey lighten-1">mdi-information</v-icon> -->
</v-btn>
</v-list-item-action>
</v-list-item>
<v-divider inset></v-divider>
<v-subheader inset>
<v-checkbox #change="changeColor()" label="Send all documents to processes above"></v-checkbox>
<v-spacer></v-spacer>
<v-btn color="success" class="mr-4" #click="printWindow()">OK</v-btn>
<v-btn color="error" class="mr-4" v-on:click="printerHidden = !printerHidden">Cancel</v-btn>
</v-subheader>
</v-list>
<v-subheader inset>
</v-subheader>
</v-card>
</v-content>
</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>
</body>
</html>

You could use an array of activeItems and a toggle method like...
toggleActive(idx) {
let pos = this.activeItems.indexOf(idx)
pos === -1 ? this.activeItems.push(idx) : this.activeItems.splice(pos,1)
}
Then check if the item is in the array of activeItems...
<v-list two-line subheader>
<v-list-item v-for="(item,idx) in items"
#click="toggleActive(idx)"
:class="{active: activeItems.indexOf(idx)>-1}"
:key="item.title">...
</v-list-item>
</v-list>
Demo

Related

How to modify Vuetify's auto-generated CSS

What I'm Using
Vuetify 2.5.6
The Problem
I'm trying to disable an odious scroll bar
But can't quite figure out how to destroy it (and its ilk). Every suggestion I've tried still yields a Vuetify auto-generated class "v-navigation-drawer__content" that has overflow-y: auto;.
I'd like to learn how to modify the default behavior of these Vuetify-generated CSS files (for this issue and for future ones).
What I've Tried
I've tried:
adding style="overflow: hidden;" to the v-navigation-bar tag.
modifying adding .v-navigation-drawer__content { overflow: hidden !important } to the style section in the view component.
adding the following CSS and also adding mounted() and destroyed() hooks from this answer
Minimal Reproducible Example
<template>
<v-navigation-drawer
app
clipped
class="side-nav-bar"
permanent>
<v-menu
bottom
offset-y>
<template v-slot:activator="{ on, attrs }">
<v-list-item
two-line
v-bind="attrs"
v-on="on">
<v-list-item-avatar>
<v-img src="https://randomuser.me/api/portraits/women/85.jpg"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title class="text-h6">Sandra Adams</v-list-item-title>
<v-list-item-subtitle>sandra_a88#gmail.com</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</template>
<v-list>
<v-list-item
v-for="(workspace, i) in workspaces"
:key="i"
#click="changeWorkspaces(workspace)">
<v-list-item-title>{{ workspace.title }}</v-list-item-title>
</v-list-item>
<v-divider />
<v-list-item
#click="createNewWorkspace">
<v-list-item-title>Create Workspace</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-divider />
<v-list
nav
dense
v-for="(item, i) in sideNavOptions"
:key="i">
<v-list-item
v-if="!item.subList"
:key="item.title"
:to="item.link">
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-title class="title-bold">{{ item.title }}</v-list-item-title>
</v-list-item>
<v-list-group
v-else
:key="item.title"
:prepend-icon="item.icon"
no-action>
<template v-slot:activator>
<v-list-item>
<v-list-item-content>
<v-list-item-title class="title-bold">{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
<v-list-item
v-for="sublist in item.subList"
:to="sublist.link"
:key="sublist.title">
<v-list-item-title>{{ sublist.title }}</v-list-item-title>
</v-list-item>
</v-list-group>
</v-list>
</v-navigation-drawer>
</template>
<script>
export default {
name: "SideNavBar",
data() {
return {
workspaces: [],
sideNavOptions:[
{ title: "Dashboard", icon: "mdi-monitor-dashboard", link: "/dashboard" },
{
title: "Workflow",
icon: "mdi-cog",
subList: [
{ title: "Inbox", link: "/workflows/inbox" },
{ title: "Action Required", link: "/workflows/action_required" },
{ title: "Waiting for Others", link: "/workflows/waiting_for_others" },
{ title: "Approved", link: "/workflows/approved" },
{ title: "Sent", link: "/workflows/sent" },
{ title: "Completed", link: "/workflows/completed" },
]
},
{
title: "Templates",
icon: "mdi-cog",
subList: [
{ title: "Placeholder", link: "/templates/placeholder" }
]
},
{
title: "Contacts",
icon: "mdi-cog",
subList: [
{ title: "Placeholder", link: "/contacts/placeholder" }
]
},
{
title: "Settings",
icon: "mdi-cog",
subList: [
{ title: "Workspace Settings", link: "/settings/workspace" },
{ title: "Company Settings", link: "/settings/company" },
{ title: "Department Settings", link: "/settings/department" }
]
},
{ title: "Reminders", icon: "mdi-cog", link: "/reminders" }
]
}
},
async beforeMount() {
await this.getUserWorkspaces()
},
methods: {
changeWorkspaces(workspace) {
console.log(workspace)
},
createNewWorkspace() {
console.log("Creating new workspace")
},
async getUserWorkspaces() {
console.log("Getting user workspaces")
this.workspaces = [ { title: "Placeholder_1" }, { title: "Placeholder_2" } ]
}
}
}
</script>
<style lang="sass" scoped>
.side-nav-bar {
overflow: hidden !important;
color: $white !important;
background: $light_gray !important;
}
.v-navigation-drawer.v-navigation-drawer__content {
overflow: hidden !important;
}
</style>
Thanks in advance for any help!
Adding .v-navigation-drawer__content { overflow: hidden !important } should work but it's not working, because you are trying to change the style of a component which not a part of your current component using scoped css.
Try to remove scoped from your <style> and it will work. I usually create a global stylesheet and add it in App.vue file and make changes in that file.
Read more here about the scoped feature.

Vue / Vuetify 3 level nested lists

I'm new to Vuetify and I am trying to create a mobile navigation using nested lists. I am having an issue with the dropdown for the grandchildren data which is at the 3rd level of this nested list. With the code below the dropdown works for the children data but no dropdown appears for the grandchildren. I believe I am not nesting properly or my conditional isn't right. I reviewed Vuetify documentation and just couldn't figure this out.
<v-app>
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-navigation-drawer
v-model="drawer"
app
width="320px"
style="margin-top: 70px; background-color: #255e35"
class="text--white"
>
<v-list style="transform: translateX(0px)">
<div id="app">
<v-app>
<v-app-bar-nav-icon
#click.stop="drawer = !drawer"
></v-app-bar-nav-icon>
<v-navigation-drawer
v-model="drawer"
app
width="320px"
style="margin-top: 70px; background-color: #255e35"
class="text--white"
>
<v-list style="transform: translateX(0px)" class="top-level-list">
<template v-for="(link, i) in links">
<v-list-item v-if="!link.children" :key="i">
<v-list-item-title>{{ link.text }}</v-list-item-title>
</v-list-item>
<v-list-group v-else-if="link.children" :key="i"
><!--FIRST DROPDOWN-->
<template v-slot:activator>
<v-list-item-title>{{ link.text }}</v-list-item-title>
</template>
<template v-for="(child, j) in link.children">
<v-list-item v-if="!child.children" :key="j">
<v-list-item-title>{{ child.text }}</v-list-item-title>
</v-list-item>
<!--END OF FIRST SUBMENU-->
<v-list-group sub-group v-else :key="j">
<template v-slot:activator>
<v-list-item-title>{{ child.text }}</v-list-item-title>
</template>
<template v-for="(grandchild, k) in child.grandchildren">
<v-list-item v-if="!grandchild.grandchildren" :key="k">
<v-list-item-title>{{
grandchild.text
}}</v-list-item-title>
</v-list-item>
</template>
</v-list-group>
</template>
</v-list-group>
</template>
</v-list>
</v-navigation-drawer>
</v-app>
</div>
</v-list>
</v-navigation-drawer>
</v-app>
</template>
Below is how the data is structured
<script>
export default {
name: "App",
data() {
return {
drawer: false,
links: [
{
to: "/",
text: "Home",
active: false,
children: [
{
text: "Swag",
to: "/swag",
target: "_blank",
active: false,
},
{
text: "About Us",
to: "/about",
active: false,
},
{
text: "Contact - General Inquiries",
to: "/contact-general",
active: false,
},
{
text: "Contact - Advertising Inquiries",
to: "/contact-ad",
active: false,
},
{
text: "Submit An Article",
to: "/submit-article",
active: false,
},
],
},
{
to: "/events",
text: "Events",
active: false,
children: [
{
text: "Hunters Event",
to: "",
grandchildren: [ <----------GRANDCHILDREN------>
{
text: "Hunters",
to: "/events/view/hunters",
active: false,
},
{
text: "Exhibitor Information",
to: "/events/view/exhibitor",
active: false,
},
{
text: "3D Archery Tournament",
to: "/events/view/3d-archery",
active: false,
},
],
},
],
},
{
to: "/marketplace",
text: "Marketplace",
active: false,
children: [
{
text: "Land And Lease",
to: "/marketplace/category/land-and-lease",
active: false,
},
{
text: "Outdoor Gear",
to: "/marketplace/category/outdoor-gear",
active: false,
},
{
text: "Employment",
to: "/marketplace/category/employment",
active: false,
},
],
},
],
};
},
};
</script>

How can I make Vuetify mobile responsive navigation bar and linked drawer have NESTED menus?

I am making a navbar component through the Vue framework using Vuetify. I would like to make the products item have a drop down into two links.
This is the template html and script code (I have some additional custom CSS for color and such that I am not adding here):
<template>
<div>
<v-toolbar id="navbar" dense elevation=1 dark >
<v-app-bar-nav-icon class="hidden-md-and-up" #click="sidebar = !sidebar"></v-app-bar-nav-icon>
<v-navigation-drawer v-model="sidebar" app hide-overlay temporary>
<v-list>
<v-list-item v-for="(item, i) in menuItems" exact :key="i" :to="item.path">{{item.title}}</v-list-item>
</v-list>
</v-navigation-drawer>
<v-toolbar-items d-flex>
<v-btn href="#" id="logo" flat depressed text>Company Name</v-btn>
</v-toolbar-items>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-sm-and-down">
<v-btn text v-for="item in menuItems" :key="item.title">
<router-link :to="item.path">{{item.title}}</router-link>
</v-btn>
</v-toolbar-items>
</v-toolbar>
</div>
</template>
<script>
export default {
data: function() {
return {
sidebar: false,
menuItems: [
{ path: "/product", name: "product", title: "Product" },
{ path: "/us", name: "us", title: "Us" },
{ path: "resources", name: "resources", title: "Resources" },
{ path: "/portal", name: "login", title: "Login" }
]
};
}
};
</script>
How about app-bar?
v-menu tag support drop down
https://vuetifyjs.com/en/components/app-bars/#dense

Activity indicator not loading correctly in Vuetify

new Vue({
el: '#app',
vuetify: new Vuetify({
theme: {
dark: true
},
}),
data() {
return {
loading: null,
requests: [{"req_id":78},{"req_id":79}],
tableHeaders: [
{
text: 'ID',
value: 'req_id',
align: 'center',
},
{ text: 'Actions', value: 'action', sortable: false, align: 'center'},
],
createloading: false,
cancelloading: false,
};
},
methods: {
createPacks(item) {
this.loading = !this.loading;
item.createloading = true;
},
excludeRequest(item) {
this.loading =!this.loading;
item.createloading = false;
},
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
<div id="app">
<v-app>
<v-row no-gutters class="align-start justify-start">
<v-col>
<v-row>
<v-data-table
:headers="tableHeaders"
:items="requests"
:loading="loading"
>
<template v-slot:item.action="{ item }">
<v-btn color="success" #click="createPacks(item)" :loading="item.createloading" :disabled="item.createloading">Create</v-btn>
<v-btn color="error" #click="excludeRequest(item)" :loading="item.cancelloading" :disabled="!item.createloading">Cancel</v-btn>
</template>
</v-data-table>
</v-row>
</v-col>
</v-row>
</v-app>
</div>
Please help me implement this code correctly, as it does not function correctly. The buttons should correctly show the loading indicator and should be independent.
Thank you in advance for your generosity.
Below is a link to codepen.
https://codepen.io/protemir/pen/MWwGaeO

changing the background color of a v-list header

I am tying to change the color of a v-list header item. I seem to only be able to change the colour of the title but not the whole tile. Note that I need this to be reactive since the background color I am trying to change will not remain the same over time.
I have tried using the color property on the v-list-tile-content but it does not do anything. Then I tried the same on the v-list-tile-title but this only changes the title part not the action/avatar part
In other words it's like changing the colour of the Dining title in the following codepen https://codepen.io/patrick2009/pen/pmdgNz
<v-list-tile-content color="red">
<v-list-tile-title>{{ subItem.title }}</v-list-tile-title>
</v-list-tile-content>
Something like that would be nice!
Thanks guys,
Pat
EDIT: I have updated my answer to show how you can add css dynamically, using props.
Example:
const myList = {
template: "#my-list",
props: ["color", "hover"],
mounted() {
var css = `
.v-list__group__header {
background-color: ${this.color};
}
.v-list__group__header:hover {
background-color: ${this.hover} !important;
}
`;
var style = document.createElement("style");
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName("body")[0].appendChild(style);
},
data() {
return {
items: [{
action: "local_activity",
title: "Attractions",
items: [{
title: "List Item"
}]
},
{
action: "restaurant",
title: "Dining",
active: true,
items: [{
title: "Breakfast & brunch"
},
{
title: "New American"
},
{
title: "Sushi"
}
]
},
{
action: "school",
title: "Education",
items: [{
title: "List Item"
}]
},
{
action: "directions_run",
title: "Family",
items: [{
title: "List Item"
}]
},
{
action: "healing",
title: "Health",
items: [{
title: "List Item"
}]
},
{
action: "content_cut",
title: "Office",
items: [{
title: "List Item"
}]
},
{
action: "local_offer",
title: "Promotions",
items: [{
title: "List Item"
}]
}
]
};
}
};
new Vue({
el: "#app",
components: {
myList
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.5.14/vuetify.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<my-list color="red" hover="blue"></my-list>
</v-flex>
</v-layout>
</v-app>
</div>
<script type="text/x-template" id="my-list">
<v-card>
<v-toolbar color="teal" dark>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title>Topics</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon>more_vert</v-icon>
</v-btn>
</v-toolbar>
<v-list>
<v-list-group v-for="item in items" :key="item.title" v-model="item.active" :prepend-icon="item.action" no-action>
<template v-slot:activator>
<v-list-tile>
<v-list-tile-content>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template>
<v-list-tile v-for="subItem in item.items" :key="subItem.title" #click="">
<v-list-tile-content color="red">
<v-list-tile-title>{{ subItem.title }}</v-list-tile-title>
</v-list-tile-content>
<v-list-tile-action>
<v-icon>{{ subItem.action }}</v-icon>
</v-list-tile-action>
</v-list-tile>
</v-list-group>
</v-list>
</v-card>
</script>
[CodePen Mirror]
Old Answer:
Looks like you have to set this via css for that class.. The class you'll have to target is v-list__group__header.
EDIT: You can also use a :hover "event" to change the background-color on hover - unfortunately, this requires you to use the !important modifier, which is typically frowned upon. Figured I would mention it regardless.
.v-list__group__header:hover {
background-color: blue !important;
}