Использование $ emit из дочернего компонента для отправки данных в родительский компонент не работает с Vue - PullRequest
2 голосов
/ 25 марта 2019

Я пишу компонент "вкладки".

Я пытаюсь отправить данные с использованием метода sendTabsData() в моем коде, и по какой-то причине он не работает с использованием $emit.

Это код компонента моей вкладки:

<template>
    <div id="tabs">
        <div id="tabs-cont">
            <div class="tabbable-panel">
                <div class="tabbable-line">
                    <ul class="nav nav-tabs" role="tablist"> 
                    </ul>
                    <div class="tab-content">
                        <slot></slot>
                    </div>
                </div>
            </div>
        </div> 
    </div> 
</template>

<script>
export default {
    name: 'DashboardTabs',
    props: {
        tabs: {
            type: Object,
            required: true,
            default: {}
        }
    },
    data() {
        return {
            displayed:      '',
            tabName:        '',
            $tabsContainer: null,
            navTabs:        null, 
            tabContent:     null
        }
    },
    created() {
    },
    mounted() {
        this.init();
    },
    watch: {
    },
    methods: {
        init: function() {
            // Fetch UI elements 
            this.$tabsContainer = $('#tabs');
            this.navTabs        = this.$tabsContainer.find('.nav-tabs');
            this.tabContent     = this.$tabsContainer.find('.tab-content');

            this.createTabs(this.tabs);
        },
        // Create tabs by result
        createTabs: function(tabs) {
            if ( this.tabs !== undefined || this.tabs.length > 0 ) {
                this.setTabsBtns(tabs);
            }
        },
        // 
        tabClick: function(e) {
            this.changeDisplayNames(e);         
            this.sendTabsData();
        },
        // Change display names
        changeDisplayNames: function(e) {

            let liItem = e['target']['dataset']['displaytable'];

            if (liItem) {
                // Update variable table name
                this.displayed = liItem;
                // Remove the '$' and 'Table' text
                let tableCategory   = this.displayed.replace('Table', '');
                tableCategory       =  tableCategory.replace('$', '');
                // Update "global" variable of the current table
                this.tabName        = tableCategory.charAt(0).toUpperCase() + tableCategory.slice(1);
            }
        }, 
        // Set tabs li btns 
        setTabsBtns: function(tabs) {

            for (let key in tabs) {
                this.navTabs.append(`<li class="nav-item" @click="this.tabClick"> <a href="#tab_default_${key}" class="nav-link" data-toggle="tab" data-displayTable="${tabs[key]}"> ${tabs[key]} </a> </li>`);
            }

            this.navTabs.find('li:first a').addClass('active');
            this.displayed  = this.tabs[0];
            this.tabName    = this.tabs[0];
        }, 
        // Set tabs content divs - not relevant if you don't want to load extra data to the DOM
        setTabsContent: function(tabs) {

            for (let key in tabs) {
                this.tabContent.append(`<div class="tab-pane" id="tab_default_${key}"> <table class="aTable hover display" id="${tabs[key]}"> </table> </div>`);
            }

            this.tabContent.find('.tab-pane').first().addClass('active');
        },
        hideTabs: function() {
            this.$tabsContainer.slideUp('slow');
        },
        showTabs: function() {
            this.$tabsContainer.slideDown('slow');
        },
        // Send tab data to parent
        sendTabsData: function(){
            let data = {
                'tabDisplayed': this.displayed,
                'tabName':      this.tabName            
            };
            this.$emit('tabsData', data);
        }
    }
};
</script>   

и это родительский компонент:

<script>
    // import ProgressBar      from "../components/ProgressBar.vue";
    // import _                from 'lodash';
    import DashboardForm    from "../components/DashboardForm.vue";
    import DashboardTabs    from "../components/DashboardTabs.vue";

    export default {
        name: 'testcomponent',
        components: {
            // ProgressBar,
            DashboardForm, 
            DashboardTabs
        },
        // mixins: [GF],
        data() {
            return {
            };
        },
        created() {
        },
        mounted() {
        },
        destroyed() {
        },
        watch: {
        },
        methods: {
            // Submit form
            formSubmit: function(data) {
                console.log('Submit form here');
                console.log(data);
            }, 
            // Tabs data 
            fetchTabsData: function(data) {
                console.log('tab was clicked');
                console.log(data);
            }
        }
    }
</script>

<!-- Template -->
<template>

    <div id="testcomponent">

        <!-- DashboardForm -->
        <DashboardForm 
            :useGroupFilter="true"
            :useDateRange="true"
            @submit="formSubmit"
        />

        <!-- Main Data Container -->
        <div id="data-container">
            <div id="chart-container"></div>
            <!-- Dashboard Tabs and Tab Container -->
            <DashboardTabs
                :tabs="{ 0: 'potato', 1: 'banana' }"
                @tabsData="fetchTabsData"
            >
                <!-- Datatable -->
                <!-- <DashboardDatatable/> -->
            </DashboardTabs>


        </div> 
        <!-- END data-container -->

    </div>
</template>

Как вы можете видеть, в моем родительском компоненте у меня есть emit submit, который извлекает данные (и работает нормально).

Единственное различие между компонентом вкладок и компонентом формы состоит в том, что компонент вкладки генерирует <li> s, с которыми связано событие click.

Так что для ясности с моим вопросом:

Как отправить данные из дочернего компонента в родительский компонент, используя $ emit, если в этом случае элемент, с которым связано событие click, (onClick ==> отправить / прослушать данные для родительского компонента) динамически самогенерируемый и не "статичный".

EDIT: использование v-for не дает запрошенного результата:

<li class="nav-item" @click="this.tabClick" v-for="(tab,index) in tabs">
<a :href="`#tab_default_${index}`" class="nav-link" data-toggle="tab" :data-displayTable="`${tab}`"> ${tab} </a>
</li>

Я получаю ошибку:

Ошибка при рендеринге: «Ошибка типа: невозможно прочитать свойство tabClick of undefined»

Похоже, это не позволяет мне добавить @ click

Edit2:

пробовал использовать @click.native="this.tabClick" в v-for - ошибок не возникает, но мои фиктивные console.logs не отображаются. событие клика не выполняется правильно.

1 Ответ

3 голосов
/ 25 марта 2019

Ваш компонент генерирует событие tabs (this.$emit('tabs', data)), поэтому ваш родитель должен прослушивать событие tabs: @tabs="tabsData" вместо отправки

...