Alenoosh Baghumian
Alenoosh Baghumian

Reputation: 115

Accessing variable parameters of Vuejs component inside a loop

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 ?

Upvotes: 3

Views: 1717

Answers (3)

Saurabh
Saurabh

Reputation: 73609

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>

Upvotes: 0

sajad Ayooby
sajad Ayooby

Reputation: 140

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">

Upvotes: 1

Alenoosh Baghumian
Alenoosh Baghumian

Reputation: 115

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.

Upvotes: 0

Related Questions