fix(core): Add type information to differs

CHANGES:

- Remove unused `onDestroy` method on the `KeyValueDiffer` and
  `IterableDiffer`.

DEPRECATION:

- `CollectionChangeRecord` is renamed to `IterableChangeRecord`.
  `CollectionChangeRecord` is aliased to `IterableChangeRecord` and is
  marked as `@deprecated`. It will be removed in `v5.x.x`.
- Deprecate `DefaultIterableDiffer` as it is private class which
  was erroneously exposed.
- Deprecate `KeyValueDiffers#factories` as it is private field which
  was erroneously exposed.
- Deprecate `IterableDiffers#factories` as it is private field which
  was erroneously exposed.

BREAKING CHANGE:

- `IterableChangeRecord` is now an interface and parameterized on `<V>`.
  This should not be an issue unless your code does
  `new IterableChangeRecord` which it should not have a reason to do.
- `KeyValueChangeRecord` is now an interface and parameterized on `<V>`.
  This should not be an issue unless your code does
  `new IterableChangeRecord` which it should not have a reason to do.

Original PR #12570

Fixes #13382
This commit is contained in:
Joao Dias
2016-10-27 20:28:11 +02:00
committed by Matias Niemelä
parent 5d9cbd7d6f
commit 8c7e93bebe
12 changed files with 471 additions and 290 deletions

View File

@ -17,4 +17,3 @@ export {CommonModule} from './common_module';
export {NgClass, NgFor, NgIf, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe} from './pipes/index';
export {VERSION} from './version';
export {Version} from '@angular/core';

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {Directive, DoCheck, ElementRef, Input, IterableChanges, IterableDiffer, IterableDiffers, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isListLikeIterable} from '../facade/collection';
import {isPresent, stringify} from '../facade/lang';
@ -41,8 +41,8 @@ import {isPresent, stringify} from '../facade/lang';
*/
@Directive({selector: '[ngClass]'})
export class NgClass implements DoCheck {
private _iterableDiffer: IterableDiffer;
private _keyValueDiffer: KeyValueDiffer;
private _iterableDiffer: IterableDiffer<string>;
private _keyValueDiffer: KeyValueDiffer<string, any>;
private _initialClasses: string[] = [];
private _rawClass: string[]|Set<string>|{[klass: string]: any};
@ -78,39 +78,35 @@ export class NgClass implements DoCheck {
ngDoCheck(): void {
if (this._iterableDiffer) {
const changes = this._iterableDiffer.diff(this._rawClass);
if (changes) {
this._applyIterableChanges(changes);
const iterableChanges = this._iterableDiffer.diff(this._rawClass as string[]);
if (iterableChanges) {
this._applyIterableChanges(iterableChanges);
}
} else if (this._keyValueDiffer) {
const changes = this._keyValueDiffer.diff(this._rawClass);
if (changes) {
this._applyKeyValueChanges(changes);
const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as{[k: string]: any});
if (keyValueChanges) {
this._applyKeyValueChanges(keyValueChanges);
}
}
}
private _cleanupClasses(rawClassVal: string[]|Set<string>|{[klass: string]: any}): void {
private _cleanupClasses(rawClassVal: string[]|{[klass: string]: any}): void {
this._applyClasses(rawClassVal, true);
this._applyInitialClasses(false);
}
private _applyKeyValueChanges(changes: any): void {
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => this._toggleClass(record.key, record.currentValue));
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => this._toggleClass(record.key, record.currentValue));
changes.forEachRemovedItem((record: KeyValueChangeRecord) => {
private _applyKeyValueChanges(changes: KeyValueChanges<string, any>): void {
changes.forEachAddedItem((record) => this._toggleClass(record.key, record.currentValue));
changes.forEachChangedItem((record) => this._toggleClass(record.key, record.currentValue));
changes.forEachRemovedItem((record) => {
if (record.previousValue) {
this._toggleClass(record.key, false);
}
});
}
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem((record: CollectionChangeRecord) => {
private _applyIterableChanges(changes: IterableChanges<string>): void {
changes.forEachAddedItem((record) => {
if (typeof record.item === 'string') {
this._toggleClass(record.item, true);
} else {
@ -119,8 +115,7 @@ export class NgClass implements DoCheck {
}
});
changes.forEachRemovedItem(
(record: CollectionChangeRecord) => this._toggleClass(record.item, false));
changes.forEachRemovedItem((record) => this._toggleClass(record.item, false));
}
private _applyInitialClasses(isCleanup: boolean) {
@ -128,7 +123,7 @@ export class NgClass implements DoCheck {
}
private _applyClasses(
rawClassVal: string[]|Set<string>|{[key: string]: any}, isCleanup: boolean) {
rawClassVal: string[]|Set<string>|{[klass: string]: any}, isCleanup: boolean) {
if (rawClassVal) {
if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) {
(<any>rawClassVal).forEach((klass: string) => this._toggleClass(klass, !isCleanup));
@ -140,11 +135,11 @@ export class NgClass implements DoCheck {
}
}
private _toggleClass(klass: string, enabled: boolean): void {
private _toggleClass(klass: string, enabled: any): void {
klass = klass.trim();
if (klass) {
klass.split(/\s+/g).forEach(
klass => { this._renderer.setElementClass(this._ngEl.nativeElement, klass, enabled); });
klass => { this._renderer.setElementClass(this._ngEl.nativeElement, klass, !!enabled); });
}
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef, isDevMode} from '@angular/core';
import {ChangeDetectorRef, Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef, isDevMode} from '@angular/core';
import {getTypeNameForDebugging} from '../facade/lang';
@ -104,7 +104,7 @@ export class NgFor implements DoCheck, OnChanges {
get ngForTrackBy(): TrackByFn { return this._trackByFn; }
private _differ: IterableDiffer = null;
private _differ: IterableDiffer<any> = null;
private _trackByFn: TrackByFn;
constructor(
@ -140,10 +140,10 @@ export class NgFor implements DoCheck, OnChanges {
}
}
private _applyChanges(changes: DefaultIterableDiffer) {
private _applyChanges(changes: IterableChanges<any>) {
const insertTuples: RecordViewTuple[] = [];
changes.forEachOperation(
(item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => {
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
if (item.previousIndex == null) {
const view = this._viewContainer.createEmbeddedView(
this._template, new NgForRow(null, null, null), currentIndex);
@ -175,7 +175,7 @@ export class NgFor implements DoCheck, OnChanges {
});
}
private _perViewChange(view: EmbeddedViewRef<NgForRow>, record: CollectionChangeRecord) {
private _perViewChange(view: EmbeddedViewRef<NgForRow>, record: IterableChangeRecord<any>) {
view.context.$implicit = record.item;
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {Directive, DoCheck, ElementRef, Input, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
/**
* @ngModule CommonModule
@ -33,7 +33,7 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
@Directive({selector: '[ngStyle]'})
export class NgStyle implements DoCheck {
private _ngStyle: {[key: string]: string};
private _differ: KeyValueDiffer;
private _differ: KeyValueDiffer<string, string|number>;
constructor(
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
@ -55,20 +55,16 @@ export class NgStyle implements DoCheck {
}
}
private _applyChanges(changes: any): void {
changes.forEachRemovedItem((record: KeyValueChangeRecord) => this._setStyle(record.key, null));
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
private _applyChanges(changes: KeyValueChanges<string, string|number>): void {
changes.forEachRemovedItem((record) => this._setStyle(record.key, null));
changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue));
changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue));
}
private _setStyle(nameAndUnit: string, value: string): void {
private _setStyle(nameAndUnit: string, value: string|number): void {
const [name, unit] = nameAndUnit.split('.');
value = value && unit ? `${value}${unit}` : value;
value = value != null && unit ? `${value}${unit}` : value;
this._renderer.setElementStyle(this._ngEl.nativeElement, name, value);
this._renderer.setElementStyle(this._ngEl.nativeElement, name, value as string);
}
}