How do I programmatically scroll to a specific v-list-item in v-list? - vuetify.js

I'm using Vue/Vuetify and have a v-list that is scrollable:
<v-layout scrollable ...
<v-list ...
<template v-for=id...
<v-list-item :key=id...
Is it possible to programmatically scroll the items so that a particular one is in the visible area of the scrollable list?

You can scroll to any DOM element using plain JavaScript method scrollIntoView.
Before that you can give an id for each element of your list. By example, this way:
<v-container>
<v-row>
<v-col>
<v-btn
ref="button"
block
color="primary"
#click="scrollTo"
>
scroll to Item-20
</v-btn>
</v-col>
<v-col cols="12">
<v-card>
<v-list max-height="300" class="overflow-y-auto">
<v-subheader>ITEMS</v-subheader>
<v-list-item
v-for="(item, i) in items"
:key="i"
:id="'list-item-' + (item.id + 1)">
<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>
</v-card>
</v-col>
</v-row>
</v-container>
...
data () {
return {
items: [],
}
},
mounted() {
for (let i = 0; i < 50; i++) {
this.items.push({ id: i, text: 'Item-' + (i + 1)})
}
},
methods: {
scrollTo() {
document.getElementById("list-item-20").scrollIntoView()
}
}
Test this at CodePen.
P.S.: there is no scrollable prop in v-layout API. At least, in latest v2.6.3.

Related

Is it possible to sort Vuetify multiple selection on change?

I have a multiple selection Vue component that feeds items to display in an input box. As of now, it adds items based on the order of selection, but I wanted to template it to sort by sort_order after selection (objective_id, category_id, objective_code, objective_description, disabled_flag, sort_order are all passed into objectiveArray object). Is this possible to do in Vuetify?
<v-flex xs12>
<v-tooltip :disabled="!showTooltip" top>
<v-select
slot="activator"
class="objective-select"
v-model="record.objectives"
:items="objectiveArray"
label="Objective(s)"
placeholder="Enter Objective(s)"
:error-messages="objectiveErrors"
:return-object="true"
item-text="objectiveDescription"
multiple
#blur="v.$each[index].objectives.$touch()">
<template v-slot:selection="{ item, index }">
<v-chip
color="primary"
dark
class="objective-chip"
:class="{
mobile:isMobile,
tablet:isTablet
}">
<span>{{ item.objectiveDescription }}</span>
</v-chip>
</template>
</v-select>
<span>Select one or more procedure objective(s)</span>
</v-tooltip>
</v-flex>
You can sort your bound v-model after the #input event fires. Here is a simple example:
<template>
<div>
<v-select
v-model="selected"
:items="items"
item-text="id"
item-value="id"
multiple
#input="sortSelection"
return-object
>
</v-select>
</div>
</template>
<script>
export default {
data: () => ({
selected: [],
items: [{id:1},{id:2},{id:3},{id:4},{id:5},{id:6}]
}),
methods: {
sortSelection() {
this.selected.sort((x, y) => {
if (x.id > y.id) return 1
else if (y.id > x.id) return -1
else return 0
})
}
}
}
</script>
As long as your sort_order is a number you can just substitute it for the id field in my example.

Display the products of an order Vuejs & Laravel

I have a Laravel application with Vuejs, I have two tables, 1-Orders 2-Order_products.
What I want is to display the products for each order in its popup.
Here is my code, thanks in advance;
My controller:
public function getAllOrders()
{
return Order::orderBy('created_at', 'DESC')->get();
}
public function getOrdersProducts(Order $order)
{
return OrderProduct::orderBy('created_at', 'DESC')->get();
}
My popup
<v-dialog
v-model="infoBox"
width="500"
>
<v-card>
<v-card-title class="headline" primary-title style="background-color:#e91e63;">
<span style="color:white;">order #{{OrderIdToView}}</span>
<v-spacer></v-spacer>
<v-btn text icon color="white" right #click="infoBox = false">
<v-icon large>close</v-icon>
</v-btn>
</v-card-title>
<v-list>
<v-chip
class="ma-2"
color="primary"
>
Salle: {{ OrderNameToView }}
<v-icon right>
water_damage
</v-icon>
</v-chip>
<v-chip
class="ma-2"
color="error"
>
Total: 23€
<v-icon right>
monetization_on
</v-icon>
</v-chip>
<v-list-item-group>
<template v-for="(orproduct, index) in $store.state.orp">
<v-list-item :key="orproduct.id + '-orproduct'">
<v-list-item-avatar>
<v-img
src="https://ecocea-bk-cdn-prd.azureedge.net/img/products/e/cc/eccba3e6-e161-4468-8193-577fdfb3205c_#2x"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title class="ml-2"><strong>{{ orproduct.id }}</strong></v-list-item-title>
</v-list-item-content>
<v-list-item-action d-flex>
<div>
<v-chip
class="ma-2"
color="success"
label
text-color="white"
>
2 x<b> 4 €</b>
</v-chip>
</div>
</v-list-item-action>
</v-list-item>
<v-divider
></v-divider>
<v-divider
v-if="index < $store.state.orp.length - 1"
:key="index"
></v-divider>
</template>
</v-list-item-group>
</v-list>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="secondary"
#click="infoBox = false"
class="white--text"
>
close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
My method:
methods: {
moreInfoOrder(orderId, orderName) {
this.infoBox = true;
this.OrderIdToView = orderId;
this.OrderNameToView = orderName;
}
}
I have an order list, when I click on the order, the popup appears with the products of this order. if someone can give me a hand that would be great,
thank you
Assuming you have followed Laravel conventions when setting up model relations, getOrdersProducts method in your controller should look something like:
public function getOrdersProducts(Order $order)
{
return $order->load('products');
}
Which makes it possible to access the list of products for the particular order with:
$order->products

Vuetify - List menu activator visibility toggle

I have 3 cards when mouse hover on card title it shows a arrow_down icon & i can click on it , it a drop down menu with Delete function when i hover over the v-card-title it shows the icon but after i click on it, mouse on drop-down menu the arrow_down icon disappeared,
how to properly implement it ?
https://codepen.io/sharon-the-encoder/pen/WLWyoG?editors=0010
const cards = [
{
title: "Gooey PBJ Brownies",
author: "John Walibur",
image: "https://placeimg.com/640/480/nature"
},
{
title: "Crisp Spanish Tortilla Matzo Brei",
author: "Colman Andrews",
image: "https://placeimg.com/640/480/animals"
},
{
title: "Grilled Shrimp with Lemon and Garlic",
author: "Celeste Mills",
image: "https://placeimg.com/640/480/arch"
}
];
new Vue({
el: "#app",
data: {
cards: cards,
selectedCard: -1
},
methods: {
hoverCard(selectedIndex) {
this.selectedCard = selectedIndex
},
isSelected(cardIndex) {
return this.selectedCard === cardIndex
},
passmsgid(index) {
alert(index)
}
}
});
body {
background-color: #e1e7e7;
}
.grey--text.selected {
color: red !important;
}
.iconkey {
display: none;
}
.iconkey.selected {
display: block;
color: blue !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.18/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.4.2/vuetify.min.js">
</script>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons'>
<div id="app">
<v-app>
<v-content>
<v-container>Hello world</v-container>
<v-container fluid>
<v-layout row wrap>
<v-flex xs12 sm4 md4 lg4 v-for="(card, index) in cards" :key="index">
<v-card class="ml-3 mt-3">
<v-img :src="card.image" height="200px">
</v-img>
<v-card-title primary-title #mouseover="hoverCard(index)" #mouseout="hoverCard(-1)">
<div>
<div class="headline">{{card.title}}</div>
<span class="grey--text" :class="{'selected': isSelected(index)}">{{card.author}} -
</span>
<v-expand-transition>
<v-menu bottom transition="scale-transition" nudge-bottom="40">
<v-btn icon slot="activator" styole="margin-bottom: -1em;">
<v-icon class="iconkey" :class="{'selected': isSelected(index)}">keyboard_arrow_down</v-icon>
</v-btn>
<v-list>
<v-list-tile>
<v-list-tile-title #click="passmsgid(index)">Delete</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-expand-transition>
</div>
</v-card-title>
<v-card-actions>
<v-btn flat>Share</v-btn>
<v-btn flat color="purple">Explore</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content>
</v-app>
</div>
Updated pen using more CSS, and without v-hover: Codepen
(Originally I used v-hover but for this case not needed)
Codepen
We will control visibility by using the following CSS class:
.hidden {
visibility: hidden;
}
menu-button is hidden unless:
a) we are hovering over its parent-tile or
b) when the corresponding menu is opened.
So we need to set up custom item (tile) component:
Set menu visibility control:
data: () => ({
menu: false, // control button-menu state (opened / closed)
})
And our template starts with v-hover component so we can detect when we hover over it and react to that event:
<template>
<v-hover>
<v-list-tile slot-scope="{ hover }" #click="">
// ...
<v-menu v-model="menu" offset-y left >
<v-btn slot="activator"
:class="{hidden: !hover && !menu}"
>
:class="{hidden: !hover && !menu}" - we set hidden class on button when we are not hovering over the parent-tile and when corresponding menu is closed.

Handsontable not immediately shown when inside Vuetify Stepper

When placing the Handsontable HotTable component inside of a Vuetify Stepper the Handsontable is only visible after you click somewhere on the page. But if I place the HotTable component outside of the Stepper it would be shown immediately. It should be visible inside step 1 immediately.
To demonstrate this unexpected behavior I forked the Vuetify Stepper example on CodePen and added "handsontable" and "#handsontable/vue".
Vuetify Stepper with Handsontable on CodePen
<div id="app">
<v-app id="inspire">
<v-stepper v-model="e1">
<v-stepper-header>
<v-stepper-step :complete="e1 > 1" step="1">Name of step 1</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step :complete="e1 > 2" step="2">Name of step 2</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Name of step 3</v-stepper-step>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<v-card
class="mb-5"
color="grey lighten-1"
height="200px"
>
<div id="hot-preview">
<hot-table :settings="hotSettings"></hot-table>
</div>
</v-card>
<v-btn
color="primary"
#click="e1 = 2"
>
Continue
</v-btn>
<v-btn flat>Cancel</v-btn>
</v-stepper-content>
<v-stepper-content step="2">
<v-card
class="mb-5"
color="grey lighten-1"
height="200px"
></v-card>
<v-btn
color="primary"
#click="e1 = 3"
>
Continue
</v-btn>
<v-btn flat>Cancel</v-btn>
</v-stepper-content>
<v-stepper-content step="3">
<v-card
class="mb-5"
color="grey lighten-1"
height="200px"
></v-card>
<v-btn
color="primary"
#click="e1 = 1"
>
Continue
</v-btn>
<v-btn flat>Cancel</v-btn>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</v-app>
</div>
new Vue({
el: '#app',
data () {
return {
e1: 0,
hotSettings: {
data: Handsontable.helper.createEmptySpreadsheetData(1, 8),
colHeaders: true,
rowHeaders: true
}
}
},
components: {
HotTable
}
});
I think the problem is because you initialize it before component is mounted.
Try to initialize it in mounted hook:
hotSettings: {
data: null,
//...
mounted() {
this.hotSettings.data = Handsontable.helper.createEmptySpreadsheetData(1, 8)
}

Vuetify v-list with v-checkbox - v-model not working properly

I'm trying to create a simple settings page with Vuetify. I use a v-checkbox inside a v-list-item, nothing special. However, my solution using v-model isn't working. See below.
Working example with input-value and #click instead of v-model:
...
<v-list>
<v-list-item link :input-value="someSetting" #click="toggleSomeSetting">
<template v-slot:default="{ active }">
<v-list-item-action>
<v-checkbox :input-value="active"></v-checkbox>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>My setting</v-list-item-title>
</v-list-item-content>
</template>
</v-list-item>
</v-list>
...
<script>
export default {
computed: {
someSetting () {
return this.$store.state.settings.someSetting
}
},
methods: {
toggleSomeSetting () {
this.$store.dispatch('settings/update', { someSetting: !this.$store.state.settings.someSetting })
}
}
}
</script>
Example with v-model - not working:
...
<v-list>
<v-list-item link v-model="someSetting">
<template v-slot:default="{ active }">
<v-list-item-action>
<v-checkbox :input-value="active"></v-checkbox>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>My setting</v-list-item-title>
</v-list-item-content>
</template>
</v-list-item>
</v-list>
...
<script>
export default {
computed: {
someSetting: {
get () {
return this.$store.state.settings.someSetting
},
set (newValue) {
console.log(newValue)
this.$store.dispatch('settings/update', { someSetting: newValue })
}
}
}
}
</script>
When I click on the item on my settings page, nothing happens. The setter of the computed property doesn't seem to be called as there is no output to the console. What am I missing here?
You are missing the wrapping <v-list-item-group> element around all <v-list-item> elements
...
<v-list>
<v-list-item-group>
<v-list-item link v-model="someSetting">
<template v-slot:default="{ active }">
<v-list-item-action>
<v-checkbox :input-value="active"></v-checkbox>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>My setting</v-list-item-title>
</v-list-item-content>
</template>
</v-list-item>
</v-list-item-group>
</v-list>
...
Or you can put the v-model in the checkbox:
...
<v-list>
<v-list-item link>
<template v-slot:default>
<v-list-item-action>
<v-checkbox v-model="someSetting"></v-checkbox>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>My setting</v-list-item-title>
</v-list-item-content>
</template>
</v-list-item>
</v-list>
...
If you have a list of multiple items and want to pass all the selected ones to maybe a database, the v-model should be put into the <v-list-item-group> element.
Also see https://vuetifyjs.com/en/components/lists/ for detailed examples.

Resources