Skip to content

Filter Use Case

Source code
TypeScript ts
// src/components/filter-showcase/FilterAdvanced.ts

import { defineCustomElements } from '@revolist/revogrid/loader';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
defineCustomElements();

import { currentTheme, useRandomData } from '../composables/useRandomData';

const { createRandomData } = useRandomData();
const { isDark } = currentTheme();
export function load(parentSelector: string) {
  const grid = document.createElement('revo-grid');

  grid.source = createRandomData(100);
  grid.columns = [
    {
      name: '🆔 ID',
      prop: 'id',
      filter: ['number', 'slider']
    },
    {
      name: '🍎 Fruit',
      prop: 'name',
    },
  ];
  // Define plugin
  grid.plugins = [AdvanceFilterPlugin, ColumnStretchPlugin];
  grid.stretch = 'all';
  grid.filter = {};
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.hideAttribution = true;
  document.querySelector(parentSelector)?.appendChild(grid);
}
Vue vue
// src/components/filter-showcase/FilterAdvanced.vue

<template>
  <div class="filter-advanced-container">
    <div class="mb-4">
      <label for="filterExpression" class="block text-gray-700 font-medium mb-1">
        Enter Filter Expression
      </label>
      <div class="flex gap-2">
        <textarea
          id="filterExpression"
          rows="2"
          :class="[
            'p-4 text-sm border rounded-lg shadow-sm focus:ring focus:ring-blue-200 focus:outline-none focus:border-blue-400 placeholder-gray-400 w-full transition-colors',
            isDark ? 'bg-slate-800 border-slate-700 text-slate-100' : 'bg-white border-slate-200 text-slate-900'
          ]"
          placeholder="Enter filters (e.g., fullName contains 't' and email contains '@gmail')"
          v-model="filterExpression"
        />
        <button
          class="self-start px-4 py-2 bg-slate-800 text-white rounded-lg hover:bg-slate-700 transition-colors shadow-sm disabled:opacity-50"
          @click="applyTextFilters"
        >
          Apply
        </button>
      </div>
    </div>
    <div class="grid-wrapper h-[500px] border border-slate-200 rounded-xl overflow-hidden shadow-sm dark:border-slate-800">
      <VGrid
        ref="grid"
        :theme="isDark ? 'darkMaterial' : 'material'"
        :columns="columns"
        :source="rows"
        :plugins="plugins"
        :colSize="250"
        stretch="all"
        :filter="filter"
        :hideAttribution="true"
        @afterfilterapply="sync"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { currentThemeVue } from '../composables/useRandomData';
import { makeData, allColumns } from '../composables/makeData';
import {
  type ColumnFilterConfig,
  VGrid,
} from '@revolist/vue3-datagrid';
import {
  AdvanceFilterPlugin,
  ColumnStretchPlugin,
  RowOddPlugin,
  RowSelectPlugin,
} from '@revolist/revogrid-pro';
import { parseFilterExpression, syncFiltersToTextInput } from './parse.filters';

const { isDark } = currentThemeVue();
const grid = ref<any>(null);

const columns = ref(allColumns());
columns.value.splice(0, 1);
if (columns.value[0]) {
  columns.value[0].rowSelect = true;
}
const rows = ref(makeData(1000));

const plugins = [
  AdvanceFilterPlugin,
  ColumnStretchPlugin,
  RowOddPlugin,
  RowSelectPlugin
];


const filter = ref<ColumnFilterConfig>({
  multiFilterItems: {
    fullName: [{ id: 0, type: 'contains', value: 't', relation: 'or' }],
    email: [
      { id: 1, type: 'contains', value: '995', relation: 'or' },
      { id: 1, type: 'contains', value: 'hall', relation: 'and' },
    ],
  },
});

// Text filter state
const filterExpression = ref('');

/**
 * Sync initial state on mount if possible
 */
onMounted(() => {
  // If we have items in filter ref, try to sync them to the expression text
  if (filter.value.multiFilterItems) {
    filterExpression.value = syncFiltersToTextInput({ 
      detail: { multiFilterItems: filter.value.multiFilterItems } 
    } as any);
  }
});

/**
 * Parse user-entered filter expression and update the filter config.
 */
function applyTextFilters() {
  const parsedFilters = parseFilterExpression(filterExpression.value);
  filter.value = {
    ...filter.value,
    multiFilterItems: parsedFilters,
  };
}

function sync(e: CustomEvent) {
  const newExpr = syncFiltersToTextInput(e);
  // Avoid recursive updates if the text matches
  if (newExpr !== filterExpression.value) {
    filterExpression.value = newExpr;
  }
}
</script>
React tsx
// src/components/filter-showcase/FilterAdvanced.tsx

import { useState, useMemo, useRef } from 'react';
import { RevoGrid, type DataType } from '@revolist/react-datagrid';
import {
  AdvanceFilterPlugin,
  ColumnStretchPlugin,
} from '@revolist/revogrid-pro';
import { useRandomData, currentTheme } from '../composables/useRandomData';

function FilterAdvanced() {
  const { isDark } = currentTheme();
  const { createRandomData } = useRandomData();
  const gridRef = useRef<HTMLRevoGridElement>(null);
  const [source] = useState<DataType[]>(createRandomData(100));

  const columns = useMemo(
    () => [
      {
        name: '🆔 ID',
        prop: 'id',
        filter: ['number', 'slider'],
      },
      {
        name: '🍎 Fruit',
        prop: 'name',
      },
    ],
    []
  );

  const additionalData = useMemo(
    () => ({
      stretch: 'all',
      filter: {},
    }),
    []
  );

  return (
    <RevoGrid
      ref={gridRef}
      columns={columns}
      source={source}
      additionalData={additionalData}
      hide-attribution
      theme={isDark() ? 'darkCompact' : 'compact'}
      plugins={[AdvanceFilterPlugin, ColumnStretchPlugin]}
    />
  );
}

export default FilterAdvanced;
Angular ts
// src/components/filter-showcase/FilterAdvancedAngular.ts

import { Component, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
import { currentTheme, useRandomData } from '../composables/useRandomData';

@Component({
  selector: 'filter-showcase-grid',
  standalone: true,
  imports: [RevoGrid],
  template: `
    <revo-grid
      [columns]="columns"
      [source]="source"
      stretch="all"
      [filter]="filter"
      [hideAttribution]="true"
      [theme]="theme"
      [plugins]="plugins"
      style="min-height: 400px;"
    ></revo-grid>`,
  encapsulation: ViewEncapsulation.None,
})
export class FilterShowcaseGridComponent {
  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  source = useRandomData().createRandomData(100);

  columns = [
    {
      name: '🆔 ID',
      prop: 'id',
      filter: ['number', 'slider'],
    },
    {
      name: '🍎 Fruit',
      prop: 'name',
    },
  ];

  filter = {};
  plugins = [AdvanceFilterPlugin, ColumnStretchPlugin];
}