diff --git a/modules/angular2/src/common/directives/ng_class.ts b/modules/angular2/src/common/directives/ng_class.ts index cae1ca01e6ca..0b997a8a88d2 100644 --- a/modules/angular2/src/common/directives/ng_class.ts +++ b/modules/angular2/src/common/directives/ng_class.ts @@ -1,14 +1,16 @@ -import {isPresent, isString, StringWrapper, isBlank, isArray} from 'angular2/src/facade/lang'; +import {isPresent, isString, isArray} from 'angular2/src/facade/lang'; import { DoCheck, OnDestroy, Directive, ElementRef, - IterableDiffer, IterableDiffers, - KeyValueDiffer, KeyValueDiffers, - Renderer + Renderer, + IterableDiffer, + KeyValueDiffer, + CollectionChangeRecord, + KeyValueChangeRecord } from 'angular2/core'; import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collection'; @@ -73,66 +75,68 @@ import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collecti */ @Directive({selector: '[ngClass]', inputs: ['rawClass: ngClass', 'initialClasses: class']}) export class NgClass implements DoCheck, OnDestroy { - private _differ: any; - private _mode: string; - private _initialClasses = []; - private _rawClass; + private _iterableDiffer: IterableDiffer; + private _keyValueDiffer: KeyValueDiffer; + private _initialClasses: string[] = []; + private _rawClass: string[] | Set; constructor(private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {} - set initialClasses(v) { + set initialClasses(v: string) { this._applyInitialClasses(true); this._initialClasses = isPresent(v) && isString(v) ? v.split(' ') : []; this._applyInitialClasses(false); this._applyClasses(this._rawClass, false); } - set rawClass(v) { + set rawClass(v: string | string[] | Set| {[key: string]: any}) { this._cleanupClasses(this._rawClass); if (isString(v)) { - v = v.split(' '); + v = (v).split(' '); } - this._rawClass = v; + this._rawClass = >v; + this._iterableDiffer = null; + this._keyValueDiffer = null; if (isPresent(v)) { if (isListLikeIterable(v)) { - this._differ = this._iterableDiffers.find(v).create(null); - this._mode = 'iterable'; + this._iterableDiffer = this._iterableDiffers.find(v).create(null); } else { - this._differ = this._keyValueDiffers.find(v).create(null); - this._mode = 'keyValue'; + this._keyValueDiffer = this._keyValueDiffers.find(v).create(null); } - } else { - this._differ = null; } } ngDoCheck(): void { - if (isPresent(this._differ)) { - var changes = this._differ.diff(this._rawClass); + if (isPresent(this._iterableDiffer)) { + var changes = this._iterableDiffer.diff(this._rawClass); if (isPresent(changes)) { - if (this._mode == 'iterable') { - this._applyIterableChanges(changes); - } else { - this._applyKeyValueChanges(changes); - } + this._applyIterableChanges(changes); + } + } + if (isPresent(this._keyValueDiffer)) { + var changes = this._keyValueDiffer.diff(this._rawClass); + if (isPresent(changes)) { + this._applyKeyValueChanges(changes); } } } ngOnDestroy(): void { this._cleanupClasses(this._rawClass); } - private _cleanupClasses(rawClassVal): void { + private _cleanupClasses(rawClassVal: string[] | Set| {[key: string]: any}): void { this._applyClasses(rawClassVal, true); this._applyInitialClasses(false); } private _applyKeyValueChanges(changes: any): void { - changes.forEachAddedItem((record) => { this._toggleClass(record.key, record.currentValue); }); - changes.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); }); - changes.forEachRemovedItem((record) => { + changes.forEachAddedItem( + (record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); }); + changes.forEachChangedItem( + (record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); }); + changes.forEachRemovedItem((record: KeyValueChangeRecord) => { if (record.previousValue) { this._toggleClass(record.key, false); } @@ -140,15 +144,17 @@ export class NgClass implements DoCheck, OnDestroy { } private _applyIterableChanges(changes: any): void { - changes.forEachAddedItem((record) => { this._toggleClass(record.item, true); }); - changes.forEachRemovedItem((record) => { this._toggleClass(record.item, false); }); + changes.forEachAddedItem( + (record: CollectionChangeRecord) => { this._toggleClass(record.item, true); }); + changes.forEachRemovedItem( + (record: CollectionChangeRecord) => { this._toggleClass(record.item, false); }); } private _applyInitialClasses(isCleanup: boolean) { this._initialClasses.forEach(className => this._toggleClass(className, !isCleanup)); } - private _applyClasses(rawClassVal: string[] | Set| {[key: string]: string}, + private _applyClasses(rawClassVal: string[] | Set| {[key: string]: any}, isCleanup: boolean) { if (isPresent(rawClassVal)) { if (isArray(rawClassVal)) { @@ -156,14 +162,15 @@ export class NgClass implements DoCheck, OnDestroy { } else if (rawClassVal instanceof Set) { (>rawClassVal).forEach(className => this._toggleClass(className, !isCleanup)); } else { - StringMapWrapper.forEach(<{[k: string]: string}>rawClassVal, (expVal, className) => { - if (expVal) this._toggleClass(className, !isCleanup); - }); + StringMapWrapper.forEach(<{[k: string]: any}>rawClassVal, + (expVal: any, className: string) => { + if (isPresent(expVal)) this._toggleClass(className, !isCleanup); + }); } } } - private _toggleClass(className: string, enabled): void { + private _toggleClass(className: string, enabled: boolean): void { className = className.trim(); if (className.length > 0) { if (className.indexOf(' ') > -1) { diff --git a/modules/angular2/src/common/directives/ng_style.ts b/modules/angular2/src/common/directives/ng_style.ts index 580f40b9a763..3b5824277fdc 100644 --- a/modules/angular2/src/common/directives/ng_style.ts +++ b/modules/angular2/src/common/directives/ng_style.ts @@ -7,7 +7,7 @@ import { Renderer } from 'angular2/core'; import {isPresent, isBlank, print} from 'angular2/src/facade/lang'; -import {KVChangeRecord} from "../../core/change_detection/differs/default_keyvalue_differ"; +import {KeyValueChangeRecord} from "../../core/change_detection/differs/default_keyvalue_differ"; /** * The `NgStyle` directive changes styles based on a result of expression evaluation. @@ -88,10 +88,11 @@ export class NgStyle implements DoCheck { private _applyChanges(changes: any): void { changes.forEachAddedItem( - (record: KVChangeRecord) => { this._setStyle(record.key, record.currentValue); }); + (record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); }); changes.forEachChangedItem( - (record: KVChangeRecord) => { this._setStyle(record.key, record.currentValue); }); - changes.forEachRemovedItem((record: KVChangeRecord) => { this._setStyle(record.key, null); }); + (record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); }); + changes.forEachRemovedItem( + (record: KeyValueChangeRecord) => { this._setStyle(record.key, null); }); } private _setStyle(name: string, val: string): void { diff --git a/modules/angular2/src/core/change_detection.ts b/modules/angular2/src/core/change_detection.ts index 1d81e799fb38..737bb3478669 100644 --- a/modules/angular2/src/core/change_detection.ts +++ b/modules/angular2/src/core/change_detection.ts @@ -21,5 +21,7 @@ export { KeyValueDiffers, KeyValueDiffer, KeyValueDifferFactory, + CollectionChangeRecord, + KeyValueChangeRecord, TrackByFn } from './change_detection/change_detection'; diff --git a/modules/angular2/src/core/change_detection/change_detection.ts b/modules/angular2/src/core/change_detection/change_detection.ts index beec120241e8..34a1f2c78ca3 100644 --- a/modules/angular2/src/core/change_detection/change_detection.ts +++ b/modules/angular2/src/core/change_detection/change_detection.ts @@ -1,9 +1,20 @@ -import {IterableDiffers, IterableDifferFactory, TrackByFn} from './differs/iterable_differs'; +import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs'; import {DefaultIterableDifferFactory} from './differs/default_iterable_differ'; import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs'; -import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ'; -import {CONST, CONST_EXPR, isPresent} from 'angular2/src/facade/lang'; +import { + DefaultKeyValueDifferFactory, + KeyValueChangeRecord +} from './differs/default_keyvalue_differ'; +import {CONST_EXPR} from 'angular2/src/facade/lang'; +export { + DefaultKeyValueDifferFactory, + KeyValueChangeRecord +} from './differs/default_keyvalue_differ'; +export { + DefaultIterableDifferFactory, + CollectionChangeRecord +} from './differs/default_iterable_differ'; export { ASTWithSource, AST, diff --git a/modules/angular2/src/core/change_detection/differs/default_keyvalue_differ.ts b/modules/angular2/src/core/change_detection/differs/default_keyvalue_differ.ts index 159342116410..1c602df46a71 100644 --- a/modules/angular2/src/core/change_detection/differs/default_keyvalue_differ.ts +++ b/modules/angular2/src/core/change_detection/differs/default_keyvalue_differ.ts @@ -13,14 +13,14 @@ export class DefaultKeyValueDifferFactory implements KeyValueDifferFactory { export class DefaultKeyValueDiffer implements KeyValueDiffer { private _records: Map = new Map(); - private _mapHead: KVChangeRecord = null; - private _previousMapHead: KVChangeRecord = null; - private _changesHead: KVChangeRecord = null; - private _changesTail: KVChangeRecord = null; - private _additionsHead: KVChangeRecord = null; - private _additionsTail: KVChangeRecord = null; - private _removalsHead: KVChangeRecord = null; - private _removalsTail: KVChangeRecord = null; + private _mapHead: KeyValueChangeRecord = null; + private _previousMapHead: KeyValueChangeRecord = null; + private _changesHead: KeyValueChangeRecord = null; + private _changesTail: KeyValueChangeRecord = null; + private _additionsHead: KeyValueChangeRecord = null; + private _additionsTail: KeyValueChangeRecord = null; + private _removalsHead: KeyValueChangeRecord = null; + private _removalsTail: KeyValueChangeRecord = null; get isDirty(): boolean { return this._additionsHead !== null || this._changesHead !== null || @@ -28,35 +28,35 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } forEachItem(fn: Function) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._mapHead; record !== null; record = record._next) { fn(record); } } forEachPreviousItem(fn: Function) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._previousMapHead; record !== null; record = record._nextPrevious) { fn(record); } } forEachChangedItem(fn: Function) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._changesHead; record !== null; record = record._nextChanged) { fn(record); } } forEachAddedItem(fn: Function) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._additionsHead; record !== null; record = record._nextAdded) { fn(record); } } forEachRemovedItem(fn: Function) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._removalsHead; record !== null; record = record._nextRemoved) { fn(record); } @@ -80,9 +80,9 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { check(map: Map): boolean { this._reset(); var records = this._records; - var oldSeqRecord: KVChangeRecord = this._mapHead; - var lastOldSeqRecord: KVChangeRecord = null; - var lastNewSeqRecord: KVChangeRecord = null; + var oldSeqRecord: KeyValueChangeRecord = this._mapHead; + var lastOldSeqRecord: KeyValueChangeRecord = null; + var lastNewSeqRecord: KeyValueChangeRecord = null; var seqChanged: boolean = false; this._forEach(map, (value, key) => { @@ -104,7 +104,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { if (records.has(key)) { newSeqRecord = records.get(key); } else { - newSeqRecord = new KVChangeRecord(key); + newSeqRecord = new KeyValueChangeRecord(key); records.set(key, newSeqRecord); newSeqRecord.currentValue = value; this._addToAdditions(newSeqRecord); @@ -132,7 +132,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { /** @internal */ _reset() { if (this.isDirty) { - var record: KVChangeRecord; + var record: KeyValueChangeRecord; // Record the state of the mapping for (record = this._previousMapHead = this._mapHead; record !== null; record = record._next) { record._nextPrevious = record._next; @@ -178,7 +178,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _truncate(lastRecord: KVChangeRecord, record: KVChangeRecord) { + _truncate(lastRecord: KeyValueChangeRecord, record: KeyValueChangeRecord) { while (record !== null) { if (lastRecord === null) { this._mapHead = null; @@ -196,7 +196,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { record = nextRecord; } - for (var rec: KVChangeRecord = this._removalsHead; rec !== null; rec = rec._nextRemoved) { + for (var rec: KeyValueChangeRecord = this._removalsHead; rec !== null; rec = rec._nextRemoved) { rec.previousValue = rec.currentValue; rec.currentValue = null; this._records.delete(rec.key); @@ -204,13 +204,13 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _isInRemovals(record: KVChangeRecord) { + _isInRemovals(record: KeyValueChangeRecord) { return record === this._removalsHead || record._nextRemoved !== null || record._prevRemoved !== null; } /** @internal */ - _addToRemovals(record: KVChangeRecord) { + _addToRemovals(record: KeyValueChangeRecord) { // todo(vicb) assert // assert(record._next == null); // assert(record._nextAdded == null); @@ -227,7 +227,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _removeFromSeq(prev: KVChangeRecord, record: KVChangeRecord) { + _removeFromSeq(prev: KeyValueChangeRecord, record: KeyValueChangeRecord) { var next = record._next; if (prev === null) { this._mapHead = next; @@ -242,7 +242,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _removeFromRemovals(record: KVChangeRecord) { + _removeFromRemovals(record: KeyValueChangeRecord) { // todo(vicb) assert // assert(record._next == null); // assert(record._nextAdded == null); @@ -264,7 +264,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _addToAdditions(record: KVChangeRecord) { + _addToAdditions(record: KeyValueChangeRecord) { // todo(vicb): assert // assert(record._next == null); // assert(record._nextAdded == null); @@ -280,7 +280,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } /** @internal */ - _addToChanges(record: KVChangeRecord) { + _addToChanges(record: KeyValueChangeRecord) { // todo(vicb) assert // assert(record._nextAdded == null); // assert(record._nextChanged == null); @@ -300,7 +300,7 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { var changes = []; var additions = []; var removals = []; - var record: KVChangeRecord; + var record: KeyValueChangeRecord; for (record = this._mapHead; record !== null; record = record._next) { items.push(stringify(record)); @@ -334,22 +334,22 @@ export class DefaultKeyValueDiffer implements KeyValueDiffer { } -export class KVChangeRecord { +export class KeyValueChangeRecord { previousValue: any = null; currentValue: any = null; /** @internal */ - _nextPrevious: KVChangeRecord = null; + _nextPrevious: KeyValueChangeRecord = null; /** @internal */ - _next: KVChangeRecord = null; + _next: KeyValueChangeRecord = null; /** @internal */ - _nextAdded: KVChangeRecord = null; + _nextAdded: KeyValueChangeRecord = null; /** @internal */ - _nextRemoved: KVChangeRecord = null; + _nextRemoved: KeyValueChangeRecord = null; /** @internal */ - _prevRemoved: KVChangeRecord = null; + _prevRemoved: KeyValueChangeRecord = null; /** @internal */ - _nextChanged: KVChangeRecord = null; + _nextChanged: KeyValueChangeRecord = null; constructor(public key: any) {} diff --git a/modules/angular2/test/public_api_spec.ts b/modules/angular2/test/public_api_spec.ts index 1a1e11893900..d1130fa07287 100644 --- a/modules/angular2/test/public_api_spec.ts +++ b/modules/angular2/test/public_api_spec.ts @@ -763,6 +763,7 @@ var NG_CORE = [ 'ProviderBuilder.token', 'ProviderBuilder.token=', 'PLATFORM_DIRECTIVES:js', + "CollectionChangeRecord", 'ChangeDetectionError', 'ChangeDetectionError.context', 'ChangeDetectionError.location', @@ -1127,6 +1128,13 @@ var NG_CORE = [ 'Key.id=', 'Key.token', 'Key.token=', + 'KeyValueChangeRecord', + 'KeyValueChangeRecord.currentValue', + 'KeyValueChangeRecord.currentValue=', + 'KeyValueChangeRecord.key', + 'KeyValueChangeRecord.key=', + 'KeyValueChangeRecord.previousValue', + 'KeyValueChangeRecord.previousValue=', 'KeyValueDiffers#create()', 'KeyValueDiffers#extend()', 'KeyValueDiffers', diff --git a/tools/public_api_guard/public_api_spec.ts b/tools/public_api_guard/public_api_spec.ts index 191bc89af146..6a69c5066440 100644 --- a/tools/public_api_guard/public_api_spec.ts +++ b/tools/public_api_guard/public_api_spec.ts @@ -81,6 +81,11 @@ const CORE = [ 'ClassDefinition', 'ClassDefinition.constructor:Function|any[]', 'ClassDefinition.extends:Type', + 'CollectionChangeRecord', + 'CollectionChangeRecord.constructor(item:any, trackById:any)', + 'CollectionChangeRecord.currentIndex:number', + 'CollectionChangeRecord.previousIndex:number', + 'CollectionChangeRecord.toString():string', 'Compiler', 'Compiler.clearCache():any', 'Compiler.compileInHost(componentType:Type):Promise', @@ -261,6 +266,11 @@ const CORE = [ 'Key.displayName:string', 'Key.get(token:Object):Key', 'Key.numberOfKeys:number', + 'KeyValueChangeRecord', + 'KeyValueChangeRecord.constructor(key:any)', + 'KeyValueChangeRecord.currentValue:any', + 'KeyValueChangeRecord.previousValue:any', + 'KeyValueChangeRecord.toString():string', 'KeyValueDiffer', 'KeyValueDiffer.diff(object:any):any', 'KeyValueDiffer.onDestroy():any', @@ -654,10 +664,10 @@ const COMMON = [ 'MinLengthValidator.validate(c:Control):{[key:string]:any}', 'NgClass', 'NgClass.constructor(_iterableDiffers:IterableDiffers, _keyValueDiffers:KeyValueDiffers, _ngEl:ElementRef, _renderer:Renderer)', - 'NgClass.initialClasses=(v:any)', + 'NgClass.initialClasses=(v:string)', 'NgClass.ngDoCheck():void', 'NgClass.ngOnDestroy():void', - 'NgClass.rawClass=(v:any)', + 'NgClass.rawClass=(v:string|string[]|Set|{[key:string]:any})', 'NgControl', 'NgControl.asyncValidator:Function', 'NgControl.name:string',