javascript - 在 VueJS 中从父组件中引用子组件的索引

标签 javascript laravel laravel-5 vuejs2 vue-component

我正在 Laravel 5.7 应用程序中的一个页面上工作,该应用程序有一系列 VueJS 子组件 "Prospect" 包裹在VueJS父组件“前景”。子组件是表行,每个行都有一个用于删除行/子项的按钮。父组件有一个删除多个子组件的按钮。

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

从子组件本身内部一次删除一个子组件效果很好。但是,我试图从父组件函数 deleteSelectedProspects() 内的循环中多次调用同一个子组件删除函数。

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

<小时/>

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

<小时/>

包含Prospects父组件的 Blade View 的源代码:

@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

父组件“prospects”的源代码:

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

子组件“prospect”的源代码:

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

最佳答案

你的代码有点困惑,所以这只是一个应该运行良好的想法。您不应该触摸引用,您只需要更改数据模型。从数据移动中删除,组件将自行删除。

在父组件中添加一个名为 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);

关于javascript - 在 VueJS 中从父组件中引用子组件的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55250686/

相关文章:

javascript - Angularjs指令点击元素

javascript - addEventListener 和 `this` 未按预期工作

mysql - 在 2 个不同地点工作的同时构建一个项目

php - 如果从 json 获取空值,如何获取文本框而不是下拉选择框

php - Laravel 中的自定义查询

javascript - 使用包含状态变量的 .map 渲染数组 - 不更新

javascript - Webpack 更改窗口全局对象范围

php - 备份管理器的 ShellProcessFailed 错误 - Laravel

laravel - 无法监听本地主机 :8000 (reason: Cannot assign requested address)

php - Laravel 5 中未找到类