-
Notifications
You must be signed in to change notification settings - Fork 467
/
angular.htm
335 lines (238 loc) · 8.34 KB
/
angular.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>
Rendering Large Datasets With Angular 2 Beta 3
</title>
<link rel="stylesheet" type="text/css" href="./demo.css"></link>
</head>
<body>
<h1>
Rendering Large Datasets With Angular 2 Beta 3
</h1>
<my-app>
Loading...
</my-app>
<!-- Load demo scripts. -->
<script type="text/javascript" src="../../vendor/angularjs-2-beta/3/es6-shim.min.js"></script>
<script type="text/javascript" src="../../vendor/angularjs-2-beta/3/Rx.umd.min.js"></script>
<script type="text/javascript" src="../../vendor/angularjs-2-beta/3/angular2-polyfills.min.js"></script>
<!-- CAUTION: This demo does not work with the minified UMD code. -->
<script type="text/javascript" src="../../vendor/angularjs-2-beta/3/angular2-all.umd.js"></script>
<!-- AlmondJS - minimal implementation of RequireJS. -->
<script type="text/javascript" src="../../vendor/angularjs-2-beta/3/almond.js"></script>
<script type="text/javascript">
// Enabling production mode to make sure there's no performance degradation
// due to assertions and other checks the framework might be doing during the
// execution of the application.
ng.core.enableProdMode();
// Defer bootstrapping until all of the components have been declared.
// --
// NOTE: Not all components have to be required here since they will be
// implicitly required by other components.
requirejs(
[ "AppComponent" ],
function run( AppComponent ) {
ng.platform.browser.bootstrap( AppComponent );
}
);
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// I provide the root App component.
define(
"AppComponent",
function registerAppComponent() {
var LogTRCreation = require( "LogTRCreation" );
var LogTDCreation = require( "LogTDCreation" );
// Configure the app component definition.
ng.core
.Component({
selector: "my-app",
// Include these directives if you want to see proof that the
// TR and TD nodes are not being destroyed and re-created on
// the shuffling of the grid - they log out the constructor
// for the TR and TD dome nodes.
// --
// directives: [ LogTRCreation, LogTDCreation ],
template:
`
<form>
<strong>Filter Data</strong>:
<input
type="text"
[(ngModel)]="form.filter"
(input)="handleFilterChange( $event.target.value )"
/>
<span *ngIf="form.filter">
—
Filtering <strong>{{ form.filter }}</strong>
over {{ dataPoints }} data points,
{{ visibleCount }} found.
</span>
<a *ngIf="grid.length" (click)="unmountGrid()">Unmount Grid</a>
<a *ngIf="! grid.length" (click)="remountGrid()">Remount Grid</a>
<a *ngIf="grid.length" (click)="reverseGrid()">Reverse Grid</a>
</form>
<table width="100%" cellspacing="2" [class.filtered]="form.filter">
<tr *ngFor="#row of grid">
<td>
{{ row.id }}
</td>
<td
*ngFor="#item of row.items"
class="item"
[class.hidden]="item.isHiddenByFilter">
{{ item.value }}
</td>
</tr>
</table>
`
})
.Class({
constructor: AppController
})
;
return( AppController );
// I control the App component.
function AppController() {
var vm = this;
// We'll start out with a grid with 10,000 items.
vm.grid = generateGrid( 1000, 10 );
// Calculate the number of data-points that may have filtering.
vm.dataPoints = ( vm.grid.length * vm.grid[ 0 ].items.length );
// I hold the number of items that are visible based on filtering.
vm.visibleCount = 0;
// I hold the form data for use with ngModel.
vm.form = {
filter: ""
};
// Expose the public API.
vm.handleFilterChange = handleFilterChange;
vm.remountGrid = remountGrid;
vm.reverseGrid = reverseGrid;
vm.unmountGrid = unmountGrid;
// ---
// PUBLIC METHODS.
// ---
// I update the visibility of the items when the filter is updated.
// --
// CAUTION: The actual value of input is being maintained via ngModel.
// We're just responding to the change event.
function handleFilterChange( newValue ) {
// Reset the visible count. As we iterate of the items checking
// for visibility, we can increment this count as necessary.
vm.visibleCount = 0;
// We are pre-calculating the column count here because we are
// assuming a uniform column distribution in the grid.
var rowCount = vm.grid.length;
var columnCount = ( vm.grid.length && vm.grid[ 0 ].items.length );
for ( var r = 0 ; r < rowCount ; r++ ) {
var row = vm.grid[ r ];
for ( var c = 0 ; c < columnCount ; c++ ) {
var item = row.items[ c ];
// The item is hidden if the given filter text cannot be
// found in the value of the item.
item.isHiddenByFilter = ( newValue && ( item.value.indexOf( newValue ) === -1 ) );
// If the item isn't hidden, track it as part of the visible
// set of data.
if ( ! item.isHiddenByFilter ) {
vm.visibleCount++;
}
}
}
}
// I repopulate the grid with data. This will help separate processing
// performance characteristics from page-load processing.
function remountGrid() {
vm.grid = generateGrid( 1000, 10 );
vm.dataPoints = ( vm.grid.length * vm.grid[ 0 ].items.length );
vm.visibleCount = 0;
vm.form.filter = "";
}
// I reverse the grid, inverting each column and row.
function reverseGrid() {
// Reverse each row and column IN-PLACE. We want to do an in-place
// reverse so that we don't break the object identity references.
// This way, we don't destroy the DOM nodes - we'll just move them
// around in the existing DOM tree.
vm.grid
.reverse()
.forEach(
function iterator( row, i ) {
row.items.reverse();
}
)
;
}
// I clear the grid of data. This will help separate processing
// performance characteristics from page-load processing.
function unmountGrid() {
vm.grid = [];
vm.dataPoints = 0;
vm.visibleCount = 0;
vm.form.filter = "";
}
// ---
// PRIVATE METHODS.
// ---
// I generate a grid of items with the given dimensions. The grid is
// represented as a two dimensional grid, of sorts. Each row has an
// object that has an items collection.
function generateGrid( rowCount, columnCount ) {
var valuePoints = [
"Daenerys", "Jon", "Sansa", "Arya", "Stannis", "Gregor", "Tyrion",
"Theon", "Joffrey", "Ramsay", "Cersei", "Bran", "Margaery",
"Melisandre", "Daario", "Jamie", "Eddard", "Myrcella", "Robb",
"Jorah", "Petyr", "Tommen", "Sandor", "Oberyn", "Drogo", "Ygritte"
];
var valueIndex = 0;
var grid = [];
for ( var r = 0 ; r < rowCount ; r++ ) {
var row = {
id: r,
items: []
};
for ( var c = 0 ; c < columnCount ; c++ ) {
row.items.push({
id: ( r + "-" + c ),
value: valuePoints[ valueIndex ],
isHiddenByFilter: false
});
if ( ++valueIndex >= valuePoints.length ) {
valueIndex = 0;
}
}
grid.push( row );
}
return( grid );
}
}
}
);
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// Create testing directives that log to the console when a particular type of
// Element is created and linked to the directive controller.
[ "TR", "TD" ].forEach(
function createNodeLogger( tagName ) {
define(
( "Log" + tagName + "Creation" ),
function registerLogTRCreation() {
return ng.core
.Directive({
selector: tagName.toLowerCase()
})
.Class({
constructor: function () {
console.log( tagName, "node has been created." );
}
})
;
}
);
}
);
</script>
</body>
</html>