I have a scrollable list that i can select multiple items from. I want to programmatically implement a way to scroll to top of the list every time i change the search input.
Desired behavior: For example; when i type 'b' in the search list, and scroll down, then if i type 'e' again i would like it to scroll to the very top
Here's a code example showing what i would like to do, I've tried two different methods. I have tried two different approaches in the code below where i utilize scrollTop feature of the html Element and goTo function from vuetify but none of them worked.
Code demo-> https://www.codeply.com/p/ZGBNEHW7YS
In case the demo expires, the actual code;
<div id="app">
<v-app>
<v-main >
<h1 >AutoComplete Infinite Scroll Example</h1>
<v-autocomplete
id="autoComplete"
ref="autoComplete"
v-model="selected"
:items="beers"
item-text="name"
item-value="id"
:search-input.sync="search"
label="Search the beers.."
return-object
multiple
autocomplete="off"
>
<template v-slot:append-item>
<div v-intersect="onIntersect" >
Loading more items ...
</div>
</template>
</v-autocomplete>
</v-main>
</v-app>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
search:'',
beers: [],
selected: null,
perPage: 30,
page: 1,
}
},
methods: {
getBeers() {
console.log('page', this.page)
const apiUrl = `https://api.punkapi.com/v2/beers?page=${this.page}&per_page=${this.perPage}`
axios.get(apiUrl)
.then(response => {
this.beers = [
...this.beers,
...response.data
]
})
},
onIntersect () {
console.log('load more...')
this.page = 1
this.getBeers()
},
},
watch:{
search:function(){
//first method
let myId=document.getElementById('autoComplete')
if(myId){
myId.scrollTop = 0
}
//second method with ref and vuetify goto
this.$nextTick(() => {
this.$vuetify.goTo(this.$refs.autoComplete)
})
}
},
created() {
this.getBeers()
}
})
CodePudding user response:
You need something like this (see demo in full page)
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
beers: [],
selected: null,
perPage: 30,
page: 1,
}),
created() {
this.getBeers()
},
methods: {
goToTop(){
this.beers = [];
this.page = 1;
this.getBeers();
},
getBeers() {
console.log('page', this.page)
const apiUrl = `https://api.punkapi.com/v2/beers?page=${this.page}&per_page=${this.perPage}`
axios.get(apiUrl)
.then(response => {
this.beers = [
...this.beers,
...response.data
]
})
},
onIntersect () {
this.page = 1
this.getBeers()
},
},
})
.scroll-to-top {
position:sticky;
bottom:8px;
width:100%;
display:flex;
justify-content :right;
background-color: rgba(0, 0, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.24.0/axios.min.js"></script>
<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/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<div id="app">
<v-app id="inspire">
<v-card>
<v-container fluid>
<v-row
align="center"
>
<v-col cols="12">
<v-autocomplete
v-model="selected"
:items="beers"
item-text="name"
item-value="id"
label="Search da beers.."
return-object
autocomplete="off"
>
<template v-slot:append-item>
<div v-intersect="onIntersect" >
Loading more items ...
</div>
<div >
<v-btn
color="primary"
small
@click="goToTop"
>
Go to top
</v-btn>
</div>
</template>
</v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-card>
</v-app>
</div>
CodePudding user response:
Here's how i solved by using zergski's example.
Casting was required because of typescript.
scrollTop(): void {
let scrollList = document.querySelector('.v-autocomplete__content')
let firstElement = document.querySelector('.company-item-name') as HTMLElement
if (scrollList && firstElement && firstElement.offsetTop) {
scrollList.scrollTop = firstElement.offsetTop
}
},