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

时间:2019-07-24 23:23:15

标签: angular-material

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

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

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

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

Params解释:

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 ???;
    }
  }

我的dataSource对象。我看到filterPredicate,数据和过滤器属性可以使用。而是抽象如何使用它们。

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 个答案:

答案 0 :(得分:0)

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

在.pipe的typeahead.compoent中,您将找到如何在实用程序中调用代码。

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

public searchLastName$ = new Subject<string>(); // 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;
      }
    }
  };