About fill handling in ReactGrid
The fill handle is enabled by default in ReactGrid. You can disable it by passing the disableFillHandle
prop to the ReactGrid
component. If you want to implement custom logic for the fill handle behavior, you can use the onFillHandle
prop.
onFillHandle?: (selectedArea: NumericalRange, fillRange: NumericalRange, cellsLookup: CellsLookup) => boolean;
Parameters
Name | Type | Description |
---|---|---|
selectedArea | NumericalRange | The range of cells that were initially selected. |
fillRange | NumericalRange | The range of cells that the fill handle is dragged over. |
cellsLookup | CellsLookup | A map object that provides callbacks to get and set cell values. Each key is a string combining row and column indices, and the value is an object with rowIndex , colIndex , onStringValueRequested (callback to get the cell value), and onStringValueReceived (callback to set the cell value). |
Return Value
The return value of these handlers determines whether the custom logic should override the default fill handle behavior.
Return Value | Type | Description |
---|---|---|
true | boolean | Prevent the default fill handle behavior. |
false | boolean | Default behavior should proceed without being prevented. It is used in case you want to perform additional actions before allowing the default fill handle behavior. |
Live example
Below is an example of logic that overrides the fill handle:
Code
const peopleData = [ { id: "66d61077035753f369ddbb16", name: "Jordan Rodriquez", age: 30, email: "jordanrodriquez@cincyr.com", company: "Zaggles", }, { id: "66d61077794e7949ab167fd5", email: "allysonrios@satiance.com", name: "Allyson Rios", age: 30, company: "Zoxy", }, { id: "66d61077dd754e88981ae434", name: "Pickett Lucas", age: 25, email: "pickettlucas@zoxy.com", company: "Techade", }, { id: "66d61077115e2f8748c334d9", name: "Louella David", age: 37, email: "louelladavid@techade.com", company: "Ginkogene", }, { id: "66d61077540d53374b427e4b", name: "Tricia Greene", age: 27, email: "triciagreene@ginkogene.com", company: "Naxdis", }, ]; const cellStyles = { header: { backgroundColor: "#55bc71", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: "bold", }, }; const getRows = (people: Person[]): Row[] => [ // header row { rowIndex: 0, height: 40, }, // data rows ...people.map((_, i) => ({ rowIndex: i + 1, height: 40, })), ]; const getColumns = (): Column[] => [ { colIndex: 0, width: 220 }, { colIndex: 1, width: 220 }, { colIndex: 2, width: 220 }, { colIndex: 3, width: 220 }, ]; type UpdatePerson = <T>(id: string, key: string, newValue: T) => void; const generateCells = (people: Person[], updatePerson: UpdatePerson): Cell[] => { const generateHeaderCells = () => { const titles = ["Name", "Age", "Email", "Company"]; return titles.map((title, colIndex) => ({ rowIndex: 0, colIndex, Template: NonEditableCell, props: { value: title, style: cellStyles.header, }, })); }; const generateRowCells = (rowIndex: number, person: Person): Cell[] => { const { id, name, age, email, company } = person; return [ { rowIndex, colIndex: 0, Template: TextCell, props: { text: name, onTextChanged: (newText: string) => updatePerson(id, "name", newText), }, }, { rowIndex, colIndex: 1, Template: NumberCell, props: { value: age, onValueChanged: (newValue: number) => updatePerson(id, "age", newValue), }, }, { rowIndex, colIndex: 2, Template: TextCell, props: { text: email, onTextChanged: (newText: string) => updatePerson(id, "email", newText), }, }, { rowIndex, colIndex: 3, Template: TextCell, props: { text: company, onTextChanged: (newText: string) => updatePerson(id, "company", newText), }, }, ]; }; const headerCells = generateHeaderCells(); const rowCells = people.flatMap((person, idx) => generateRowCells(idx + 1, person)); return [...headerCells, ...rowCells]; }; const ReactGridExample = () => { const [people, setPeople] = useState(peopleData); const updatePerson = (id, key, newValue) => { setPeople((prev) => { return prev.map((p) => (p.id === id ? { ...p, [key]: newValue } : p)); }); }; const rows = getRows(people); const [columns, setColumns] = useState(getColumns()); const cells = generateCells(people, updatePerson); return ( <div> <ReactGrid rows={rows} columns={columns} cells={cells} onFillHandle={handleFill} stickyLeftColumns={1} /> </div> ); }; const handleFill = ( selectedArea: NumericalRange, fillRange: NumericalRange, cellsLookup: CellsLookup ): boolean => { // Check if the fill handle is being dragged upwards const isFillingUpwards = fillRange.startRowIdx < selectedArea.startRowIdx; // Calculate the number of rows and columns in the selected area const relativeRowSize = selectedArea.endRowIdx - selectedArea.startRowIdx; const relativeColSize = selectedArea.endColIdx - selectedArea.startColIdx; // Iterate over the rows and columns in the fill range for (let i = fillRange.startRowIdx; i < fillRange.endRowIdx; i++) { for (let j = fillRange.startColIdx; j < fillRange.endColIdx; j++) { const currentCellCallbacks = cellsLookup.get(`${i} ${j}`); if (!currentCellCallbacks) continue; // Skip cells of type 'header' if (i === 0) continue; // Calculate the relative row and column indices within the selected area const relativeRowIdx = isFillingUpwards ? (selectedArea.endRowIdx - i - 1) % relativeRowSize : (i - fillRange.startRowIdx) % relativeRowSize; const relativeColIdx = (j - fillRange.startColIdx) % relativeColSize; // Get the value from the cell in the selected area that corresponds to the relative row and column indices const sourceCellCallbacks = cellsLookup.get( `${selectedArea.startRowIdx + relativeRowIdx} ${selectedArea.startColIdx + relativeColIdx}` ); if (sourceCellCallbacks) { const newValue = sourceCellCallbacks.onStringValueRequested(); currentCellCallbacks.onStringValueReceived(newValue); } } } // Override the default fill handle behavior return true; }; render(<ReactGridExample />, document.getElementById("root"));
Preview