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:
parent
62e7c0f464
commit
ba88db5141
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue