【问题标题】:Angular2 filter/pipe using radio buttons to filterAngular2过滤器/管道使用单选按钮进行过滤
【发布时间】:2017-07-03 04:05:08
【问题描述】:

我正在寻找一种过滤解决方案,可以实时过滤一组重复的元素。我在答案here 中有一个基本的管道解决方案。

我发现<input [(ngModel)]='query'/> 只有在同一个组件中才有效。

但是 - 我需要让过滤器值来自另一个组件中预先填充的单选按钮。

这是我目前的代码。

filter.component

<div class="topic" *ngFor="let topic of topics">
  {{topic.term}}
  <input [(ngModel)]="query" type="radio" name="topicFilter" [value]="topic.term"/>
</div>

grid.component

<router-outlet></router-outlet> // this pulls in the filter.component

<input [(ngModel)]="query"> // this is a text input that works as wanted ( for showing what I'm wanting to achieve )

<grid-item *ngFor="let user of users | topicFilterPipe: 'topic':query">
  <a [routerLink]="['user-story', user.uid]">
    <h1>{{user.fname}}</h1>
  </a>
  {{user.topic}}
</grid-item>

filter.pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'topicFilterPipe'
})
export class TopicFilterPipePipe implements PipeTransform {

  public transform(value: Array<any>, keys: string, term: string) {
    console.log('pipe has run');
    if (!term) return value;
    return (value || []).filter((item) => keys.split(',').some(key => item.hasOwnProperty(key) && new RegExp(term, 'gi').test(item[key])));

  }

}

基本上 - 尝试实现与文本输入相同的方法,但使用 filter.component 中的选定单选。但是我正在努力将选定的值传递到管道中,然后使用 ngModel 进行过滤。谢谢!

注意:我对 angular2 非常陌生 + 过滤器组件必须保留在单独的组件中

【问题讨论】:

  • 如果您有多于几行数据,使用管道进行过滤通常不是一个好主意。请参阅:angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe 您可以改为在组件本身中进行过滤。
  • @DeborahK 我至少有 500 行数据。所以你可能是对的。我将如何处理 filter.component 中的过滤并将其传递给 grid.component
  • 在下面的答案中查看我的回复。
  • 正如其他人在回答中提到的那样,服务是管理多个组件之间的状态信息的好方法。这就是你实际在做的事情,改变应用程序的状态。该服务也可以扩展为从其他过滤器传递信息,但目的应该保持一致。例如一个管理用户体验偏好的服务,另一个管理用户看到的广告流。

标签: angular


【解决方案1】:

您的问题是关于组件之间的通信。 FilterComponent 需要通知 GridComponent 新查询已更新。

由于服务在 Angular 中是一个单例(存在例外但在这里不相关),如果我们从一个组件设置服务中的数据,其他组件可以访问数据。我们通过使用 BehaviorSubject 来存储信息来使用观察者模式。

查询服务:

此服务将具有查询数据。 getQuery 将提供一个可被任何组件收听的可观察对象。

@Injectable()
export class QueryService{

    public query = new BehaviorSubject<string>('');

    public getQuery(){
        return query;
    }

    public setQuery(queryStr){
        this.query.next(queryStr);
    }
}

过滤器组件

FilterComponent 将在值更改时调用服务并更新。

HTML

<input 
    [ngModel]="query"
    (ngModelChange)="updateQuery($event)" 
    type="radio"
    name="topicFilter" [value]="topic.term"/>

TS

constructor(private queryService: QueryService){}
public updateQuery(query){
    queryService.setQuery(query);
}

网格组件

public query:string; 

constructor(private queryService: QueryService){}

ngOnInit(){
  // .... other code
  queryService.getQuery()
     .subscribe(queryVal => {
          this.query = queryVal;
     });

}

您可以使用角度事件机制并触发事件,以便 gridcomponent 可以捕获事件并获取新的查询。但服务的做事方式更好。由于您在路由器内部有FilterComponent,因此这里很难使用事件机制。

在任何一种情况下,您都可以使用问题中提到的管道。

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'topicFilterPipe'
})
export class TopicFilterPipePipe implements PipeTransform {

  public transform(value: Array<any>, keys: string, term: string) {
    console.log('pipe has run');
    if (!term) return value;
    return (value || []).filter((item) => keys.split(',').some(key => item.hasOwnProperty(key) && new RegExp(term, 'gi').test(item[key])));

  }

}

您可以使用问题中提到的管道,也可以直接在组件中自己过滤列表。

如果您仍然有问题,请创建一个 plnkr,我可以用这个答案为您更新它。

【讨论】:

  • 对不起 - 我不完全确定我是否遵循。我对angular2非常陌生。你能说得清楚一点吗?
  • 当然,为什么不呢。我会在一小时后更详细地更新答案。现在正在旅行。
  • 不幸的是,当我尝试实现此代码时出现错误?主要在您提供的 query.service 代码中。我错过了什么吗?
  • 有什么错误。您是否将导入添加到行为主题
  • Used import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 但是在类的第一行出现错误。 @Injectable() export class QueryService { let query = new BehaviorSubject&lt;string&gt;(''); // error on let public getQuery(){ //error here return query.toObservable(); } public setQuery(queryStr){ //error here this.query.next(queryStr); } } 意外令牌。需要构造函数、方法、访问器或属性。找不到名称“getQuery”。找不到名称“setQuery”。找不到名称“queryStr”。
【解决方案2】:

您可以使用如下方法构建服务:

performFilter(filterBy: string): IProduct[] {
    filterBy = filterBy.toLocaleLowerCase();
    return this.products.filter((product: IProduct) =>
          product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}

这是过滤产品列表...但您可以对其进行定制以过滤您需要的任何内容。而且由于这需要在服务中以便可以共享,因此您很可能需要传入要过滤的列表。所以更像这样:

performFilter(products: IProduct[], filterBy: string): IProduct[] {
    filterBy = filterBy.toLocaleLowerCase();
    return products.filter((product: IProduct) =>
          product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}

【讨论】:

  • 恐怕我不完全确定如何在我的代码中实现这一点。由于我没有采用与您从 API 收集“产品”相同的方法 - 我无法完全掌握如何在我的代码中实现它。我是 Angular 的新手
  • 如果您可以使用您的一些示例代码构建一个 plunker,我们可以提供更详细的示例。您可以使用 Plunker 使用此链接构建示例 Angular 应用程序:plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue
猜你喜欢
  • 2016-09-29
  • 2020-08-30
  • 2017-05-13
  • 1970-01-01
  • 2017-10-04
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多