CollectionView入門

Wijmoは、扱いやすい強力なデータ層に基づく堅固なインフラストラクチャを備えています。 主要なデータバインディングインタフェースはICollectionViewです。 Wijmoには、ICollectionViewを実装するクラスがいくつか用意されています。 最も基本的なものはCollectionViewで、これは通常のJavaScript配列をデータソースとして使用します。

CollectionViewクラスは以下のインタフェースを実装しています。

CollectionViewクラスは、データに加えられた変更を追跡できます。 この機能は変更をサーバーに送信する必要がある状況で役立ちます。

はじめに

CollectionViewクラスを使用するには、まずクラスを宣言し、通常の配列をデータソースとして渡します。 次に、itemsプロパティを使用してビューにアクセスします。

ここでは、CollectionViewインスタンスをHTMLテーブルに表示します。

CollectionViewクラスをAngularJSアプリケーションで使用する手順は以下のとおりです。

  1. AngularJS、WijmoおよびAngularJSディレクティブへの参照を追加します。
  2. (オプション)FlexGridへの参照を追加します。
  3. appモジュール、servicesモジュール、filtersモジュール、directivesモジュールへの参照を追加します。
  4. テーブルのマークアップをページに追加し、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; }

結果(ライブ):

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

カレントレコード管理

CollectionViewICollectionViewインタフェースを実装しているため、カレントレコードを管理できます。

この例は、CollectionViewクラスによって提供されるAPIを使用してカレントレコードを管理する方法を示します。グリッドの行またはグリッドの上のボタンをクリックしてカレントレコードを変更できます。

currentPositionプロパティを使用してコレクション内のカレントレコードの位置を確認しています。 また、以下のメソッドでカレントポジションを変更します。

ポジションを変更した時、currentChangingcurrentChangedイベントで変更を追跡します。 また、currentChangingイベントでポジションの変更をキャンセルすることができます。

[次へ移動]ボタンをクリックすると、現在のレコードが次のレコードに移動します。 [前へ移動]をクリックすると、現在のレコードが前のレコードに移動します。 [4行目で停止]ボタンをクリックすると、現在のレコードが4行目のとき、位置が変更できなくなります。 [停止の解除]ボタンをクリックすると、現在のレコードが再び自由に移動できるようになります。

<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()"> 4行目で停止</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); }; });

結果(ライブ):

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

ソート

CollectionViewクラスは、ICollectionViewインタフェース(これは.NETのICollectionViewインタフェースと同一です)によってソートをサポートします。 ソートを有効にするには、1つ以上のsortDescriptionsオブジェクトをCollectionView.sortDescriptionsプロパティに追加します。 ソートされた結果は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 ''; }; });

結果(ライブ):

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

フィルタリング

CollectionViewクラスは、ICollectionViewインタフェース(これは.NETのICollectionViewインタフェースと同一です)によってフィルタリングをサポートします。 フィルタリングを有効にするには、ビューに含めるオブジェクトを決定する関数をCollectionView.filterプロパティに設定します。

この例では、国のフィルタを作成し、入力コントロールからフィルタ値を取得します。フィルタを入力すると、グリッドが更新されてフィルタリングされたデータが表示されます。

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

結果(ライブ):

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

グループ化

CollectionViewクラスは、ICollectionViewインタフェース(これは.NETのICollectionViewインタフェースと同一です)によってグループ化をサポートします。 グループ化を有効にするには、1つ以上の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; } });

結果(ライブ):

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

編集

CollectionViewは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"> 詳細の編集...</button> <button class="btn btn-default" data-toggle="modal" data-target="#dlgDetail" ng-click="cvEditing.addNew()"> 追加...</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">項目の編集</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; }); });

結果(ライブ):

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

ページング

CollectionViewクラスは、IPagedCollectionViewインタフェース(これは.NETのIPagedCollectionViewインタフェースとほぼ同じです)によってページングをサポートします。 ページングを有効にするには、各ページに表示する項目数をIPagedCollectionView.pageSizeプロパティに設定し、ページを移動するためのUIを提供します。

この例では、1ページに10項目が表示されるようにCollectionViewオブジェクトが初期設定されています。テキストボックスでこの数をカスタマイズできます。ナビゲーションボタンが用意されており、ボタンをクリックするとIPagedCollectionViewメソッドが呼び出されます。また、pageIndexプロパティとpageCountプロパティを使用して現在のページと総ページ数を表示しています。ページサイズは最初のテキストボックスでカスタマイズできます。このテキストボックスを空にするか0を入力すると、CollectionViewがページングなしになり、ナビゲーションボタンが非表示になります。

<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(); });

結果(ライブ):

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

変更の追跡

CollectionViewクラスは、データに加えられた変更を追跡できます。 これは変更をサーバーに送信する必要がある状況で役立ちます。 変更の追跡を有効にするには、trackChangesプロパティをtrueに設定します。 そうすると、データに加えられた変更がCollectionViewによって追跡され、以下の3つの配列で公開されます。

FlexGridを使用してこの機能を実現した例を以下に示します。 グリッドがCollectionViewにバインドされており、そこでtrackChangesがtrueに設定されています。

<div ng-controller="appTCCtrl"> <h5>データを変更</h5> <wj-flex-grid class="sGrid" items-source="cvTrackingChanges" allow-add-new="true" allow-delete="true"> </wj-flex-grid> <h5>変更データを確認</h5> <h6>編集された項目:</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>追加された項目:</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>削除された項目:</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; }

結果(ライブ):

データを変更
変更データを確認
編集された項目:
追加された項目:
削除された項目:

変更の追跡(カスタマイズ)

変更の追跡をしているCollectionViewの上の項目を編集すると、アイテムがitemdEditedのコレクションに追加されます。 しかし、CollectionViewは追跡中の元の値を保持しません。よって、もし、値の変更後、再度値を編集して元の値へ復元しても、itemdEditedコレクションにアイテムは残ったままになります。

しかし、この動作を変更することもできます。 このサンプルはCollectionViewと追跡するためのitemsChangedにより、公開されているイベントを利用して、もし元の値を復元した場合、itemsEditedからそのアイテムを削除します。

<div ng-controller="appTCCtrlX"> <h5>データを変更</h5> <wj-flex-grid class="sGrid" items-source="cvTrackingChanges" allow-add-new="true" allow-delete="true"> </wj-flex-grid> <h5>変更データを確認</h5> <h6>編集された項目:</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>追加された項目:</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>削除された項目:</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; }

結果(ライブ):

データを変更
変更データを確認
編集された項目:
追加された項目:
削除された項目: