In my project, I have an email field to implement using the chip component.
But I am facing a problem here, first time, when I paste multiple email values it gets inserted into the field, but second time when I copy some other values and paste them into the field, it replaces the previous values.
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import Chip from "#material-ui/core/Chip";
import TextField from "#material-ui/core/TextField";
import './styles.css';
export const TagActions = () => {
const [items, setItem] = useState<string[]>([]);
const [value, setValue] = useState('')
const [error, setError]= useState('')
const divRef = useRef<HTMLDivElement>(null)
const [flag, setFlag] = useState(false)
const handleDelete = (item:any) => {
console.log("handleDelete", item)
const result = items.filter(i => i !== item)
setItem(result)
};
const handleItemEdit = (item:any) =>{
console.log("handleItemEdit", item)
const result = items.filter(i => i !== item)
setItem(result)
setValue(item)
console.log("value", value)
};
const handleKeyDown = (evt:any) => {
if (["Enter", "Tab", ","].includes(evt.key)) {
evt.preventDefault();
var test = value.trim();
if (test && isValid(test)) {
items.push(test)
setValue("")
}
}
};
const isValid = (email:any)=> {
let error = null;
if (isInList(email)) {
error = `${email} has already been added.`;
}
if (!isEmail(email)) {
setFlag(true)
// error = `${email} is not a valid email address.`;
}
if (error) {
setError(error);
return false;
}
return true;
}
const isInList = (email:any)=> {
return items.includes(email);
}
const isEmail = (email:any)=> {
return /[\w\d\.-]+#[\w\d\.-]+\.[\w\d\.-]+/.test(email);
}
const handleChange = (evt:any) => {
setValue(evt.target.value)
// setError("")
};
const handlePaste = (evt:any) => {
evt.preventDefault();
var paste = evt.clipboardData.getData("text");
var emails = paste.match(/[\w\d\.-]+#[\w\d\.-]+\.[\w\d\.-]+/g);
if (emails) {
var toBeAdded = emails.filter((email:any) => !isInList(email));
setItem(toBeAdded)
}
};
return (
<>
<div>
<TextField id="outlined-basic" variant="outlined"
InputProps={{
startAdornment: items.map(item => (
<Chip
className={!isEmail(item) ? "chip-tag-error": "chip-tag"}
key={item}
tabIndex={-1}
label={item}
onDelete={() => handleDelete(item)}
onClick={() => handleItemEdit(item)}
/>
)),
}}
ref={divRef}
value={value}
placeholder="Type or paste email addresses and press `Enter`..."
onKeyDown={(e) => handleKeyDown(e)}
onChange={(e) => handleChange(e)}
onPaste={(e) => handlePaste(e)}
/>
</div>
{error && <p className="error">{error}</p>}
</>
);
}
Please give me a solution to fix this problem.
You can do this by using the Autocomplete with renderTags function here is an example
import {
Box,
TextField,
Autocomplete,
Chip,
} from '#mui/material'
...
const {
handleSubmit,
control,
formState: { errors },
} = useForm()
...
<Box mt={2}>
<Controller
control={control}
name="tags"
rules={{
required: "Veuillez choisir une réponse",
}}
render={({ field: { onChange } }) => (
<Autocomplete
defaultValue={
useCasesData?.tags ? JSON.parse(useCasesData?.tags) : []
}
multiple
id="tags-filled"
options={[]}
freeSolo
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
/>
))
}
onChange={(event, values) => {
onChange(values);
}}
renderInput={(params) => (
<TextField
{...params}
label="Métadonnées"
placeholder="Ecriver les métadonnées"
helperText={errors.tags?.message}
error={!!errors.tags}
/>
)}
/>
)}
/>
</Box>
Related
I'm trying to make an Autocomplete input for categories from an API response and allow the user to be able to create one if he didn't find
a match.
Issues:
1- How to avoid Non-unique when I have same key which is name can I make on ID cause it's unique?
Warning: Encountered two children with the same key, `Flour & Bread Mixes`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behaviour is unsupported and could change in a future version.
2- The dialog for entring new category doesn't open and I don't see any errors in the console
Code Sandbox
https://codesandbox.io/s/asynchronous-material-demo-forked-70eff?file=/demo.js
import React, {useState} from "react";
import TextField from '#mui/material/TextField';
import Autocomplete , { createFilterOptions } from '#mui/material/Autocomplete';
import CircularProgress from '#mui/material/CircularProgress';
import parse from 'autosuggest-highlight/parse';
import match from 'autosuggest-highlight/match';
import axios from "axios";
import Dialog from '#mui/material/Dialog';
import DialogTitle from '#mui/material/DialogTitle';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import DialogActions from '#mui/material/DialogActions';
import Button from '#mui/material/Button';
import { Input } from "#material-ui/core";
export default function Asynchronous() {
const filter = createFilterOptions();
const [open, setOpen] = React.useState(false);
const [options, setOptions] = React.useState([]);
const loading = open && options.length === 0;
const [categories, setCategories] = useState([]);
const [openDialog, toggleOpenDialog] = React.useState(false);
const handleClose = () => {
setDialogValue({
name: '',
slug: '',
image: '',
});
toggleOpenDialog(false);
};
const handleSubmit = (event) => {
event.preventDefault();
setCategories({
name: dialogValue.name,
slug: dialogValue.slug,
image: dialogValue.image
});
handleClose();
};
const [dialogValue, setDialogValue] = React.useState({
name: '',
slug: '',
image: '',
});
React.useEffect(() => {
let active = true;
if (!loading) {
return undefined;
}
(async () => {
var config = {
method: 'get',
url: 'https://null.free.mockoapp.net/getCategories',
};
axios(config)
.then(function (response) {
response.data = response.data.filter((category) => category.name)
if (active) {
setOptions([...response.data]);
}
})
.catch(function (error) {
console.log(error);
});
})();
return () => {
active = false;
};
}, [loading]);
React.useEffect(() => {
if (!open) {
setOptions([]);
}
}, [open]);
return (
<>
<Autocomplete
id="asynchronous-demo"
open={open}
limitTags={3}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
isOptionEqualToValue={(option, value) => option.name === value.name}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.name;
}}
options={options}
loading={loading}
multiple
renderInput={(params) => (
<>
<TextField
{...params}
label="Asynchronous"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
{console.log(options)}
</>
)}
renderOption={(props, option, { inputValue }) => {
const matches = match(option.name, inputValue);
const parts = parse(option.name, matches);
return (
<li {...props}>
<div>
{parts.map((part, index) => (
<span
key={index}
style={{
color: part.highlight ? "red" : 'inherit',
fontWeight: part.highlight ? 700 : 400,
}}
>
{part.text}
</span>
))}
</div>
</li>
);
}}
value={categories}
onChange={(event, newValue) => {
if (typeof newValue === 'string') {
// timeout to avoid instant validation of the dialog's form.
setTimeout(() => {
toggleOpenDialog(true);
setDialogValue({
name: newValue,
slug: '',
image: ''
});
});
} else if (newValue && newValue.inputValue) {
toggleOpenDialog(true);
setDialogValue({
name: newValue.inputValue,
slug: '',
image: ''
});
} else {
setCategories(newValue);
}
}}
filterOptions={(options, params) => {
const filtered = filter(options, params);
const { inputValue } = params;
const isExisting = options.some((option) => inputValue === option.name);
if (inputValue !== '' && !isExisting) {
filtered.push({
inputValue:inputValue,
name: `Add "${inputValue}"`,
});
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
/>
<Dialog open={openDialog} onClose={handleClose}>
<form onSubmit={handleSubmit}>
<DialogTitle>Add a new film</DialogTitle>
<DialogContent>
<DialogContentText>
Did you miss any film in our list? Please, add it!
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
value={dialogValue.name}
onChange={(event) =>
setDialogValue({
...dialogValue,
name: event.target.value,
})
}
label="title"
type="text"
variant="standard"
/>
<TextField
margin="dense"
id="slug"
value={dialogValue.slug}
onChange={(event) =>
setDialogValue({
...dialogValue,
slug: event.target.value,
})
}
label="slug"
type="text"
variant="standard"
/>
<Input
margin="dense"
id="image"
value={dialogValue.image}
onChange={(event) =>
setDialogValue({
...dialogValue,
image: event.target.value,
})
}
label="image"
type="file"
variant="standard"
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit">Add</Button>
</DialogActions>
</form>
</Dialog>
</>
);
}
I found a lot of mistakes in your code so I made a new working fork on Codesandbox
https://codesandbox.io/s/asynchronous-material-demo-forked-oeg2p?file=/demo.js
Notes:
save the api response in a state instead of doing an API call
whenever the user opens the dropdown.
you could make an API request in handleSubmit function to create a new category in the back-end
handleFormSubmit will output the value of Autocomplete.
Let me know if you have any questions.
Read more about autocomplete at
https://mui.com/components/autocomplete/#asynchronous-requests
I am trying to implement Formik's Field component and Material-Ui Autocomplete for Multiple values with checkboxs.
Every time I try to select a value from the dropdown list it closes the popup and again I have to open it for next value selection.
I am using setFieldValue() method to update the field value because of the Autocomplete's onChange behaviour.
import React, { useState, useEffect } from "react";
import { ErrorMessage, useField, Field, useFormikContext } from "formik";
import styles from "./Form.module.scss";
import { makeStyles, TextField, Checkbox } from "#material-ui/core";
import { Autocomplete } from "#material-ui/lab";
import service from "http-service";
import CheckBoxOutlineBlankIcon from "#material-ui/icons/CheckBoxOutlineBlank";
import CheckBoxIcon from "#material-ui/icons/CheckBox";
// Interface
interface IProps {
name: string;
rest?: any;
className?: string;
marginBottom?: string;
label?: string;
options?: any[];
disabled?: boolean;
tabIndex?: number;
multiple?: boolean;
returnArray?: boolean;
referentialIdKey?: string;
referentialNameKey?: string;
serviceConfig?: string;
query?: string;
processResponse?: Function;
}
// Custom Style
const useStyles = makeStyles((theme) => ({
root: {
"& .MuiAutocomplete-inputRoot": {
padding: "6px",
},
},
}));
const AsyncSearchMultiSelect: React.FC<IProps> = (props) => {
const {
name,
className,
disabled,
options,
marginBottom,
label,
tabIndex,
multiple,
returnArray,
referentialIdKey,
referentialNameKey,
serviceConfig,
query,
processResponse,
...rest
} = props;
const { setFieldValue } = useFormikContext();
const [field] = useField(name);
const classes = useStyles();
// States :
const [asyncOptions, setAsyncOptions] = useState<any[]>([]);
const [fetchedData, setFetchedData] = useState<any>();
// all
const [selectedOpt, setSelectedOpt] = useState<any>([]);
// API Call for Dropdown Options :
useEffect(() => {
if (!serviceConfig) return;
service[serviceConfig]
.getDataByQuery(query || "")
.then(({ data }: { data: any[] }) => {
let dataSet = processResponse ? processResponse(data) : data;
if (dataSet.data) {
dataSet = dataSet.data;
}
setFetchedData(dataSet);
let tempOptions = dataSet.map((item: any) => {
return {
name: referentialNameKey ? item[referentialNameKey] : item["name"],
value: referentialIdKey ? item[referentialIdKey] : item["id"],
} as never;
});
tempOptions.unshift({ name: "All", value: "all" });
console.log("tempOptions >>>> ", tempOptions);
setAsyncOptions(tempOptions);
})
.catch((err: any) => console.log("Error! : ", err));
}, []);
if (field.value.length > 0 && asyncOptions !== []) {
let fullObjValues = asyncOptions.filter((option) =>
field.value.includes(option.value)
);
console.log("fullObjValues >>> ", fullObjValues);
if (fullObjValues.length > 0) {
setFieldValue(name, fullObjValues);
}
}
const handleChange = (event: any, newValue: any) => {
console.log("AsyncSearchableEvent (value) >>> ", newValue);
setFieldValue(name, newValue);
};
const getOptionLabelCustom = (option: any) => {
if (typeof option != "object") {
let optionTitle: any = asyncOptions.find(
(element: { value: any }) => element?.value == option
);
return optionTitle?.name;
} else {
return option?.name;
}
};
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;
const getComponent = () => {
return (
<Autocomplete
// {...field}
disableCloseOnSelect
multiple
options={options ? options : asyncOptions}
value={field.value}
limitTags={2}
getOptionLabel={(option) => getOptionLabelCustom(option)}
onChange={(event, value) => handleChange(event, value)}
renderOption={(option, { selected }) => {
// 'all' option
const selectOptIndex = selectedOpt.findIndex(
(opt: any) => opt.name.toLowerCase() === "all"
);
if (selectOptIndex > -1) {
selected = true;
}
//
return (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.name}
</React.Fragment>
);
}}
renderInput={(params) => (
<TextField
{...params}
label={label}
classes={classes}
fullWidth
variant="outlined"
/>
)}
/>
);
};
return (
<div
className={styles.element_wrapper}
style={{ marginBottom: marginBottom }}
>
<Field
{...field}
id={name}
name={name}
disabled={disabled}
component={getComponent}
autoComplete="off"
/>
<div className={styles.error}>
<ErrorMessage name={name} />
</div>
</div>
);
};
export default AsyncSearchMultiSelect; ```
try to controll it with open :
const [open, setOpen] = React.useState(false);
<Autocomplete
disabled={disabled}
id={name}
name={name}
sx={{width: "100%"}}
open={open}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
I have created 3 conditional lists with react-select but the third element cannot render the selected value, I am trying to update it even with useEffect but I don't know if it is correct.
Example of my code:
import React, { useState, useEffect } from "react";
import Select from "react-select";
import data from "../data.json";
const Dropdowns = ()=>{
const [product, setProduct] = useState(null);
const [type, setType] = useState(null);
const [typesList, setTypesList] = useState(null);
const [title, setTitle] = useState(null);
const [titlesList, setTitlesList] = useState(null);
// handle change event of the product dropdown
const handleProductChange = (obj) => {
setProduct(obj);
setTypesList(obj.types)
setType(null);
};
// handle change event of the types dropdown
const handleTypesChange = (obj) => {
setType(obj);
setTitlesList(obj.titles);
};
// handle change event of the titles dropdown
const handleTitlesChange = (obj) => {
setTitle(obj);
};
useEffect( () => {
if ( title ) {
setTitle(title)
}
}, [title])
return (
<>
<br />
<h3>Products</h3>
<Select
placeholder="Select Product"
value={ product }
options={ data }
onChange={ handleProductChange }
getOptionLabel={ (x) => x.product }
/>
<br />
<h3>Types</h3>
<Select
placeholder="Select Types"
value={ type }
options={ typesList }
onChange={ handleTypesChange }
getOptionLabel={ (x) => x.type }
/>
<br />
<h3>Titles</h3>
<Select
placeholder="Select Title"
value={ title }
options={ titlesList }
onChange={ handleTitlesChange }
getOptionLabel={ (x) => x }
/>
</>
)
}
export default Dropdowns;
Thank you very much for your help!
How to show Material-UI Autocomplete drop-down list only when typing something? I added a Material-UI Autocomplete component to one of my project. But the problem is when I clicked the TextField, it automatically drop down all the list options. I want to drop down only suggestions when the user is going to type something. Below is my code.
import React, { useEffect, useState } from "react";
import { Grid, Popper } from "#material-ui/core";
import axios from "axios";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { useStyles, CssTextField } from "./classes";
export default function SearchItems({ setFieldValue, dialogOpen }) {
const classes = useStyles();
const [results, setResults] = useState([]);
useEffect(() => {
loadSearchItemsList();
}, []);
//load restaurants and tags
const loadSearchItemsList = async () => {
try {
let { data } = await axios.get("/search");
// console.log(data)
setResults(data);
} catch (error) {
// setAlert({
// showAlert: true,
// severity: "error",
// message: "Loading failed!",
// });
dialogOpen(true)
}
};
return (
<Grid item xs={12} sm={12} md={12} lg={12} className={classes.gapSpace}>
<Autocomplete
id="free-solo-demo"
freeSolo
getOptionLabel={(option) => option.name}
autoComplete
onChange={(event, newValue) => {
if (newValue) {
const { id, type, name } = newValue;
setFieldValue("id", id);
setFieldValue("type", type);
setFieldValue("name", name);
} else {
setFieldValue("id", null);
setFieldValue("type", null);
setFieldValue("name", null);
}
}}
options={results}
renderInput={(params) => (
<CssTextField
{...params}
className={classes.input}
placeholder="Restaurant, Food"
variant="outlined"
id="custom-css-outlined-input"
/>
)}
/>
</Grid>
);
}
You can control the open and inputValue state of Autocomplete and call setOpen(false) to close the menu list when there is nothing in the inputValue:
const [open, setOpen] = useState(false);
const [inputValue, setInputValue] = useState("");
return (
<Autocomplete
open={open}
onOpen={() => {
// only open when in focus and inputValue is not empty
if (inputValue) {
setOpen(true);
}
}}
onClose={() => setOpen(false)}
inputValue={inputValue}
onInputChange={(e, value, reason) => {
setInputValue(value);
// only open when inputValue is not empty after the user typed something
if (!value) {
setOpen(false);
}
}}
options={top100Films}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
Live Demo
Hello everyone :D I need your advise/tip. Right now I have a APIDataTable component. It has its rows, columns and etc. This component is responsible to show/build data table on frontend with search bar in it above the table. I have an search bar, which is not functional right now. I want it to search data from data table. What should I start from? How can i make it perform search in Table. Thank you for any advise and tip <3
import React, { useEffect, useState } from "react";
import { plainToClassFromExist } from "class-transformer";
import { Pagination } from "../../models/Pagination";
import {
DataTable,
DataTableHead,
DataTableHeadCell,
DataTableBody,
DataTableRow,
DataTableCell,
} from "../DataTable";
import { request } from "../../api";
import "./index.css";
import { MenuSurface } from "../MenuSurface";
import { IconButton } from "../IconButton";
import { Checkbox } from "../Checkbox";
import { Dialog } from "../Dialog";
import { GridCell, GridRow } from "../Grid";
import { Button } from "../Button";
export class Column<T> {
label: string;
width?: number;
filter?: JSX.Element;
render: (row: T) => JSX.Element | string;
constructor(column: Partial<Column<T>>) {
Object.assign(this, column);
}
}
type APIDataTableProps<T> = {
apiPath?: string;
params?: string;
columns?: Column<T>[];
type: Function;
onRowClick?: (row: T) => void;
};
export const APIDataTable = <T extends object>({
apiPath,
params,
columns,
type,
onRowClick,
}: APIDataTableProps<T>) => {
const [data, setData] = useState<Pagination<T>>(null);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(15);
const [isLoading, setIsLoading] = useState(false);
const [isDialogOpen, setDialogOpen] = useState(false);
const [isMenuSurFaceOpen, setMenuSurfaceOpen] = useState(false);
const [hiddenColumns, setHiddenColumns] = useState<number[]>(
JSON.parse(localStorage.getItem(`hiddenColumns-${apiPath + params}`)) || []
);
const fetchData = async () => {
const urlSearchParams = new URLSearchParams(params);
urlSearchParams.set("page", page.toString());
urlSearchParams.set("page_size", pageSize.toString());
const url = `${apiPath}?${urlSearchParams}`;
const response = await request(url);
const data = plainToClassFromExist(new Pagination<T>(type), response, {
excludeExtraneousValues: true,
});
setData(data);
setIsLoading(false);
};
useEffect(() => {
if (!!apiPath) {
setIsLoading(true);
fetchData();
}
}, [page, pageSize]);
const headCells = columns
.filter((e, i) => !hiddenColumns?.includes(i))
.map((column) => (
<DataTableHeadCell key={column.label} width={column.width}>
{column.label}
</DataTableHeadCell>
));
const rows = data?.results?.map((row, index) => (
<DataTableRow
key={"row-" + index}
onClick={() => !!onRowClick && onRowClick(row)}
>
{columns
.filter((e, i) => !hiddenColumns?.includes(i))
.map((column) => {
return (
<DataTableCell key={column.label} width={column.width}>
<div className="data-table-cell-text">{column.render(row)}</div>
</DataTableCell>
);
})}
</DataTableRow>
));
let uncheckedCheckboxes = hiddenColumns;
const onCheckboxChange = (index: number, value: boolean) => {
if (!value) {
uncheckedCheckboxes.push(index);
//setHiddenColumns(uncheckedCheckboxes);
} else {
const array = [...uncheckedCheckboxes];
array.splice(array.indexOf(index), 1);
uncheckedCheckboxes = array;
}
};
const [isOpen, setIsOpen] = useState(false);
return (
<div className="data-table-container">
<div className="search-test">
<div className="mdc-menu-surface--anchor">
<label
className="mdc-text-field mdc-text-field--filled mdc-text-field--no-label mdc-text-field--with-leading-icon mdc-text-field--with-trailing-icon"
htmlFor="input"
id="search-menu-surface"
>
<IconButton density={-1} icon="search" />
<input
className="mdc-text-field__input "
type="text"
placeholder="Поиск"
id="searchinput"
/>
<IconButton
density={-1}
icon="arrow_drop_down"
onClick={() => {
setMenuSurfaceOpen(true);
}}
/>
</label>
<MenuSurface
isOpen={isMenuSurFaceOpen}
onClose={() => setMenuSurfaceOpen(false)}
fullwidth
>
<div className="data-table-filters-container">
{columns.map(
(column) =>
!!column.filter && (
<div className="data-table-filter">
<div className="data-table-filter-label mdc-typography--subtitle1">
{column.label}
</div>
<div className="data-table-column-filter">
{column.filter}
</div>
</div>
// <GridRow>
// <GridCell span={3}>{column.label}</GridCell>
// <GridCell span={3}>{column.filter}</GridCell>
// </GridRow>
)
)}
{/* <GridCell span={2}> */}
{/* <Button label="Поиск" raised /> */}
{/* <Button
label="Отмена"
raised
onClick={() => {
setIsOpen(false);
}}
/> */}
{/* </GridCell> */}
</div>
</MenuSurface>
</div>
<IconButton
onClick={() => {
setDialogOpen(true);
}}
density={-1}
icon="settings"
/>
<Dialog
isOpen={isDialogOpen}
onOkClick={() => {
localStorage.setItem(
`hiddenColumns-${apiPath + params}`,
JSON.stringify(uncheckedCheckboxes)
);
setDialogOpen(false);
setHiddenColumns(uncheckedCheckboxes);
}}
onCloseClick={() => setDialogOpen(false)}
>
<div
style={{
display: "flex",
flexDirection: "column",
}}
>
{columns.map((column, index) => (
<Checkbox
label={column.label}
onChange={(value) => onCheckboxChange(index, value)}
defaultChecked={!uncheckedCheckboxes.includes(index)}
/>
))}
</div>
</Dialog>
</div>
<DataTable
pagination={true}
count={data?.count}
rowsNumber={data?.results.length}
page={page}
next={data?.next}
previous={data?.previous}
isLoading={isLoading}
onNextClick={() => setPage(page + 1)}
onPreviosClick={() => setPage(page - 1)}
>
<DataTableHead>{headCells}</DataTableHead>
<DataTableBody>{rows}</DataTableBody>
</DataTable>
</div>
);
};
I'm guessing that you want to search bar to effectively filter out rows that don't match. in this case what you want to do is add a filter to the search text (naturally you'll add a state for the search value, but it looks like you'll have that handled.
You'll add your filter here const rows = data?.results?.filter(...).map
You filter function will look something like this
const rows = data?.results.filter((row) => {
// In my own code if I have other filters I just make them return false
// if they don't match
if (
searchText &&
!(
// exact match example
row.field === searchText ||
// case-insensitive example
row.otherField?.toLowerCase().includes(searchText)
// can continue with '||' and matching any other field you want to search by
)
)
return false;
return true;
}).map(...)