How to "stop" an event? - vue.js

I'm learning a Vuetifyjs and try writing a "file explorer".
There is an example:
codepen-snippet
I can’t understand how to make sure that when you click on the right icon, the entry in the "tree" does not become "active".
Probably need to “stop” the events, but I don’t know how to do it.
Tell me.
Thank.
I want to click on this menu: Menu
it became like this: need
not like now: now
Snippet:
<div id="app">
<v-app id="inspire">
<v-content>
<v-container >
<v-layout justify-center>
<v-card min-width=400>
<v-treeview
v-model="tree"
:open="open"
:items="items"
activatable
hoverable
item-key="name"
open-on-click
>
<template v-slot:prepend="{ item, open }">
<v-icon v-if="!item.file">
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
</v-icon>
<v-icon v-else>
{{ files[item.file] }}
</v-icon>
</template>
<template v-slot:label="{item}">
<v-hover v-slot:default="{ hover }">
<div class="d-flex align-center">
<span>{{item.name}}</span>
<v-menu
class="ml-auto"
style="display: inline"
:nudge-width="200"
offset-y
>
<template v-slot:activator="{ on }">
<!--
-->
<v-btn
v-show="hover"
icon
small
v-on="on"
class="pa-0 ma-0"
>
<v-icon small class="pa-0 ma-0">more_vert</v-icon>
</v-btn>
</template>
<v-card>
<v-list>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>mdi-information-variant</v-icon>
</v-list-item-action>
<v-list-item-title>Info</v-list-item-title>
</v-list-item>
<v-list-item v-if="item.type === 'process' || item.type === 'state'" #click="() => {}">
<v-list-item-action>
<v-icon>power_settings_new</v-icon>
</v-list-item-action>
<v-list-item-title>Status</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>create</v-icon>
</v-list-item-action>
<v-list-item-title>Rename</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>file_copy</v-icon>
</v-list-item-action>
<v-list-item-title>Copy</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>mdi-folder-plus</v-icon>
</v-list-item-action>
<v-list-item-title>Create folder</v-list-item-title>
</v-list-item>
<v-list-item #click="() => {}">
<v-list-item-action>
<v-icon>delete</v-icon>
</v-list-item-action>
<v-list-item-title>Delete</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</div>
</v-hover>
</template
</v-treeview>
</v-card
</v-layout justify-center>
</v-container>
</v-content>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
open: ['public'],
files: {
html: 'mdi-language-html5',
js: 'mdi-nodejs',
json: 'mdi-json',
md: 'mdi-markdown',
pdf: 'mdi-file-pdf',
png: 'mdi-file-image',
txt: 'mdi-file-document-outline',
xls: 'mdi-file-excel',
},
tree: [],
items: [
{
name: '.git',
},
{
name: 'node_modules',
},
{
name: 'public',
children: [
{
name: 'static',
children: [{
name: 'logo.png',
file: 'png',
}],
},
{
name: 'favicon.ico',
file: 'png',
},
{
name: 'index.html',
file: 'html',
},
],
},
{
name: '.gitignore',
file: 'txt',
},
{
name: 'babel.config.js',
file: 'js',
},
{
name: 'package.json',
file: 'json',
},
{
name: 'README.md',
file: 'md',
},
{
name: 'vue.config.js',
file: 'js',
},
{
name: 'yarn.lock',
file: 'txt',
},
],
}),
})

What is happening here is that your click event is propagating to its parent element, so when you click on the icon to display the menu it also triggers the click event of your parent element which is the file or folder container.
You can add #click.stop to your v-btn in line 44, like this:
<template v-slot:activator="{ on }">
<!--
-->
<v-btn
v-show="hover"
icon
small
v-on="on"
class="pa-0 ma-0"
#click.stop
>
<v-icon small class="pa-0 ma-0">more_vert</v-icon>
</v-btn>
</template>
This will stop the event from propagating to its parent element, you can try it out here: codepen-snippet
Now when you click the button it will display your menu and won't change the active or inactive state on your files or folders.

To remove the blue highlighting of items when clicked, remove "activatable" from the v-treeview component:
<v-treeview
v-model="tree"
:open="open"
:items="items"
activatable
hoverable
item-key="name"
open-on-click >

Related

Keep v-menu open state when the activator is pressed again

I'm trying to make a custom v-autocomplete using v-text-field and v-menu.
What confuses me is that v-menu closes when you click on the v-text-field again. The first click on the v-text field opens the v-menu, and the second click closes it. I couldn't find any property that turns off toggle mode.
Although, if you look at the html markup, v-menu is used in the v-select and v-autocomplete components, which close when you click on the content or outside the menu.
Codepen
<template>
<div id="app">
<v-app id="inspire">
<div class="text-center">
<v-main>
<v-container>
<v-row>
<v-col cols="3">
<v-menu bottom offset-y max-height="304px">
<template v-slot:activator="{ on, attrs }">
<v-text-field v-model="model && model.title"
dense color="primary"
v-bind="attrs" v-on="on"
label="Choose" outlined>
</v-text-field>
</template>
<v-list dense>
<v-list-item-group v-model="model"
color="primary">
<v-list-item v-for="(item, index) in items"
:key="item.id" :value="item"
dense>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list-item-group>
</v-list>
</v-menu>
</v-col>
</v-row>
</v-container>
</v-main>
</div>
</v-app>
</div>
</template>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [
{id:1, title: 'Click Me 1' },
{id:2, title: 'Click Me 2' },
{id:3, title: 'Click Me 3' },
{id:4, title: 'Click Me 4' },
],
model: null
}),
})
</script>

Vuetify: My navigation drawer is positioned over another element (toolbar)

I would like to put my navigation drawer under the toolbar.
I'm trying to achieve something like this :
I am trying to do something similar but all attempts are unsuccessful, at the moment I have the following:
My code:
<template>
<nav>
<v-snackbar v-model="snackbar" :timeout="4000" top color="success">
<span>Awesome! You added a new project.</span>
<v-btn text flat #click="snackbar = false">Close</v-btn>
</v-snackbar>
<v-toolbar app clipped-left >
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title class="text-uppercase gr ey--text">
<span class="font-weight-light">estudos</span>
<span>vue</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn text
color="primary"
dark
v-bind="attrs"
v-on="on"
>
<v-icon left>expand_more</v-icon>
<span>Menu</span>
</v-btn>
</template>
<v-list>
<v-list-item v-for="link in links" :key="link.text" router :to="link.route">
<v-list-item-title>{{link.text}}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn text color="grey">
<span>Sign Out</span>
<v-icon right>exit_to_app</v-icon>
</v-btn>
</v-toolbar>
<v-navigation-drawer v-model="drawer" app class="indigo white--text">
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-layout column align-center>
<v-flex class="mt-5">
<v-avatar size="90">
<img src="/avatar-64.png">
</v-avatar>
<p class="white-text dubheading mt-1">
Estudos Vue
</p>
</v-flex>
<v-flex class="mt-4 mb-3">
<popup #projectAdded="snackbar=true" />
</v-flex>
</v-layout>
<v-list >
<v-divider></v-divider>
<v-list-item
v-for="link in links"
:key="link.text"
router :to="link.route"
>
<v-list-item-action >
<v-icon class="white--text">{{ link.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content class="white--text">
<v-list-item-title>{{ link.text }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-row>
<v-col
>
<v-img
max-height="76%"
max-width="100%"
src="/imgtest.jpg"
gradient="to top right, rgba(14,12,11,.51), rgba(14,12,11,.71)"
>
<v-img-title class="heading white--text">
Bien saude</v-img-title></v-img>
</v-col>
</v-row>
</nav>
</template>
<script>
import Popup from './Popup'
export default {
components: { Popup },
data() {
return {
drawer:false,
links:[
{icon: 'dashboard', text:'Dashboard', route:'/'},
{icon: 'folder', text:'My Projects', route:'/projects'},
{icon: 'person', text:'Team', route:'/team'},
],
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
snackbar: true
}
},
}
</script>
I tried adding Block and removing the app, but it didn't solve the problem...
How do I put my drawer under the toolbar?
Add clipped to v-navigation-drawer props like:
<v-navigation-drawer
clipped>
<!-- ... -->
</v-navigation-drawer>
I would suggest following vuetify.js' default markup first.
Then you'll supposed to use clipped property in the <v-navigation-drawer> element like #mamadou-hady-barry already described. (<v-navigation-drawer clipped app>).
Secondly add the 'clipped-left' to the <v-app-bar> element resulting in: <v-app-bar clipped-left app>.
You are currently using <v-toolbar> which does not have a clipped-left property according to their "API".

How can I use bottom navigation and navigation drawers together? v-app doesn't work

I am new to vuetify and vue, I want to create a layout in which the users with sm or smaller screens will use the bottom-navigation component and the users with md or higher will use the navigation drawers.
I am using the v-app component, that according to the docs "help bootstrap your application with the proper sizing around component" and "These (components) can be mixed and matched and only one of each particular component should exist at any time."
<template>
<v-app>
<v-navigation-drawer app>
<v-list rounded>
<v-subheader>REPORTS</v-subheader>
<v-list-item-group v-model="item" color="primary">
<v-list-item v-for="(item, i) in items" :key="i">
<v-list-item-icon>
<v-icon v-text="item.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="item.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
<v-app-bar app>
<v-toolbar-title class="headline text-uppercase">
<span>Vuetify</span>
<span class="font-weight-light">MATERIAL DESIGN</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn text href="https://github.com/vuetifyjs/vuetify/releases/latest" target="_blank">
<span class="mr-2">Latest Release</span>
</v-btn>
</v-app-bar>
<v-content fluid>
<HelloWorld />
</v-content>
<v-bottom-navigation app>
<v-btn value="recent">
<span>Recent</span>
<v-icon>history</v-icon>
</v-btn>
<v-btn value="favorites">
<span>Favorites</span>
<v-icon>favorite</v-icon>
</v-btn>
<v-btn value="nearby">
<span>Nearby</span>
<v-icon>place</v-icon>
</v-btn>
</v-bottom-navigation>
</v-app>
</template>
<script lang="ts">
import Vue from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default Vue.extend({
name: "App",
components: {
HelloWorld
},
data: () => ({
item: 1,
items: [
{ text: "Real-Time", icon: "mdi-clock" },
{ text: "Audience", icon: "mdi-account" },
{ text: "Conversions", icon: "mdi-flag" }
]
})
});
</script>
So the documentation it's perhaps a bit unclear from the text.
It's up to you to display them as you see fit. But you should for example not have two v-app-bars visible at the same time.
So here is the solution:
<template>
<v-app>
<v-navigation-drawer app v-model="$vuetify.breakpoint.mdAndUp" stateless class="hidden-sm-and-down">
<v-list rounded>
<v-subheader>REPORTS</v-subheader>
<v-list-item-group v-model="item" color="primary">
<v-list-item v-for="(item, i) in items" :key="i">
<v-list-item-icon>
<v-icon v-text="item.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="item.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
<v-app-bar app class="hidden-sm-and-down">
<v-toolbar-title class="headline text-uppercase">
<span>Vuetify</span>
<span class="font-weight-light">MATERIAL DESIGN</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn text href="https://github.com/vuetifyjs/vuetify/releases/latest" target="_blank">
<span class="mr-2">Latest Release</span>
</v-btn>
</v-app-bar>
<v-content fluid>
<HelloWorld />
</v-content>
<v-bottom-navigation app class="d-flex d-md-none">
<v-btn value="recent">
<span>Recent</span>
<v-icon>history</v-icon>
</v-btn>
<v-btn value="favorites">
<span>Favorites</span>
<v-icon>favorite</v-icon>
</v-btn>
<v-btn value="nearby">
<span>Nearby</span>
<v-icon>place</v-icon>
</v-btn>
</v-bottom-navigation>
</v-app>
</template>
<script lang="ts">
import Vue from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default Vue.extend({
name: "App",
components: {
HelloWorld
},
data: () => ({
item: 1,
items: [
{ text: "Real-Time", icon: "mdi-clock" },
{ text: "Audience", icon: "mdi-account" },
{ text: "Conversions", icon: "mdi-flag" }
]
})
});
</script>

Vueutify Navigation Drawer - Change Background Image

Hi I am learning vuetify and I want to change the background of a navigation drawer that I imported from vuetify default layout template.
The tamplate was found and imported on official vuetify docs.
The problem is I am unable to change the background of the drawer and set it to image
This is the Default layout with drawer
<template>
<v-app
id="inspire"
dark
>
<v-navigation-drawer
v-model="drawer"
fixed
clipped
app
>
<v-list dense>
<v-list-tile v-for="item in items" :key="item.text" #click="">
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-subheader class="mt-3 grey--text text--darken-1">SUBSCRIPTIONS</v-subheader>
<v-list>
<v-list-tile v-for="item in items2" :key="item.text" avatar #click="">
<v-list-tile-avatar>
<img :src="`https://randomuser.me/api/portraits/men/${item.picture}.jpg`" alt="">
</v-list-tile-avatar>
<v-list-tile-title v-text="item.text"></v-list-tile-title>
</v-list-tile>
</v-list>
<v-list-tile class="mt-3" #click="">
<v-list-tile-action>
<v-icon color="grey darken-1">add_circle_outline</v-icon>
</v-list-tile-action>
<v-list-tile-title class="grey--text text--darken-1">Browse Channels</v-list-tile-title>
</v-list-tile>
<v-list-tile #click="">
<v-list-tile-action>
<v-icon color="grey darken-1">settings</v-icon>
</v-list-tile-action>
<v-list-tile-title class="grey--text text--darken-1">Manage Subscriptions</v-list-tile-title>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar
color="red"
dense
fixed
clipped-left
app
>
<v-toolbar-side-icon #click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-icon class="mx-3">fab fa-youtube</v-icon>
<v-toolbar-title class="mr-5 align-center">
<span class="title">Youtube</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-layout row align-center style="max-width: 650px">
<v-text-field
:append-icon-cb="() => {}"
placeholder="Search..."
single-line
append-icon="search"
color="white"
hide-details
></v-text-field>
</v-layout>
</v-toolbar>
<v-content>
<v-container fill-height>
<v-layout justify-center align-center>
<v-flex shrink>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn :href="source" icon large target="_blank" v-on="on">
<v-icon large>code</v-icon>
</v-btn>
</template>
<span>Source</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn icon large href="https://codepen.io/johnjleider/pen/YeRKwQ" target="_blank" v-on="on">
<v-icon large>mdi-codepen</v-icon>
</v-btn>
</template>
<span>Codepen</span>
</v-tooltip>
</v-flex>
</v-layout>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
data: () => ({
drawer: null,
items: [
{ icon: 'trending_up', text: 'Most Popular' },
{ icon: 'subscriptions', text: 'Subscriptions' },
{ icon: 'history', text: 'History' },
{ icon: 'featured_play_list', text: 'Playlists' },
{ icon: 'watch_later', text: 'Watch Later' }
],
items2: [
{ picture: 28, text: 'Joseph' },
{ picture: 38, text: 'Apple' },
{ picture: 48, text: 'Xbox Ahoy' },
{ picture: 58, text: 'Nokia' },
{ picture: 78, text: 'MKBHD' }
]
}),
props: {
source: String
}
}
</script>
I am expecting apply the background image to drawer, example : https://cdn.vuetifyjs.com/images/backgrounds/bg-2.jpg
I tried to use in my drawer src atribute :
<v-navigation-drawer
v-model="drawer"
fixed
clipped
app
src="https://cdn.vuetifyjs.com/images/backgrounds/bg-2.jpg"
>
But that is not working, also I tried wrapping drawer in Div and accessing the class with scoped css but without any success.
There is a backgrounds ready component for drawers at official vuetify codepen : https://codepen.io/pen/?&editable=true&editors=101
that shows using src atribute.
But for some reason it is not working with this example.
Vuetify v1
Codepen
src property does not exist in v1 Navigation drawer
docs, so probably the way to go is just put v-img with 100% height inside the drawer:
<v-navigation-drawer>
<v-img
src="https://cdn.vuetifyjs.com/images/backgrounds/bg-2.jpg"
height="100%"
>
Vuetify v2
Codepen
In Vuetify v2 Navigation drawer
docs it has src property, so it works like so:
<v-navigation-drawer src="https://cdn.vuetifyjs.com/images/backgrounds/bg-2.jpg">

How to get values of an item in the loop in Vue?

Problem:
I'm trying to figure out how to pass a value of a clicked item into another component
See codepen: https://codepen.io/anon/pen/zRXBNY
In the codepen menu of an item is triggered by right click
Let's say we have a loop (this iterator component) that's displaying all the items of object items
<v-data-iterator
:items="items"
hide-actions
class="ma-4"
>
<v-flex
slot="item"
slot-scope="props"
xs12 sm6 md4 lg3
>
<v-card #contextmenu="show" class="ma-3 elevation-4">
<v-card-title>
<h4>{{ props.item.name }}</h4>
</v-card-title>
</v-card>
</v-flex>
</v-data-iterator>
And we also have this "menu" component in the same .vue component:
<v-menu
absolute
offset-y
:position-x="x"
:position-y="y"
v-model="showMenu"
>
<v-list>
<p class="white ma-3">menu for item: [TITLE]</p>
<v-list-tile
v-for="item in menuItems"
:key="item.title" #click=""
>
<v-list-tile-title>
{{ item.title }}
</v-list-tile-title>
</v-list-tile>
<v-text-field
class="ma-3"
label="rename">
</v-text-field>
</v-list>
</v-menu>
Question:
How do we trigger the menu component and pass the data of that particular item in it (so that we can do something with it)? As an example I put this menu for item: [TITLE] paragraph there, I don't understand how do we pass the title of the clicked item there?
It seem a bit messy to me (i'm not very familiar with Vuetify), but the first solution that comes to my mind is to pass item object to the handler. So your code goes as:
<v-card #contextmenu="show($event, props.item)" class="ma-3 elevation-4"></v-card>
Then once the event is fired and handler function is called you can store the item you clicked on:
show (e, item) {
this.selectedItem = item;
e.preventDefault()
// ...
Now you can use the item inside the model component as:
<v-list>
<p class="white ma-3">
menu for item: {{selectedItem.name}}
</p>
//...
Full demo:
new Vue({
el: '#app',
methods: {
show (e, item) {
this.selectedItem = item;
e.preventDefault()
this.showMenu = false
this.x = e.clientX
this.y = e.clientY
this.$nextTick(() => {
this.showMenu = true
})
}
},
data: () => ({
x: 0,
y: 0,
selectedItem: {},
showMenu: false,
menuItems: [
{ title: 'copy' },
{ title: 'paste' },
{ title: 'delete' }
],
items: [
{
value: false,
name: 'Frozen Yogurt'
},
{
value: false,
name: 'Ice cream sandwich'
},
{
value: false,
name: 'Eclair'
},
{
value: false,
name: 'Cupcake'
}
]
})
})
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
<div id="app" >
<v-app id="inner" class="grey lighten-3">
<h1 class="ma-2 ml-4">right click on an item to trigger menu</h1>
<!-- ITEMS ON THE PAGE -->
<v-data-iterator
:items="items"
hide-actions
class="ma-4"
>
<v-flex
slot="item"
slot-scope="props"
xs12 sm6 md4 lg3
>
<v-card #contextmenu="show($event, props.item)" class="ma-3 elevation-4">
<v-card-title>
<h4>{{ props.item.name }}</h4>
</v-card-title>
</v-card>
</v-flex>
</v-data-iterator>
<!-- MENU COMPONENT -->
<v-menu
absolute
offset-y
:position-x="x"
:position-y="y"
v-model="showMenu"
>
<v-list>
<p class="white ma-3">menu for item: {{selectedItem.name}}</p>
<v-list-tile
v-for="item in menuItems"
:key="item.title" #click=""
>
<v-list-tile-title>
{{ item.title }}
</v-list-tile-title>
</v-list-tile>
<v-text-field
class="ma-3"
label="rename">
</v-text-field>
</v-list>
</v-menu>
</v-app>
</div>