3

I'm new to Vuejs. I have written a vuejs component for delete confirmation modal. I call this inside a list of records, here is my code :

<template id="bs-modal">
    <div class="modal fade" id="confirmDeleteModal" tabindex="-1"
         role="dialog" aria-labelledby="confirmDeleteModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close"
                            data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                    <h4 class="modal-title"
                        id="confirmDeleteModalLabel">
                        Delete {{ item | capitalize }}
                    </h4>
                </div>
                <div class="modal-body">
                    Are you sure about deleting the {{ name }} {{ item }} ?
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default"
                            data-dismiss="modal">No</button>
                    <button type="button" class="btn btn-primary"
                            v-on:click="deleteItem(id)">Yes</button>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data () {
            return {
            }
        },
        props: ['item', 'name', 'id'],
        methods: {
            deleteItem : function(id) {
                var url           = window.location.href;
                var baseUrl       = url.substring(0,
                        url.indexOf('/', url.indexOf('://') + 3) + 1);
                var adminPosition = url.indexOf('admin/') + 6;
                var entity        = url.substring(adminPosition,
                                     url.indexOf('/', adminPosition));

                this.$http.delete(baseUrl + "admin/" + entity + "/" + id).then((response) => {
                    if (response.body.status_code == '200') {

                        // Calling just modal('hide') does not hide the backdrop
                        // There should be a better solution for this
                        $("#confirmDeleteModal").modal("hide");
                        $("#confirmDeleteModal").hide();
                        $('.modal-backdrop').hide();
                        $("body").removeClass("modal-open");

                        $("tr[data-id=" + id + "]").remove();

                        // Display success message
                    }
                });
            }
        },
        filters: {
            capitalize: function (value) {
                if (!value) {
                    return '';
                }
                value = value.toString();

                return value.charAt(0).toUpperCase() + value.slice(1);
            }
        }
    }
</script>

And here is my blade template where I call this component (I'm using laravel 5.3) :

@foreach ($categories as $category)
    <tr data-id="{{ $category->id }}">
        <td>{{ $category->id }}</td>
        <td>{{ $category->name }}</td>
        <td id="actions">
            <a href="{{ url('admin/category/' . $category->id . '/get') }}">Show</a>
            <a href="{{ url('admin/category/' . $category->id . '/edit') }}">Edit</a>
            <a href="#" data-toggle="modal" data-target="#confirmDeleteModal">Delete</a>
            <confirm-delete-modal item="category" id="{{ $category->id }}" name="{{ $category->name }}"></confirm-delete-modal>
        </td>
    </tr>
@endforeach

The parameters I pass to the component are variable and according to Vue devtools, the component gets the correct value for each record but when I run the code, it always gets the parameters of first record in list.

Am I missing something ?

3 Answers 3

1

I think the main issue came from same Id for all components and when you click on a link first element with ID (confirmDeleteModal) will be opened.

You can set an unique id for each components like this:

<div class="modal fade" :id="'confirmDeleteModal_'+id" tabindex="-1"
     role="dialog" aria-labelledby="confirmDeleteModalLabel">
Sign up to request clarification or add additional context in comments.

Comments

0

I think calling the confirm-delete-modal for each record is a wrong method. I moved the modal outside the loop and made some changes to the code to solve the problem :

Here is the code of confirmDelete.vue :

<template id="modal-template">
    <transition name="confirm-delete-modal">
        <div class="modal-mask">
            <div class="modal-wrapper">
                <div class="modal-container">

                    <div class="modal-header">
                        <slot name="header">
                            default header
                        </slot>
                    </div>

                    <div class="modal-body">
                        <slot name="body">
                            Are you sure about deleting the {{ this.$parent.item_name }} {{ item }} ?
                        </slot>
                    </div>

                    <div class="modal-footer">
                        <slot name="footer">
                            <button class="modal-default-button" @click="deleteItem();">
                                Yes
                            </button>
                            <button class="modal-default-button" @click="$emit('close')">
                                No
                            </button>
                        </slot>
                    </div>
                </div>
            </div>
        </div>
    </transition>
</template>

<script>
    export default {
        data () {
            return {
            }
        },
        props: ['item'],
        methods: {
             deleteItem : function() {
                 var url           = window.location.href;
                 var baseUrl       = url.substring(0, url.indexOf('/', url.indexOf('://') + 3) + 1);
                 var adminPosition = url.indexOf('admin/') + 6;
                 var entity        = url.substring(adminPosition, url.indexOf('/', adminPosition));

                 this.$http.delete(baseUrl + "admin/" + entity + "/" + this.$parent.item_id).then((response) => {
                     if (response.body.status_code == '200') {

                         $("tr[data-id=" + this.$parent.item_id + "]").remove();

                         this.$emit('close');
                         // Display success message
                     }
                 });
             }
         },
         filters: {
             capitalize: function (value) {
                 if (!value) {
                     return '';
                 }
                 value = value.toString();

                 return value.charAt(0).toUpperCase() + value.slice(1);
             }
         }
    }
</script>

And here is the blade template :

    @foreach ($categories as $category)
        <tr data-id="{{ $category->id }}">
            <td>{{ $category->id }}</td>
            <td>{{ $category->name }}</td>
            <td id="actions">
                <a href="{{ url('admin/category/' . $category->id . '/get') }}">Show</a>
                <a href="{{ url('admin/category/' . $category->id . '/edit') }}">Edit</a>
                <a href="#" id="{{ $category->name }}_{{ $category->id }}" @click="setDeleteModal($event)">Delete</a>
            </td>
        </tr>
    @endforeach
    <confirm-delete-modal item="category"
                          v-if="showDeleteModal"
                          @close="closeDeleteModal">
        <h3 slot="header">Delete Category</h3>
    </confirm-delete-modal>

And finally here is the code of parent vue instance :

    new Vue({
        el: '#crud',
        data: {
            showDeleteModal: false,
            item_id: '',
            item_name: ''
        },
        methods: {
            setDeleteModal: function(e) {
                this.showDeleteModal = true;
                params               = e.target.id.split("_");
                this.item_id         = params[1];
                this.item_name       = params[0];
            },
            closeDeleteModal: function() {
                this.showDeleteModal = false;
            }
        }
    });

I hope this helps someone else.

I'll be glad to know the idea of experts in vuejs.

Comments

0

You need to use v-bind when passing variables as props, like following"

<confirm-delete-modal item="category" v-bind:id="{{ $category->id }}" v-bind:name="{{ $category->name }}"></confirm-delete-modal>

or in short you can replace v-bind with : as:

<confirm-delete-modal item="category" :id="{{ $category->id }}" :name="{{ $category->name }}"></confirm-delete-modal>

1 Comment

I get the '[Vue warn]: Property or method "value-of-param" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.' error

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.