fix(ngClass): do not deconstruct classes on element removal (#10303)

Prior to this fix [ngClass] would remove all dynamic classes
when destroyed. It's essential that classes are persisted such
that remove-based animations will still be stylistically correct.
This patch fixes this issue.

Closes #10008
Closes #10303
This commit is contained in:
Matias Niemelä 2016-07-26 15:20:27 -07:00 committed by GitHub
parent 62e7c0f464
commit ba88db5141
3 changed files with 36 additions and 6 deletions

View File

@ -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 {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, OnDestroy, Renderer} from '@angular/core'; import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {StringMapWrapper, isListLikeIterable} from '../facade/collection'; import {StringMapWrapper, isListLikeIterable} from '../facade/collection';
import {isArray, isPresent, isString} from '../facade/lang'; import {isArray, isPresent, isString} from '../facade/lang';
@ -75,7 +75,7 @@ import {isArray, isPresent, isString} from '../facade/lang';
* @stable * @stable
*/ */
@Directive({selector: '[ngClass]'}) @Directive({selector: '[ngClass]'})
export class NgClass implements DoCheck, OnDestroy { export class NgClass implements DoCheck {
private _iterableDiffer: IterableDiffer; private _iterableDiffer: IterableDiffer;
private _keyValueDiffer: KeyValueDiffer; private _keyValueDiffer: KeyValueDiffer;
private _initialClasses: string[] = []; private _initialClasses: string[] = [];
@ -129,8 +129,6 @@ export class NgClass implements DoCheck, OnDestroy {
} }
} }
ngOnDestroy(): void { this._cleanupClasses(this._rawClass); }
private _cleanupClasses(rawClassVal: string[]|Set<string>|{[key: string]: any}): void { private _cleanupClasses(rawClassVal: string[]|Set<string>|{[key: string]: any}): void {
this._applyClasses(rawClassVal, true); this._applyClasses(rawClassVal, true);
this._applyInitialClasses(false); this._applyInitialClasses(false);

View File

@ -874,6 +874,39 @@ function declareTests({useJit}: {useJit: boolean}) {
}))); })));
}); });
describe('ng directives', () => {
describe('[ngClass]', () => {
it('should persist ngClass class values when a remove element animation is active',
inject(
[TestComponentBuilder, AnimationDriver],
fakeAsync(
(tcb: TestComponentBuilder, driver: InnerContentTrackingAnimationDriver) => {
makeAnimationCmp(
tcb, `<div [ngClass]="exp2" *ngIf="exp" @trigger></div>`,
[
trigger('trigger', [transition('* => void', [animate(1000)])]),
],
(fixture: any /** TODO #9100 */) => {
var cmp = fixture.debugElement.componentInstance;
cmp.exp = true;
cmp.exp2 = 'blue';
fixture.detectChanges();
flushMicrotasks();
expect(driver.log.length).toEqual(0);
cmp.exp = false;
fixture.detectChanges();
flushMicrotasks();
var animation = driver.log.pop();
var element = animation['element'];
(<any>expect(element)).toHaveCssClass('blue');
});
})));
});
});
describe('animation states', () => { describe('animation states', () => {
it('should throw an error when an animation is referenced that isn\'t defined within the component annotation', it('should throw an error when an animation is referenced that isn\'t defined within the component annotation',
inject( inject(

View File

@ -291,14 +291,13 @@ export declare const NG_VALIDATORS: OpaqueToken;
export declare const NG_VALUE_ACCESSOR: OpaqueToken; export declare const NG_VALUE_ACCESSOR: OpaqueToken;
/** @stable */ /** @stable */
export declare class NgClass implements DoCheck, OnDestroy { export declare class NgClass implements DoCheck {
initialClasses: string; initialClasses: string;
ngClass: string | string[] | Set<string> | { ngClass: string | string[] | Set<string> | {
[key: string]: any; [key: string]: any;
}; };
constructor(_iterableDiffers: IterableDiffers, _keyValueDiffers: KeyValueDiffers, _ngEl: ElementRef, _renderer: Renderer); constructor(_iterableDiffers: IterableDiffers, _keyValueDiffers: KeyValueDiffers, _ngEl: ElementRef, _renderer: Renderer);
ngDoCheck(): void; ngDoCheck(): void;
ngOnDestroy(): void;
} }
/** @experimental */ /** @experimental */