vue.jsdatatablenuxt.jsprimevue

How to resolve problem with DataTable in PrimeVue


Can someone help me with datatables filters.

I have an object. This object has paymentStatus provided by string 0, 1 or 2 (don't ask me why is not int lol). I have const paymentStatuses is an object. I have keys name, code and severity.

My filter is not working. I don't know why.

<script setup>
import { FilterMatchMode } from 'primevue/api';
import { storeToRefs } from 'pinia'
import { ref, onMounted } from 'vue';
import { CharteredService } from '@/service/CharteredService';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const { $api } = useNuxtApp();
const selectedChartered = ref()
const charteredList = ref()
const charteredItem = ref(
    {
        "type": "",
        "name": "",
        "description": "",
        "client": "",
        "performer": "",
        "contacts": "",
        "orderSumm": "",
        "paymentType": "",
        "paymentStatus": 0,
        "orderDate": "",
        "receiptDate": "",
        "dopInfo": ""
    }
)

const filters = ref({
    global: { value: null, matchMode: FilterMatchMode.CONTAINS },
    paymentStatuses: {value: null, matchMode: FilterMatchMode.IN },
});

const onChartSelect = async (event) => {
    selectedChartered.value = event.data
};
const onChartUnselect = async (event) => {
}
const onCellEditComplete = async (event) => {
    let { data, newValue, field } = event;

    if (data[field] !== newValue) {
        data[field] = newValue;
        await CharteredService.updateChartered(data)
            .then(response => response.json())
            .then(result =>
                toast.add({ severity: 'success', summary: 'Данные успешно сохранены!', detail: result.message, life: 4000 })
            )
            .catch((err) => {
                let data = JSON.parse(err.request.response);
                toast.add({ severity: 'error', summary: 'Что то пошло не так!', detail: data.error_description, life: 4000 });

            })
    }
    else {
        toast.add({ severity: 'info', summary: 'Изменений нет', detail: 'Вы ничего не меняли', life: 4000 });
    }//event.preventDefault();

};
onMounted(async () => {
    await CharteredService.loadCharteredList()
        .then(response => response.json())
        .then(result => charteredList.value = result.result)

});

const paymentStatuses = ref([
    { name: 'Ожидает оплаты', code: '0', severity: 'danger' },
    { name: 'Оплачено', code: '1', severity: 'success' },
    { name: 'В работе', code: '2', severity: 'info' },
])

const expandedRows = ref([]);

const addNewRow = () => {
    charteredList.value.unshift(charteredItem.value)
    CharteredService.addChartered($api, charteredItem.value)
}

const onRowExpand = (event) => {
    const expandedChartedInfo = CharteredService.getCharteredInfo($api, event.data.id).then((response) => response.json().result)
}
</script>
<template>
    <div class="card">
        <h5>Заказные перевозки</h5>
        <DataTable v-model:expandedRows="expandedRows" :filters="filters" scrollable editMode="cell" @cell-edit-complete="onCellEditComplete"
            v-model:selection="selectedChartered" :value="charteredList" :paginator="true" class="p-datatable-sm"
            showGridlines :rows="40" dataKey="id" :rowHover="true" responsiveLayout="scroll" filterDisplay="row"
            :globalFilterFields="['name', 'contacts', 'paymentStatuses']" :metaKeySelection=false @rowSelect="onChartSelect"
            @rowExpand="onRowExpand($event)"
            @rowUnselect="onChartUnselect">
            <template #header>
                <div class="flex justify-content-between flex-column sm:flex-row">
                    <div class="flex">
                        <Button @click="addNewRow()" type="button" icon="pi pi-plus-circle" label="Новый заказ"></Button>
                    </div>
                    <div class="flex">
                        <span class="p-input-icon-left mb-2">
                            <i class="pi pi-search" />
                            <InputText v-model="filters['global'].value" placeholder="Искать..." style="width: 100%"
                                name="filterForm" />
                        </span>
                        <Button type="button" icon="pi pi-filter-slash" class="p-button-outlined mb-2 ml-2"
                            @click="clearFilter1()" />
                    </div>
                </div>
            </template>
            <template #empty> Совпадения не найдены. </template>
            <template #loading> <i class="pi pi-spin pi-spinner" style="font-size: 2rem"></i> Загрузка данных. Пожалуйста подождите. </template>
            <Column expander style="width: 2rem" />
            <Column header="ID" field="id" sortable style="min-width: 2rem; max-width: 2rem;">
                <template #body="{ data }">
                    <div class="text-center p-2 border-round-sm font-bold ">{{ data.id }}</div>
                </template>
            </Column>
            <Column header="Название" field="name" sortable sortField="name">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.name"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Тип заказа" field="type" sortable sortField="type">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.type"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Дата" field="orderDate" sortable sortField="orderDate">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.orderDate"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Контакты" field="contacts" sortable sortField="contacts">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.contacts"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Сумма" field="orderSumm" sortable sortField="orderSumm">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.orderSumm"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Тип оплаты" field="paymentType" sortable sortField="paymentType">
                <template #body="{ data }">
                    <div>
                        <p v-html="data.paymentType"></p>
                    </div>
                </template>
                <template #editor="{ data, field }">
                    <InputText v-model="data[field]" autofocus />
                </template>
            </Column>
            <Column header="Статус" filterField="paymentStatuses" :showFilterMenu="false" sortable sortField="paymentStatus">
                <template #filter="{ filterModel, filterCallback }">
                    <Dropdown v-model="filterModel.value" @change="filterCallback()" :options="paymentStatuses" optionValue="code" optionLabel="name" placeholder="Статусы" class="p-column-filter" style="min-width: 12rem" :showClear="true">
                        <template #option="slotProps">
                            <Tag :value="slotProps.option.name" :severity="slotProps.option.severity" >{{ slotProps.option.name }}</Tag>
                        </template>
                    </Dropdown>
                </template>
                <template #body="{ data }">
                    <div>
                        <Tag v-if="data.paymentStatus === '0'" severity="danger">Ожидает оплаты</Tag>
                        <Tag v-if="data.paymentStatus === '1'" severity="success">Оплачено</Tag>
                        <Tag v-if="data.paymentStatus === '2'" severity="info">В работе</Tag>
                    </div>
                </template>
                
            </Column>
            <template #expansion="slotProps">
                <div class="p-3">
                    <h5>Дополнительная информация для {{ slotProps.data.name }}</h5>
                    <DataTable :value="slotProps.data.charteredInfo">
                        <Column field="id" header="ID" sortable></Column>
                        <Column field="dataTimeStart" header="Дата и время начала заказа" sortable></Column>
                        <Column field="dataTimeEnd" header="Дата и время ориентировочного освобождения" sortable></Column>
                        <Column field="type" header="Тип" sortable></Column>
                        <Column field="vedomostiiID" header="Ведомости ID"></Column>
                        <Column field="driver" header="Водитель"></Column>
                    </DataTable>
                </div>
            </template>
        </DataTable>
    </div>
</template>

First of all, I tried to do as stated in the documentation. But unfortunately it didn’t work out.


Solution

  • Finally found solution. Template Filter has filterCallback. For some reasons this not work for me. So, i'am created function setFilterPaymentStatus and add value for payments status. I'am changed global filters and added paymentStatus from received object item from API.

    So, you have to do this:

    <template #filter="{ filterModel }">
                    <Dropdown v-model="filterModel.value" @change="setFilterPaymentStatus(filterModel.value)" :options="paymentStatuses" optionValue="code" optionLabel="name" placeholder="Статусы" class="p-column-filter" style="min-width: 12rem" :showClear="true">
                        <template #option="slotProps">
                            <Tag :value="slotProps.option.name" :severity="slotProps.option.severity" >{{ slotProps.option.name }}</Tag>
                        </template>
                    </Dropdown>
     </template>
    

    Add global filters:

    :globalFilterFields="['name', 'contacts', 'name', 'orderDate', 'orderSumm', 'paymentType', 'type', 'paymentStatus']"
    

    Next, you need add custom callback:

    const setFilterPaymentStatus = (value) => {
    filters.value.paymentStatus.value = value}
    

    Done!