@MSAFT

Как исправить ошибку Invalid handler for event: got undefined Vue JS?

В наследство досталось приложение Laravel с Vue.JS

В админке есть таблица с заказы с возможностью фильтра по значениям.

Изначально все работало, но после нескольких коммитов все отвалилось.
Invalid handler for event "changed": got undefined

found in

---> <Calendar> at resources/assets/js/components/@shared/Calendar.vue
       <TableFilterCell>
         <Anonymous>
           <Anonymous>
             <DxTemplatePlaceholder>
               <DxTemplateConnector>
                 <DxTemplatePlaceholder>
                   <Anonymous>
                     <TableRow>
                       <DxTemplatePlaceholder>
                         <Anonymous>
                           <RowLayout>
                             <Anonymous>
                               <RowsBlockLayout>
                                 <Table>
                                   <Anonymous>
                                     <Anonymous>
                                       <Anonymous>
                                         <Anonymous>
                                           <DxTemplateConnector>
                                             <DxTemplatePlaceholder>... (1 recursive calls)
                                               <Anonymous>
                                                 <DxTemplatePlaceholder>
                                                   <DxPluginHost>
                                                     <App> at resources/assets/js/components/orders/OrdersTable.vue
                                                       <Root>


Не мог понять в чем причина, а когда залез в код нашел, вот смотрю и не могу понять в чем была логика и доставляет комментарий в коде - todo i hope noone will see this crap

<template>
    <div>
        <h3 v-if="company">{{company.name}}</h3>
        <div class="card orders-table" v-if="!loading">
            <dx-grid
                :rows="rows"
                :columns="columns"
            >
                <dx-sorting-state
                    :sorting.sync="sorting"
                    :columnExtensions="sortingStateColumnExtensions"
                />
                <dx-integrated-sorting />
                <dx-filtering-state
                    :filters.sync="filters"
                    :columnExtensions="filteringStateColumnExtensions"
                />
                <dx-integrated-filtering />
                <dx-table
                    :cellComponent="Cells"
                    :columnExtensions="tableColumnExtensions"
                />
                <dx-table-header-row
                    showSortingControls
                />
                <dx-table-filter-row
                    :cellComponent="FilterCell"
                />
            </dx-grid>
        </div>
    </div>
</template>

<script>
  import "@devexpress/dx-vue-grid-bootstrap4/dist/dx-vue-grid-bootstrap4.css";
  import {
    DxSortingState,
    DxIntegratedSorting,
    DxFilteringState,
    DxIntegratedFiltering,
  } from '@devexpress/dx-vue-grid';
  import {
    DxGrid,
    DxTable,
    DxTableHeaderRow,
    DxTableFilterRow,
  } from '@devexpress/dx-vue-grid-bootstrap4';

  import moment from 'moment';
  import swal from 'sweetalert2';
  import { Actions, OrderId } from './comps';
  import Calendar from '../@shared/Calendar';

  const createComponent = (data, filter = null) => ({
    props: ['column', 'row'],
    template: `<dx-cell v-bind="$attrs" v-on="$listeners">${data}</dx-cell>`,
    components: {
      DxCell: filter ? DxTableFilterRow.components.DxCell : DxTable.components.DxCell,
      Actions,
      OrderId,
      Calendar,
    },
    computed: {
      changeStatus() {
        return OrdersTable.methods.changeStatus;
      },
      onChange() {
        return this.$parent.$parent.$parent.$parent.$parent.$parent
          .$parent.$parent.$parent.$parent.$parent.$parent.$parent
          .$parent.$parent.$parent.$parent.$parent.$parent.$parent.onChange; // todo i hope noone will see this crap
      },
    },
  });

  const createCells = (cells = {}, filter = null) => ({
    inheritAttrs: false,
    props: ['column', 'row'],
    data() {
      return {
        componentId: cells[this.column.name] ? cells[this.column.name] : 'dx-cell',
      }
    },

    template: `
        <component
            :is="componentId"
            :column="column"
            :row="row"
            v-bind="$attrs"
            v-on="$listeners"
         />
    `,
    components: {
      DxCell: filter ? DxTableFilterRow.components.DxCell : DxTable.components.DxCell,
      [this.componentId]: this.componentId,
    }
  });

  const OrdersTable = {
    name: "App",
    props: ['companyJson'],
    data() {
      return {
        loading: false,
        user: {},
        columns: [
          { name: "date", title: "Дата" }, // sortable: true
          { name: "time", title: "Время" },
          { name: "order", title: "№ заказа", getCellValue: row => row.id },
          { name: "price", title: "Сумма", getCellValue: row => row.price },
          { name: "phone", title: "Телефон", getCellValue: row => row.user.phone },
          { name: "email", title: "Email", getCellValue: row => row.user.email },
          { name: "actions", title: "Статус" },
          { name: "updated_at", title: "Изменено" },
        ],
        rows: [],
        tableColumnExtensions: [
          { columnName: 'date', width: 180 },
          { columnName: 'time', width: 80 },
          { columnName: 'order', width: 100 },
        ],
        sorting: [],
        sortingStateColumnExtensions: [
          { columnName: 'time', sortingEnabled: false },
          { columnName: 'actions', sortingEnabled: false },
        ],
        filters: [],
        filteringStateColumnExtensions: [
          { columnName: 'time', filteringEnabled: false },
          { columnName: 'actions', filteringEnabled: false },
          { columnName: 'updated_at', filteringEnabled: false },
        ],
        filterCells: null,
      };
    },
    components: {
      DxSortingState,
      DxIntegratedSorting,
      DxFilteringState,
      DxIntegratedFiltering,
      DxGrid,
      DxTable,
      DxTableHeaderRow,
      DxTableFilterRow,
    },

    computed: {
      Cells() {
        const data = {
          price: createComponent(`{{row.price}} лей`),
          phone: createComponent(`<a :href="'tel:'+row.user.phone">{{row.user.phone}}</a>`),
          email: createComponent(`<a :href="'mailto:'+row.user.email">{{row.user.email}}</a>`),
          order: createComponent(`<OrderId :order-id="row.id" />`),
          actions: createComponent(`
                <Actions
                    :changeStatus="changeStatus"
                    :row="row"
                 />
            `),
        };
        return createCells(data);
      },

      FilterCell() {
        return createCells({
          date: createComponent(`
                    <Calendar  v-on:changed="onChange" />
                `, true)
        }, true);
      },

      company() {
        return this.companyJson ? JSON.parse(this.companyJson) : null;
      },
    },
    mounted() {
      axios.get('/api/users/me').then((response) => {
        this.user = response.data.data;
        if (this.user.role === 2) {
          this.columns.splice(3, 0, { name: "company", title: "Компания" });
          this.loading = false;
        }
      });

      const url = this.company ? `/api/users/${this.company.id}/orders` : '/api/orders';

      axios.get(url)
        .then(
          response => this.rows = response.data.data
            .map(item => ({
                ...item,
                company: ((item.customer.company)
                  ? item.customer.company.name
                  : 'NoName'),
                date: moment(item.created_at, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD'),
                time: moment(item.created_at, 'YYYY-MM-DD HH:mm:ss').format('HH:mm'),
              })
            )
        );
    },

    methods: {
      changeStatus: function (id) {
        if (id === 4) {
          swal({
            title: 'Отменить заказ?',
            text: 'Заполните причину отказа',
            input: 'text',
            showCancelButton: true,
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            cancelButtonText: 'Отменить',
            confirmButtonText: 'Подтвердить'
          }).then((result) => {
            if (result.value) {
              axios.post(`/api/orders/${this.row.id}`, {
                status_id: 4,
                comment: result.value
              }).then(response => {
                if (response.data.status === 200) {
                  this.currentStatus = response.data.data.status;
                }
              });
            }
          });
        }
        else {
          axios.post(`/api/orders/${this.row.id}`, {
            status_id: id,
          }).then(response => {
            this.currentStatus = response.data.data.status;
            this.row.updated_at = response.data.data.updated_at;
          })
        }
      },
      onChange(data) {
        let value = null;
        this.filters = this.filters.map(filter => filter.columnName !== 'date');
        if(data) {
          value = moment(data).format('YYYY-MM-DD');
          console.log('DATE VALUE', value, this.filters);
          this.filters = [...this.filters, { columnName: 'date', value }];
        }
      },
    }
  };

  export default OrdersTable;
</script>

<style>
    .orders-table {
        overflow-x: auto;
    }
    .orders-table .table-responsive,
    .orders-table .table,
    .orders-table .dx-g-bs4-table-cell {
        overflow: unset;
    }
</style>


Как починить?
  • Вопрос задан
  • 995 просмотров
Решения вопроса 1
Здесь похожая проблема:

Если вкратце, то:
1. Проверь функцию onChange, которую ты подаешь в v-on:change. Там была как раз не о функции верхнего уровня, а о функции внутри компонента, который вызывал функцию. По крайней мере в этом коде всего один вызов v-on:change
2. Проверь, не дублируется ли внутри компонента объявление onChange: например, объявлен метод onChange и свойство computed onChange.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы