Angular 使用角度管道实现自定义搜索相关性
我目前有一个带有自定义管道过滤器的基本课程搜索功能。它根据Angular 使用角度管道实现自定义搜索相关性,angular,pipe,angular-pipe,Angular,Pipe,Angular Pipe,我目前有一个带有自定义管道过滤器的基本课程搜索功能。它根据课程标题、说明或关键字中是否存在匹配项返回结果,但它以任意顺序返回课程。我想首先修改管道以返回更相关的结果,优先顺序是搜索查询在1中匹配。标题,2。描述,3。关键词 一些测试用例示例: 查询“chinese”当前返回“1X chinese”之前的“1 French”,因为“1 French”的关键字与“chinese”匹配 查询“线性代数”首先返回54 Math,然后返回89A statistics,即使后者在所有3个字段中都匹配 实施这
课程标题
、说明
或关键字
中是否存在匹配项返回结果,但它以任意顺序返回课程。我想首先修改管道以返回更相关的结果,优先顺序是搜索查询在1中匹配。标题,2。描述,3。关键词
一些测试用例示例:
“chinese”
当前返回“1X chinese”
之前的“1 French”
,因为“1 French”
的关键字与“chinese”
匹配“线性代数”
首先返回54 Math
,然后返回89A statistics
,即使后者在所有3个字段中都匹配 <li *ngFor="let course of courses | courseFilter: searchText |
orderBy: ['title', 'description', ''keywords]">
然而,我对Angular比较陌生,实现细节超出了我目前的理解范围。这是最直接的方法吗?如果我知道我只是在过滤课程对象,是否可以在不定义第二个orderBy管道的情况下修改当前课程过滤管道
任何提示都将不胜感激 您首先要将排名添加到每门课程中,然后按此顺序排序。i、 e
addRank(a: Course, query: string): number{
var rank: number;
if(course.course_title.toUpperCase().includes(query)) rank += 5;
if(course.description.toUpperCase().includes(query)) rank += 3;
if(course.keywords.toUpperCase().includes(query)) rank += 1;
course.rank = rank
然后按该排名按降序排列:
但是,AngularJs(与AngularJs/Angular 1不同)不提供orderBy或filter,他们建议您自己在组件中执行这些操作,而不是使用管道:
Angular不提供用于筛选或排序列表的管道。
熟悉AngularJS的开发人员将其称为filter和orderBy。
在角度上没有等价物
这不是疏忽。Angular不提供此类管道,因为它们
表现不佳,防止过度缩小
参考:
注意这一点,您可能会使用一个单独的courseResults列表,它是courses数组的过滤和排序版本。当然,在输入任何搜索/筛选条件之前,您可以将其初始化为课程。您还可以通过在搜索输入中添加一个按钮来最小化不必要的搜索/筛选调用(如果您是按键入方式进行的;如果您是按按钮单击进行的,那么您将跳过该操作)
简单解决方案:
因此,在你的StackBlitz的基础上,我完全不用管道,做了一个新的:
我们不显示所有课程,但显示课程结果…:
-
。。。初始化为空或所有课程(如下所示):
公共课程结果:课程[]=this.courses;
然后搜索可以是:
搜索($event){
this.courseResults=this.sortByRank(this.rankAndFilter(this.courses,this.searchText.toUpperCase());
}
私有筛选器(课程:课程[],查询:字符串){
var结果=[];
变量秩:个数;
为了(让我们来上课程){
秩=0;
if(course.course_title.toUpperCase().includes(query)){rank+=5};
if(course.description.toUpperCase().includes(query)){rank+=3};
if(course.keywords.toUpperCase().includes(query)){rank+=1};
course.rank=等级;
如果(排名>0)结果推送(路线);
}
返回结果;
}
私人分拣银行(课程:课程[]){
返回课程。排序(函数(a:课程,b:课程){
返回b.rank-a.rank;
});
}
扩展解决方案:
[编辑]一个新的应用程序,它使用debounce(因此,如果用户输入速度非常快,则不会对每次击键进行整个筛选和排序)和distinctUntilChanged(如果用户将字符退格,则不会麻烦),并创建了数组的全局扩展(sortBy和sortByDesc)
现在我们有了输入:
然后将该ViewChild作为ElementRef获取:
@ViewChild('searchInput')searchInputRef:ElementRef;
然后在init之后,我们在本机元素上设置输入上的observable,并订阅它:
ngAfterViewInit(){
var subscription=fromEvent(this.searchInputRef.nativeElement,'input').pipe(
映射((e:KeyboardEvent)=>(e.target).value),
去BounceTime(400),
distinctUntilChanged()
//开关映射(()=>this.performSearch())
);
订阅。订阅(数据=>{
此。性能搜索(数据);
});
}
私人performSearch(搜索文本){
console.log(“搜索:+searchText”);
this.searchText=searchText;
this.courseResults=this.rankAndFilter(this.courses,searchText).sortByDesc('rank');
返回此.courseResults;
}
感谢您的帮助,我用您的建议更新了,但无法获得所需的输出。我做错了什么?非常感谢。啊,直到你在这里再次指出,我才注意到你的闪电战。通过适当的更改进行更新。当然,将需要精细化,但这是出于性能和最小化原因(即远离使用管道)的基本方法。您可以分享您的分叉链接吗?我更深入地研究了角度应用程序中的过滤和排序数据,并对将过滤逻辑移动到组件本身进行了修改(如您所建议的),但在实现排序逻辑时遇到了困难。谢谢@Matt I已经为简单版本和使用debounce和distinctUntilChanged(也是阵列的全局扩展)的版本提供了StackBlitz分叉
<li *ngFor="let course of courses | courseFilter: searchText |
orderBy: ['title', 'description', ''keywords]">
addRank(a: Course, query: string): number{
var rank: number;
if(course.course_title.toUpperCase().includes(query)) rank += 5;
if(course.description.toUpperCase().includes(query)) rank += 3;
if(course.keywords.toUpperCase().includes(query)) rank += 1;
course.rank = rank