CollectionView 101

Wijmo5具有一个可靠的基础设施,它是.NET开发者熟悉的并且强大数据层。主要的数据绑定接口是 ICollectionView 。 Wijmo包括了几个类来实现ICollectionView。最基础的是 CollectionView 类,它使用常规的JavaScript数组作为数据源。

CollectionView类实现了下列的接口:

CollectionView类可以追踪对数据所做的更改。这个功能在必须向服务器提交更改的情景中是非常有用的。

入门

要使用CollectionView类,先声明它并传入一个常规数组作为数据源。然后使用items属性访问视图。

在这个示例中,我们在一个HTML表格中展示CollectionView实例。

在AngularJS应用中开始使用CollectionView类的步骤:

  1. 添加对AngularJS,Wijmo,和Wijmo AngularJS指令的引用。
  2. 选择性地对FlexGrid添加引用。
  3. 对你的应用,服务,过滤器和指令模块添加引用。
  4. 向当前页面添加一个表格(或FlexGrid)并且将它绑定到CollectionView数据。
  5. 添加一个控制器来提供数据和逻辑
  6. 选择性地添加一些CSS来自定义表格的外观。

注意: 在下面的追踪更改示例中,我们使用的是FlexGrid而不是一般表格,所以你会发现标记上的不同。

<html> <head> <link rel="stylesheet" type="text/css" href="css/bootstrap.css"/> <link rel="stylesheet" type="text/css" href="css/wijmo.css" /> <link href="css/app.css" rel="stylesheet" type="text/css" /> <script src="scripts/angular.js" type="text/javascript"></script> <script src="scripts/wijmo.js" type="text/javascript"></script> <script src="scripts/wijmo.grid.js" type="text/javascript"></script> <script src="scripts/wijmo.angular.js" type="text/javascript"></script> <script src="scripts/app.js" type="text/javascript"></script> </head> <body ng-app="app"> <div ng-controller="appGSCtrl"> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}} </th> </tr> </thead> <tbody> <tr ng-repeat="item in cvGettingStarted.items"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}} </td> </tr> </tbody> </table> </div> </div> </body> </html>
/* define the controller for getting started */ var app = angular.module('app'); app.controller('appGSCtrl', function ($scope, dataSvc) { var cv = new wijmo.collections.CollectionView(dataSvc.getData(10)); $scope.fieldNames = dataSvc.getNames(); $scope.viewItems = cv.items; });
/* set default grid height and some shadow */ .sGrid { background-color: #fff; box-shadow: 4px 4px 10px 0 rgba(50, 50, 50, 0.75); height: 300px; margin-bottom: 12px; overflow: auto; }

Result (live):

{{fieldName}}
{{item[name] | globalize}}

当前记录管理

既然已经实现了ICollectionView接口,你可以使用CollectionView类来处理当前的记录。

这个示例演示如何使用CollectionView提供的API,通过单击表格的行或者表格上方的按钮来更改当前的记录。

我们使用currentPosition属性来获取集合中当前记录的位置,使用下面的方法更改当前的位置:

当位置更改后,我们使用currentChangingcurrentChanged事件来追踪它。 我们可以在currentChanging事件中撤销位置的更改。

单击下一个按钮来设置下一个记录为当前记录。单击上一个设置上一个记录为当前记录。 单击停在第4行按钮,阻止当前记录到达第四行时被更改。 单击清除按钮移除Stop按钮的效果并且允许当前记录被自由更改。

<div ng-controller="appCRMCtrl"> <div class="row-fluid well btn-group"> <button class="btn btn-default" ng-click="cvCRM.moveCurrentToNext()"> Next</button> <button class="btn btn-default" ng-click="cvCRM.moveCurrentToPrevious()"> Previous</button> <button class="btn btn-default" ng-click="stopCurrent()"> Stop at 4th Row</button> <button class="btn btn-default" ng-click="reset()"> Clear</button> </div> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}}</th> </tr> </thead> <tbody> <tr ng-repeat="item in cvCRM.items" ng-class="{success: item == cvCRM.currentItem}" ng-click="cvCRM.moveCurrentTo(item)"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}}</td> </tr> </tbody> </table> </div> </div>
/* Define the controller for current record management */ var app = angular.module('app'); app.controller('appCRMCtrl', function ($scope, dataSvc) { var cv = new wijmo.collections.CollectionView(dataSvc.getData(10)); $scope.cvCRM = cv; $scope.fieldNames = dataSvc.getNames(); // Forbid changing the current record when the 4th one is current. var stopCurrentIn4th = function (sender, e) { // When the current record is the 4th record, stop moving. if (sender.currentPosition === 3) { e.cancel = true; } } $scope.stopCurrent = function () { cv.currentChanging.addHandler(stopCurrentIn4th); }; // Restore the ability to change the current record. $scope.reset = function () { cv.currentChanging.removeHandler(stopCurrentIn4th); }; });

Result (live):

{{fieldName}}
{{item[name] | globalize}}

排序

CollectionView类,就像.NET中那样,实现了ICollectionView接口来支持排序。 要实现排序,添加一个或多个 SortDescription 对象到一个数组中,并把该数组传递给CollectionView.sortDescription属性。 现在你就可以从CollectionView.items属性获得排序结果了。

SortDescription对象是灵活的,允许你根据值按升序或降序来排列数据。 在下面的示例中,单击一个表格头部的属性可以对该属性按升序排序。再次单击会按该属性降序排序。

<div ng-controller="appSortingCtrl"> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames" ng-click="toggleSort(fieldName)" style="cursor:pointer"> {​{fieldName}} <span style="color: red"> {​{getSort(fieldName)}}</span> </th> </tr> </thead> <tbody> <tr ng-repeat="item in cvSorting.items"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}}</td> </tr> </tbody> </table> </div> </div>
/* Define the controller for sorting. */ var app = angular.module('app'); app.controller('appSortingCtrl', function ($scope, dataSvc) { // Initialize the CollectionView. var cv = new wijmo.collections.CollectionView(dataSvc.getData(10)); // Initialize the scope data. $scope.cvSorting = cv; $scope.fieldNames = dataSvc.getNames(); // Sorting $scope.toggleSort = function (fieldName) { // Get all of the sort descriptions. var sd = cv.sortDescriptions; var ascending = true; // Find whether the field is sorted. if (sd.length > 0 && sd[0].property === fieldName) { // If sorting is found, toggle the sort order. ascending = !sd[0].ascending; } // Create a new SortDescription object. var sdNew = new wijmo.collections.SortDescription(fieldName, ascending); // Remove any old sort descriptions and add the newly created one. sd.splice(0, sd.length, sdNew); }; // Get the sort label. $scope.getSort = function (propName) { var sd = cv.sortDescriptions; if (sd.length > 0 && sd[0].property === propName) { return sd[0].ascending ? '▲' : '▼'; } return ''; }; });

Result (live):

{{fieldName}}{{getSort(fieldName)}}
{{item[name] | globalize}}

过滤

CollectionView类,就像.NET中那样,实现了ICollectionView接口来支持过滤。 要实现过滤,设置CollectionView.filter属性为一个函数,它决定视图中包含哪一个对象。

在这个示例中,我们为country创建了一个过滤器,并且可以从输入控件获取过滤的值。 当你输入一个过滤值时,表格会刷新并且只显示过滤后的数据。

<div ng-controller="appFilteringCtrl"> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}} </th> </tr> </thead> <tbody> <tr ng-repeat="item in cvFiltering.items"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}} </td> </tr> </tbody> </table> </div> </div>
/* define the controller for filtering */ var app = angular.module('app'); app.controller('appFilteringCtrl', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(10)); // initialize the scope data. $scope.cvFiltering = cv; $scope.filter = ''; $scope.fieldNames = dataSvc.getNames(); // define the filter function for collectionview function filterFunction(item) { var filter = $scope.filter.toLowerCase(); if (!filter) { return true; } return item['country'].toLowerCase().indexOf(filter) > -1; } // apply filter (applied on a 500 ms timeOut) var toFilter; $scope.$watch('filter', function () { if (toFilter) { clearTimeout(toFilter); } toFilter = setTimeout(function () { toFilter = null; if (cv.filter === filterFunction) { cv.refresh(); } else { cv.filter = filterFunction; } $scope.$apply('cvFiltering.items'); }, 500); }); });

Result (live):

{{fieldName}}
{{item[name] | globalize}}

分组

CollectionView类,就像.NET中那样,实现了ICollectionView接口来支持分组。 要实现分组,添加一个或多个 GroupDescription 对象到一个数组并且将这个数组传递给CollectionView.groupDescriptions属性。 在创建表格实例时,你必须设置表格的showGroups属性为true,默认值是false。

GroupDescription对象是灵活的,允许你根据值或值分组函数来进行分组。

下面的示例根据你从列表中选择的任意一个字段进行分组。 表格不仅展示项的内容也会展示分组信息:组名,组汇总的平均值,它会出现在组头部的行。

注意:选择列表中的一个项会添加一个新的GroupDescription实例。随后的选择会嵌套组。 如果你选择列表中已经存在GroupDescription对象的项,则不会有任何事发生。要清除组设置,选择列表的第一项。

<div class="appGroupingCtrl"> <div class="row-fluid well"> <select class="form-control" ng-model="selectedGroupOpt" ng-options="opt for opt in fieldNames"> <option value="" selected="selected"> Please choose the field you want to group by...</option> </select> </div> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}}</th> </tr> </thead> <tbody> <tr ng-repeat="item in groupItems"> <td class="active" ng-show="isGroupItem(item)" colspan="6"> <span ng-style="{ display:'inline-block', width: (item.level*25) + 'px'}"></span> <b>{​{item.name | globalize}}</b> ({​{item.items.length}} items) </td> <td class="text-center" colspan="2" ng-show="isGroupItem(item)"> {​{avgAmount(item)}} </td> <td class="text-center" ng-repeat="name in fieldNames" ng-hide="isGroupItem(item)"> {​{item[name] | globalize}} </td> </tr> </tbody> </table> </div> </div>
/* define the controller for grouping */ var app = angular.module('app'); app.controller('appGroupingCtrl', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(20)); // initialize the scope data. $scope.cvGrouping = cv; $scope.fieldNames = dataSvc.getNames(); $scope.groupItems = cv.items; $scope.selectedGroupOpt = ''; $scope.isGroupItem = function (item) { return item instanceof wijmo.collections.CollectionViewGroup; }; $scope.avgAmount = function (item) { // it only works when the item is a group item. if (!$scope.isGroupItem(item)) { return; } // get the average value of group amount values. var avg = item.getAggregate(wijmo.Aggregate.Avg, 'amount'); return wijmo.Globalize.format(avg); }; // update the group list cv.collectionChanged.addHandler(function () { $scope.groupItems = cv.items; if (cv.groups && cv.groups.length > 0) { $scope.groupItems = []; for (var i = 0; i < cv.groups.length; i++) { addGroup(cv.groups[i]); } } }); function addGroup(g) { $scope.groupItems.push(g); if (g.isBottomLevel) { for (var i = 0; i < g.items.length; i++) { $scope.groupItems.push(g.items[i]); } } else { for (var i = 0; i < g.groups.length; i++) { addGroup(g.groups[i]); } } } //apply the group setting $scope.$watch('selectedGroupOpt', function () { var gd, fieldName = $scope.selectedGroupOpt; gd = cv.groupDescriptions; if (!fieldName) { // clear all the group settings. gd.splice(0, gd.length); return; } if (findGroup(fieldName) >= 0) { return; } if (fieldName === 'amount') { // when grouping by amount, use ranges instead of specific values gd.push(new wijmo.collections.PropertyGroupDescription(fieldName, function (item, propName) { var value = item[propName]; // amount if (value > 1000) return 'Large Amounts'; if (value > 100) return 'Medium Amounts'; if (value > 0) return 'Small Amounts'; return 'Negative Amounts'; })); } else { // group by specific property values gd.push(new wijmo.collections.PropertyGroupDescription(fieldName)); } }); // check whether the group with the specified property name already exists. function findGroup(propName) { var gd = cv.groupDescriptions; for (var i = 0; i < gd.length; i++) { if (gd[i].propertyName === propName) { return i; } } return -1; } });

Result (live):

{{fieldName}}
{{item.name | globalize}} ({{item.items.length}} items) {{avgAmount(item)}} {{item[name] | globalize}}

编辑

CollectionView类,就像.NET中那样,实现了IEditableCollectionView接口来支持编辑。

这个示例展示你应该如何更新、添加和删除集合中的项。

在这个表格中,选中一个行然后按下下面的编辑详情按钮会开始编辑。 当你在弹出对话框完成编辑后,按下OK按钮来提交你的更新。 如果你想要添加一个新的记录到集合中,按下添加按钮并且在对话框中输入项的内容。按下OK来提交该新纪录。 选中一个行然后按下删除按钮来从集合中移除一个记录。

<div ng-controller="appEditingCtrl"> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}}</th> </tr> </thead> <tbody> <tr ng-repeat="item in cvEditing.items" ng-click="cvEditing.moveCurrentTo(item)" ng-class="{success: item == cvEditing.currentItem}"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}}</td> </tr> </tbody> </table> </div> <!-- commands --> <div class="row-fluid well"> <!-- edit details in a popup --> <button class="btn btn-default" data-toggle="modal" data-target="#dlgDetail" ng-click="cvEditing.editItem(currentItem)" ng-disabled="!currentItem"> Edit Detail...</button> <button class="btn btn-default" data-toggle="modal" data-target="#dlgDetail" ng-click="cvEditing.addNew()"> Add...</button> <button class="btn btn-default" ng-click="cvEditing.remove(currentItem)" ng-disabled="!currentItem"> Delete</button> </div> <!-- a dialog for editing item details --> <div class="modal fade" id="dlgDetail"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> &times;</button> <h4 class="modal-title">Edit Item</h4> </div> <div class="modal-body"> <dl class="dl-horizontal"> <dt>ID</dt> <dd> <input class="form-control" type="text" ng-model="currentItem.id" /> </dd> <dt>Start Date</dt> <dd> <input formatted-model class="form-control" type="text" ng-model="currentItem.start" /> </dd> <dt>End Start</dt> <dd> <input formatted-model class="form-control" type="text" ng-model="currentItem.end" /> </dd> <dt>Country</dt> <dd> <input class="form-control" type="text" ng-model="currentItem.country" /> </dd> <dt>Product</dt> <dd> <input class="form-control" type="text" ng-model="currentItem.product" /> </dd> <dt>Color</dt> <dd> <input class="form-control" type="text" ng-model="currentItem.color" /> </dd> <dt>Amount</dt> <dd> <input class="form-control" type="text" ng-model="currentItem.amount" /> </dd> <dt>Active</dt> <dd> <input class="form-control" type="checkbox" ng-model="currentItem.active" /> </dd> </dl> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="confirmUpdate()"> OK</button> <button type="button" class="btn btn-warning" data-dismiss="modal" ng-click="cancelUpdate()"> Cancel</button> </div> </div> </div> </div> </div>
/* define the controller for editing */ var app = angular.module('app'); app.controller('appEditingCtrl', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(10)); // define the new item value. cv.newItemCreator = function () { var item = dataSvc.getData(1)[0]; // aggregate the max value of id in the collection. item.id = wijmo.getAggregate(wijmo.Aggregate.Max, cv.sourceCollection, 'id') + 1; return item; } // initialize the scope data. $scope.cvEditing = cv; $scope.fieldNames = dataSvc.getNames(); $scope.currentItem = cv.currentItem; $scope.confirmUpdate = function () { // commit edit or addition cv.commitEdit(); cv.commitNew(); }; $scope.cancelUpdate = function () { // cancel editing or adding cv.cancelEdit(); cv.cancelNew(); }; // Sync the currentItem scope with the CollectionView. cv.currentChanged.addHandler(function () { $scope.currentItem = cv.currentItem; }); });

Result (live):

{{fieldName}}
{{item[name] | globalize}}

分页

CollectionView类,就像.NET中那样,实现了IPagedCollectionView接口来支持分页。要实现分页, 设置IPagedCollectionView.pageSize属性为你想要在每个页面展示的项的数量,然后提供一个导航页面的UI。

在这个示例中,CollectionView对象被初始化为每页显示10个项。你可以在textbox中自定义一个数字。 我们添加了导航按钮,并且在按钮的点击事件中调用IPagedCollectionView方法。 注意我们使用pageIndexpageCount属性来展示当前页面和页面的总数。 你可以在第一个文本框自定义页面的大小。将它设为空或0会禁用分页并且隐藏导航按钮。

<div ng-controller="appPagingCtrl"> <div class="row-fluid well row"> <div class="col-md-5"> <input number-input type="text" class="form-control" placeholder="0 or empty is for no paging." ng-model="cvPaging.pageSize" /> </div> <div class="btn-group col-md-7" ng-show="cvPaging.pageSize > 0"> <button type="button" class="btn btn-default" ng-disabled="cvPaging.pageIndex <= 0" ng-click="cvPaging.moveToFirstPage()"> <span class="glyphicon glyphicon-fast-backward"></span> </button> <button type="button" class="btn btn-default" ng-disabled="cvPaging.pageIndex <= 0" ng-click="cvPaging.moveToPreviousPage()"> <span class="glyphicon glyphicon-step-backward"></span> </button> <button type="button" class="btn btn-default" disabled style="width:100px" > {​{cvPaging.pageIndex + 1 | number}} / {​{cvPaging.pageCount | number}} </button> <button type="button" class="btn btn-default" ng-disabled="cvPaging.pageIndex >= cvPaging.pageCount - 1" ng-click="cvPaging.moveToNextPage()"> <span class="glyphicon glyphicon-step-forward"></span> </button> <button type="button" class="btn btn-default" ng-disabled="cvPaging.pageIndex >= cvPaging.pageCount - 1" ng-click="cvPaging.moveToLastPage()"> <span class="glyphicon glyphicon-fast-forward"></span> </button> </div> </div> <div class="sGrid"> <table class="table table-condensed table-bordered"> <thead> <tr class="active"> <th class="text-center" ng-repeat="fieldName in fieldNames"> {​{fieldName}}</th> </tr> </thead> <tbody> <tr ng-repeat="item in cvPaging.items"> <td class="text-center" ng-repeat="name in fieldNames"> {​{item[name] | globalize}}</td> </tr> </tbody> </table> </div> </div>
/* define the controller for paging */ var app = angular.module('app'); app.controller('appPagingCtrl', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(55)); // initialize the page size with 10. cv.pageSize = 10; // initialize the scope data. $scope.cvPaging = cv; $scope.fieldNames = dataSvc.getNames(); });

Result (live):

{{fieldName}}
{{item[name] | globalize}}

追踪更改

CollectionView类可以追踪对数据的更改。这个功能在一些必须提交更改到服务器的情形是有用的。 要打开更改追踪的功能,把trackChanges属性改为true。 一旦你那样做了,CollectionView会跟踪数据的任何变化并且在三个数组中显示它们:

这个功能在下方通过一个FlexGrid展现。这个表格与CollectionView绑定,并把trackChanges设为真。 当你编辑表格时,这些更改会出现在下方的三个表格中。

<div ng-controller="appTCCtrl"> <h5>Change the data here</h5> <wj-flex-grid class="sGrid" items-source="cvTrackingChanges" allow-add-new="true" allow-delete="true"> </wj-flex-grid> <h5>See the changes here</h5> <h6>Items edited:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsEdited" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> <h6>Items added:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsAdded" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> <h6>Items removed:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsRemoved" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> </div>
/* define the controller for tracking changes */ var app = angular.module('app'); app.controller('appTCCtrl', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(6)); //track the changes cv.trackChanges = true; // initialize the scope data. $scope.cvTrackingChanges = cv; });
/* set default grid height and some shadow */ .sGrid { background-color: #fff; box-shadow: 4px 4px 10px 0 rgba(50, 50, 50, 0.75); height: 300px; margin-bottom: 12px; overflow: auto; } /* set the record grids height and some shadow */ .tcGrid { background-color: #fff; box-shadow: 4px 4px 10px 0 rgba(50, 50, 50, 0.75); height: 100px; margin-bottom: 12px; overflow: auto; }

Result (live):

Change the data here
See the changes here
Items edited:
Items added:
Items removed:

自定义追踪更改

当你在追踪更改的CollectionView编辑一个项目时,这个项目会添加到itemdEdited集合。 不过,CollectionView不会追踪项的初始值, 因此如果你之后又编辑它并且恢复了初始值,该项仍然会保留在itemdEdited集合中。

但是如果你愿意的话你可以改变这个行为。 这个示例使用了CollectionViewitemsChanged类暴露的事件来追踪每一项是否是原始数据并且 如果用户恢复了原始数据的话将它们从itemsEdited集合中移除。

<div ng-controller="appTCCtrlX"> <h5>Change the data here</h5> <wj-flex-grid class="sGrid" items-source="cvTrackingChanges" allow-add-new="true" allow-delete="true"> </wj-flex-grid> <h5>See the changes here</h5> <h6>Items edited:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsEdited" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> <h6>Items added:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsAdded" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> <h6>Items removed:</h6> <wj-flex-grid class="tcGrid" style="background:#eeeeff" items-source="cvTrackingChanges.itemsRemoved" is-read-only="true"> <wj-flex-grid-column binding="id" header="id" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="start" header="start"> </wj-flex-grid-column> <wj-flex-grid-column binding="end" header="end"> </wj-flex-grid-column> <wj-flex-grid-column binding="country" header="country"> </wj-flex-grid-column> <wj-flex-grid-column binding="product" header="product"> </wj-flex-grid-column> <wj-flex-grid-column binding="color" header="color"> </wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="amount" data-type="Number"> </wj-flex-grid-column> <wj-flex-grid-column binding="active" header="active" data-type="Boolean"> </wj-flex-grid-column> </wj-flex-grid> </div>
/* define the controller for tracking changes with extra/custom tracking */ var app = angular.module('app'); app.controller('appTCCtrlX', function ($scope, dataSvc) { // initialize the collectionview var cv = new wijmo.collections.CollectionView(dataSvc.getData(6)); //track the changes cv.trackChanges = true; // initialize the scope data. $scope.cvTrackingChanges = cv; // keep the original state of the current item var current = cv.currentItem ? JSON.stringify(cv.currentItem) : null; cv.currentChanged.addHandler(function (s, e) { current = s.currentItem ? JSON.stringify(s.currentItem) : null; }); // keep track of the original state of edited items var original = []; cv.itemsEdited.collectionChanged.addHandler(function (s, e) { if (e.action == wijmo.collections.NotifyCollectionChangedAction.Add || e.action == wijmo.collections.NotifyCollectionChangedAction.Change) { // check if we have this item's original data var index = cv.sourceCollection.indexOf(e.item); var found = -1; for (var i = 0; i < original.length && found < 0; i++) { if (original[i].index == index) { found = i; } } // if we have the item, check original value if (found > -1) { // if the current value is the same as the original, remove var valueNow = JSON.stringify(e.item); if (valueNow == original[found].value) { original.splice(found, 1); index = cv.itemsEdited.indexOf(e.item); cv.itemsEdited.splice(index, 1); } } else { // if we don't, store it now found = original.length; original.push({ index: index, value: current }); } } }); });
/* set default grid height and some shadow */ .sGrid { background-color: #fff; box-shadow: 4px 4px 10px 0 rgba(50, 50, 50, 0.75); height: 300px; margin-bottom: 12px; overflow: auto; } /* set the record grids height and some shadow */ .tcGrid { background-color: #fff; box-shadow: 4px 4px 10px 0 rgba(50, 50, 50, 0.75); height: 100px; margin-bottom: 12px; overflow: auto; }

Result (live):

Change the data here
See the changes here
Items edited:
Items added:
Items removed: