How to open new window with vvuetify v-icon vue router? - vuetify.js

I am trying to open a new page but it cannot. When I click on my home icon, it opens my home page and when click on dashboard it says
dashboard 'app' has been removed, use '' instead.
VToolbar>
at src/components/Navbar.vue
at src/App.vue
App.vue
template>
<nav>
<v-toolbar flat app>
<v-app-bar-nav-icon class="grey--text" #click="drawer =! drawer"></v-app-bar-nav-icon>
<v-toolbar-title class="text-uparcase grey--text">
<span class="font-weighted-light">Blue</span>
<span>Berry</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn flat color="grey">
<span>Home</span>
</v-btn>
</v-toolbar>
<v-navigation-drawer v-model="drawer" app class="indigo">
<v-list-item >
<v-list-item-content>
</v-list-item-content>
</v-list-item>
<v-divider></v-divider>
<v-list
dense
nav
>
<v-list-item
v-for="item in items"
:key="item.title"
router:to="item.route"
>
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
</nav>
</template>
<script>
export default {
data() {
return {
drawer:false,
items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard',route:'/' },
{ title: 'Photos', icon: 'mdi-image',route:'/photos'},
{ title: 'Home', icon: 'mdi-home' ,route:'/home'},
{ title: 'About', icon: 'mdi-help-box' ,route:'/about'}
],
right: null,
}
}
}
</script>

Try to nest every v-list items in a < router-link />
Like that
<router-link :to="{ name: item.title }">
<v-list-item>
...
</v-list-item>
</router-link>

Related

vuetifyjs v-list. If click to item second time item not active. v-model="undefined"

I use standard v-list component of vuetifyjs. For create menu and show list of items.
But if I click second time the active element is hide. And I don't see active element of menu. It is bad for my menu. Link for example v-list
If use pug template below
v-list(dense)
v-list-item-group(color="success" v-model="selectedItem")
v-list-item(v-for="(gallery, key) in galleries" :key="key")
v-list-item-content
v-list-item-title(v-text="gallery")
I have solution. It needs watch variable and set force index by key of clicked item. If we have 'undefined' set force data method
Run examle solution Solution
Code below:
<template>
<div id="app">
<v-app id="inspire">
<v-card max-width="300" >
<v-list dense>
<v-list-item-group
v-model="selectedItem"
color="primary"
>
<v-list-item
v-for="(item, i) in items"
:key="i"
>
<v-list-item-content #click="setItem(i)">
<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-card>
</v-app>
</div>
</template>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
index: 0,
selectedItem: 0,
items: [
{ text: 'Real-Time'},
{ text: 'Audience' },
{ text: 'Conversions'},
],
}),
watch: {
selectedItem() {
if (typeof this.selectedItem === 'undefined') {
setTimeout(() => {
this.selectedItem = this.index;
}, 500);
}
},
},
methods: {
setItem(index) {
this.index = index;
},
},
})
Another solution would be to disable the v-list-item that has the same index as the selectedItem
<template>
<div id="app">
<v-app id="inspire">
<v-card max-width="300" >
<v-list dense>
<v-list-item-group
v-model="selectedItem"
color="primary"
>
<v-list-item
v-for="(item, i) in items"
:key="i"
:disabled="i == selectedItem"
>
<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-card>
</v-app>
</div>
</template>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selectedItem: 0,
items: [
{ text: 'Real-Time'},
{ text: 'Audience' },
{ text: 'Conversions'},
],
}),
})

How to make Vutify VMenu right aligned?

I need to make right aligned v-menu with "attach" option.
Template:
<div id="app">
<v-app id="inspire">
<h1>VMenu bug with "right" option</h1>
<div class="place"></div>
<div class="text-center">
<v-btn
color="primary"
dark
#click="show = !show"
>
Dropdown
</v-btn>
</div>
<v-menu attach=".place" v-model="show" :right="true">
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
#click=""
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-app>
</div>
JS:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
show: false,
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
}),
})
I expect right aligned menu in ".place" element. But the menu is left aligned. Also top border of menu is under the ".place" element. It is strange. How can I fix it?
Demo
It is possible to align the content of v-menu to right border of the page
Here is the working codepen: https://codepen.io/chansv/pen/OJyjWmX
<div id="app">
<v-app id="inspire">
<h1>VMenu bug with "right" option</h1>
<div>
<div id="attachMenu" style="float: right;position: relative;width: 134px;left: 27px;"></div>
</div>
<div class="text-center">
<v-btn
color="primary"
dark
#click="show = !show"
>
Dropdown
</v-btn>
</div>
<v-menu attach="#attachMenu" v-model="show" :right="true">
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
#click=""
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
show: false,
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
}),
})
You almost got the right solution, the position with the right and left prop is inverted
So this is what you need to do:
<v-menu attach=".place" v-model="show" left>
I am using Vuetify 3 and I had the same problem. I solved it by using
<v-menu location="bottom end">
See :
https://next.vuetifyjs.com/en/components/menus/#location
https://next.vuetifyjs.com/en/components/overlays/#location-strategies

How to upload my image file with my token, Vue JS

I'm trying to upload my image so that it goes to my API, the thing is the validation needs to stay on the page, after they have logged in. It works with the upload through postman, by when i try to do it in the frontend of my Vue code it doesn't.
If someone knows how I can change this code to make it work, please let me know.
<template>
<v-app id="inspire">
<v-content>
<v-layout align-center justify-center>
<v-flex xs12 sm8 md4>
<v-card class="elevation-12">
<v-toolbar dark color="green">
<v-toolbar-title>Upload Images</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn slot="activator" icon large href="https://codepen.io/johnjleider/pen/wyYVVj" target="_blank">
<v-icon large>mdi-codepen</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<v-form class="upload" #keydown.enter="addImage" method="post">
<v-text-field v-model="uploadImage.title" prepend-icon="title" id="title" name="title" label="Image Title" type="text"></v-text-field>
<v-text-field v-model="uploadImage.description" id="description" prepend-icon="description" name="description" label="Description" type="text"></v-text-field>
<v-text-field v-model="uploadImage.album_path" id="ablum_path" prepend-icon="photo_album" name="album_path" label="Choose an album" type="search"></v-text-field>
<input #change="onFileSelected" type="file" name="image" id="image">
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn v-on:click="addImage" type="submit" color="green white--text">Upload</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-content>
</v-app>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
feedback: null,
selectedFile: null,
uploadImage: [
{ title: '' },
{ description: '' },
{ album_path: '' },
{image: null}
]
}
},
methods:{
addImage() {
axios.post('/api/image/upload',
{
'title': this.uploadImage.title,
'description': this.uploadImage.description,
'album_path': this.uploadImage.album_path,
'image': this.selectedFile,
},
{ headers: { 'Authorization': 'Bearer ' + this.$store.state.token }
})
.then(response => {
console.log("headers: {'Authorization': 'Bearer '" + this.$store.state.token);
console.log(response);
})
}
}
}
</script>
<style>
.red-text {
color: red;
font-size: 20px;
text-align: center;
}
</style>
you can try adding content-type to your header for axios before sending post request.
"Content-Type": "multipart/form-data; boundary=----",
},

Setting up a router-view for tabs when I have a different setup for navdrawers

Versions and Environment
Vuetify: 1.0.13
Vue: 2.5.13
Browsers: Chrome 67.0.3396.48
OS: Windows 10
Steps to reproduce the problem
Create a nav-drawer that has router-links in it.
In one of the links create a v-tab component that shows router-view for each tab.
Expected Behavior
In one of the links in the navigation-drawer, I have a link that connects to router view in one of it I have <v-tab> that connects to another router-view. Can you please help me?
Actual Behavior
The router-view for the tabs doesn't show up
Reproduction Link:
https://codepen.io/aabbrrm234/pen/deQjEe
<v-app id="inspire">
<v-navigation-drawer fixed :clipped="true" app v-model="drawer">
<v-list dense>
<template v-for="item in items">
<v-layout
row
v-if="item.heading"
align-center
:key="item.heading"
>
<v-flex xs6>
<v-subheader v-if="item.heading">
{{ item.heading }}
</v-subheader>
</v-flex>
<v-flex xs6 class="text-xs-center">
EDIT
</v-flex>
</v-layout>
<v-list-group
v-else-if="item.children"
v-model="item.model"
:key="item.text"
:prepend-icon="item.model ? item.icon : item['icon-alt']"
append-icon=""
>
<v-list-tile slot="activator">
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
v-for="(child, i) in item.children"
:key="i"
#click=""
>
<v-list-tile-action v-if="child.icon">
<v-icon>{{ child.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ child.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-group>
<v-list-tile v-else router :to="item.link" :key="item.text">
<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>
</template>
</v-list>
</v-navigation-drawer>
<v-toolbar color="grey lighten-3" light app
:clipped-left="$vuetify.breakpoint.lgAndUp"
fixed
>
<v-toolbar-title style="width: 300px" class="ml-0 pl-3">
<v-toolbar-side-icon #click.stop="drawer = !drawer"></v-toolbar-side-icon>
<span class="hidden-xs-and-down">App</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-menu offset-y>
<v-icon slot="activator">more_vert</v-icon>
<v-list>
<v-list-tile #click="logout">
<v-list-tile-title>Logout</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-toolbar>
<v-content>
<!-- <v-container xs7 offset-xs2 offset-md2 offset-lg5> -->
<!-- <v-layout> -->
<!-- content goes here -->
<!-- <router-view class="mt-0.3"></router-view> -->
<!-- end content -->
<!-- </v-layout>
</v-container> -->
<!-- <v-container grid-list-xl text-xs-center> -->
<v-layout row wrap>
<v-flex xs12 sm12 md12>
<router-view></router-view>
</v-flex>
</v-layout>
<!-- </v-container> -->
</v-content>
<!-- <v-btn
fab
bottom
right
color="pink"
dark
fixed
#click.stop="dialog = !dialog"
>
<v-icon>add</v-icon>
</v-btn> -->
</v-app>
<script>
export default {
data: () => ({
// userId : authUser.id ,
dialog: false,
drawer: null,
items: [
{ icon: 'home', text: 'Home', link: '/' },
{ icon: 'motorcycle', text: 'Start Delivery', link: '/delivery' },
{ icon: 'people', text: 'Account Settings', link: '/account' },
{ icon: 'exit_to_app', text: 'Logout', link: 'logout' },
{ icon: 'map', text: 'Addresses', link: '/addresses' },
{ icon :'list', text : 'Parcels To Pack', link : '/to-pack'}
],
tabItems : [
{ text : 'Parcels to Pack', routeName : 'showParcelsToPack' },
{ text : 'Show Delivery Map', routeName : 'deliveryMap'},
],
// speed dial
direction: 'top',
fab: false,
fling: false,
hover: false,
tabs: null,
top: false,
right: true,
bottom: true,
left: false,
transition: 'slide-y-reverse-transition'
}),
props: {
source: String
},
methods: {
logout () {
window.location.href = '/auth/logout'
}
}
};
</script>
in one of the view :
<v-tabs icons-and-text centered dark color="red">
<v-tab to="/delivery">
Addresses
<v-icon>shopping_cart</v-icon>
</v-tab>
<v-tab :to="{ name : 'parcelsToPack', params : { id : 3 }}">
Parcels To Pack
<v-icon>list</v-icon>
</v-tab>
<v-tab :to="{ name : 'googleMap', params : { id : 3 } }">
Map<v-icon>map</v-icon>
</v-tab>
<v-tabs-slider color="white"></v-tabs-slider>
I added this another router-view to display the result of the tab.
<router-view name="main"></router-view>
</v-tabs>
To give you an overview something like this is all I needed :
video
Codepen
You need to use nested routes:
routes: [
{path: '/',name: 'Home', component: homePage,},
{path: '/user',name: 'User', component: userPage,
children: [
{path: '/profile',name: 'Profile', component: profile},
{path: '/activity',name: 'Activity', component: activity},
],
},
]
Components that you want to show in tabs should be included in your child routes.
Then place router-view inside v-tab-items (in case you use v-for, don't forget to use keys):
<v-tabs v-model="activeTab">
<v-tab to="profile">Profile</v-tab>
<v-tab to="activity">Activity</v-tab>
</v-tabs>
<v-tabs-items v-model="activeTab">
<v-tab-item id="profile">
<router-view></router-view>
</v-tab-item>
<v-tab-item id="activity">
<router-view></router-view>
</v-tab-item>
</v-tabs-items>

How to wire up external data in Vuetify datatables

I have just started with Vue and found Vuetify ( and very impressed ) . I'm a bit of a newbie with node.js as well but some experience.
I am trying to find some examples on loading data from external API's into the vuetify datagrid - CRUD type stuff, reasonably large amounts of data paginated. The documentation in Vuetify is a little lacking in this regard. Should I be using Vuex?
If you want to call external API using REST, you'll need to use axios, which is a NPM package allowing you to make GET, POST and all that kind.
Let's use this online working API for our example. First, you need to get your data by calling this API. A good tutorial on Internet will show you more details, but let's use this code.
this.todos = axios.get('https://jsonplaceholder.typicode.com/todos/')
.then(response => { this.todos = response.data })
.catch(error => { console.log(error)});
Then you just have to use the datatable like in the documentation. Here is a CodePen to help you see, briefly, how I made the API call and then displayed it. It all comes from the official documentation, just modified to call a REST API. I'll put the code also here, in order to save it for future readers too.
<div id="app">
<v-app id="inspire">
<div>
<v-toolbar flat color="white">
<v-toolbar-title>Todos CRUD</v-toolbar-title>
<v-divider
class="mx-2"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="500px">
<v-btn slot="activator" color="primary" dark class="mb-2">New Item</v-btn>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.userId" label="User ID"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.id" label="ID"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.title" label="Title"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-checkbox v-model="editedItem.completed" label="Completed?"></v-checkbox>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat #click="close">Cancel</v-btn>
<v-btn color="blue darken-1" flat #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
<v-data-table
:headers="headers"
:items="todos"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td class="text-xs-right">{{ props.item.userId }}</td>
<td class="text-xs-right">{{ props.item.id }}</td>
<td class="text-xs-right">{{ props.item.title }}</td>
<td class="text-xs-right">{{ props.item.completed }}</td>
<td class="justify-center layout px-0">
<v-icon
small
class="mr-2"
#click="editItem(props.item)"
>
edit
</v-icon>
<v-icon
small
#click="deleteItem(props.item)"
>
delete
</v-icon>
</td>
</template>
<template slot="no-data">
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</div>
</v-app>
</div>
And then the associated JS.
new Vue({
el: '#app',
data: () => ({
dialog: false,
headers: [
{
text: 'User ID',
align: 'left',
sortable: false,
value: 'userId',
width: '10'
},
{ text: 'ID', value: 'id', width: '10' },
{ text: 'Title', value: 'title' },
{ text: 'Completed', value: 'completed' }
],
todos: [],
editedIndex: -1,
editedItem: {
userId: 0,
id: 0,
title: '',
completed: false
},
defaultItem: {
userId: 0,
id: 0,
title: '',
completed: false
}
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
}
},
watch: {
dialog (val) {
val || this.close()
}
},
created () {
this.initialize()
},
methods: {
initialize () {
this.todos = axios.get('https://jsonplaceholder.typicode.com/todos/')
.then(response => { this.todos = response.data })
.catch(error => { console.log(error)});
},
editItem (item) {
this.editedIndex = this.todos.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.todos.indexOf(item)
confirm('Are you sure you want to delete this item?') && this.todos.splice(index, 1)
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.todos[this.editedIndex], this.editedItem)
} else {
this.todos.push(this.editedItem)
}
this.close()
}
}
})

Resources