Giter Club home page Giter Club logo

Comments (8)

coolsam726 avatar coolsam726 commented on June 1, 2024

Hi @asbator
Could you kindly share your Vue template to see how you have set it up?

Essentially, you don't need to pass the selected value. You should just use v-model="form.myField" and it should work seamlessly.

If you haven't explicitly specified "reduce" then you should know that it deals with objects. So the initial selected value you pass as v-model should be an object, not an id.

from jetstream-inertia-generator.

asbator avatar asbator commented on June 1, 2024

I think i use it as it was generated, don't remember changing anything except label (and cosmetics)

<div class=" sm:col-span-4"> <jet-label for="woj" value="Woj" /> <infinite-select class="w-full" id="woj" name="woj" :api-url="route('api.branches.index')" v-model="form.woj" label="nazwa" :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.woj}" ></infinite-select> <jet-input-error :message="form.errors.woj" class="mt-2" /> </div>

Where woj inside Branch model is:
public function woj() { return $this->belongsTo(\App\Models\Branch::class,"woj_id","id"); }

Inside JigComponents/InfiniteSelect.vue, method mounted is line 86:
this.selected = this.initValue;
But neither of two variables are actually used in the component, so i thought its a job to do.

from jetstream-inertia-generator.

coolsam726 avatar coolsam726 commented on June 1, 2024

I am trying to figure out the relationship between the two models (woj and branches) so that I understand how they are loaded. Maybe you could post the JSON that is fetched from the server when loading the options, and also the structure of your form object so that I can advise better.

For clarity, the label prop for InfiniteSelect is supposed to be the name of the field that will be used in the options and to display the selected option. Ensure nazwa is an existing field in the database table.

from jetstream-inertia-generator.

asbator avatar asbator commented on June 1, 2024

Select option example:

0: {
api_route: "http://localhost/api/branches"
can: {view: true, update: true, delete: true, restore: false, forceDelete: true}
id: 2
kod_so: "50-552"
nazwa: "dolnośląskie"
poczta_so: "Wrocław"
ulica_so: "Borowska 138"
}

It is relationship to itself. I have branches which are territory areas.
Provinces (woj) are on the top of hierarchy and are divided on districts. So inside district branch form i have a select to pick to which province it belongs to. Branch model consist personal data, so i had to make my own api call and narrow data returned for options to just office address.

I modified InfiniteSelect.vue slightly to fix some minor problems: style scss was not loading, default value of perPage was not loaded to api request. Somewhere was auto-generated @click.native obsolete modifier, i removed that (don't remember from where). Also fetched results inside mounted hook.
Overall it looks like that:

<template>
    <v-select
        class="px-2 py-1 border border-gray-200 rounded-none shadow-none  bg-gray-50"
        :model-value="modelValue"
        @update:modelValue="onSelect"
        :multiple="multiple"
        :options="paginatedObject.data"
        :filterable="false"
        :clear-on-select="true"
        :reduce="reduce"
        :placeholder="placeholder"
        :label="label"
        @open="onOpen"
        @close="onClose"
        @search="fetchResults"
    >
        <template #search="{ attributes, events }">
            <input
                style="border-right: none !important"
                class="vs__search"
                v-bind="attributes"
                v-on="events"
            />
        </template>
        <template #list-footer v-if="hasNextPage">
            <li ref="infiniteSelectLoad" class="loader">
                Wczytywanie kolejnych danych...
            </li>
        </template>
    </v-select>
</template>

<script>
import vSelect from "vue-select/src/index";
import { defineComponent } from "vue";
export default defineComponent({
    name: "InfiniteSelect",
    components: {
        "v-select": vSelect,
    },
    emits: ["update:modelValue"],
    model: {
        prop: "modelValue",
        event: "update:modelValue",
    },
    props: {
        apiUrl: {
            required: true,
            type: String,
        },
        queryParams: {
            required: false,
            default: () => {
                return {};
            },
        },
        perPage: {
            required: false,
            default: 20,
        },
        multiple: {
            type: Boolean,
            default: false,
        },
        modelValue: {
            default: null,
        },
        label: {
            required: true,
            type: String,
        },
        reduce: {
            type: Function,
        },
        placeholder: String,
    },
    data: () => ({
        observer: null,
        paginatedObject: {
            data: [],
        },
        searchQuery: null,
    }),
    mounted() {
        this.paginatedObject.per_page = parseInt(this.perPage) || 20;
        this.observer = new IntersectionObserver(this.infiniteScroll);
        this.fetchResults(null, true, true);
        this.selected = this.initValue; //probably TODO
    },
    methods: {
        async onOpen() {
            //console.log(this.modelValue);
            if (this.hasNextPage) {
                await this.$nextTick(() => {
                    this.observer.observe(this.$refs.infiniteSelectLoad);
                });
            }
        },
        onClose() {
            this.observer.disconnect();
            this.searchQuery = null;
        },
        onSelect(value) {
            this.$emit("update:modelValue", value);
        },
        async fetchResults(query, loading, more = false) {
            const vm = this;
            let params = {};
            if (query) {
                vm.searchQuery = query;
                params.search = vm.searchQuery;
            }
            params.per_page = vm.paginatedObject.per_page;
            if (vm.paginatedObject.current_page && more) {
                if (!vm.paginatedObject.next_page_url) {
                    return false;
                }
                params.page = vm.paginatedObject.current_page + 1;
            }
            params = { ...params, ...vm.queryParams };
            return new Promise((resolve, reject) => {
                const vm = this;
                loading = true;
                axios
                    .get(vm.apiUrl, {
                        params: params,
                    })
                    .then((res) => {
                        // process and store results.
                        const bak = vm.paginatedObject.data;
                        vm.paginatedObject = res.data.payload;
                        if (more) {
                            vm.paginatedObject.data = [
                                ...bak,
                                ...res.data.payload.data,
                            ];
                        }
                        resolve(res);
                    })
                    .catch((err) => {
                        // reset Object, report error.
                        reject(err);
                    })
                    .finally((res) => {
                        loading = false;
                    });
            });
        },
        async infiniteScroll([{ isIntersecting, target }]) {
            if (isIntersecting) {
                const ul = target.offsetParent;
                const scrollTop = target.offsetParent.scrollTop;
                await this.fetchResults(null, true, true);
                ul.scrollTop = scrollTop;
            }
        },
    },
    computed: {
        hasNextPage() {
            let vm = this;
            return (
                (vm.paginatedObject.current_page &&
                    vm.paginatedObject.next_page_url) ||
                (!vm.paginatedObject.data.length &&
                    !vm.paginatedObject.current_page)
            );
        },
    },
    watch: {},
});
</script>

<style lang="scss">
@import "node_modules/vue-select/src/scss/vue-select.scss";

.loader {
    text-align: center;
    color: #bbbbbb;
}
.vs__dropdown-toggle {
    border: none !important;
}
</style>

Form:

<template>
    <form @submit.prevent="updateModel">
         
        <div class=" sm:col-span-4">
            <jet-label for="nazwa" value="Nazwa" />
            <jet-input class="w-full" type="text" id="nazwa" name="nazwa" v-model="form.nazwa"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.nazwa}"
            ></jet-input>
            <jet-input-error :message="form.errors.nazwa" class="mt-2" />
        </div>
                                    
        <div class=" sm:col-span-4">
            <jet-label for="woj" value="Woj" />
            <infinite-select class="w-full" id="woj" name="woj"
                        :api-url="route('api.branches.provinces')"
                        v-model="form.woj"
                        @update:modelValue="onSelectWoj"
                        label="nazwa"
                        :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.woj}"
            ></infinite-select>
            <jet-input-error :message="form.errors.woj" class="mt-2" />
        </div>
        
        <div class=" sm:col-span-4">
            <jet-label for="pow" value="Pow" />
            <infinite-select class="w-full" id="pow" name="pow"
                            :api-url="route('api.branches.districts', this.selectedWojId)"
                            v-model="form.pow" label="nazwa"
                            :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.pow}"
            ></infinite-select>
            <jet-input-error :message="form.errors.pow" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="co" value="Co" />
            <jet-input class="w-full" type="text" id="co" name="co" v-model="form.co"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.co}"
            ></jet-input>
            <jet-input-error :message="form.errors.co" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="typ" value="Typ" />
            <jet-input class="w-full" type="text" id="typ" name="typ" v-model="form.typ"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.typ}"
            ></jet-input>
            <jet-input-error :message="form.errors.typ" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="typ_oddz" value="Typ Oddz" />
            <jet-input class="w-full" type="text" id="typ_oddz" name="typ_oddz" v-model="form.typ_oddz"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.typ_oddz}"
            ></jet-input>
            <jet-input-error :message="form.errors.typ_oddz" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="ulica_so" value="Ulica So" />
            <jet-input class="w-full" type="text" id="ulica_so" name="ulica_so" v-model="form.ulica_so"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.ulica_so}"
            ></jet-input>
            <jet-input-error :message="form.errors.ulica_so" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="kod_so" value="Kod So" />
            <jet-input class="w-full" type="text" id="kod_so" name="kod_so" v-model="form.kod_so"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.kod_so}"
            ></jet-input>
            <jet-input-error :message="form.errors.kod_so" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="poczta_so" value="Poczta So" />
            <jet-input class="w-full" type="text" id="poczta_so" name="poczta_so" v-model="form.poczta_so"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.poczta_so}"
            ></jet-input>
            <jet-input-error :message="form.errors.poczta_so" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="tel_so" value="Tel So" />
            <jet-input class="w-full" type="text" id="tel_so" name="tel_so" v-model="form.tel_so"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.tel_so}"
            ></jet-input>
            <jet-input-error :message="form.errors.tel_so" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="fax_so" value="Fax So" />
            <jet-input class="w-full" type="text" id="fax_so" name="fax_so" v-model="form.fax_so"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.fax_so}"
            ></jet-input>
            <jet-input-error :message="form.errors.fax_so" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="ulica_k" value="Ulica K" />
            <jet-input class="w-full" type="text" id="ulica_k" name="ulica_k" v-model="form.ulica_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.ulica_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.ulica_k" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="kod_k" value="Kod K" />
            <jet-input class="w-full" type="text" id="kod_k" name="kod_k" v-model="form.kod_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.kod_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.kod_k" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="poczta_k" value="Poczta K" />
            <jet-input class="w-full" type="text" id="poczta_k" name="poczta_k" v-model="form.poczta_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.poczta_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.poczta_k" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="imie_k" value="Imie K" />
            <jet-input class="w-full" type="text" id="imie_k" name="imie_k" v-model="form.imie_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.imie_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.imie_k" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="nazwisko_k" value="Nazwisko K" />
            <jet-input class="w-full" type="text" id="nazwisko_k" name="nazwisko_k" v-model="form.nazwisko_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.nazwisko_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.nazwisko_k" class="mt-2" />
        </div>
         
        <div class=" sm:col-span-4">
            <jet-label for="inst_k" value="Inst K" />
            <jet-input class="w-full" type="text" id="inst_k" name="inst_k" v-model="form.inst_k"
                       :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.inst_k}"
            ></jet-input>
            <jet-input-error :message="form.errors.inst_k" class="mt-2" />
        </div>
        
        <div class=" sm:col-span-4">
            <jet-label for="data_adres" value="Data Adres" />
            <jig-datepicker
                class="w-full"
                id="data_adres"
                name="data_adres"
                v-model="form.data_adres"
                data-date-format="Y-m-d"
                :data-alt-input="true"
                data-alt-format="l M J, Y"
                :class="{'border-red-500 sm:focus:border-red-300 sm:focus:ring-red-100': form.errors.data_adres}"
            ></jig-datepicker>
            <jet-input-error :message="form.errors.data_adres" class="mt-2" />
        </div>
                                    
        <div class="mt-2 text-right">
            <inertia-button type="submit" class="font-semibold text-white bg-primary" :disabled="form.processing">Submit</inertia-button>
        </div>
    </form>
</template>

<script>
    import JetLabel from "@/Jetstream/Label.vue";
    import InertiaButton from "@/JigComponents/InertiaButton.vue";
    import JetInputError from "@/Jetstream/InputError.vue";
    import {useForm} from "@inertiajs/inertia-vue3";
    import JigDatepicker from "@/JigComponents/JigDatepicker.vue";
    import JetInput from "@/Jetstream/Input.vue";
    import InfiniteSelect from '@/JigComponents/InfiniteSelect.vue';
    import FiniteSelect from '@/JigComponents/FiniteSelect.vue';
    import { defineComponent } from "vue";

    export default defineComponent({
        name: "EditBranchForm",
        props: {
            model: Object,
        },
        components: {
            InertiaButton,
            JetLabel,
            JetInputError,
            JetInput,
            JigDatepicker,
            InfiniteSelect,
            FiniteSelect,

        },
        data() {
            return {
                form: useForm({
                    ...this.model,
                },{remember:false}),
            }
        },
        created() {
        },
        computed: {
            flash() {
                return this.$page.props.flash || {}
            },
            selectedWojId: function () {
                if (this.form.woj)
                    return this.form.woj.id;
                else
                    return 0;
            }
        },
        methods: {
            async updateModel() {
                this.form.put(this.route('admin.branches.update',this.form.id),
                    {
                        onSuccess: res => {
                            if (this.flash.success) {
                                this.$emit('success',this.flash.success);
                            } else if (this.flash.error) {
                                this.$emit('error',this.flash.error);
                            } else {
                                this.$emit('error',"Unknown server error.")
                            }
                        },
                        onError: res => {
                            this.$emit('error',"A server error occurred");
                        }
                    },{remember: false, preserveState: true})
            },
            onSelectWoj(value) {
                this.form.pow = null;
            }
        }
    });
</script>

from jetstream-inertia-generator.

coolsam726 avatar coolsam726 commented on June 1, 2024

Did you manage to solve this?

from jetstream-inertia-generator.

asbator avatar asbator commented on June 1, 2024

No, but i tested it with vue-select and simple array, problem is same. Or rather lack feature.
Sorry for posting this problem here.

from jetstream-inertia-generator.

coolsam726 avatar coolsam726 commented on June 1, 2024

@asbator , the official vue-select does not support Vue 3 yet, but 9 days ago they released v 4.0.0-beta.1 that has support for Vue 3.

As a temporal solution I had already made an temporary fork of the package that worked with vue3 and that is what we have been using with JIG, I personally have never experienced the problem you are having. See the screenshot and tell me if that is what you have been using.

image
If not, you can modify vue-select in package.json as below and run npm install --update or yarn upgrade

{
"devDependencies": {
    "...",
    "vue-select": "savannabits/vue-select#v4.0.0-alpha.0",
    "..."
}
}

I haven't tried vue-select v4.0.0-beta.1 but I am sure it will have some breaking changes. You could try it and see if it works

from jetstream-inertia-generator.

coolsam726 avatar coolsam726 commented on June 1, 2024

I have tested [email protected] and it seems to work perfectly with vue3. If you want to give it a try here are the changes you need to make:

  1. Run yarn add -D [email protected]
  2. Modify vue-select import statement in resources/js/JigComponents/InfiniteSelect.vue and resources/js/JigComponents/JigSelect.vue:
// import vSelect from "vue-select/src/index"; // Remove this line 
import vSelect from "vue-select"; // Replace with this line

From here you should be good to go.

from jetstream-inertia-generator.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.