角度材料数据表 - 如何为具有提前类型/自动完成搜索的列设置 filterPredicate?

Posted

技术标签:

【中文标题】角度材料数据表 - 如何为具有提前类型/自动完成搜索的列设置 filterPredicate?【英文标题】:Angular Material Data Table - How To Setup filterPredicate For A Column With Type Ahead / Auto Complete Search? 【发布时间】:2019-12-03 04:05:03 【问题描述】:

我已经阅读了 SO、Github 等上 filterPredicate 的各种实现,但它们对我理解如何处理预输入搜索没有帮助。

我在输入表单字段中输入了一个字母,比如p,然后我从数据库中收到了姓氏以p 开头的所有数据。我设置的那部分工作正常。但是,当我输入下一个字母时,我不想再次点击数据库,比如r。我想过滤以pr 开头的姓氏的数据表。这就是麻烦的开始。

当我键入第二个字母时,我有一个 if/else 语句来测试我正在使用的 var 在字符串中是否有 >1。当它发生时,我将参数传递给一个函数,用于在表上使用已经从数据库下载的数据进行自定义过滤。我避免对每个字母进行 db 调用,这确实有效。我不明白“(数据,过滤器)”。它们看起来像参数,但不是。它们是如何工作的?完成这个需要什么代码?

(我有 `dataSource.filter = filterValue; 在其他地方工作正常。)

参数解释:

column = user_name
filterValue = pr...

困惑:

public filterColumn(column: string, filterValue: string, dataSource) 

    dataSource.filterPredicate = (data, filter) => 
      console.log('data in filter column: ', data);  // Never called.
      // What goes here?
      // return ???;
    
  

我的数据源对象。我看到了可以使用的 filterPredicate、data 和 filter 属性。而是抽象如何使用它们。

dataSource in filterColumn:  MatTableDataSource _renderData: BehaviorSubject, _filter: BehaviorSubject, _internalPageChanges: Subject, _renderChangesSubscription: Subscriber, sortingDataAccessor: ƒ, …
filterPredicate: (data, filter) => …arguments: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
    at Function.invokeGetter (<anonymous>:2:14)]caller: (...)length: 2name: ""__proto__: ƒ ()[[FunctionLocation]]: data-utilities.service.ts:43[[Scopes]]: Scopes[3]
filteredData: (3) […, …, …]
sortData: (data, sort) => …
sortingDataAccessor: (data, sortHeaderId) => …
_data: BehaviorSubject _isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …
_filter: BehaviorSubject _isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …
_internalPageChanges: Subject _isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …
_paginator: MatPaginator _isInitialized: true, _pendingSubscribers: null, initialized: Observable, _disabled: false, _intl: MatPaginatorIntl, …
_renderChangesSubscription: Subscriber closed: false, _parentOrParents: null, _subscriptions: Array(1), syncErrorValue: null, syncErrorThrown: false, …
_renderData: BehaviorSubject _isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …data: (...)filter: (...)paginator: (...)sort: (...)__proto__: DataSource

【问题讨论】:

【参考方案1】:

我已经包含了我在 Angular 中制作的大部分组件,用于预输入搜索。预输入代码的内容位于底部的实用程序共享组件中。我在这里使用了一个共享组件,因为我会在很多地方使用它。但是,我认为这是一个 hack,并且可能有一个更优雅的答案。这很有效,很容易,但不是那么漂亮。我现在不能花更多的时间来弄清楚漂亮。我怀疑答案在 RegEx 中。

在 .pipe 的 typeahead.compoent 中,您会发现我如何调用实用程序中的代码。

此代码在共享组件 typeahead.component.ts 中

public searchLastName$ = new Subject&lt;string&gt;(); // Binds to the html text box element.

ngAfterViewInit() 

// -------- For Column Incremental Queries --------- //
  // searchLastName$ binds to the html element.

    this.searchLastName$.subscribe(result => 
         this.queryLastName(result);
    );



//  --------- LAST NAME INCREMENTAL QUERY --------------- //

private queryLastName(filterValue) 

    // Custom filter for this function.  If in ngOnInit on the calling component then it applies 
    // to the whole calling component.  We need various filters so that doesn't work.

    this.membersComponent.dataSource.filterPredicate = (data:  last_name: string , filterValue: string) =>
        data.last_name.trim().toLowerCase().indexOf(filterValue) !== -1;

    //  When the first letter is typed then get data from db.  After that just filter the table.
    if (filterValue.length === 1) 

      filterValue = filterValue.trim(); // Remove whitespace
      // filterValue = filterValue.toUpperCase(); // MatTableDataSource defaults to lowercase matches

      const lastNameSearch = gql`
        query ($last_name: String!) 
            lastNameSearch(last_name: $last_name) 
                ...membersTableFrag
            
        
        $membersTableFrag
      `;

      this.apollo
          .watchQuery(
              query: lastNameSearch,
              variables: 
                  last_name: filterValue,
              ,
          )
          .valueChanges
          .pipe(
              map(returnedArray => 
                  // console.log('returnedArray  in map: ', returnedArray); // All last_name's with the letter in them someplace.
                  const membersArray = returnedArray.data['lastNameSearch'];  // extract items array from GraphQL JSON array

                  // For case insensitive search
                  const newArray = membersArray.filter(this.utilitiesService.filterBy(filterValue, 'last_name'));

                  return newArray;
              )
          )
          .subscribe(result => 
              this.membersComponent.dataSource.data = result;
          );

     else 
        // Filter the table instead of calling the db for each letter entered.
        // Note:  Apollo client doesn't seem able to query the cache with this kind of search.

        filterValue = filterValue.trim(); // Remove whitespace
        filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches

        // Interface and redefinition of filterPredicate in the ngOnInit

        this.membersComponent.dataSource.filter = filterValue;  // Filters all columns unless modifed by filterPredicate.

    

utilities.service.ts

// -------------- DATABASE COLUMN SEARCH -------------
  // Shared with other components with tables.
  // For case insensitive search.

  // THIS NEEDS TO BE CLEANED UP BUT I'M MOVING ON, MAYBE LATER

  public filterBy = (filterValue, column) => 

    return (item) => 
      const charTest = item[column].charAt(0);
      if (charTest === filterValue.toLowerCase()) 
        return true;
       else if (charTest === filterValue.toUpperCase()) 
        return true;
       else 
        return false;
      
    
  ;

【讨论】:

以上是关于角度材料数据表 - 如何为具有提前类型/自动完成搜索的列设置 filterPredicate?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 SQL 表自动生成数据类型

Google Places API 网络服务:如何为自动完成设置多种类型

如何在具有角度嵌套数据组的材料表中显示拆分标题

角度材料自动完成力选择不起作用

方法在角度材料自动完成中被多次调用

角度材料自动完成 - 如何防止键盘输入以在建议面板中选择一个选项