ReactJS Как отфильтровать массив по нужным условиям?
Всем привет! Пытаюсь реализовать простую функцию поиска в проекте. Проект - список атрибутов. У меня есть массив этих элементов:
const selectedAttributesArray = [
{
attrType: "ЭЛЕМЕНТ",
code: "Teen",
id: 162,
links: [],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "DE_unicode1",
id: 141,
links: [
{idElementConnect: 162,
protectionFunc: 'DE1_string',
unprotectionFunc: 'DE2_string',
codeElementConnect: 'IK_HIVE'
},
],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "R1_to_de",
id: 81,
links: [
{idElementConnect: 182,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'HIVE'},
{idElementConnect: null,
protectionFunc: 'FUNCTION_FOR',
unprotectionFunc: null,
codeElementConnect: null},
{idElementConnect: 201,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'SPARK'},
],
note: "string1",
type: "protegrity",
}
]
Чтобы найти элемент массива есть инпут с отдельным стейтом searchValue (стейт находится в родительском компоненте):
export const SearchWidget = ({ searchValue, handleSearchQuery }) => {
return (
<div className={styles.mainContainer}>
<Input
placeholder='Найти атрибут...'
value={searchValue}
onChange={(e: string) => handleSearchQuery(e)}
/>
</div>
)
}
и в итоге с помощью функции я фильтрую массив, чтобы уже из него мапить данные при рендеринге:
export const DataResultCards = ({ selectedAttributesArray, searchValue, handleOpenSideBar }) => {
const filteredAttributeList = selectedAttributesArray?.filter(attribute =>
new RegExp(`${searchValue.toLowerCase().replace(/%/g, '.')}`).test(attribute.code.toLowerCase()),
);
return (
<>
{filteredAttributeList.length > 0 ? (
filteredAttributeList?.map(attribute => {
return <DataResultCard attribute={attribute} />;
})
) : (
<div>Ничего не найдено</div>
)}
</>
);
};
Как должен осуществляться поиск НАПРИМЕР:
- при вводе в поиск "de" я получаю в качестве результата два объекта: карточку атрибута "DEunicode1" и "R1_tode" (нашли по названию атрибута)
- если я ввожу в поиск "hiv", то получу на экране карточки "DE_unicode1" (у него codeElementConnect: 'IK_HIVE') и "R1_to_de" (у него codeElementConnect: 'HIVE').
- при вводе "Str" результаты те же, потому что у них protectionFunc: 'DE1_string' и protectionFunc: 'ptyProtectStr'.
Код отдельной карточки атрибута:
export const DataResultCard = ({ attribute, handleOpenSideBar }) => {
return (
<Card
style={{ width: 804, minHeight: 180, marginBottom: '5px' }}
>
<Tag classes={{ tag: styles.typeTag }}>{attribute.attrType}</Tag>
{attribute.links.length > 0
? attribute.links?.map(link => {
if (link.codeElementConnect === null) {
return null;
} else {
return (
<div onClick={() => handleOpenSideBar(link)}>
<Tag classes={{ tag: styles.connectedAttrTag }}>{link.codeElementConnect}</Tag>
</div>
);
}
})
: null}
<Text kind="h4b">{attribute.code}</Text>
<Text kind="textSb">Функции шифрования: </Text>
{attribute.links?.map(link => {
return (
<ul>
<li>
<ListEncryptionFunction link={link} attribute={attribute} />
</li>
</ul>
);
})}
</Card>
);
};
Я пыталась переписать фильтр, чтобы и по массиву ссылок от атрибутов тоже можно было найти элемент по названию ссылки:
const filteredAttributeList = selectedAttributesArray?.filter((attribute) => {
attribute.links?.map((link) => {
if (link.codeElementConnect !== null) {
new RegExp(`${searchValue.toLowerCase().replace(/%/g, '.')}`).test(link.codeElementConnect.toLowerCase()),
} else {
new RegExp(`${searchValue.toLowerCase().replace(/%/g, '.')}`).test(attribute.code.toLowerCase()),
}
}
)
}
);
Но так поиск не работает. Как можно задать фильтр с несколькими условиями, чтобы найти элемент и по названию его ссылок?
Ответы (2 шт):
Если я правильно понял задачу, и вам нужно искать либо по code
либо по значению в объектах в links
, то такой код будет верным.
const selectedAttributesArray = [
{
attrType: "ЭЛЕМЕНТ",
code: "Teen",
id: 162,
links: [],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "DE_unicode1",
id: 141,
links: [
{
idElementConnect: 162,
protectionFunc: 'DE1_string',
unprotectionFunc: 'DE2_string',
codeElementConnect: 'IK_HIVE'
},
],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "R1_to_de",
id: 81,
links: [
{
idElementConnect: 182,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'HIVE'
},
{
idElementConnect: null,
protectionFunc: 'FUNCTION_FOR',
unprotectionFunc: null,
codeElementConnect: null
},
{
idElementConnect: 201,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'SPARK'
},
],
note: "string1",
type: "protegrity",
}
];
const filteredAttributeList = useMemo(() =>
{
const filtered = selectedAttributesArray.filter((attribute) =>
{
const searchValueReg = new RegExp(searchValue.replace(/%/g, '.'), "i");
if (searchValueReg.test(attribute.code))
{
return true;
}
return attribute.links.some((link) =>
{
return Object.values(link).filter((linkValue) =>
{
return searchValueReg.test(linkValue);
}).length > 0
});
});
return filtered;
}, [ searchValue, selectedAttributesArray ]);
Как должен осуществляться поиск НАПРИМЕР: при вводе в поиск "de" я получаю в качестве результата два объекта: карточку атрибута "DEunicode1" и "R1_tode" (нашли по названию атрибута) если я ввожу в поиск "hiv", то получу на экране карточки "DE_unicode1" (у него codeElementConnect: 'IK_HIVE') и "R1_to_de" (у него codeElementConnect: 'HIVE'). при вводе "Str" результаты те же, потому что у них protectionFunc: 'DE1_string' и protectionFunc: 'ptyProtectStr'.
Предложу такой вариант фильтрации...
const arr = [
{
attrType: "ЭЛЕМЕНТ",
code: "Teen",
id: 162,
links: [],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "DE_unicode1",
id: 141,
links: [
{
idElementConnect: 162,
protectionFunc: 'DE1_string',
unprotectionFunc: 'DE2_string',
codeElementConnect: 'IK_HIVE'
},
],
note: "string",
type: "protegrity",
},
{
attrType: "ЭЛЕМЕНТ",
code: "R1_to_de",
id: 81,
links: [
{
idElementConnect: 182,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'HIVE'
},
{
idElementConnect: null,
protectionFunc: 'FUNCTION_FOR',
unprotectionFunc: null,
codeElementConnect: null
},
{
idElementConnect: 201,
protectionFunc: 'ptyProtectStr',
unprotectionFunc: 'ptyUnprotectStr',
codeElementConnect: 'SPARK'
},
],
note: "string1",
type: "protegrity",
}
]
const a = ['de', 'hiv', 'Str']
a.forEach(v => console.log(v, test(arr, v).map(o => o.code)))
//
function test(arr, txt = '') {
const r = new RegExp(txt, 'i')
const fn1 = v => r.test(v)
const fn2 = o => Object.values(o).some(fn1)
const fn3 = obj => r.test(obj.code) || obj.links.some(fn2)
return arr.filter(fn3)
}