从VueJS的父组件中引用子组件的索引

时间:2019-03-19 22:07:44

标签: javascript laravel laravel-5 vuejs2 vue-component

我正在处理 Laravel 5.7 应用程序中的页面,该应用程序中包含一系列 VueJS 子组件“前景” VueJS 父组件“前景” 。子组件是表行,每个表行都有一个删除行/子组件的按钮。父组件具有一个删除多个子组件的按钮。

但是,我不确定如何使父组件函数调用子组件函数来删除已标记为删除的子组件。

从子组件本身中一次删除一个子组件可以正常工作。但是,我试图从父组件函数 deleteSelectedProspects()中的循环中多次调用同一个子组件删除函数。

deleteSelectedProspects()中,我需要访问分配给子组件的 index ,以便在 $ refs 中引用正确的行数组。


如何在 selectedBoxes.forEach 循环内的$ refs数组中正确访问子组件的索引?


包含 Prospects父级组件的刀片视图的源代码:

@extends('layouts.admin')

@section('content')
    <section id="widget-grid">
        <div class="row">
            <article class="col-xs-12 col-sm-12 col-md-12 col-lg-12 sortable-grid ui-sortable">
                <prospects inline-template class="">
                <div>


                    <div class="jarviswidget jarviswidget-sortable" id="wid-id-1" data-widget-editbutton="false" data-widget-deletebutton="false">
                        <header class="ui-sortable-handle">
                            <div class="widget-header"> 
                                <h2><i class="fa fa-list text-orange"></i> Prospects/Leads List</h2>
                            </div>

                            <button class="btn btn-sm btn-primary d-none" @click="markSelectedProspectsContacted" id="btnMarkSelectedProspectsContacted">
                                <span class="fa fa-check-square-o"></span> Mark Selected as Contacted
                            </button>
                            <button class="btn btn-sm btn-danger d-none" @click="deleteSelectedProspects" id="btnDeleteSelectedProspects"><span class="fa fa-trash"></span> Delete Selected</button>
                        </header>

                        <!-- widget div-->
                        <div role="content">
                            <!-- widget content -->
                            <div class="widget-body">
                                <table id="prospectsTable" class="table table-striped table-bordered table-hover">
                                    <thead>
                                        <tr>
                                            <th>
                                                <label class="vcheck">
                                                    <input type="checkbox" id="toggleCheckAllProspects" value="1" /> <span></span>
                                                </label>
                                            </th>
                                            <th>Name</th>
                                            <th>Food Category</th>
                                            <th>Contact</th>
                                            <th>Admin Comments</th>
                                            <th></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr is="prospect"
                                            v-for="(prospect, index) in prospects" 
                                            :prospect="prospect" 
                                            :index="index" 
                                            :key="prospect.id" 
                                            ref="refIds" 
                                            @delete-prospect="removeProspect()" 
                                            @update-contacted="updateContacted(index)">
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                            <!-- end widget content -->
                        </div>
                    </div>
                    <!-- end jarviswidget div -->
                </div>
                </prospects>
            </article>
        </div>
    </section>
@endsection

@push('js-block')
    <script>
    $.widget( "ui.tabs", $.ui.tabs, {
        _getPanelForTab: function( tab ) {
            var id = $( tab ).attr( "aria-controls" );
            return $( this._sanitizeSelector( "#" + id ) );
        }
    });

    $(function() {
        $('#prospectTabs').tabs({
            create: removeLoader($('#prospectTabs'))
        });

        $('#prospectTabsAdd').click(function() {
            $('#add-tab').removeClass('d-none');
        });

        $('#toggleCheckAllProspects').click(function() {
            $('.prospect-check').prop('checked', ($(this).is(':checked') ? true : false));
        });
    });
    </script>
@endpush

父组件“前景” 的源代码:

<script>
    export default {
        data: function() {
            return {
                formProspect: {
                    inputs: {
                        name:           '',
                        food_cat_id:    '', 
                        phone:          '',
                        website:        '',
                        contact_fname:  '',
                        contact_lname:  '',
                        contact_title:  '',
                        address:        '', 
                        address2:       '',
                        city:           '', 
                        state_id:       '',
                        zip:            '', 
                        response_notes: ''
                    },
                    headerText: "<i class='fa fa-plus-square-o text-orange'></i> Add Prospect / Lead",
                    btnText: "<i class='fa fa-plus-square-o'></i> Add Prospect / Lead", 
                    errors: false
                },
                formSearchProspect: {
                    inputs: {
                        keywords:   '',
                        contacted:  '', 
                        location:   '', 
                        radius:     5
                    }
                }, 
                formProspectMode: 'add',
                prospects: []
            }
        }, 
        computed: {

        },
        watch: {
            formProspectMode: function(newMode) {
                switch(newMode) {
                    case 'add':
                        this.formProspect.headerText = "<i class='fa fa-plus-square-o text-orange'></i> Add Prospect / Lead";
                        this.formProspect.btnText = "<i class='fa fa-plus-square-o'></i> Add Prospect / Lead";
                        this.clearFormProspect();
                        break;

                    case 'edit':
                        this.formProspect.headerText = "<i class='fa fa-edit text-orange'></i> Edit Prospect / Lead";
                        this.formProspect.btnText = "<i class='fa fa-save'></i> Save Prospect / Lead";
                        break;
                }
            }

        },

        methods: {
            fetchProspects() {
                var self = this;
                $.get('/prospect/fetch', function(r) {
                    if(r.successMsg) {
                        self.prospects = r.prospects;
                    }
                })
            },

            searchProspects() {
                var self = this;

                var params = {
                    'keywords'  : this.formSearchProspect.inputs.keywords, 
                    'contacted' : this.formSearchProspect.inputs.contacted
                };

                if(this.formSearchProspect.inputs.location) {
                    params.location     = this.formSearchProspect.inputs.location;
                    params.radius       = this.formSearchProspect.inputs.radius;
                }

                $.get('/prospect/search', params, function(r) {
                    if(r.successMsg) {
                        self.prospects = r.prospects;
                    }
                })
            }, 

            addProspect() {
                var self = this;

                $.ajax({
                    type:       "POST",
                    dataType:   "json", 
                    async:      false,
                    url:        "/prospect/add", 
                    data:       {
                        name:                   this.formProspect.inputs.name,
                        food_cat_id:            this.formProspect.inputs.food_cat_id,
                        phone:                  this.formProspect.inputs.phone,
                        website:                this.formProspect.inputs.website,
                        contact_fname:          this.formProspect.inputs.contact_fname,
                        contact_lname:          this.formProspect.inputs.contact_lname,
                        contact_title:          this.formProspect.inputs.contact_title,

                        address:                this.formProspect.inputs.address, 
                        address2:               this.formProspect.inputs.address2, 
                        city:                   this.formProspect.inputs.city,
                        state_id:               this.formProspect.inputs.state_id, 
                        zip:                    this.formProspect.inputs.zip,
                        response_notes:         this.formProspect.inputs.response_notes
                    }, success(r) {
                        if(r.successMsg) {
                            var newProspect = self.formProspect.inputs;
                            newProspect.id = r.newId;
                            newProspect.state = r.state;
                            newProspect.food_cat = r.food_cat;

                            console.log(newProspect);

                            self.prospects.push(Object.assign({}, newProspect));

                            self.clearFormProspect();   
                        } else if(r.errors) {
                            self.formProspect.errors = r.errors; 
                        }
                    }       
                });
            },

            saveProspect() {
                var self = this;

                $.post('/prospect/edit', {
                    id:                     this.formProspect.inputs.id,
                    name:                   this.formProspect.inputs.name,
                    food_cat_id:            this.formProspect.inputs.food_cat_id,
                    phone:                  this.formProspect.inputs.phone,
                    website:                this.formProspect.inputs.website,
                    contact_fname:          this.formProspect.inputs.contact_fname,
                    contact_lname:          this.formProspect.inputs.contact_lname,
                    contact_title:          this.formProspect.inputs.contact_title,

                    address:                this.formProspect.inputs.address, 
                    address2:               this.formProspect.inputs.address2, 
                    city:                   this.formProspect.inputs.city,
                    state_id:               this.formProspect.inputs.state_id, 
                    zip:                    this.formProspect.inputs.zip, 
                    response_notes:         this.formProspect.inputs.response_notes
                }, function(r) { 
                    if(r.successMsg) {
                        var savedProspect = self.prospects.filter(prospect => prospect.id == self.formProspect.inputs.id)[0];
                        savedProspect = Object.assign({}, self.formProspect.inputs);

                        self.formProspectMode = "add";
                    } else if(r.errors) {
                        self.formProspect.errors = r.errors; 
                    }
                });
            },

            removeProspect(index) {
                this.prospects.splice(index, 1);
            }, 

            clearFormProspect() {
                this.formProspect.inputs = {};
                this.formProspect.errors = false;
            }, 

            deleteSelectedProspects() {
                var self = this;
                var selectedBoxes = self.prospects.filter(prospect => prospect.selected); 

                $.SmartMessageBox({
                    title: "<i class='fa fa-trash text-orange-dark'></i> Delete (" + selectedBoxes.length + ") Selected Prospects",
                    content: "Are you sure you want to delete the selected leads?",
                    buttons: "[No][Yes]"
                }, function(e) {
                    if("Yes" == e) {
                        selectedBoxes.forEach(function(p) {
                            var lostChild = self.prospects.filter(prospect => prospect.id == p.id);

                            // HOW CAN I ACCESS THE INDEX OF THE LOST CHILD TO REFERENCE IT IN THE $refs ARRAY BELOW
                            // HOW CAN I ACCESS THE INDEX OF THE LOST CHILD TO REFERENCE IT IN THE $refs ARRAY BELOW
                            //self.$refs.refIds[lostChildIndex].deleteProspect();
                        });
                    }
                });
            }, 

            markSelectedProspectsContacted() {
                var self = this;
                var selectedBoxes = self.prospects.filter(prospect => prospect.selected); 

                $.SmartMessageBox({
                    title: "<i class='fa fa-trash text-orange-dark'></i> Mark (" + selectedBoxes.length + ") Selected Prospects as Contacted",
                    content: "Are you sure you want to mark the selected leads as contacted?",
                    buttons: "[No][Yes]"
                }, function(e) {
                    if("Yes" == e) {
                        selectedBoxes.forEach(function(p) {

                            /*
                            mark contacted
                            */
                        });
                    }
                });
            }, 

            updateRadiusSearchDiv() {
                if($('#searchLocation').val()) {
                    $('#radiusSearchDiv').removeClass('d-none');
                } else {
                    $('#radiusSearchDiv').addClass('d-none');
                }
            }
        }, 
        mounted() {
            this.fetchProspects();

            setTimeout(function() {
                $('#prospectsTable').DataTable({
                    "columnDefs": [
                        { "orderable": false, "targets": [0,4,5] }
                    ], 
                    "language": {
                        "search": "Filter Results:" 
                    }, 
                    "dom": "ftilp"
                });

                $('#prospectsTable > thead > tr th:first-child').removeClass('sorting_asc');
            }, 500);

            $('#btnDeleteSelectedProspects, #btnMarkSelectedProspectsContacted').removeClass('d-none');
        }
    }

</script>

子组件“前景” 的源代码:

<template>
    <transition name="fade">
        <tr v-if="show">
            <td class="text-center align-middle">
                <label class="vcheck">
                    <input type="checkbox" class="prospect-check" value="1" v-model="prospect.selected" /> <span></span>
                </label>
            </td>
            <td>
                <div>{{ prospect.name }}</div>
                <div v-show="prospect.contacted" class="label label-success"><span class="fa fa-check-square-o"></span> Contacted!</div>
            </td>
            <td>{{ prospect.food_cat.title }}</td>
            <td>{{ prospect.contact_fname }}<span v-if="prospect.contact_lname"> {{ prospect.contact_lname }}</span><span v-if="prospect.contact_title">, {{ prospect.contact_title }}</span></td>
            <td>{{ prospect.response_notes }}</td>
            <td class="text-right align-middle">
                <button class="btn btn-primary" @click="updateContacted" v-show="!prospect.contacted"><span class="fa fa-check-square-o"></span> Mark As Contacted</button>
                <button class="btn btn-primary" @click="editProspect"><span class="fa fa-edit"></span> Edit Lead</button>
                <button class="btn btn-danger" @click="removeProspect"><span class="fa fa-trash"></span> Delete Lead</button>
            </td>
        </tr>
    </transition>
</template>

<script>
    export default {
        props: ['prospect', 'index'],
        data: function() {
            return {
                prospectData: this.prospect, 
                show: true, 
                prospectIndex: this.index
            }
        },
        methods: {
            editProspect() {
                this.$parent.formProspect.inputs = this.prospectData;
                this.$parent.formProspectMode = "edit";

                $('#prospectTabs').tabs('option', 'active', 1);
                $('#add-tab').removeClass('d-none');

                window.scrollTo({ top: 0, behavior: 'smooth' });
            },
            updateContacted() {
                var self = this;

                $.SmartMessageBox({
                    title: "<i class='fa fa-trash text-orange-dark'></i> Mark as Contacted?",
                    buttons: "[No][Yes]"
                }, function(e) {
                    if("Yes" == e) {
                        $.post('/prospect/updateContacted/' + self.prospectData.id, function(r) {
                            if(r.successMsg) {
                                self.$emit('update-contacted');
                            }
                        });
                    }
                });
            }, 
            removeProspect() {
                var self = this;
                $.SmartMessageBox({
                    title: "<i class='fa fa-trash text-orange-dark'></i> Delete Prospect/Lead",
                    content: "Are you sure you want to delete this prospect/lead?",
                    buttons: "[No][Yes]"
                }, function(e) {
                    if("Yes" == e) {
                        self.deleteProspect();
                    }
                });
            }, 
            deleteProspect() {
                var self = this;

                $.post('/prospect/delete/' + self.prospectData.id, function(r) {
                    if(r.successMsg) {
                        self.show = false;
                        self.$emit('delete-prospect');
                    }
                });
            }
        },
        mounted() {

        }   
    }
</script>

1 个答案:

答案 0 :(得分:1)

您的代码有些混乱,因此,这只是一个应该很好用的想法。您不应该碰参考,您只需要更改数据模型即可。从数据移动中删除,组件将自行删除。

在父组件中添加一个名为checkProspect之类的方法

data: {
   ...
   checkedProspects: []
},
methods: {
   checkProspect(prospectId){
      checkedProspects.push(prospectId);
   },
   deleteCheckedProspects(){
     // Remove from the model by checkedProspects ids
   }
}

然后添加处理程序:

<tr is="prospect"
   v-for="(prospect, index) in prospects" 
   :prospect="prospect" 
   :index="index" 
   :key="prospect.id" 
   ref="refIds" 
   @checkProspect="checkProspect" 
   @delete-prospect="removeProspect()" 
   @update-contacted="updateContacted(index)">

在子组件中,单击以进行检查时,发出事件:

this.$emit('checkProspect', this.id);