From 2957b0b32e50f57bd17b508d13bf895c3853871f Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Mon, 26 Oct 2015 09:50:51 -0700 Subject: [PATCH] fix(ng_class): support sets correctly Previously, NgClass threw in Dart checked mode. Closes #4910 --- .../angular2/src/core/directives/ng_class.ts | 9 ++++-- .../test/core/directives/ng_class_spec.ts | 28 ++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/modules/angular2/src/core/directives/ng_class.ts b/modules/angular2/src/core/directives/ng_class.ts index 6396aa7f8f..72c8fbb1a1 100644 --- a/modules/angular2/src/core/directives/ng_class.ts +++ b/modules/angular2/src/core/directives/ng_class.ts @@ -1,4 +1,4 @@ -import {isPresent, isString, StringWrapper, isBlank} from 'angular2/src/core/facade/lang'; +import {isPresent, isString, StringWrapper, isBlank, isArray} from 'angular2/src/core/facade/lang'; import {DoCheck, OnDestroy} from 'angular2/lifecycle_hooks'; import {Directive} from 'angular2/src/core/metadata'; import {ElementRef} from 'angular2/src/core/linker'; @@ -146,10 +146,13 @@ export class NgClass implements DoCheck, OnDestroy { this._initialClasses.forEach(className => this._toggleClass(className, !isCleanup)); } - private _applyClasses(rawClassVal: string[] | {[key: string]: string}, isCleanup: boolean) { + private _applyClasses(rawClassVal: string[] | Set| {[key: string]: string}, + isCleanup: boolean) { if (isPresent(rawClassVal)) { - if (isListLikeIterable(rawClassVal)) { + if (isArray(rawClassVal)) { (rawClassVal).forEach(className => this._toggleClass(className, !isCleanup)); + } 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); diff --git a/modules/angular2/test/core/directives/ng_class_spec.ts b/modules/angular2/test/core/directives/ng_class_spec.ts index 8b585a19fe..9474ec268e 100644 --- a/modules/angular2/test/core/directives/ng_class_spec.ts +++ b/modules/angular2/test/core/directives/ng_class_spec.ts @@ -14,7 +14,7 @@ import { it, xit, } from 'angular2/testing_internal'; -import {ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection'; +import {ListWrapper, StringMapWrapper, SetWrapper} from 'angular2/src/core/facade/collection'; import {Component, View, NgFor, provide} from 'angular2/angular2'; import {NgClass} from 'angular2/src/core/directives/ng_class'; import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/linker/view_pool'; @@ -253,6 +253,29 @@ export function main() { })); }); + describe('expressions evaluating to sets', () => { + + it('should add and remove classes if the set instance changed', + inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { + var template = '
'; + + tcb.overrideTemplate(TestComponent, template) + .createAsync(TestComponent) + .then((rootTC) => { + var setExpr = new Set(); + setExpr.add('bar'); + rootTC.debugElement.componentInstance.setExpr = setExpr; + detectChangesAndCheck(rootTC, 'bar'); + + setExpr = new Set(); + setExpr.add('baz'); + rootTC.debugElement.componentInstance.setExpr = setExpr; + detectChangesAndCheck(rootTC, 'baz'); + + async.done(); + }); + })); + }); describe('expressions evaluating to string', () => { it('should add classes specified in a string literal', @@ -452,6 +475,9 @@ class TestComponent { condition: boolean = true; items: any[]; arrExpr: string[] = ['foo']; + setExpr: Set = new Set(); objExpr = {'foo': true, 'bar': false}; strExpr = 'foo'; + + constructor() { this.setExpr.add('foo'); } }