在转换后的数据上过滤 smart-table

Filtering smart-table on transformed data

提前致歉,我不是一个非常有经验的 JS 程序员,使用 AngularJS 更是如此,但我正在尝试对使用 Angular 1.5 的遗留代码库进行一些改进.9 和智能 Table 显示数据库中的信息。

我已经阅读了所有关于 st-searchst-safe-srcst-table 等的内容,但是我无法过滤 table,因为有基础数据在显示之前发生的转换。在我的例子中,ng-repeat 变量是 transaction,它有各种字段来保存该事务的信息,例如 payee,它保存指向另一个数据库文档的 UUID。在应用程序中,我们使用来自另一个控制器 (dbCtrl.getPayeeName()) 的函数显示该收款人的姓名,但底层数据是 UUID。因此,当尝试使用 Smart Table 进行过滤时,它不会过滤显示的名称,并且仅在将 UUID 输入过滤字段时才起作用。

一个小例子(删除了很​​多中间位,但希望足以证明我的困惑):

<div class="account"
     st-table="displayedTransactions"
     st-safe-src="transactions"
     disable-ng-animate>
...
<div><input st-search="payee" placeholder="search for payee" class="input-sm form-control" type="search"/></div>
...
<div ng-repeat="transaction in displayedTransactions track by transaction.id"> 
...
  <div class="account__td" transaction-field-focus-name="payee">
    {{dbCtrl.getPayeeName(transaction.payee)}}
  </div>
...
</div>

对于这种显示数据与基础数据不同的情况,是否有一种相对简单的方法可以使过滤起作用?从我在文档中阅读的内容来看,这听起来可能需要某种自定义插件,这听起来像是更多的工作,但我也许可以弄清楚。我只是想看看在沿着那条路线前进之前我是否遗漏了一些明显的东西。

回到这个问题上,我能够使用 st-set-filter 属性完成我需要的工作,如 2014 年 laurent 的 Strict mode filtering section of the documentation, as well as this helpful answer 中所述。

本质上,我在 html 模板中将 st-set-filter="transactionFilters" 添加到我的 table,以及具有 st-search="prop_to_search" 属性的 input 标签。然后在我的应用程序模块中(我把它放在其中一个控制器中,不确定这是否完全正确)我定义了一个过滤器,如下所示。 expression 作为一个对象传递到此代码中,其中包含您输入的任何内容的字符串值,因此如果您有三个搜索字段,您将得到一个对象,如:

{
  "prop_to_search1": "value1",
  "prop_to_search2": "value2",
  "prop_to_search3": "value3"
}

在过滤器函数中,我为每个可能进入的 属性 编写了一个 if 块,然后在那里进行自定义转换和模式匹配。这样,我就可以完全控制最终的匹配,而不是搜索 UUID,我可以做类似 $rootScope.dbCtrl.getPayeeName(uuidToSearch) 的事情。这在我的用例中都是可以接受的性能,但我可能会缓存这些数据库查找作为潜在的优化。

angular.module('myApp').filter('transactionFilters', function($rootScope, $filter){
  return function(array, expression){
    // console.log(`expression is: ${JSON.stringify(expression, null, 4)}`)
      return array.filter(function(val, index){
        // in this function's context, `expression` is an object with
        // the active filters entered in each field; `val` is the data
        // representation of each row of the table

        // if this function returns true, the row will match and smart-table
        // will show it, otherwise it will be hidden

        // define matches all at once, check them all, then return
        // a big logical AND on all of them

        let accountMatch = true;
        let payeeMatch = true;
        let categoryMatch = true;

        if (expression.account) {
          uuidToSearch = val.account  // this is the account UUID
          strToSearch = $rootScope.dbCtrl.getAccountName(uuidToSearch).toLowerCase();  // convert to an account name (we could memoize this to improve performance)
          if (strToSearch) {
            // if the account had a name (it always should, but catch in case)
            // then check if the row's account contains the text entered in the filter field
            accountMatch = strToSearch.includes(expression.account.toLowerCase());
          } else {
            accountMatch = false;
          }
        }

        if (expression.payee){
          if (val.payee) {
            uuidToSearch = val.payee
            strToSearch = $rootScope.dbCtrl.getPayeeName(uuidToSearch).toLowerCase();
          }

          if (strToSearch) {
            payeeMatch = strToSearch.includes(expression.payee.toLowerCase());
          } else {
            payeeMatch = false;
          }
        }

        if (expression.category) {
          if (val.category) {
            strToSearch = $rootScope.dbCtrl.getCategoryName(val.category, val.date).toLowerCase()
            categoryMatch = strToSearch.includes(expression.category.toLowerCase())
          } else {
            categoryMatch = false;
          }
        }

        return (
          accountMatch && 
          payeeMatch &&
          categoryMatch
        )
    })
  }
});