0

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

Kedor
  • 1,488
  • 5
  • 29
  • 53

1 Answers1

1

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"
    >
    ...
Tachibana Shin
  • 2,605
  • 1
  • 5
  • 9
  • That looks great, but is there a way to make it dynamic, so it works also after completely filtering out orders? – Kedor Jun 26 '23 at 06:04
  • What do you mean? either way this will work even if you do filtering with `products` or `DataTable` or not – Tachibana Shin Jun 26 '23 at 06:07
  • In my example, there is a filter box which filters only orders. And i assume it doesn't change `products.orders` variable. https://i.stack.imgur.com/PC0AB.png -- i would love it would hide main rows also after i've put some filtering string in, and it excluded all orders of an item – Kedor Jun 26 '23 at 06:10
  • oh don't worry vue will react to this and change automatically it's progressive power! – Tachibana Shin Jun 26 '23 at 06:36
  • but i've added your change here: https://codesandbox.io/p/sandbox/primevue-demo-forked-3sn4wz and it doesn't :P It works on first load, and t-shirt is not visible, but once i filter out band or bracelet orders it still shows those rows. Try puttin in "Stacey Leja" in filter. It should hide bracelet. I probably am doing something wrong then – Kedor Jun 26 '23 at 07:00
  • you will have to write a custom function for it i will include the example in the answer – Tachibana Shin Jun 26 '23 at 07:23