CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ag-grid-react

AG Grid React Component wrapper for integrating the high-performance data grid into React applications

Pending
Overview
Eval results
Files

react-hooks.mddocs/

React Hooks Integration

Specialized React hooks for integrating custom component callbacks with the AG Grid system, providing seamless communication between React components and the grid.

Capabilities

Cell Editor Hook

Hook for integrating custom cell editor components with the grid's editing system.

/**
 * Hook to allow custom cell editor component callbacks to be provided to the grid
 * @param callbacks - Cell editor callback implementations
 */
function useGridCellEditor(callbacks: CustomCellEditorCallbacks): void;

/**
 * Callbacks for custom cell editor components
 */
interface CustomCellEditorCallbacks extends BaseCellEditor {}

Usage Example:

import React, { useState, useRef, useImperativeHandle, forwardRef } from 'react';
import { useGridCellEditor, CustomCellEditorProps } from 'ag-grid-react';

const NumericCellEditor = forwardRef<any, CustomCellEditorProps<any, number>>((props, ref) => {
  const [value, setValue] = useState<number>(props.initialValue || 0);
  const inputRef = useRef<HTMLInputElement>(null);

  // Use the hook to provide callbacks to the grid
  useGridCellEditor({
    getValue: () => value,
    
    isPopup: () => false,
    
    isCancelBeforeStart: () => {
      // Cancel editing if initial value is invalid
      return isNaN(props.initialValue as number);
    },
    
    isCancelAfterEnd: () => {
      // Cancel if final value is invalid
      return isNaN(value);
    },
    
    focusIn: () => {
      // Custom focus behavior
      if (inputRef.current) {
        inputRef.current.focus();
        inputRef.current.select();
      }
    },
    
    focusOut: () => {
      // Custom blur behavior
      console.log('Editor lost focus');
    }
  });

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = parseFloat(e.target.value) || 0;
    setValue(newValue);
    props.onValueChange(newValue);
  };

  return (
    <input
      ref={inputRef}
      type="number"
      value={value}
      onChange={handleChange}
      style={{ width: '100%', height: '100%' }}
    />
  );
});

Date Component Hook

Hook for integrating custom date picker components with date filters.

/**
 * Hook to allow custom date component callbacks to be provided to the grid
 * @param callbacks - Date callback implementations
 */
function useGridDate(callbacks: CustomDateCallbacks): void;

/**
 * Callbacks for custom date components
 */
interface CustomDateCallbacks extends BaseDate {}

Usage Example:

import React, { useState, useEffect } from 'react';
import { useGridDate, CustomDateProps } from 'ag-grid-react';

const CustomDatePicker: React.FC<CustomDateProps> = (props) => {
  const [selectedDate, setSelectedDate] = useState<Date | null>(props.date);

  // Use the hook to provide callbacks to the grid
  useGridDate({
    getDate: () => selectedDate,
    
    setDate: (date: Date | null) => {
      setSelectedDate(date);
    },
    
    refresh: () => {
      // Refresh the component if needed
      setSelectedDate(props.date);
    }
  });

  const handleDateChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const newDate = event.target.value ? new Date(event.target.value) : null;
    setSelectedDate(newDate);
    props.onDateChange(newDate);
  };

  const dateString = selectedDate ? selectedDate.toISOString().split('T')[0] : '';

  return (
    <div style={{ padding: '8px' }}>
      <input
        type="date"
        value={dateString}
        onChange={handleDateChange}
        style={{ width: '100%' }}
      />
      <button 
        onClick={() => {
          setSelectedDate(null);
          props.onDateChange(null);
        }}
        style={{ marginTop: '4px', width: '100%' }}
      >
        Clear
      </button>
    </div>
  );
};

Filter Component Hook

Hook for integrating custom filter components with the grid's filtering system.

/**
 * Hook to allow custom filter component callbacks to be provided to the grid
 * @param callbacks - Filter callback implementations
 */
function useGridFilter(callbacks: CustomFilterCallbacks): void;

/**
 * Callbacks for custom filter components
 */
interface CustomFilterCallbacks extends BaseFilter {}

Usage Example:

import React, { useState, useEffect } from 'react';
import { useGridFilter, CustomFilterProps } from 'ag-grid-react';

interface RangeFilterModel {
  filterType: 'range';
  min: number | null;
  max: number | null;
}

const RangeFilter: React.FC<CustomFilterProps<any, any, RangeFilterModel>> = (props) => {
  const [min, setMin] = useState<number | null>(props.model?.min || null);
  const [max, setMax] = useState<number | null>(props.model?.max || null);

  // Use the hook to provide callbacks to the grid
  useGridFilter({
    doesFilterPass: (params) => {
      const value = props.valueGetter(params);
      const numValue = parseFloat(value);
      
      if (isNaN(numValue)) return false;
      
      if (min !== null && numValue < min) return false;
      if (max !== null && numValue > max) return false;
      
      return true;
    },
    
    isFilterActive: () => min !== null || max !== null,
    
    getModel: () => {
      if (min === null && max === null) return null;
      return { filterType: 'range', min, max };
    },
    
    setModel: (model: RangeFilterModel | null) => {
      if (model) {
        setMin(model.min);
        setMax(model.max);
      } else {
        setMin(null);
        setMax(null);
      }
    },
    
    refresh: () => {
      // Refresh the component if needed
      return true;
    }
  });

  const handleMinChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value ? parseFloat(e.target.value) : null;
    setMin(value);
    updateModel(value, max);
  };

  const handleMaxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value ? parseFloat(e.target.value) : null;
    setMax(value);
    updateModel(min, value);
  };

  const updateModel = (newMin: number | null, newMax: number | null) => {
    if (newMin === null && newMax === null) {
      props.onModelChange(null);
    } else {
      props.onModelChange({ filterType: 'range', min: newMin, max: newMax });
    }
  };

  return (
    <div style={{ padding: '8px' }}>
      <div style={{ marginBottom: '8px' }}>
        <label>Min:</label>
        <input
          type="number"
          value={min || ''}
          onChange={handleMinChange}
          placeholder="Min value"
          style={{ width: '100%' }}
        />
      </div>
      <div>
        <label>Max:</label>
        <input
          type="number"
          value={max || ''}
          onChange={handleMaxChange}
          placeholder="Max value"
          style={{ width: '100%' }}
        />
      </div>
    </div>
  );
};

Filter Display Hook

Hook for integrating custom filter display components when using enableFilterHandlers = true.

/**
 * Hook to allow custom filter component callbacks when using enableFilterHandlers = true
 * @param callbacks - Filter display callback implementations
 */
function useGridFilterDisplay(callbacks: CustomFilterDisplayCallbacks): void;

/**
 * Callbacks for custom filter components when using enableFilterHandlers = true
 */
interface CustomFilterDisplayCallbacks extends SharedFilterUi {}

Floating Filter Hook

Hook for integrating custom floating filter components with the grid's filtering system.

/**
 * Hook to allow custom floating filter component callbacks to be provided to the grid
 * @param callbacks - Floating filter callback implementations
 */
function useGridFloatingFilter(callbacks: CustomFloatingFilterCallbacks): void;

/**
 * Callbacks for custom floating filter components
 */
interface CustomFloatingFilterCallbacks extends BaseFloatingFilter {}

Usage Example:

import React, { useState, useEffect } from 'react';
import { useGridFloatingFilter, CustomFloatingFilterProps } from 'ag-grid-react';

const QuickSearchFloatingFilter: React.FC<CustomFloatingFilterProps> = (props) => {
  const [filterText, setFilterText] = useState('');

  // Use the hook to provide callbacks to the grid
  useGridFloatingFilter({
    onParentModelChanged: (parentModel) => {
      // Update floating filter when parent filter changes
      setFilterText(parentModel?.filter || '');
    },
    
    refresh: () => {
      // Refresh the floating filter
      return true;
    }
  });

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setFilterText(value);
    
    // Update the parent filter
    if (value) {
      props.parentFilterInstance(instance => {
        instance.setModel({ filter: value, type: 'contains' });
        props.api.onFilterChanged();
      });
    } else {
      props.parentFilterInstance(instance => {
        instance.setModel(null);
        props.api.onFilterChanged();
      });
    }
  };

  return (
    <input
      type="text"
      value={filterText}
      onChange={handleInputChange}
      placeholder="Quick search..."
      style={{ 
        width: '100%', 
        height: '100%',
        border: 'none',
        padding: '4px 8px'
      }}
    />
  );
};

Menu Item Hook

Hook for integrating custom menu item components with context and column menus.

/**
 * Hook to allow custom menu item component callbacks to be provided to the grid
 * @param callbacks - Menu item callback implementations
 */
function useGridMenuItem(callbacks: CustomMenuItemCallbacks): void;

/**
 * Callbacks for custom menu item components
 */
interface CustomMenuItemCallbacks extends BaseMenuItem {}

Usage Example:

import React, { useState } from 'react';
import { useGridMenuItem, CustomMenuItemProps } from 'ag-grid-react';

const InteractiveMenuItem: React.FC<CustomMenuItemProps> = (props) => {
  const [isProcessing, setIsProcessing] = useState(false);

  // Use the hook to provide callbacks to the grid
  useGridMenuItem({
    configureDefaults: () => {
      // Configure default behavior
      return {
        name: props.name,
        disabled: props.disabled,
        tooltip: props.tooltip
      };
    }
  });

  const handleClick = async () => {
    if (props.action) {
      setIsProcessing(true);
      try {
        await props.action();
      } catch (error) {
        console.error('Menu action failed:', error);
      } finally {
        setIsProcessing(false);
      }
    }
  };

  return (
    <div
      onClick={handleClick}
      style={{
        padding: '8px 16px',
        cursor: props.disabled || isProcessing ? 'not-allowed' : 'pointer',
        opacity: props.disabled || isProcessing ? 0.5 : 1,
        backgroundColor: props.active ? '#f0f0f0' : 'transparent',
        display: 'flex',
        alignItems: 'center',
        gap: '8px'
      }}
    >
      {isProcessing ? (
        <span>⏳</span>
      ) : (
        props.icon && <span>{props.icon}</span>
      )}
      <span>{props.name}</span>
    </div>
  );
};

Advanced Hook Integration Pattern

Example showing how to combine multiple hooks in a complex custom component:

import React, { useState, useEffect, useRef } from 'react';
import { 
  useGridCellEditor, 
  useGridFilter, 
  CustomCellEditorProps,
  CustomFilterProps 
} from 'ag-grid-react';

// Multi-purpose component that can act as both editor and filter
const MultiPurposeComponent: React.FC<CustomCellEditorProps & CustomFilterProps> = (props) => {
  const [value, setValue] = useState(props.initialValue || props.model?.value || '');
  const inputRef = useRef<HTMLInputElement>(null);
  const isEditor = 'onValueChange' in props;
  const isFilter = 'onModelChange' in props;

  // Editor integration
  if (isEditor) {
    useGridCellEditor({
      getValue: () => value,
      focusIn: () => inputRef.current?.focus(),
      isCancelBeforeStart: () => false,
      isCancelAfterEnd: () => false
    });
  }

  // Filter integration
  if (isFilter) {
    useGridFilter({
      doesFilterPass: (params) => {
        const cellValue = props.valueGetter(params);
        return String(cellValue).toLowerCase().includes(String(value).toLowerCase());
      },
      isFilterActive: () => !!value,
      getModel: () => value ? { value } : null,
      setModel: (model) => setValue(model?.value || '')
    });
  }

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = e.target.value;
    setValue(newValue);
    
    if (isEditor && props.onValueChange) {
      props.onValueChange(newValue);
    }
    
    if (isFilter && props.onModelChange) {
      props.onModelChange(newValue ? { value: newValue } : null);
    }
  };

  return (
    <input
      ref={inputRef}
      type="text"
      value={value}
      onChange={handleChange}
      style={{ width: '100%', height: '100%' }}
      placeholder={isEditor ? 'Enter value...' : 'Filter...'}
    />
  );
};

Install with Tessl CLI

npx tessl i tessl/npm-ag-grid-react

docs

custom-cell-components.md

custom-filter-components.md

custom-header-components.md

custom-ui-components.md

index.md

main-component.md

react-hooks.md

utility-functions.md

tile.json