Rxjs / Ngrx Filtering Stream基于另一个流的属性

时间:2018-05-01 07:27:43

标签: angular rxjs ngrx

我在理解和使用RxJS Observables和ngrx Store时遇到了问题。

我尝试了combineLatest,过滤器,连接数组等,但似乎无法获得有效的无错解决方案。

对于哪种技术最适合实现此结果的任何意见/反馈我将不胜感激

要求

  1. 从ngrx Store中取出2个对象,然后用a过滤第一个Object 第二个Object中的属性
    • 人物 - 第一个人物对象列表
    • 公司 - 第二份公司对象清单
    • PeopleFromSelectedCompanies - 过滤第一个对象仅显示 在第二个对象d中与公司ID匹配的人。如果不 公司存在于2nd Object中,然后我想显示所有来自01st Object的人
  2. 将PeopleFromSelectedCompanies分配给Angular Material DataTable的DataSource
  3. 接受字符串过滤器以过滤包含字符串
  4. 的任何属性的PeopleFromSelectedCompanies

    所有ngOnInit代码都运行良好我可以访问所需的所有列表,每次选择getSelectedCustomersPeople运行的另一个客户时。 目前的意大利面条代码,如果你能理解我想做什么

    组件

    ngOnInit() {
      this.peopleStore.dispatch(new fromPeopleStore.LoadPeople());
    
      this.people$ = this.peopleStore.select(fromPeopleStore.getAllPeople);
    
      this.selectedCustomers$ = this.toolbarStore
        .select(fromToolbarStore.getSelectedCustomers);
    
      this.selectedCustomers$.subscribe(selected => {
        this.selectedCustomersPeople$ = this.getSelectedCustomersPeople();
      });
    }
    
    getSelectedCustomersPeople(): Observable<Person[]> {
      return combineLatest(this.selectedCustomers$, this.people$, (customers, people) => {
        const allSelectedPeople = customers.map(
          customer => Object.assign(people.filter(
            person => person.company === customer.id
          ))
        );
    
        const flattenSelectedPeople = [].concat.apply([], allSelectedPeople);
    
        return flattenSelectedPeople;
      });
    }
    
    applyFilter(filterValue = ' ') {
      filterValue = filterValue.trim();
      filterValue = filterValue.toLowerCase();
      this.selectedCustomersPeople$ = filterValue;
      // Would like to filter here not sure how
    }
    

    模板

    <mat-table #table [dataSource]="selectedCustomersPeople$ | async"
      matSort
      [@animateStagger]="{ value: '50' }">
      <!-- Name Column -->
      <ng-container cdkColumnDef="firstName">
        <mat-header-cell *cdkHeaderCellDef mat-sort-header>First Name</mat-header-cell>
        <mat-cell *cdkCellDef="let person">
          <p class="text-truncate font-weight-600">
            {{ person.firstName }} {{ person.familyName }}
          </p>
        </mat-cell>
      </ng-container>
    
      <mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *cdkRowDef="let person; columns: displayedColumns;"
        class="person"
        (click)="editPerson(person)"
        [ngClass]="{'mat-light-blue-50-bg': checkboxes[person.id]}"
        matRipple
        [@animate]="{ value: '*', params: { y: '100%' } }">
      </mat-row>
    </mat-table>
    

2 个答案:

答案 0 :(得分:0)

如果其他人试图做类似的事情,我得到了一个有效的解决方案。下面更新的代码可能不是最好或最干净的方法,但它运作良好:

() -> Void = { [weak self] in
    guard let `self` = self else { 
        self.callMethod2()
    }
    self.callMethod3()
}

答案 1 :(得分:0)

我做了一个基本的例子,说明如何通过使用rx流来做得更清洁。

我做了一个基本的独立示例,其中我创建了两个源(客户$和公司$),它们将发出所有0.8 - 1秒。这只是我可以在本地测试。你应该能够使用people $和selectedCompanies $ observables来做同样的事情。

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/interval';
import 'rxjs/add/observable/combineLatest';

interface Customer {
    id: number;
    company: number;
}

interface Company {
    id: number;
}

export function test() {
    // Emits a customer list all 1000 milliseconds
    const customers$: Observable<Customer[]> = Observable
        .interval(1000)
        .map(() => <Customer[]>[{ id: 1, company: 1}, {id: 2, company: 1}, {id: 3, company: 5}]);
    // Emits a company list all 800 milliseconds
    const companies$: Observable<Customer[]> = Observable
        .interval(800)
        .map(() => <Customer[]>[{ id: 1, company: 1}, {id: 2, company: 1}]);

    // Create a stream that combines the latest value of both lists
    const both$ = Observable.combineLatest(customers$, companies$);

    // Create a new observable which will emit the filtered customers
    const filteredCustomers$ = both$.map((data: any) => {
        const customers: Customer[] = data[0];
        const companies: Company[] = data[1];
        // We did not receive any companies, so we can return the full customer list
        if (!companies || companies.length === 0) {
            return customers;
        }

        // Create an object that will have keys of existing companies as id
        const companyIds = {};
        companies.forEach(c => companyIds[c.id] = true);

        // Return the filtered version of the customers
        return customers
            // In the filter statement, we check if the company id exists
            // in our helper object. You could leave out the "=== true" part.
            .filter(customer => companyIds[customer.company] === true);
    });

    // Now we have a filteredCustomers$ observable where we can subscribe:
    filteredCustomers$.subscribe(customers => console.log('Filtered Customers: ', customers));
}