refactor(NgFor): cleanup
This commit is contained in:
parent
32d8cde9c6
commit
8cd97c2054
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, IterableDiffer, IterableDiffers, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
|
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
|
||||||
|
|
||||||
import {BaseException} from '../facade/exceptions';
|
import {BaseException} from '../facade/exceptions';
|
||||||
import {getTypeNameForDebugging, isBlank, isPresent} from '../facade/lang';
|
import {getTypeNameForDebugging, isBlank, isPresent} from '../facade/lang';
|
||||||
|
@ -76,41 +76,42 @@ export class NgForRow {
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForTrackBy', 'ngForOf', 'ngForTemplate']})
|
@Directive({selector: '[ngFor][ngForOf]'})
|
||||||
export class NgFor implements DoCheck {
|
export class NgFor implements DoCheck, OnChanges {
|
||||||
/** @internal */
|
@Input() ngForOf: any;
|
||||||
_ngForOf: any;
|
@Input() ngForTrackBy: TrackByFn;
|
||||||
/** @internal */
|
|
||||||
_ngForTrackBy: TrackByFn;
|
|
||||||
private _differ: IterableDiffer;
|
private _differ: IterableDiffer;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<NgForRow>,
|
private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<NgForRow>,
|
||||||
private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {}
|
private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {}
|
||||||
|
|
||||||
set ngForOf(value: any) {
|
@Input()
|
||||||
this._ngForOf = value;
|
|
||||||
if (isBlank(this._differ) && isPresent(value)) {
|
|
||||||
try {
|
|
||||||
this._differ = this._iterableDiffers.find(value).create(this._cdr, this._ngForTrackBy);
|
|
||||||
} catch (e) {
|
|
||||||
throw new BaseException(
|
|
||||||
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set ngForTemplate(value: TemplateRef<NgForRow>) {
|
set ngForTemplate(value: TemplateRef<NgForRow>) {
|
||||||
if (isPresent(value)) {
|
if (isPresent(value)) {
|
||||||
this._templateRef = value;
|
this._templateRef = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set ngForTrackBy(value: TrackByFn) { this._ngForTrackBy = value; }
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if ('ngForOf' in changes) {
|
||||||
|
// React on ngForOf changes only once all inputs have been initialized
|
||||||
|
const value = changes['ngForOf'].currentValue;
|
||||||
|
if (isBlank(this._differ) && isPresent(value)) {
|
||||||
|
try {
|
||||||
|
this._differ = this._iterableDiffers.find(value).create(this._cdr, this.ngForTrackBy);
|
||||||
|
} catch (e) {
|
||||||
|
throw new BaseException(
|
||||||
|
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngDoCheck() {
|
ngDoCheck() {
|
||||||
if (isPresent(this._differ)) {
|
if (isPresent(this._differ)) {
|
||||||
var changes = this._differ.diff(this._ngForOf);
|
const changes = this._differ.diff(this.ngForOf);
|
||||||
if (isPresent(changes)) this._applyChanges(changes);
|
if (isPresent(changes)) this._applyChanges(changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +119,7 @@ export class NgFor implements DoCheck {
|
||||||
private _applyChanges(changes: DefaultIterableDiffer) {
|
private _applyChanges(changes: DefaultIterableDiffer) {
|
||||||
// TODO(rado): check if change detection can produce a change record that is
|
// TODO(rado): check if change detection can produce a change record that is
|
||||||
// easier to consume than current.
|
// easier to consume than current.
|
||||||
var recordViewTuples: RecordViewTuple[] = [];
|
const recordViewTuples: RecordViewTuple[] = [];
|
||||||
changes.forEachRemovedItem(
|
changes.forEachRemovedItem(
|
||||||
(removedRecord: CollectionChangeRecord) =>
|
(removedRecord: CollectionChangeRecord) =>
|
||||||
recordViewTuples.push(new RecordViewTuple(removedRecord, null)));
|
recordViewTuples.push(new RecordViewTuple(removedRecord, null)));
|
||||||
|
@ -127,7 +128,7 @@ export class NgFor implements DoCheck {
|
||||||
(movedRecord: CollectionChangeRecord) =>
|
(movedRecord: CollectionChangeRecord) =>
|
||||||
recordViewTuples.push(new RecordViewTuple(movedRecord, null)));
|
recordViewTuples.push(new RecordViewTuple(movedRecord, null)));
|
||||||
|
|
||||||
var insertTuples = this._bulkRemove(recordViewTuples);
|
const insertTuples = this._bulkRemove(recordViewTuples);
|
||||||
|
|
||||||
changes.forEachAddedItem(
|
changes.forEachAddedItem(
|
||||||
(addedRecord: CollectionChangeRecord) =>
|
(addedRecord: CollectionChangeRecord) =>
|
||||||
|
@ -135,17 +136,17 @@ export class NgFor implements DoCheck {
|
||||||
|
|
||||||
this._bulkInsert(insertTuples);
|
this._bulkInsert(insertTuples);
|
||||||
|
|
||||||
for (var i = 0; i < insertTuples.length; i++) {
|
for (let i = 0; i < insertTuples.length; i++) {
|
||||||
this._perViewChange(insertTuples[i].view, insertTuples[i].record);
|
this._perViewChange(insertTuples[i].view, insertTuples[i].record);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
|
for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
|
||||||
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
|
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
|
||||||
viewRef.context.index = i;
|
viewRef.context.index = i;
|
||||||
viewRef.context.count = ilen;
|
viewRef.context.count = ilen;
|
||||||
}
|
}
|
||||||
|
|
||||||
changes.forEachIdentityChange((record: any /** TODO #9100 */) => {
|
changes.forEachIdentityChange((record: any) => {
|
||||||
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
|
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
|
||||||
viewRef.context.$implicit = record.item;
|
viewRef.context.$implicit = record.item;
|
||||||
});
|
});
|
||||||
|
@ -159,9 +160,9 @@ export class NgFor implements DoCheck {
|
||||||
tuples.sort(
|
tuples.sort(
|
||||||
(a: RecordViewTuple, b: RecordViewTuple) =>
|
(a: RecordViewTuple, b: RecordViewTuple) =>
|
||||||
a.record.previousIndex - b.record.previousIndex);
|
a.record.previousIndex - b.record.previousIndex);
|
||||||
var movedTuples: RecordViewTuple[] = [];
|
const movedTuples: RecordViewTuple[] = [];
|
||||||
for (var i = tuples.length - 1; i >= 0; i--) {
|
for (let i = tuples.length - 1; i >= 0; i--) {
|
||||||
var tuple = tuples[i];
|
const tuple = tuples[i];
|
||||||
// separate moved views from removed views.
|
// separate moved views from removed views.
|
||||||
if (isPresent(tuple.record.currentIndex)) {
|
if (isPresent(tuple.record.currentIndex)) {
|
||||||
tuple.view =
|
tuple.view =
|
||||||
|
@ -176,7 +177,7 @@ export class NgFor implements DoCheck {
|
||||||
|
|
||||||
private _bulkInsert(tuples: RecordViewTuple[]): RecordViewTuple[] {
|
private _bulkInsert(tuples: RecordViewTuple[]): RecordViewTuple[] {
|
||||||
tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
|
tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
|
||||||
for (var i = 0; i < tuples.length; i++) {
|
for (let i = 0; i < tuples.length; i++) {
|
||||||
var tuple = tuples[i];
|
var tuple = tuples[i];
|
||||||
if (isPresent(tuple.view)) {
|
if (isPresent(tuple.view)) {
|
||||||
this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
|
this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
|
||||||
|
@ -190,10 +191,5 @@ export class NgFor implements DoCheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecordViewTuple {
|
class RecordViewTuple {
|
||||||
view: EmbeddedViewRef<NgForRow>;
|
constructor(public record: any, public view: EmbeddedViewRef<NgForRow>) {}
|
||||||
record: any;
|
|
||||||
constructor(record: any, view: EmbeddedViewRef<NgForRow>) {
|
|
||||||
this.record = record;
|
|
||||||
this.view = view;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,12 +345,13 @@ export declare class NgControlStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class NgFor implements DoCheck {
|
export declare class NgFor implements DoCheck, OnChanges {
|
||||||
ngForOf: any;
|
ngForOf: any;
|
||||||
ngForTemplate: TemplateRef<NgForRow>;
|
ngForTemplate: TemplateRef<NgForRow>;
|
||||||
ngForTrackBy: TrackByFn;
|
ngForTrackBy: TrackByFn;
|
||||||
constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef<NgForRow>, _iterableDiffers: IterableDiffers, _cdr: ChangeDetectorRef);
|
constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef<NgForRow>, _iterableDiffers: IterableDiffers, _cdr: ChangeDetectorRef);
|
||||||
ngDoCheck(): void;
|
ngDoCheck(): void;
|
||||||
|
ngOnChanges(changes: SimpleChanges): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
|
|
Loading…
Reference in New Issue