how to make an good working select input component in vue 3

Viewed 549

Im trying to make an pagination with an select field but i dont get it how the v-model and the value properties should be given, for now i have like this ↓...

This is the select/pagination part in that component..

        <p v-on:click="back" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded-l cursor-pointer">Zurück</p>
        <p class="bg-gray-300 text-gray-800 font-bold py-2 px-4 "><span>{{siteCount}}/{{siteTotal}}</span></p>
        <select :value="modelValue" v-on:change="selectPage">
            <option v-for="select in select" :value="select">{{select}}</option>
        </select>
        <p v-on:click="next" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded-r cursor-pointer">Weiter</p>
    </div>
</template>

<script>
import SearchIcon from "../Assets/SearchIcon";
import NavBar from "./NavBar";
export default {
    name: "PaginateSeason",
    props: {
        data: {
            name: String,
            description: String,
            thumbnail: String,
        },
        siteCount: Number,
        siteTotal: Number,
        select: Array,
        modelValue: String,
    },
    components: {
        NavBar,
        SearchIcon
    },
    emits: ['next', 'back', 'selectPage'],
    methods:{
        next() {
            this.$emit('next')
        },
        back() {
            this.$emit('back')
        },
        selectPage() {
            this.$emit('selectPage')
        }
    },
}
</script>

This is the main Component where i fetch anything i need...

<template>
    <router-view>
        <NavBar :is-disabled="true"></NavBar>
        <div v-if="isLoading" class="flex flex-col items-center justify-center mt-9">
            <LoaderSpinner></LoaderSpinner>
            <p>Daten werden geladen...</p>
        </div>
        <div v-else>
            <PaginateSeason
                v-model="count"
                :data="seasons"
                :site-count="current"
                :site-total="siteCountTotal"
                :select="select"
                @next="paginateNext"
                @back="paginateBack"
                @selectPage="allCount"
            />
        </div>
    </router-view>
</template>

<script>
import NavBar from './NavBar'
import PaginateSeason from './PaginateSeason'
import LoaderSpinner from "../Assets/LoaderSpinner";
export default {
    name: "AllSeasons",
    components: {
        PaginateSeason,
        NavBar,
        LoaderSpinner
    },
    data(){
        return {
            seasons: null,
            current: 1,
            pageSize: 4,
            isLoading: true,
            siteCountTotal: null,
            select: [],
            count: '',
        }
    },
    mounted(){
        this.list(this.current)
        const list = async () => {
            await axios.get(`/api/seasons/all`).then(response => {
                let meta = response.data.meta
                this.siteCountTotal = meta.last_page
                for (let i = 1; i <= this.siteCountTotal; i++) {
                    this.select.push(i)
                }
            }).catch(error => {
                console.log(error)
            })
        }
        list()
    },
    methods: {
        async list(page) {
            await axios.get(`/api/seasons/all?page=${page}`).then(response => {
                this.seasons = response.data.data
            }).catch(error => {
                console.log(error)
            }).finally(() => {
                setTimeout(() => {
                    this.isLoading = false
                },1000)
            })
        },
        paginateNext () {
            if (this.seasons.length < this.pageSize) {
                this.current = 1
                this.list(this.current)
            } else {
                this.current += 1
                this.list(this.current)
            }
        },
        paginateBack () {
            if (this.current === 1) {
                this.current -= 0
            } else {
                this.current -= 1
                this.list(this.current)
            }
        },
        allCount() {
            console.log(this.count)
        }
    },

IF you can help me with that i would be very gratefull!

1 Answers

The count variable on the AllSeasons component will not be updated, because you pass it as v-model to the PaginateSeason component, but PaginateSeason never emits update:modelValue.

Implement selectPage like this to address this issue:

selectPage(event) {
  this.$emit('update:modelValue', event.target.value)
}

You can also keep the selectPage event, or add a wach for the count variable in AllSeasons component to watch for page changes. You may also want to emit the update:modelValue event from next and back functions in the PaginateSeason component.

Related