1
1
import {
2
2
AfterViewInit ,
3
+ ChangeDetectionStrategy ,
3
4
ChangeDetectorRef ,
4
5
Component ,
5
6
ElementRef ,
6
7
NgZone ,
7
8
QueryList ,
9
+ signal ,
8
10
ViewChild ,
9
11
ViewChildren ,
10
12
ViewEncapsulation ,
11
13
} from '@angular/core' ;
12
- import { asyncScheduler } from 'rxjs-zone-less' ;
14
+ import { coalesceWith } from '@rx-angular/cdk/coalescing' ;
15
+ import { RxState } from '@rx-angular/state' ;
13
16
import {
17
+ animationFrameScheduler ,
14
18
BehaviorSubject ,
19
+ combineLatest ,
15
20
defer ,
16
21
merge ,
17
- Observable ,
18
22
scheduled ,
19
23
Subject ,
20
24
} from 'rxjs' ;
21
- import { environment } from '../../../../../environments/environment' ;
25
+ import { asyncScheduler } from 'rxjs-zone-less' ;
26
+ import {
27
+ delay ,
28
+ map ,
29
+ shareReplay ,
30
+ switchMap ,
31
+ switchMapTo ,
32
+ } from 'rxjs/operators' ;
33
+ import { Hooks } from '../../../../shared/debug-helper/hooks' ;
22
34
import {
23
35
ArrayProviderService ,
24
36
removeItemsImmutable ,
25
37
shuffleItemsImmutable ,
26
38
TestItem ,
27
39
} from '../../../../shared/debug-helper/value-provider' ;
28
40
import { ArrayProviderComponent } from '../../../../shared/debug-helper/value-provider/array-provider/array-provider.component' ;
29
- import { RxState } from '@rx-angular/state' ;
30
- import { Hooks } from '../../../../shared/debug-helper/hooks' ;
31
- import { map , switchMap , switchMapTo } from 'rxjs/operators' ;
32
41
33
42
let itemIdx = 0 ;
34
43
@@ -149,96 +158,175 @@ const moveChangeSet1 = [items5k];
149
158
selector : 'rxa-rx-for-list-actions' ,
150
159
template : `
151
160
<rxa-visualizer>
152
- <div visualizerHeader class="row">
153
- <div class="col-sm-12">
154
- <h2>Reactive Iterable Differ</h2>
155
- <rxa-array-provider
156
- [unpatched]=""
157
- [buttons]="true"
158
- #arrayP="rxaArrayProvider"
159
- ></rxa-array-provider>
160
- <rxa-strategy-select
161
- (strategyChange)="strategy$.next($event)"
162
- ></rxa-strategy-select>
163
- <mat-button-toggle-group
164
- name="visibleExamples"
165
- *rxLet="view; let viewMode"
166
- aria-label="Visible Examples"
167
- [value]="viewMode"
168
- #group="matButtonToggleGroup"
169
- >
170
- <mat-button-toggle value="tile" (click)="view.next('tile')"
171
- >Tile
172
- </mat-button-toggle>
173
- <mat-button-toggle value="list" (click)="view.next('list')"
174
- >List
175
- </mat-button-toggle>
176
- </mat-button-toggle-group>
177
- <button mat-raised-button (click)="triggerChangeSet.next()">
178
- ChangeSet
179
- </button>
180
- <button mat-raised-button (click)="triggerMoveSet.next()">
181
- MoveSet
182
- </button>
183
- <button mat-raised-button (click)="triggerMoveSetSwapped.next()">
184
- MoveSet Swapped
185
- </button>
186
- <p *rxLet="rendered$; let rendered">
187
- <strong>Rendered</strong> {{ rendered }}
188
- </p>
189
- <p *rxLet="viewBroken$; let viewBroken">
190
- <ng-container>
191
- <span [ngStyle]="{ color: viewBroken ? 'red' : 'green' }"
192
- >VIEW BROKEN {{ viewBroken }}</span
193
- >
194
- </ng-container>
195
- </p>
161
+ <ng-container visualizerHeader>
162
+ <div class="row">
163
+ <div class="col-sm-12">
164
+ <h2>Reactive Iterable Differ</h2>
165
+ <rxa-array-provider
166
+ [unpatched]=""
167
+ [buttons]="true"
168
+ #arrayP="rxaArrayProvider"
169
+ ></rxa-array-provider>
170
+ <rxa-strategy-select
171
+ (strategyChange)="strategy$.next($event)"
172
+ ></rxa-strategy-select>
173
+ <mat-button-toggle-group
174
+ name="visibleExamples"
175
+ *rxLet="view; let viewMode"
176
+ aria-label="Visible Examples"
177
+ [value]="viewMode"
178
+ #group="matButtonToggleGroup"
179
+ >
180
+ <mat-button-toggle value="tile" (click)="view.next('tile')"
181
+ >Tile
182
+ </mat-button-toggle>
183
+ <mat-button-toggle value="list" (click)="view.next('list')"
184
+ >List
185
+ </mat-button-toggle>
186
+ </mat-button-toggle-group>
187
+ <mat-button-toggle-group
188
+ [value]="reconciler()"
189
+ #group="matButtonToggleGroup"
190
+ >
191
+ <mat-button-toggle
192
+ value="experimental"
193
+ (click)="reconciler.set('experimental')"
194
+ >experimental
195
+ </mat-button-toggle>
196
+ <mat-button-toggle
197
+ value="legacy"
198
+ (click)="reconciler.set('legacy')"
199
+ >legacy
200
+ </mat-button-toggle>
201
+ </mat-button-toggle-group>
202
+ <button mat-raised-button (click)="triggerChangeSet.next()">
203
+ ChangeSet
204
+ </button>
205
+ <button mat-raised-button (click)="triggerMoveSet.next()">
206
+ MoveSet
207
+ </button>
208
+ <button mat-raised-button (click)="triggerMoveSetSwapped.next()">
209
+ MoveSet Swapped
210
+ </button>
211
+ </div>
196
212
</div>
197
- </div>
213
+ <div class="row">
214
+ <div class="col-sm-12">
215
+ <div>
216
+ <input
217
+ type="text"
218
+ placeholder="filter"
219
+ #searchInput
220
+ (input)="filter$.next(searchInput.value)"
221
+ />
222
+ </div>
223
+ <p *rxLet="rendered$; let rendered">
224
+ <strong>Rendered</strong> {{ rendered }}
225
+ </p>
226
+ <!--<p *rxLet="viewBroken$; let viewBroken">
227
+ <ng-container>
228
+ <span [ngStyle]="{ color: viewBroken ? 'red' : 'green' }"
229
+ >VIEW BROKEN {{ viewBroken }}</span
230
+ >
231
+ </ng-container>
232
+ </p>-->
233
+ </div>
234
+ </div>
235
+ </ng-container>
198
236
<div class="d-flex flex-column justify-content-start w-100">
199
237
<div
200
238
class="work-container d-flex flex-wrap w-100"
201
239
[class.list-view]="viewMode === 'list'"
202
240
*rxLet="view; let viewMode"
203
241
>
204
- <div
205
- #workChild
206
- class="work-child d-flex"
207
- *rxFor="
208
- let a of data$;
209
- let index = index;
210
- let count = count;
211
- let even = even;
212
- let odd = odd;
213
- let first = first;
214
- let last = last;
215
- renderCallback: renderCallback;
216
- trackBy: trackById;
217
- strategy: strategy$
218
- "
219
- [title]="a.id + '_' + index + '_' + count"
220
- [class.even]="even"
221
- >
222
- <div class="child-bg" [ngStyle]="{ background: color(a) }"></div>
223
- <!--<div class="child-bg" [class.even]="even"></div>-->
224
- <div class="child-context flex-column flex-wrap">
225
- <button (click)="clickMe()">click me</button>
226
- <!--<small>{{ a }}</small>-->
227
- <small>id: {{ a.id }}</small>
228
- <small>value: {{ a.value }}</small>
229
- <small>index: {{ index }}</small>
230
- <small>count: {{ count }}</small>
231
- <small>even: {{ even }}</small>
232
- <small>odd: {{ odd }}</small>
233
- <small>first: {{ first }}</small>
234
- <small>last: {{ last }}</small>
235
- </div>
236
- </div>
242
+ @if (reconciler() === 'experimental') {
243
+ <ng-container provideExperimentalReconciliation>
244
+ <div
245
+ #workChild
246
+ class="work-child d-flex"
247
+ *rxFor="
248
+ let a of data$;
249
+ let index = index;
250
+ let count = count;
251
+ let even = even;
252
+ let odd = odd;
253
+ let first = first;
254
+ let last = last;
255
+ renderCallback: renderCallback;
256
+ trackBy: trackById;
257
+ strategy: strategy$
258
+ "
259
+ [title]="a.id + '_' + index + '_' + count"
260
+ [class.even]="even"
261
+ >
262
+ <list-action-item>
263
+ <div
264
+ class="child-bg"
265
+ [ngStyle]="{ background: color(a) }"
266
+ ></div>
267
+ <!--<div class="child-bg" [class.even]="even"></div>-->
268
+ <div class="child-context flex-column flex-wrap">
269
+ <button (click)="clickMe()">click me</button>
270
+ <!--<small>{{ a }}</small>-->
271
+ <small>id: {{ a.id }}</small>
272
+ <small>value: {{ a.value }}</small>
273
+ <small>index: {{ index }}</small>
274
+ <small>count: {{ count }}</small>
275
+ <small>even: {{ even }}</small>
276
+ <small>odd: {{ odd }}</small>
277
+ <small>first: {{ first }}</small>
278
+ <small>last: {{ last }}</small>
279
+ </div>
280
+ </list-action-item>
281
+ </div>
282
+ </ng-container>
283
+ } @else {
284
+ <ng-container provideLegacyReconciliation>
285
+ <div
286
+ #workChild
287
+ class="work-child d-flex"
288
+ *rxFor="
289
+ let a of data$;
290
+ let index = index;
291
+ let count = count;
292
+ let even = even;
293
+ let odd = odd;
294
+ let first = first;
295
+ let last = last;
296
+ renderCallback: renderCallback;
297
+ trackBy: trackById;
298
+ strategy: strategy$
299
+ "
300
+ [title]="a.id + '_' + index + '_' + count"
301
+ [class.even]="even"
302
+ >
303
+ <list-action-item>
304
+ <div
305
+ class="child-bg"
306
+ [ngStyle]="{ background: color(a) }"
307
+ ></div>
308
+ <!--<div class="child-bg" [class.even]="even"></div>-->
309
+ <div class="child-context flex-column flex-wrap">
310
+ <button (click)="clickMe()">click me</button>
311
+ <!--<small>{{ a }}</small>-->
312
+ <small>id: {{ a.id }}</small>
313
+ <small>value: {{ a.value }}</small>
314
+ <small>index: {{ index }}</small>
315
+ <small>count: {{ count }}</small>
316
+ <small>even: {{ even }}</small>
317
+ <small>odd: {{ odd }}</small>
318
+ <small>first: {{ first }}</small>
319
+ <small>last: {{ last }}</small>
320
+ </div>
321
+ </list-action-item>
322
+ </div>
323
+ </ng-container>
324
+ }
237
325
</div>
238
326
</div>
239
327
</rxa-visualizer>
240
328
` ,
241
- changeDetection : environment . changeDetection ,
329
+ changeDetection : ChangeDetectionStrategy . OnPush ,
242
330
encapsulation : ViewEncapsulation . None ,
243
331
providers : [ ArrayProviderService ] ,
244
332
styles : [
@@ -291,18 +379,24 @@ const moveChangeSet1 = [items5k];
291
379
.work-child .child-bg.even {
292
380
background-color: red;
293
381
}
382
+ .work-child.broken {
383
+ outline: 3px solid red;
384
+ }
294
385
` ,
295
386
] ,
296
387
standalone : false ,
297
388
} )
298
389
export class ListActionsComponent extends Hooks implements AfterViewInit {
299
- @ViewChild ( 'arrayP' , { read : ArrayProviderComponent , static : true } ) arrayP ;
390
+ @ViewChild ( 'arrayP' , { read : ArrayProviderComponent , static : true } )
391
+ arrayP : ArrayProviderComponent ;
300
392
301
393
@ViewChildren ( 'workChild' ) workChildren : QueryList < ElementRef < HTMLElement > > ;
302
394
303
395
private numRendered = 0 ;
304
396
305
397
readonly view = new BehaviorSubject < 'list' | 'tile' > ( 'list' ) ;
398
+ readonly reconciler = signal < 'experimental' | 'legacy' > ( 'experimental' ) ;
399
+ readonly filter$ = new BehaviorSubject < string > ( '' ) ;
306
400
readonly triggerChangeSet = new Subject < void > ( ) ;
307
401
readonly activeChangeSet$ = this . triggerChangeSet . pipe (
308
402
switchMapTo ( scheduled ( customChangeSet , asyncScheduler ) ) ,
@@ -317,11 +411,21 @@ export class ListActionsComponent extends Hooks implements AfterViewInit {
317
411
) ;
318
412
319
413
readonly data$ = defer ( ( ) =>
320
- merge ( this . arrayP . array$ , this . activeChangeSet$ , this . activeMoveSet$ ) ,
321
- ) ;
414
+ combineLatest ( [
415
+ merge ( this . arrayP . array$ , this . activeChangeSet$ , this . activeMoveSet$ ) ,
416
+ this . filter$ ,
417
+ ] ) . pipe (
418
+ map ( ( [ items , search ] ) => {
419
+ return items . filter ( ( item ) =>
420
+ ( item . value * 100 ) . toString ( ) . startsWith ( search ) ,
421
+ ) ;
422
+ } ) ,
423
+ ) ,
424
+ ) . pipe ( shareReplay ( 1 ) ) ;
322
425
readonly renderCallback = new Subject ( ) ;
323
426
readonly rendered$ = this . renderCallback . pipe ( map ( ( ) => ++ this . numRendered ) ) ;
324
427
readonly viewBroken$ = this . renderCallback . pipe (
428
+ coalesceWith ( scheduled ( [ ] , asyncScheduler ) , ( this . cdRef as any ) . context ) ,
325
429
map ( ( ) => {
326
430
const children = Array . from (
327
431
document . getElementsByClassName ( 'work-child' ) ,
@@ -335,6 +439,7 @@ export class ListActionsComponent extends Hooks implements AfterViewInit {
335
439
( ! even && child . classList . contains ( 'even' ) )
336
440
) {
337
441
broken = true ;
442
+ child . classList . add ( 'broken' ) ;
338
443
break ;
339
444
}
340
445
i ++ ;
0 commit comments