UI组件库Kendo UI for Angular入门指南 – 从代码中动态过滤 格

Telerik_KendoUI产品技术交流群:726377843    欢迎一起进群讨论

我们的案例研究应用程序相对简单:有一个显示客户列表和国家下拉列表的Grid,当用户从下拉列表中选择一个国家时,代码将更新Grid来只显示该国家的客户。同时还将添加一个复选框,允许用户根据客户是否加入公司的忠诚度计划来选择客户,下面是UI的样子:

UI组件库Kendo UI for Angular入门指南 - 从代码中动态过滤 格
定义UI

这个 格显示的Customer类有六个属性,然而对于这个案例研究,只对国家和inLoyaltyProgram属性感兴趣:

export class Customer{constructor(public id: number,public country: string,public inLoyaltyProgram: Boolean,public custName: string,public signUpDate: Date | null,public amountPurchased: number) { }}

定义下拉列表和复选框的标记看起来像这样:

Select Country:<kendo-dropdownlist[data]="countries"defaultItem=”Pick a Country”(selectionChange)="CountryChange($event)"></kendo-dropdownlist><br/><br/>Loyalty Program Only: <input type="checkbox" #loyalty kendoCheckBox(change)="LoyaltyChange($event)"/>

这些组件中的每一个都调用一个函数,并在用户更改组件的值时传递相关的事件对象。我将把这两个函数(CountryChange用于下拉列表,LoyaltyChange用于复选框)称为“过滤器函数”。

还需要两个客户数组,第一个数组是客户的“完整/未过滤”数组(可能从某些Web服务获取),但是我们将Grid绑定到第二个名为selectCustomers的数组,该数组显示当前选定的客户。最初我们是希望两个数组是相同的,所以我像这样初始化数组:

public customers: Customer[];public selectCustomers: Customer[] = [];this.customers = [new Customer(1, "Peter Vogel", "USA", new Date(), 3250, true),…more Customers…];this.selectCustomers = this.customers;

最后用kendo-Grid组件定义Grid,并将Grid绑定到selectCustomers列表。同时还定义了Grid中的每一列,以便可以将每一列绑定到公司的一个属性,控制列中的数据格式,在列的顶部设置标题,并指定列的宽度。

所有的Grid标记看起来像这样:

<kendo-Grid[kendoGridBinding]="selectCustomers"[height]="250"(filterChange)= "this.filterCustomers($event)"><kendo-Grid-column title="Id" field="id" [width]="50"></kendo-Grid-column><kendo-Grid-column title="Name" field="custName" [width]="150"></kendo-Grid-column><kendo-Grid-column title="Purchase" field="amountPurchased" [width]="125" format="99,999"></kendo-Grid-column><kendo-Grid-column title="Signed Up" field="signUpDate" [width]="200" format="MMM-dd-yyyy"></kendo-Grid-column><kendo-Grid-column title="In Program" field="inLoyaltyProgram" [width]="100"></kendo-Grid-column></kendo-Grid>
过滤的基础设施

要过滤一个 格,需要一个CompositeFilterDescriptor,它包含0个或多个FilterDescriptors(如果CompositeFilterDescriptor没有FilterDescriptors,那么没有行被“过滤掉”)。我们需要导入这两个类,因为稍后还需要filterBy函数,所以也将导入它:

import { CompositeFilterDescriptor, FilterDescriptor, filterBy }from "@progress/kendo-data-query";

FilterDescriptor有三个属性对这个案例研究很重要:

  • field:要筛选的属性名称
  • operator:要使用的比较运算符(例如,eq, neq, gt等)
  • value:要比较的值

将两个filterdescriptor设置为属性是有意义的,一个用于按客户筛选,一个用于按忠诚度计划筛选,这可以将每个FilterDescriptor上的所有属性设置为一些默认值。这可以简化后面的代码:当用户在下拉列表和复选框中进行更改时,两个过滤器函数中唯一需要更改的属性是每个FilterDescriptor的value属性。

这两个FilterDescriptor属性的声明如下:

countryFilter: FilterDescriptor = {field:"country", operator:"eq", value:"Pick a country"};loyaltyFilter: FilterDescriptor = {field:"inLoyaltyProgram", operator:"eq", value:false};

现在在过滤器函数中,只是从传递给函数的事件中检索当前值,并在适当的FilterDescriptor中设置value属性。这对于下拉列表来说非常简单,因为下拉列表的选择事件只是传递当前在下拉列表中选择的值:

CountryChange(e:string): void{this.countryFilter.value = e;this.CreateFilter();}

对于复选框来说有点复杂,因为该函数传递的是一个Event对象。然而,可以将事件对象的目标属性转换为HtmlInput对象,然后检索元素的checked属性来设置FieldDescriptor的value属性:

LoyaltyChange(e:Event): void{const cbx = e.target as HTMLInputElement;this.loyaltyFilter.value = cbx.checked;this.CreateFilter();}

在每个函数末尾调用的CreateFilter函数将两个FilterDescriptors组装成一个CompositeFilter,并实际过滤数据(您将在接下来的短暂中断后看到该函数)。

用户体验中断

我们只给了用户筛选客户是否在忠诚度计划中的功能——用户不能筛选不在计划中的客户,这是因为在用户界面中使用了一个复选框来控制这个过滤选项。

虽然Kendo UI下拉列表有一个“不确定”的状态,允许复选框表明它还没有被触摸,一旦用户选中复选框,复选框只在true和false状态之间交替。如果我使用false将列表过滤到那些不在忠诚度计划中的客户,那么一旦用户选中复选框,用户将被限制在使用true查看计划中的客户和使用false查看计划中没有的客户之间切换,但不会是所有客户。

如果想让用户可以选择忠诚度计划过滤器的三种状态(在忠诚度计划中,不在忠诚度计划中,并且“不关心忠诚度计划”),我们将不得不使用一些其他组件组合(可能是两个单选按钮或另一个下拉列表)。

过滤客户

现在已经构建了FilterDescriptors,将它们组合在CreateFilter方法中。

在CreateFilter函数中,检查了两个FilterConditions中四个可能的值组合,并使用它们来加载CompositeFilterDescriptor的Filters数组:

  • 如果LoyaltyFilter设置为false, CustomerFilter设置为下拉列表的默认值,就不设置任何过滤器。
  • 如果LoyaltyFilter设置为true, CustomerFilter设置为某些国家(即,不是默认值),加载两个过滤器。
  • 对于任何其他组合,只加载具有其值集的筛选器。

当Filters条件中确实有多个项时,必须将CompositeFilterDescriptor的逻辑属性设置为” and “或” or “,以指示如何组合过滤器。当使用两个过滤器时,希望它们是“and”一起的,所以在CompositeFilterDescriptor中已经将逻辑属性设置为“and”。

在只有一个(或没有)过滤器的情况下,将逻辑属性设置为什么并不重要——将属性设置为” and “就可以了。

下面是构建ComponsiteFilterDescriptor的代码(可能有更复杂的方法,但这个版本的优势是显而易见的):

GridFilter:CompositeFilterDescriptor = {filters:[],logic:"and"};CreateFilter(){if (!this.loyaltyFilter.value && this.countryFilter.value == "Pick a country"){this.GridFilter.filters = [];}if (!this.loyaltyFilter.value && this.countryFilter.value != "Pick a country"){this.GridFilter.filters = [this.countryFilter];}if (this.loyaltyFilter.value && this.countryFilter.value == "Pick a country"){this.GridFilter.filters = [this.loyaltyFilter];}if (this.loyaltyFilter.value && this.countryFilter.value != "Pick a country"){this.GridFilter.filters = [this.loyaltyFilter, this.countryFilter];}

在CreateFilter函数的末尾,终于可以将完整的客户数组过滤到Grid所绑定的selectCustomers数组中。为此,使用前面导入的filterBy函数,传递完整的customers数组和CompositeFilterDescriptor,使用调用filterBy的结果来设置Grid绑定到的数组的代码如下所示:

…{this.GridFilter.filters = [this.loyaltyFilter, this.countryFilter];}this.selectCustomers = filterBy(this.customers, this.GridFilter);}

现在,当用户与应用程序UI的其他部分交互时,代码将控制Grid显示的行。


标签:

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2023年1月4日
下一篇 2023年1月4日

相关推荐

发表回复

登录后才能评论