我想开发此功能来搜索/过滤列表。基本上,我将从输入框中获取搜索词,然后必须从数组中获取所有包含搜索词的项。
这是到目前为止我尝试过的方法,它适用于根级属性,但不适用于嵌套数组/对象:
// Filter List
this.filterList = query => {
if (typeof query === "string") {
// transform query to lowercase
query = query.toLowerCase();
// clear the current list being displayed
this.filteredList = [];
// filter the lsit and store the results with
// matching criteria in "filteredList" array
let filteredResults = _.filter(this.itemList, item => {
if (item && typeof item === "object") {
// loop over the item object
for (let property in item) {
if (item.hasOwnProperty(property)) {
let key = item[property];
// address, phone and emails
if (typeof key === "object" && _.isArray(key)) {
_.filter(key, element => {
if (typeof element === "object") {
for (let nestedProperty in element) {
let nestedKey = element[nestedProperty];
if (nestedKey) {
nestedKey = nestedKey.toString().toLowerCase();
}
if (nestedKey && nestedKey.includes(query)) {
return item;
}
}
}
});
} else {
if (key) key = key.toString().toLowerCase();
if (key && key.includes(query)) return item;
}
}
}
}
});
// assign the filtered results to the list being displayed
this.filteredList = [...filteredResults];
} else {
// if query is empty or null or anything other than string
// revert all changes and assign the original list to display list
this.filteredList = this.itemList;
}
};
如果有帮助,这是我要遍历的数组中的一个对象:
[
{
"id": "number",
"dealerCode": "string",
"name": "string",
"gstin": "string",
"pan": "string",
"cin": "string",
"emails": [
{
"name": "string",
"address": "string",
"isPrimary": "boolean"
}
],
"phoneNumbers": [
{
"countryCode": "number",
"number": "number",
"isPrimary": "boolean"
}
],
"addresses": [
{
"addressLine1": "string",
"addressLine2": "string",
"addressLine3": "string",
"country": "string",
"state": "string",
"city": "string",
"postalCode": "number",
"isPrimary": "boolean"
}
],
"status": "string",
"statusId": "number"
}
]
我正在AngularJS中进行此操作,也使用了Lodash。
答案 0 :(得分:1)
对于类似这样的问题,您需要比较不同类型的基元和对象/数组,通常最好使用递归命名函数。根据以下假设,这可能应该可以解决您正在寻找的问题:
该解决方案的工作方式如下:
// test data for trial runs
const testData = [
{
id: 123488,
dealerCode: "ACb3",
name: "Some Name",
gstin: "string",
pan: "string",
cin: "string",
emails: [
{
name: "Some Email name",
address: "anemail.domain.com",
isPrimary: "boolean"
}
],
phoneNumbers: [
{
countryCode: "9398",
number: "number",
isPrimary: "boolean"
}
],
addresses: [
{
addressLine1: "Florida",
addressLine2: "Street place",
addressLine3: "string",
country: "string",
state: "string",
city: "string",
postalCode: "number",
isPrimary: "boolean"
}
],
status: "string",
statusId: "number"
},
{
id: 88888,
dealerCode: "NMC",
name: "Some Other",
gstin: "string",
pan: "string",
cin: "string",
emails: [
{
name: "An Email thing",
address: "athing.somewhere.org",
isPrimary: "boolean"
}
],
phoneNumbers: [
{
countryCode: "93948",
number: "number",
isPrimary: "boolean"
}
],
addresses: [
{
addressLine1: "Denver",
addressLine2: "Street place",
addressLine3: "string",
country: "string",
state: "string",
city: "string",
postalCode: "number",
isPrimary: "boolean"
}
],
status: "string",
statusId: "number"
}
];
// broke these into separate helper functions, but you can combine all of them except the recursive one if you'd like
const returnFilterResults = (userEntry, dataItems) => {
const compareValues = (entry, dataValue) => {
if ( _.isBoolean(dataValue)) {
return entry === dataValue;
} else if (_.isNumber(dataValue)) {
// if the dataValue is a number, we convert both it and the user's entry (which probably already is a string) to a string to compare
// you can make this comparison more strict if desired
return _.includes(_.toLower(_.toString(dataValue)), _.toLower(entry));
} else if (_.isString(dataValue)) {
return _.includes(_.toLower(dataValue), _.toLower(entry));
} else {
return false;
}
};
const matchesEntryInTree = (entry, dataItem) => {
// if this dataItem is an object or array, let's drill back in again
if (_.isObject(dataItem) || _.isArray(dataItem)) {
// as we recursively move through the tree, check to see if *any* of the entries match, using 'some'
return _.some(dataItem, innerDataItem => {
return matchesEntryInTree(entry, innerDataItem);
});
} else {
// if it's a primitive, then let's compare directly
return compareValues(entry, dataItem);
}
};
// I created a results variable so we could console log here in this snippet
// but you can just return from the filter directly
const results = _.filter(dataItems, dataItem => {
return matchesEntryInTree(userEntry, dataItem);
});
console.log(userEntry, results);
return results;
};
returnFilterResults("place", testData);
// both entries return
returnFilterResults("Denver", testData);
// second entry is returned
returnFilterResults(48, testData);
// both entries return - ID in first, countryCode in second
returnFilterResults(12, testData);
// first entry is returned
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
答案 1 :(得分:0)
您为什么不使用Flatten函数来展平对象/ JSON然后搜索您的值?以下是一个示例:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
对于嵌套对象,假设
{
A : {
B: {
C: "V"
}
}
}
您将获得一个键为A.B.C且值为“ V”的对象。这样,您只有一个级别可以搜索您的价值。
希望这会有所帮助! 干杯!