Primevue datatable, how to hide a row which has no data in expanded row

624 Views Asked by At

I am using primevue datatable to show my data, and row expansion to show additional details. https://primevue.org/datatable/#row_expansion

My problem is that some of the rows have no data in expanded row (blue T-shirt in example), and I would love this whole row to be hidden.
Lets say I have no control over data I receive, I can just edit frontend.

Example what I have: https://codesandbox.io/p/sandbox/primevue-demo-forked-3sn4wz

So I want that the row with blue T-shirt would be completely hidden/gone. Is there any easy way to do that? I tried doing that in CSS but I can hide expanded row which contains no data (using has() selector) but I cannot get rid of the main row: enter image description here

In the future I plan to use it to add filtering, and once user filters out everything from details, I want to hide main row as well

My try with CSS was:

.p-datatable-row-expansion:has(.p-datatable-emptymessage) {
  display: none;
}

EDIT: My newest try was to watch for filter variable change, and then just hide rows using javascript. Unfortunately hiding occurs before filtering, leaving sometimes empty expanded rows, and hiding them one input later.
Part of code I added:

watch(filters.value["global"], (newValue, oldValue) => {
  console.log(newValue, oldValue);
  xxxx();
});

Is there a filtering callback function after its done?
Code: https://codesandbox.io/p/sandbox/primevue-demo-forked-844j47

1

There are 1 best solutions below

6
Tachibana Shin On BEST ANSWER

a filter will solve this problem:

<template>
  <div class="card">
    <DataTable
      v-model:expandedRows="expandedRows"
      :value="products?.filter((item) => item.orders.length > 0)"
      dataKey="id"
      tableStyle="min-width: 60rem"
    >
    ...

if you want to filter advanced functions based on filters like PrimeVue you have to add it:

import { FilterMatchMode, FilterService } from "primevue/api";
import { ObjectUtils } from 'primevue/utils';

// your filters
const filters = ref({
  global: { value: null, matchMode: FilterMatchMode.CONTAINS },
  name: { value: null, matchMode: FilterMatchMode.STARTS_WITH },
  "country.name": { value: null, matchMode: FilterMatchMode.STARTS_WITH },
  representative: { value: null, matchMode: FilterMatchMode.IN },
  status: { value: null, matchMode: FilterMatchMode.EQUALS },
  verified: { value: null, matchMode: FilterMatchMode.EQUALS },
});

const productsFilterFn = ({ orders }) => {
  if (!orders.length) return false
  
  return orders.some(order => {
    for (const prop in order) {
      const type = filters.value[prop] ?? filters.value.global
      if (type.matchMode === FilterMatchMode.EQUALS)
      return ObjectUtils.resolveFieldData(order, prop) === type.value
      
      if (FilterService.filters[type.matchMode](ObjectUtils.resolveFieldData(order, prop), type.value)) {
        return true
      }
    }
    return false 
  })
}

and use fn:

<template>
  <div class="card">
    <DataTable
      v-model:expandedRows="expandedRows"
      :value="products?.filter(productsFilterFn)"
      dataKey="id"
      tableStyle="min-width: 60rem"
    >
    ...