Angular 11:通过管道使用对象列表过滤对象列表
Angular 11 : Filter List of Objects with List of Objects via Pipe
我有一个 FormControl 和页面顶部,我可以在其中 select 个对象(我称之为 'Tags')以便过滤它下面的其他对象列表
例如,我会 select 两个像这样的对象 :
[
{
"id": "4",
"index": 4,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 4"
},
{
"id": "5",
"index": 5,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 5"
}
]
然后尝试根据我的列表(我称之为 'Posts')根据 post.postTags 属性.
过滤它
{
"id": "RMjImD7Iy327rZOIBDfm",
"createdDate": "07/17/2021 20:31:02",
"posterId": "GI2Xs9YDV2UOh8M1J6zISvDt7wb2",
"posterName": "example@email.com",
"title": "New post with example email",
"bodyText": "The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled.",
"posterPicture": "../../../../../assets/images/user/wip-avatar.png",
"postTags": [
{
"id": "4",
"index": 4,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 4"
},
{
"picture": "https://via.placeholder.com/20x20",
"id": "7",
"name": "Interest 7",
"isActive": false,
"index": 7
},
{
"id": "2",
"name": "Interest 2",
"isActive": false,
"index": 2,
"picture": "https://via.placeholder.com/20x20"
}
]
}
列表截图console.log
我当前的 filterPipe 如下所示:
但到目前为止无法找出正确的逻辑。
我希望逻辑能够:
- 过滤在帖子 postTags 字段中拥有任何(一个或多个)selected 标签的帖子。
- Return 原始列表,如果没有标签 selected。
如果你想return你的原始数组,如果没有选择标签,你可以像这样使用三元运算符。
return term.length > 0 ? otherStuffHere : items
在 otherStuffHere
或 items
可以为空或未定义的情况下,您可以通过添加一些空合并来改善这一点,如果需要,return 设置默认值。
return (term.length > 0 ? otherStuffHere : items) ?? []
这基本上意味着:如果 (term ? otherStuffHere : items)
为 null 或未定义,请改用 []
。 (check this out)
这仅在您使用 angular 12 或更大时才有效。否则,使用 ||
而不是 ??
.
你的问题的第二部分已经有了答案 (Return original list if no tags are selected.
)
至于你问题的第一部分,事情变得更有趣了。
您基本上想要的是检查是否至少有一个条件为真(该项目的至少一个标签在标签列表中),以便某个项目出现在您的筛选列表中。
Javascript 在数组原型中实现 some()
方法,这正是您想要的。 docs here.
在您的情况下,过滤器方法应该如下所示:
items.filter(item =>
item.postTag.some(pTag => term.some(t => t.id === pTag.id))
);
另一种方法是这样
items.filter(item =>
item.postTag.some(pTag => term.map(t => t.id).include(pTag.id))
);
你可以将 term.map(t => t.id)
保存在一个变量中,将第二个代码示例更改为:
const termIds = term.map(t => t.id);
items.filter(item =>
item.postTag.some(pTag => termIds.include(pTag.id))
);
请注意,这非常重要。我的箭头函数不包含 return,因为我不使用大括号。 Some reading here。这也是您在代码中遇到的一个问题。
items.filter(item => {
item.postTags.filter(tag => tag === term);
});
总是 returned []
,一个空数组。
代码中的另一个问题是 tag === term
,它比较对象的引用,而不是它们的值。这就是为什么我比较他们 id 上的项目。
因此,作为您问题的最终答案,您的 transofrm 方法(如果我是正确的)应该如下所示:
transform(items: any[], term: any[]): any[] {
return (term.length > 0 ?
items.filter(item =>
item.postTag.some(pTag => term.map(t => t.id).include(pTag.id))
) :
items ) ?? [];
}
我有一个 FormControl 和页面顶部,我可以在其中 select 个对象(我称之为 'Tags')以便过滤它下面的其他对象列表
例如,我会 select 两个像这样的对象 :
[
{
"id": "4",
"index": 4,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 4"
},
{
"id": "5",
"index": 5,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 5"
}
]
然后尝试根据我的列表(我称之为 'Posts')根据 post.postTags 属性.
过滤它{
"id": "RMjImD7Iy327rZOIBDfm",
"createdDate": "07/17/2021 20:31:02",
"posterId": "GI2Xs9YDV2UOh8M1J6zISvDt7wb2",
"posterName": "example@email.com",
"title": "New post with example email",
"bodyText": "The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled.",
"posterPicture": "../../../../../assets/images/user/wip-avatar.png",
"postTags": [
{
"id": "4",
"index": 4,
"isActive": false,
"picture": "https://via.placeholder.com/20x20",
"name": "Interest 4"
},
{
"picture": "https://via.placeholder.com/20x20",
"id": "7",
"name": "Interest 7",
"isActive": false,
"index": 7
},
{
"id": "2",
"name": "Interest 2",
"isActive": false,
"index": 2,
"picture": "https://via.placeholder.com/20x20"
}
]
}
列表截图console.log
我当前的 filterPipe 如下所示:
但到目前为止无法找出正确的逻辑。 我希望逻辑能够:
- 过滤在帖子 postTags 字段中拥有任何(一个或多个)selected 标签的帖子。
- Return 原始列表,如果没有标签 selected。
如果你想return你的原始数组,如果没有选择标签,你可以像这样使用三元运算符。
return term.length > 0 ? otherStuffHere : items
在 otherStuffHere
或 items
可以为空或未定义的情况下,您可以通过添加一些空合并来改善这一点,如果需要,return 设置默认值。
return (term.length > 0 ? otherStuffHere : items) ?? []
这基本上意味着:如果 (term ? otherStuffHere : items)
为 null 或未定义,请改用 []
。 (check this out)
这仅在您使用 angular 12 或更大时才有效。否则,使用 ||
而不是 ??
.
你的问题的第二部分已经有了答案 (Return original list if no tags are selected.
)
至于你问题的第一部分,事情变得更有趣了。
您基本上想要的是检查是否至少有一个条件为真(该项目的至少一个标签在标签列表中),以便某个项目出现在您的筛选列表中。
Javascript 在数组原型中实现 some()
方法,这正是您想要的。 docs here.
在您的情况下,过滤器方法应该如下所示:
items.filter(item =>
item.postTag.some(pTag => term.some(t => t.id === pTag.id))
);
另一种方法是这样
items.filter(item =>
item.postTag.some(pTag => term.map(t => t.id).include(pTag.id))
);
你可以将 term.map(t => t.id)
保存在一个变量中,将第二个代码示例更改为:
const termIds = term.map(t => t.id);
items.filter(item =>
item.postTag.some(pTag => termIds.include(pTag.id))
);
请注意,这非常重要。我的箭头函数不包含 return,因为我不使用大括号。 Some reading here。这也是您在代码中遇到的一个问题。
items.filter(item => {
item.postTags.filter(tag => tag === term);
});
总是 returned []
,一个空数组。
代码中的另一个问题是 tag === term
,它比较对象的引用,而不是它们的值。这就是为什么我比较他们 id 上的项目。
因此,作为您问题的最终答案,您的 transofrm 方法(如果我是正确的)应该如下所示:
transform(items: any[], term: any[]): any[] {
return (term.length > 0 ?
items.filter(item =>
item.postTag.some(pTag => term.map(t => t.id).include(pTag.id))
) :
items ) ?? [];
}