
Kendo UI for Angular是Kendo UI系列商业产品的最新产品。Kendo UI for Angular是专用于Angular开发的专业级Angular组件。telerik致力于提供纯粹的高性能Angular UI组件无需任何jQuery依赖关系。虽然Kendo UI for Angular网格带有内置的过滤功能但开发者有时需要允许用户控制过滤器显示的内容。在本文中我们将看到一个现实的示例如何将过滤集成到应用程序中以便当用户与应用程序的UI交付时代码可以控制Grid网格显示哪些行。我们的案例研究应用程序相对简单有一个显示客户列表和国家下拉列表的Grid当用户从下拉列表中选择一个国家时代码将更新Grid来只显示该国家的客户。同时还将添加一个复选框允许用户根据客户是否加入公司的忠诚度计划来选择客户下面是UI的样子定义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-dropdownlistbr/br/ Loyalty Program Only: input typecheckbox #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 titleId fieldid [width]50/kendo-Grid-column kendo-Grid-column titleName fieldcustName [width]150/kendo-Grid-column kendo-Grid-column titlePurchase fieldamountPurchased [width]125 format99,999/kendo-Grid-column kendo-Grid-column titleSigned Up fieldsignUpDate [width]200 formatMMM-dd-yyyy/kendo-Grid-column kendo-Grid-column titleIn Program fieldinLoyaltyProgram [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显示的行。