skip to Main Content

I’m working on a VUE app. Part of the app is to show a table (team) with information from the backend (by axios / django rest_framework). This all works.

When I click "nieuwe categorie" the modal opens with a form. Onsubmit, the function "submitHandler" is used. However, in that function I can’t get the form data? Which I need to "POST" with axios to the backend….

I’ve tried v-model on the modal form, but gives a reference error.

Anyway, any help would be appreciated.

The modal component:

<script setup>
import { defineProps, defineEmits, ref } from "vue";
import { onClickOutside } from '@vueuse/core'

const offset = 6

const props = defineProps({
    isOpen: Boolean,
    isTest: String,
    Categorie: String,
    modalAction: String,
});

const emit = defineEmits(["modal-close"]);

const target = ref(null)
onClickOutside(target, () => emit('modal-close'))

</script>

<template>
    <div v-if="isOpen" class="modal-mask">
        <div class="modal-wrapper">
            <div class="modal-container" ref="target">
                <div class="modal-header py-5">
                    <slot name="header">
                        <div v-if="modalAction === 'new'">
                            <h1>Nieuwe Categorie</h1>
                        </div>
                        <div v-else-if="modalAction === 'edit'"> {{ Categorie }}</div>
                    </slot>
                </div>
                <div class="modal-body">
                    <slot name="content">
                        <div class="mx-2" v-if="modalAction === 'new'">
                            <form class="w-full" @submit.prevent="submitHandler">
                                <div class="flex -mx-2">
                                    <div class="items-center border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Categorie
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            placeholder="1:1" aria-label="">
                                            <option v-for="n in 14">Onder-{{ n + offset }}
                                            </option>


                                        </select>
                                    </div>
                                </div>
                                <div class="flex -mx-2">
                                    <div class="w-full items-center border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            T/M geboortejaar
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            placeholder="1:1" aria-label="">
                                            <option v-for="n in 14">{{ n + 2003 }}</option>
                                        </select>
                                    </div>
                                    <div class="w-10"></div>
                                    <div class="w-full items-center border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Aantal veldspelers
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            placeholder="1:1" aria-label="">
                                            <option>4</option>
                                            <option>6</option>
                                            <option>8</option>
                                            <option>11</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="flex -mx-2">
                                    <div class="items-center w-full border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Veldomvang
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            type="select" placeholder="1:1" aria-label="veld">
                                            <option>1:8</option>
                                            <option>1:4</option>
                                            <option>1:2</option>
                                            <option>1:1</option>
                                        </select>
                                    </div>
                                    <div class="w-10"></div>
                                    <div class="items-center w-full border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Wedstrijdduur
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            placeholder="1:1" aria-label="">
                                            <option>12</option>
                                            <option>2x20 (na 10min time-out)</option>
                                            <option>2x25 (na 12,5min time-out)</option>
                                            <option>2x30 (na 15min time-out)</option>
                                            <option>2x30</option>
                                            <option>2x35</option>
                                            <option>2x40</option>
                                            <option>2x45</option>

                                        </select>
                                    </div>
                                </div>
                                <div class="flex -mx-2">
                                    <div class="w-full items-center border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Dispensatie
                                        </label>
                                        <select
                                            class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            placeholder="1:1" aria-label="">
                                            <option v-for="n in 3">{{ n }}</option>


                                        </select>
                                    </div>
                                    <div class="w-10"></div>
                                    <div class="w-full items-center border-b border-teal-500 py-2 px-2">
                                        <label
                                            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
                                            for="grid-first-name">
                                            Actief binnen club
                                        </label>
                                        <input
                                            class="appearance-none bg-transparent border-blue text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
                                            type="checkbox" placeholder="1" aria-label="dispensatie">
                                        </input>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </slot>
                </div>
                <div class="modal-footer">
                    <slot name="footer">
                        <div>
                            <!--<button @click.stop="emit('modal-close')">Submit</button>-->
                            <button>Submit</button>
                        </div>
                    </slot>
                </div>
            </div>
        </div>
    </div>
</template>

<script>


</script>

<style scoped>
.modal-mask {
    position: fixed;
    z-index: 9998;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}

.modal-container {
    width: 800px;
    margin: 150px auto;
    padding: 20px 30px;
    background-color: #fff;
    border-radius: 2px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
}
</style>

and the view:

<script setup>
import { ref } from "vue";
import ModalComponent from "../components/ModalComponent.vue";
import axios from 'axios'

const isModalOpened = ref(false);
const test = ref('')
const editCategorie = ref('')
const modalAction = ref('new')
const form = ref([])
const openModal = (cat, action) => {
    if (!action) {
        console.log('action: ', action)
        action = 'new'
    }
    modalAction.value = action
    editCategorie.value = cat.categorie
    isModalOpened.value = true;
};
const closeModal = () => {
    isModalOpened.value = false;

};

const submitHandler = () => {
    //here I should be able to get the form data
    console.log('data:', this.form) //this gives an error 'form not defined'
}
</script>
<template>
    <div class="p-2 pt-20 sm:ml-64">
        <div class="p-4 border-2 border-gray-200 border-dashed bg-gray-200 rounded-lg dark:border-gray-700 mt-14">
            <!-- CRUD table goes here-->
            <!-- Start block -->
            <section class="bg-gray-50 dark:bg-gray-900 p-3 sm:p-5 antialiased">
                <div class="mx-auto max-w-screen-xl px-4 lg:px-12">
                    <!-- Start coding here -->
                    <div class="bg-white dark:bg-gray-800 relative shadow-md sm:rounded-lg overflow-hidden">
                        <div
                            class="flex flex-col md:flex-row items-center justify-between space-y-3 md:space-y-0 md:space-x-4 p-4">
                        </div>
                        <div class="overflow-x-auto">
                            <table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
                                <thead
                                    class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
                                    <tr>
                                        <th scope="col" class="px-4 py-3">Actief binnen club</th>
                                        <th scope="col" class="px-4 py-3">Categorie</th>
                                        <th scope="col" class="px-4 py-3">t/m geboortejaar</th>
                                        <th scope="col" class="px-4 py-3">Max. aantal veldspelers</th>
                                        <th scope="col" class="px-4 py-3">Veldomvang</th>
                                        <th scope="col" class="px-4 py-3">Wedstrijdduur</th>
                                        <th scope="col" class="px-4 py-3">Dispensatie</th>
                                        <th scope="col" class="px-4 py-3">Wijzig</th>

                                    </tr>
                                </thead>
                                <tbody v-for="cat in teamcats">

                                    <tr class="border-b dark:border-gray-700">
                                        <td class="px-4 py-3">
                                            <input v-model="cat.actief" type="checkbox" />
                                        </td>
                                        <th scope="row"
                                            class="px-4 py-3 font-medium text-gray-900 whitespace-nowrap dark:text-white">
                                            {{ cat.categorie }}</th>
                                        <td class="px-4 py-3">{{ cat.geboortejaar }}</td>
                                        <td class="px-4 py-3">{{ cat.veldspelers }}</td>
                                        <td class="px-4 py-3 max-w-[12rem] truncate">{{ cat.veldomvang }}</td>
                                        <td class="px-4 py-3">{{ cat.wedstrijdduur }}</td>
                                        <td class="px-4 py-3">{{ cat.dispensatie }}</td>
                                        <td class="px-4 py-3"><button class="bg-blue-300"
                                                @click="openModal(cat, mode = 'edit')">Wijzig</button>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <div class="flex flex-col italic md:flex-row justify-between items-start md:items-center space-y-3 md:space-y-0 p-4"
                            aria-label="Table navigation">
                            <span class="text-sm font-normal text-gray-500 dark:text-gray-400">
                                Datum laatste wijziging:
                                <span class="font-semibold text-gray-900 dark:text-white">22-03-2024</span>
                            </span>
                            <div>
                                <!-- Modal toggle -->
                                <div>
                                    <!--<button @click="openModal">Toevoegen Categorie</button>-->
                                    <button @click="openModal">Toevoegen Categorie</button>
                                </div>

                            </div>
                        </div>
                    </div>
                    <!-- modal-->

                    <ModalComponent :isOpen="isModalOpened" :modalAction="modalAction" :Categorie="editCategorie"
                        @modal-close="closeModal" @submit="submitHandler" name="first-modal">
                        <template #header></template>
                        <template #content></template>
                        <template #footer><button @click="submitHandler">submit</button></template>
                    </ModalComponent>


                    <!-- modal-->
                </div>
            </section>
            <!-- End block -->
            <!-- END OF CRUD Table-->
        </div>
    </div>
</template>

<script>

import axios from 'axios'
import TestView from "./TestView.vue";

export default {
    data() {
        return {
            teamcats: [],

        }
    },
    mounted() {

        this.getTeamCats()
    },
    methods: {
        getTeamCats() {
            axios
                .get('/api/team/view')
                .then(response => {
                    console.log(response.data)
                    this.teamcats = response.data
                })
                .catch(error => {
                    console.log('error', error)
                })
        },



    }

}

</script>

2

Answers


  1. Chosen as BEST ANSWER

    with the support of @wbiller (THANKS SO MUCH!)

    and some logic thinking...data was 'nothing' the final solution was to create a reactive data object:

    const data = reactive({ categorie: '' })
    

    and in the modal, the correct data binding:

    v-model="data.categorie">
    

    Now I see the data in the submithandler: {categorie: 'Onder-14'}


  2. You can pass the data using emit to the table component

    In the modal component, define another emit. For that change this line

    const emit = defineEmits(["modal-close"]);

    to this here

    const emit = defineEmits(["modal-close", "submit"]);.

    Then define a function to emit this event and the data. Currently, you don’t have the data model in your modal, you need to create this first and bind it with v-model to the controls.

    const submit = () => {
      emit('submit', data);
    }
    

    I saw you have overwritten the footer slot, either you undo that and call the submit function from the existing button, or you provide the submit function as a scoped slot (v-bind on slot). Then you can also use it in your table.

    <slot name="footer" v-bind="{ submit }">
      <button @click.prevent="submit">Submit</button>
    </slot>
    

    In your table make the submitHandler function accent one parameter, that will be the data.

    const submitHandler = (data) => {
        // do the things with axios
        // close the modal
    }
    

    If you want to be in control of the submit button, the footer of the modal in the table component must look like this:

    <template #footer="{ submit }"><button @click="submit">submit</button></template>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search