Filtro de búsqueda de cuadrícula React
The Ignite UI for React Search Filter feature in React Grid enables the process of finding values in the collection of data. We make it easier to set up this functionality and it can be implemented with a search input box, buttons, keyboard navigation and other useful features for an even better user experience. While browsers natively provide content search functionality, most of the time the IgrGrid virtualizes its columns and rows that are out of view. In these cases, the native browser search is unable to search data in the virtualized cells, since they are not part of the DOM. We have extended the React Material table-based grid with a search API that allows you to search through the virtualized content of the IgrGrid.
React Search Example
The following example represents IgrGrid with search input box that allows searching in all columns and rows, as well as specific filtering options for each column.
React Search Usage
Grid Setup
Comencemos creando nuestra cuadrícula y vinculándola a nuestros datos. ¡También agregaremos algunos estilos personalizados para los componentes que usaremos!
.gridSize {
--ig-size: var(--ig-size-small);
}
<IgrGrid ref={gridRef} className="gridSize" autoGenerate={false} allowFiltering={true} data={data}>
<IgrColumn field="IndustrySector" dataType="string" sortable={true}></IgrColumn>
<IgrColumn field="IndustryGroup" dataType="string" sortable={true}></IgrColumn>
<IgrColumn field="SectorType" dataType="string" sortable={true}></IgrColumn>
<IgrColumn field="KRD" dataType="number" sortable={true}></IgrColumn>
<IgrColumn field="MarketNotion" dataType="number" sortable={true}></IgrColumn>
</IgrGrid>
Great, and now let's prepare for the search API of our IgrGrid! We can create a few properties, which can be used for storing the currently searched text and whether the search is case sensitive and/or by an exact match.
const gridRef = useRef<IgrGrid>(null);
const [caseSensitiveSelected, setCaseSensitiveSelected] = useState<boolean>(false);
const [exactMatchSelected, setExactMatchSelected] = useState<boolean>(false);
const [searchText, setSearchText] = useState('');
React Search Box Input
Now let's create our search input! By binding our searchText to the value property to our newly created input and subscribe to the inputOccured event, we can detect every single searchText modification by the user. This will allow us to use the IgrGrid's findNext and findPrev methods to highlight all the occurrences of the searchText and scroll to the next/previous one (depending on which method we have invoked).
Both the findNext and the findPrev methods have three arguments:
Text: string (the text we are searching for)- (optional)
CaseSensitive: boolean (should the search be case sensitive or not, default value is false) - (optional)
ExactMatch: boolean (should the search be by an exact match or not, default value is false)
When searching by an exact match, the search API will highlight as results only the cell values that match entirely the SearchText by taking the case sensitivity into account as well. For example the strings 'software' and 'Software' are an exact match with a disregard for the case sensitivity.
The methods from above return a number value (the number of times the IgrGrid contains the given string).
const handleOnSearchChange = (event: IgrComponentValueChangedEventArgs) => {
setSearchText(event.detail);
nextSearch(event.detail, caseSensitiveSelected, exactMatchSelected);
}
<IgrInput name="searchBox" value={searchText} onInput={handleOnSearchChange}>
</IgrInput>
Add Search Buttons
In order to freely search and navigate among our search results, let's create a couple of buttons by invoking the findNext and the findPrev methods inside the buttons' respective click event handlers.
const prevSearch = (text: string, caseSensitive: boolean, exactMatch: boolean) => {
gridRef.current.findPrev(text, caseSensitive, exactMatch);
}
const nextSearch = (text: string, caseSensitive: boolean, exactMatch: boolean) => {
gridRef.current.findNext(text, caseSensitive, exactMatch);
}
<IgrIconButton variant="flat" name="prev" collection="material" onClick={() => prevSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
</IgrIconButton>
<IgrIconButton variant="flat" name="next" collection="material" onClick={() => nextSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
</IgrIconButton>
Add Keyboard Search
We can also allow the users to navigate the results by using the keyboard's arrow keys and the ENTER key. In order to achieve this, we can handle the keydown event of our search input by preventing the default caret movement of the input with the PreventDefault method and invoke the findNext/findPrev methods depending on which key the user has pressed.
const searchKeyDown = (e: KeyboardEvent<HTMLElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
nextSearch(searchText, caseSensitiveSelected, exactMatchSelected);
} else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
e.preventDefault();
prevSearch(searchText, caseSensitiveSelected, exactMatchSelected);
}
}
<div onKeyDown={searchKeyDown}>
<IgrInput name="searchBox" value={searchText} onInput={handleOnSearchChange}></IgrInput>
</div>
Case Sensitive and Exact Match
Now let's allow the user to choose whether the search should be case sensitive and/or by an exact match. For this purpose we can use the IgrChip component along with a boolean state variable to indicate whether the IgrChip is selected.
const [caseSensitiveSelected, setCaseSensitiveSelected] = useState<boolean>(false);
const [exactMatchSelected, setExactMatchSelected] = useState<boolean>(false);
const handleCaseSensitiveChange = (event: IgrComponentBoolValueChangedEventArgs) => {
setCaseSensitiveSelected(event.detail);
nextSearch(searchText, event.detail, exactMatchSelected);
}
const handleExactMatchChange = (event: IgrComponentBoolValueChangedEventArgs) => {
setExactMatchSelected(event.detail);
nextSearch(searchText, caseSensitiveSelected, event.detail);
}
<IgrChip selectable={true} onSelect={handleCaseSensitiveChange}>
<span>Case Sensitive</span>
</IgrChip>
<IgrChip selectable={true} onSelect={handleExactMatchChange}>
<span>Exact Match</span>
</IgrChip>
Persistence
What if we would like to filter and sort our IgrGrid or even to add and remove records? After such operations, the highlights of our current search automatically update and persist over any text that matches the SearchText! Furthermore, the search will work with paging and will persist the highlights through changes of the IgrGrid's PerPage property.
Adding icons
Al utilizar algunos de nuestros otros componentes, podemos crear una interfaz de usuario enriquecida y mejorar el diseño general de toda nuestra barra de búsqueda. Podemos tener un bonito icono de búsqueda o eliminación a la izquierda de la entrada de búsqueda, un par de fichas para nuestras opciones de búsqueda y algunos iconos de diseño de materiales combinados con bonitos botones de estilo ondulado para nuestra navegación a la derecha.
Let's begin by creating the search navigation buttons on the right of the input by adding two ripple styled buttons with material icons. The handlers for the click events remain the same - invoking the findNext/findPrev methods.
- For displaying a couple of chips that toggle the
CaseSensitiveand theExactMatchproperties. We have replaced the checkboxes with two stylish chips. Whenever a chip is clicked, we invoke its respective handler.
const prevSearch = (text: string, caseSensitive: boolean, exactMatch: boolean) => {
gridRef.current.findPrev(text, caseSensitive, exactMatch);
}
const nextSearch = (text: string, caseSensitive: boolean, exactMatch: boolean) => {
gridRef.current.findNext(text, caseSensitive, exactMatch);
}
<div slot="suffix">
<IgrIconButton variant="flat" name="prev" collection="material" onClick={() => prevSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
<IgrRipple></IgrRipple>
</IgrIconButton>
<IgrIconButton variant="flat" name="next" collection="material" onClick={() => nextSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
<IgrRipple></IgrRipple>
</IgrIconButton>
</div>
Ahora agreguemos los iconos de búsqueda y borrado a la izquierda de la entrada:
const clearSearch = () => {
setSearchText('');
gridRef.current.clearSearch();
}
<div slot="prefix">
{searchText.length === 0 ? (
<IgrIconButton variant="flat" name="search" collection="material">
</IgrIconButton>
) : (
<IgrIconButton variant="flat" name="clear" collection="material" onClick={clearSearch}>
</IgrIconButton>
)}
</div>
Finalmente, este es el resultado final cuando combinamos todo:
useEffect(() => {
registerIconFromText("search", searchIconText, "material");
registerIconFromText("clear", clearIconText, "material");
registerIconFromText("prev", prevIconText, "material");
registerIconFromText("next", nextIconText, "material");
}, []);
<IgrInput name="searchBox" value={searchText} onInput={handleOnSearchChange}>
<div slot="prefix">
{searchText.length === 0 ? (
<IgrIconButton variant="flat" name="search" collection="material">
</IgrIconButton>
) : (
<IgrIconButton variant="flat" name="clear" collection="material" onClick={clearSearch}>
</IgrIconButton>
)}
</div>
<div slot="suffix">
<IgrIconButton variant="flat" name="prev" collection="material" onClick={() => prevSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
<IgrRipple></IgrRipple>
</IgrIconButton>
<IgrIconButton variant="flat" name="next" collection="material" onClick={() => nextSearch(searchText, caseSensitiveSelected, exactMatchSelected)}>
<IgrRipple></IgrRipple>
</IgrIconButton>
</div>
</IgrInput>
Known Limitations
| Limitación | Descripción |
|---|---|
| Buscando en celdas con una plantilla | Las funciones destacadas de búsqueda funcionan solo para las plantillas de celda predeterminadas. Si tiene una columna con una plantilla de celda personalizada, los resaltados no funcionarán, por lo que deberá utilizar enfoques alternativos, como un formateador de columnas, o configurar elsearchable propiedad en la columna a falso. |
| Virtualización remota | La búsqueda no funcionará correctamente al utilizar la virtualización remota |
| Celdas con texto cortado | Cuando el texto en la celda es demasiado grande para caber y el texto que estamos buscando está cortado por los puntos suspensivos, aún nos desplazaremos hasta la celda y la incluiremos en el recuento de coincidencias, pero no se resaltará nada. |
API References
In this article we implemented our own search bar for the IgrGrid with some additional functionality when it comes to navigating between the search results. We also used some additional Ignite UI for React components like icons, chips and inputs. The search API is listed below.
IgrGrid methods:
IgrColumn properties:
Componentes adicionales con API relativas que se utilizaron:
Additional Resources
- Virtualización y rendimiento
- Filtración
- Paginación
- Clasificación
- resúmenes
- Columna en movimiento
- Fijación de columnas
- Cambio de tamaño de columna
- Selección
Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.