perf(animations): always run the animation queue outside of zones
Related #12732 Closes #13440
This commit is contained in:

committed by
Victor Berchet

parent
ecfad467a1
commit
e2622add07
@ -91,8 +91,8 @@ function sanitizedValue(
|
|||||||
|
|
||||||
export function triggerAnimation(
|
export function triggerAnimation(
|
||||||
view: o.Expression, componentView: o.Expression, boundProp: BoundElementPropertyAst,
|
view: o.Expression, componentView: o.Expression, boundProp: BoundElementPropertyAst,
|
||||||
eventListener: o.Expression, renderElement: o.Expression, renderValue: o.Expression,
|
boundOutputs: BoundEventAst[], eventListener: o.Expression, renderElement: o.Expression,
|
||||||
lastRenderValue: o.Expression) {
|
renderValue: o.Expression, lastRenderValue: o.Expression) {
|
||||||
const detachStmts: o.Statement[] = [];
|
const detachStmts: o.Statement[] = [];
|
||||||
const updateStmts: o.Statement[] = [];
|
const updateStmts: o.Statement[] = [];
|
||||||
|
|
||||||
@ -121,23 +121,32 @@ export function triggerAnimation(
|
|||||||
.set(animationFnExpr.callFn([view, renderElement, lastRenderValue, emptyStateValue]))
|
.set(animationFnExpr.callFn([view, renderElement, lastRenderValue, emptyStateValue]))
|
||||||
.toDeclStmt());
|
.toDeclStmt());
|
||||||
|
|
||||||
const registerStmts = [
|
const registerStmts: o.Statement[] = [];
|
||||||
animationTransitionVar
|
const animationStartMethodExists = boundOutputs.find(
|
||||||
.callMethod(
|
event => event.isAnimation && event.name == animationName && event.phase == 'start');
|
||||||
'onStart',
|
if (animationStartMethodExists) {
|
||||||
[eventListener.callMethod(
|
registerStmts.push(
|
||||||
o.BuiltinMethod.Bind,
|
animationTransitionVar
|
||||||
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'start'))])])
|
.callMethod(
|
||||||
.toStmt(),
|
'onStart',
|
||||||
animationTransitionVar
|
[eventListener.callMethod(
|
||||||
.callMethod(
|
o.BuiltinMethod.Bind,
|
||||||
'onDone',
|
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'start'))])])
|
||||||
[eventListener.callMethod(
|
.toStmt());
|
||||||
o.BuiltinMethod.Bind,
|
}
|
||||||
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'done'))])])
|
|
||||||
.toStmt(),
|
|
||||||
|
|
||||||
];
|
const animationDoneMethodExists = boundOutputs.find(
|
||||||
|
event => event.isAnimation && event.name == animationName && event.phase == 'done');
|
||||||
|
if (animationDoneMethodExists) {
|
||||||
|
registerStmts.push(
|
||||||
|
animationTransitionVar
|
||||||
|
.callMethod(
|
||||||
|
'onDone',
|
||||||
|
[eventListener.callMethod(
|
||||||
|
o.BuiltinMethod.Bind,
|
||||||
|
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'done'))])])
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
|
||||||
updateStmts.push(...registerStmts);
|
updateStmts.push(...registerStmts);
|
||||||
detachStmts.push(...registerStmts);
|
detachStmts.push(...registerStmts);
|
||||||
|
@ -70,7 +70,7 @@ export class DirectiveWrapperCompiler {
|
|||||||
addCheckInputMethod(inputFieldName, builder);
|
addCheckInputMethod(inputFieldName, builder);
|
||||||
});
|
});
|
||||||
addNgDoCheckMethod(builder);
|
addNgDoCheckMethod(builder);
|
||||||
addCheckHostMethod(hostParseResult.hostProps, builder);
|
addCheckHostMethod(hostParseResult.hostProps, hostParseResult.hostListeners, builder);
|
||||||
addHandleEventMethod(hostParseResult.hostListeners, builder);
|
addHandleEventMethod(hostParseResult.hostListeners, builder);
|
||||||
addSubscribeMethod(dirMeta, builder);
|
addSubscribeMethod(dirMeta, builder);
|
||||||
|
|
||||||
@ -235,7 +235,8 @@ function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addCheckHostMethod(
|
function addCheckHostMethod(
|
||||||
hostProps: BoundElementPropertyAst[], builder: DirectiveWrapperBuilder) {
|
hostProps: BoundElementPropertyAst[], hostEvents: BoundEventAst[],
|
||||||
|
builder: DirectiveWrapperBuilder) {
|
||||||
const stmts: o.Statement[] = [];
|
const stmts: o.Statement[] = [];
|
||||||
const methodParams: o.FnParam[] = [
|
const methodParams: o.FnParam[] = [
|
||||||
new o.FnParam(
|
new o.FnParam(
|
||||||
@ -262,7 +263,7 @@ function addCheckHostMethod(
|
|||||||
let checkBindingStmts: o.Statement[];
|
let checkBindingStmts: o.Statement[];
|
||||||
if (hostProp.isAnimation) {
|
if (hostProp.isAnimation) {
|
||||||
const {updateStmts, detachStmts} = triggerAnimation(
|
const {updateStmts, detachStmts} = triggerAnimation(
|
||||||
VIEW_VAR, COMPONENT_VIEW_VAR, hostProp,
|
VIEW_VAR, COMPONENT_VIEW_VAR, hostProp, hostEvents,
|
||||||
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME)
|
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME)
|
||||||
.or(o.importExpr(createIdentifier(Identifiers.noop))),
|
.or(o.importExpr(createIdentifier(Identifiers.noop))),
|
||||||
RENDER_EL_VAR, evalResult.currValExpr, field.expression);
|
RENDER_EL_VAR, evalResult.currValExpr, field.expression);
|
||||||
|
@ -17,7 +17,7 @@ import {Identifiers, createIdentifier} from '../identifiers';
|
|||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {isDefaultChangeDetectionStrategy} from '../private_import_core';
|
import {isDefaultChangeDetectionStrategy} from '../private_import_core';
|
||||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||||
import {BoundElementPropertyAst, BoundTextAst, DirectiveAst, PropertyBindingType} from '../template_parser/template_ast';
|
import {BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, PropertyBindingType} from '../template_parser/template_ast';
|
||||||
import {CompileElement, CompileNode} from './compile_element';
|
import {CompileElement, CompileNode} from './compile_element';
|
||||||
import {CompileView} from './compile_view';
|
import {CompileView} from './compile_view';
|
||||||
import {DetectChangesVars} from './constants';
|
import {DetectChangesVars} from './constants';
|
||||||
@ -41,7 +41,8 @@ export function bindRenderText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function bindRenderInputs(
|
export function bindRenderInputs(
|
||||||
boundProps: BoundElementPropertyAst[], hasEvents: boolean, compileElement: CompileElement) {
|
boundProps: BoundElementPropertyAst[], boundOutputs: BoundEventAst[], hasEvents: boolean,
|
||||||
|
compileElement: CompileElement) {
|
||||||
const view = compileElement.view;
|
const view = compileElement.view;
|
||||||
const renderNode = compileElement.renderNode;
|
const renderNode = compileElement.renderNode;
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ export function bindRenderInputs(
|
|||||||
case PropertyBindingType.Animation:
|
case PropertyBindingType.Animation:
|
||||||
compileMethod = view.animationBindingsMethod;
|
compileMethod = view.animationBindingsMethod;
|
||||||
const {updateStmts, detachStmts} = triggerAnimation(
|
const {updateStmts, detachStmts} = triggerAnimation(
|
||||||
o.THIS_EXPR, o.THIS_EXPR, boundProp,
|
o.THIS_EXPR, o.THIS_EXPR, boundProp, boundOutputs,
|
||||||
(hasEvents ? o.THIS_EXPR.prop(getHandleEventMethodName(compileElement.nodeIndex)) :
|
(hasEvents ? o.THIS_EXPR.prop(getHandleEventMethodName(compileElement.nodeIndex)) :
|
||||||
o.importExpr(createIdentifier(Identifiers.noop)))
|
o.importExpr(createIdentifier(Identifiers.noop)))
|
||||||
.callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR]),
|
.callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR]),
|
||||||
|
@ -44,7 +44,7 @@ class ViewBinderVisitor implements TemplateAstVisitor {
|
|||||||
visitElement(ast: ElementAst, parent: CompileElement): any {
|
visitElement(ast: ElementAst, parent: CompileElement): any {
|
||||||
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
|
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
|
||||||
const hasEvents = bindOutputs(ast.outputs, ast.directives, compileElement, true);
|
const hasEvents = bindOutputs(ast.outputs, ast.directives, compileElement, true);
|
||||||
bindRenderInputs(ast.inputs, hasEvents, compileElement);
|
bindRenderInputs(ast.inputs, ast.outputs, hasEvents, compileElement);
|
||||||
ast.directives.forEach((directiveAst, dirIndex) => {
|
ast.directives.forEach((directiveAst, dirIndex) => {
|
||||||
const directiveWrapperInstance =
|
const directiveWrapperInstance =
|
||||||
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
|
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
|
||||||
|
@ -5,30 +5,47 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {Injectable} from '../di/metadata';
|
||||||
|
import {NgZone} from '../zone/ng_zone';
|
||||||
import {AnimationPlayer} from './animation_player';
|
import {AnimationPlayer} from './animation_player';
|
||||||
|
|
||||||
let _queuedAnimations: AnimationPlayer[] = [];
|
@Injectable()
|
||||||
|
export class AnimationQueue {
|
||||||
|
public entries: AnimationPlayer[] = [];
|
||||||
|
|
||||||
/** @internal */
|
constructor(private _zone: NgZone) {}
|
||||||
export function queueAnimation(player: AnimationPlayer) {
|
|
||||||
_queuedAnimations.push(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal */
|
enqueue(player: AnimationPlayer) { this.entries.push(player); }
|
||||||
export function triggerQueuedAnimations() {
|
|
||||||
// this code is wrapped into a single promise such that the
|
flush() {
|
||||||
// onStart and onDone player callbacks are triggered outside
|
// given that each animation player may set aside
|
||||||
// of the digest cycle of animations
|
// microtasks and rely on DOM-based events, this
|
||||||
if (_queuedAnimations.length) {
|
// will cause Angular to run change detection after
|
||||||
Promise.resolve(null).then(_triggerAnimations);
|
// each request. This sidesteps the issue. If a user
|
||||||
|
// hooks into an animation via (@anim.start) or (@anim.done)
|
||||||
|
// then those methods will automatically trigger change
|
||||||
|
// detection by wrapping themselves inside of a zone
|
||||||
|
if (this.entries.length) {
|
||||||
|
this._zone.runOutsideAngular(() => {
|
||||||
|
// this code is wrapped into a single promise such that the
|
||||||
|
// onStart and onDone player callbacks are triggered outside
|
||||||
|
// of the digest cycle of animations
|
||||||
|
Promise.resolve(null).then(() => this._triggerAnimations());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _triggerAnimations() {
|
||||||
|
NgZone.assertNotInAngularZone();
|
||||||
|
|
||||||
|
while (this.entries.length) {
|
||||||
|
const player = this.entries.shift();
|
||||||
|
// in the event that an animation throws an error then we do
|
||||||
|
// not want to re-run animations on any previous animations
|
||||||
|
// if they have already been kicked off beforehand
|
||||||
|
if (!player.hasStarted()) {
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _triggerAnimations() {
|
|
||||||
for (let i = 0; i < _queuedAnimations.length; i++) {
|
|
||||||
const player = _queuedAnimations[i];
|
|
||||||
player.play();
|
|
||||||
}
|
|
||||||
_queuedAnimations = [];
|
|
||||||
}
|
|
||||||
|
@ -23,12 +23,14 @@ export class AnimationTransition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onStart(callback: (event: AnimationTransitionEvent) => any): void {
|
onStart(callback: (event: AnimationTransitionEvent) => any): void {
|
||||||
const event = this._createEvent('start');
|
const fn =
|
||||||
this._player.onStart(() => callback(event));
|
<() => void>Zone.current.wrap(() => callback(this._createEvent('start')), 'player.onStart');
|
||||||
|
this._player.onStart(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDone(callback: (event: AnimationTransitionEvent) => any): void {
|
onDone(callback: (event: AnimationTransitionEvent) => any): void {
|
||||||
const event = this._createEvent('done');
|
const fn =
|
||||||
this._player.onDone(() => callback(event));
|
<() => void>Zone.current.wrap(() => callback(this._createEvent('done')), 'player.onDone');
|
||||||
|
this._player.onDone(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {AnimationQueue} from './animation/animation_queue';
|
||||||
import {ApplicationInitStatus} from './application_init';
|
import {ApplicationInitStatus} from './application_init';
|
||||||
import {ApplicationRef, ApplicationRef_} from './application_ref';
|
import {ApplicationRef, ApplicationRef_} from './application_ref';
|
||||||
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
|
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
|
||||||
@ -37,6 +38,7 @@ export function _keyValueDiffersFactory() {
|
|||||||
Compiler,
|
Compiler,
|
||||||
APP_ID_RANDOM_PROVIDER,
|
APP_ID_RANDOM_PROVIDER,
|
||||||
ViewUtils,
|
ViewUtils,
|
||||||
|
AnimationQueue,
|
||||||
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
|
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
|
||||||
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
|
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
|
||||||
{provide: LOCALE_ID, useValue: 'en-US'},
|
{provide: LOCALE_ID, useValue: 'en-US'},
|
||||||
|
@ -7,14 +7,15 @@
|
|||||||
*/
|
*/
|
||||||
import {AnimationGroupPlayer} from '../animation/animation_group_player';
|
import {AnimationGroupPlayer} from '../animation/animation_group_player';
|
||||||
import {AnimationPlayer} from '../animation/animation_player';
|
import {AnimationPlayer} from '../animation/animation_player';
|
||||||
import {queueAnimation as queueAnimationGlobally} from '../animation/animation_queue';
|
import {AnimationQueue} from '../animation/animation_queue';
|
||||||
import {AnimationSequencePlayer} from '../animation/animation_sequence_player';
|
import {AnimationSequencePlayer} from '../animation/animation_sequence_player';
|
||||||
import {ViewAnimationMap} from '../animation/view_animation_map';
|
import {ViewAnimationMap} from '../animation/view_animation_map';
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
|
|
||||||
export class AnimationViewContext {
|
export class AnimationViewContext {
|
||||||
private _players = new ViewAnimationMap();
|
private _players = new ViewAnimationMap();
|
||||||
|
|
||||||
|
constructor(private _animationQueue: AnimationQueue) {}
|
||||||
|
|
||||||
onAllActiveAnimationsDone(callback: () => any): void {
|
onAllActiveAnimationsDone(callback: () => any): void {
|
||||||
const activeAnimationPlayers = this._players.getAllPlayers();
|
const activeAnimationPlayers = this._players.getAllPlayers();
|
||||||
// we check for the length to avoid having GroupAnimationPlayer
|
// we check for the length to avoid having GroupAnimationPlayer
|
||||||
@ -27,7 +28,7 @@ export class AnimationViewContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
queueAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
queueAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
||||||
queueAnimationGlobally(player);
|
this._animationQueue.enqueue(player);
|
||||||
this._players.set(element, animationName, player);
|
this._players.set(element, animationName, player);
|
||||||
player.onDone(() => this._players.remove(element, animationName, player));
|
player.onDone(() => this._players.remove(element, animationName, player));
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ export abstract class AppView<T> {
|
|||||||
public viewUtils: ViewUtils, public parentView: AppView<any>, public parentIndex: number,
|
public viewUtils: ViewUtils, public parentView: AppView<any>, public parentIndex: number,
|
||||||
public parentElement: any, public cdMode: ChangeDetectorStatus,
|
public parentElement: any, public cdMode: ChangeDetectorStatus,
|
||||||
public declaredViewContainer: ViewContainer = null) {
|
public declaredViewContainer: ViewContainer = null) {
|
||||||
this.ref = new ViewRef_(this);
|
this.ref = new ViewRef_(this, viewUtils.animationQueue);
|
||||||
if (type === ViewType.COMPONENT || type === ViewType.HOST) {
|
if (type === ViewType.COMPONENT || type === ViewType.HOST) {
|
||||||
this.renderer = viewUtils.renderComponent(componentType);
|
this.renderer = viewUtils.renderComponent(componentType);
|
||||||
} else {
|
} else {
|
||||||
@ -74,7 +74,7 @@ export abstract class AppView<T> {
|
|||||||
|
|
||||||
get animationContext(): AnimationViewContext {
|
get animationContext(): AnimationViewContext {
|
||||||
if (!this._animationContext) {
|
if (!this._animationContext) {
|
||||||
this._animationContext = new AnimationViewContext();
|
this._animationContext = new AnimationViewContext(this.viewUtils.animationQueue);
|
||||||
}
|
}
|
||||||
return this._animationContext;
|
return this._animationContext;
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,12 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {triggerQueuedAnimations} from '../animation/animation_queue';
|
import {AnimationQueue} from '../animation/animation_queue';
|
||||||
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||||
import {ChangeDetectorStatus} from '../change_detection/constants';
|
import {ChangeDetectorStatus} from '../change_detection/constants';
|
||||||
import {unimplemented} from '../facade/errors';
|
import {unimplemented} from '../facade/errors';
|
||||||
|
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@ -92,7 +90,7 @@ export class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
_originalMode: ChangeDetectorStatus;
|
_originalMode: ChangeDetectorStatus;
|
||||||
|
|
||||||
constructor(private _view: AppView<C>) {
|
constructor(private _view: AppView<C>, public animationQueue: AnimationQueue) {
|
||||||
this._view = _view;
|
this._view = _view;
|
||||||
this._originalMode = this._view.cdMode;
|
this._originalMode = this._view.cdMode;
|
||||||
}
|
}
|
||||||
@ -109,7 +107,7 @@ export class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef {
|
|||||||
detach(): void { this._view.cdMode = ChangeDetectorStatus.Detached; }
|
detach(): void { this._view.cdMode = ChangeDetectorStatus.Detached; }
|
||||||
detectChanges(): void {
|
detectChanges(): void {
|
||||||
this._view.detectChanges(false);
|
this._view.detectChanges(false);
|
||||||
triggerQueuedAnimations();
|
this.animationQueue.flush();
|
||||||
}
|
}
|
||||||
checkNoChanges(): void { this._view.detectChanges(true); }
|
checkNoChanges(): void { this._view.detectChanges(true); }
|
||||||
reattach(): void {
|
reattach(): void {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {AnimationQueue} from '../animation/animation_queue';
|
||||||
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
|
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
|
||||||
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
||||||
import {Inject, Injectable} from '../di';
|
import {Inject, Injectable} from '../di';
|
||||||
@ -14,17 +15,21 @@ import {ViewEncapsulation} from '../metadata/view';
|
|||||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||||
import {Sanitizer} from '../security';
|
import {Sanitizer} from '../security';
|
||||||
import {VERSION} from '../version';
|
import {VERSION} from '../version';
|
||||||
|
import {NgZone} from '../zone/ng_zone';
|
||||||
|
|
||||||
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
import {ViewContainer} from './view_container';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ViewUtils {
|
export class ViewUtils {
|
||||||
sanitizer: Sanitizer;
|
sanitizer: Sanitizer;
|
||||||
private _nextCompTypeId: number = 0;
|
private _nextCompTypeId: number = 0;
|
||||||
|
|
||||||
constructor(private _renderer: RootRenderer, sanitizer: Sanitizer) { this.sanitizer = sanitizer; }
|
constructor(
|
||||||
|
private _renderer: RootRenderer, sanitizer: Sanitizer,
|
||||||
|
public animationQueue: AnimationQueue) {
|
||||||
|
this.sanitizer = sanitizer;
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
renderComponent(renderComponentType: RenderComponentType): Renderer {
|
renderComponent(renderComponentType: RenderComponentType): Renderer {
|
||||||
|
@ -1493,6 +1493,36 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
expect(message).toMatch(/Couldn't find an animation entry for "something"/);
|
expect(message).toMatch(/Couldn't find an animation entry for "something"/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw an error if an animation output is referenced that is not bound to as a property on the same element',
|
||||||
|
() => {
|
||||||
|
TestBed.overrideComponent(DummyLoadingCmp, {
|
||||||
|
set: {
|
||||||
|
template: `
|
||||||
|
<if-cmp (@trigger.done)="callback($event)"></if-cmp>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
TestBed.overrideComponent(DummyIfCmp, {
|
||||||
|
set: {
|
||||||
|
template: `
|
||||||
|
<div [@trigger]="exp"></div>
|
||||||
|
`,
|
||||||
|
animations: [trigger('trigger', [transition('one => two', [animate(1000)])])]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let message = '';
|
||||||
|
try {
|
||||||
|
const fixture = TestBed.createComponent(DummyIfCmp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
} catch (e) {
|
||||||
|
message = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(message).toMatch(
|
||||||
|
/Unable to listen on \(@trigger.done\) because the animation trigger \[@trigger\] isn't being used on the same element/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw an error if an animation output is referenced that is not bound to as a property on the same element',
|
it('should throw an error if an animation output is referenced that is not bound to as a property on the same element',
|
||||||
() => {
|
() => {
|
||||||
TestBed.overrideComponent(DummyIfCmp, {
|
TestBed.overrideComponent(DummyIfCmp, {
|
||||||
@ -2177,6 +2207,23 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function assertStatus(value: string) {
|
||||||
|
const text = getDOM().getText(el);
|
||||||
|
const regexp = new RegExp(`Animation Status: ${value}`);
|
||||||
|
expect(text).toMatch(regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertTime(value: number) {
|
||||||
|
const text = getDOM().getText(el);
|
||||||
|
const regexp = new RegExp(`Animation Time: ${value}`);
|
||||||
|
expect(text).toMatch(regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishAnimation(player: WebAnimationsPlayer, cb: () => any) {
|
||||||
|
getDOM().dispatchEvent(player.domPlayer, getDOM().createEvent('finish'));
|
||||||
|
Promise.resolve(null).then(cb);
|
||||||
|
}
|
||||||
|
|
||||||
afterEach(() => { destroyPlatform(); });
|
afterEach(() => { destroyPlatform(); });
|
||||||
|
|
||||||
it('should automatically run change detection when the animation done callback code updates any bindings',
|
it('should automatically run change detection when the animation done callback code updates any bindings',
|
||||||
@ -2187,24 +2234,82 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
appRef.components.find(cmp => cmp.componentType === AnimationAppCmp).instance;
|
appRef.components.find(cmp => cmp.componentType === AnimationAppCmp).instance;
|
||||||
const driver: ExtendedWebAnimationsDriver = ref.injector.get(AnimationDriver);
|
const driver: ExtendedWebAnimationsDriver = ref.injector.get(AnimationDriver);
|
||||||
const zone: NgZone = ref.injector.get(NgZone);
|
const zone: NgZone = ref.injector.get(NgZone);
|
||||||
let text = '';
|
|
||||||
zone.run(() => {
|
zone.run(() => {
|
||||||
text = getDOM().getText(el);
|
assertStatus('pending');
|
||||||
expect(text).toMatch(/Animation Status: pending/);
|
assertTime(0);
|
||||||
expect(text).toMatch(/Animation Time: 0/);
|
|
||||||
appCmp.animationStatus = 'on';
|
appCmp.animationStatus = 'on';
|
||||||
setTimeout(() => {
|
zone.runOutsideAngular(() => {
|
||||||
text = getDOM().getText(el);
|
|
||||||
expect(text).toMatch(/Animation Status: started/);
|
|
||||||
expect(text).toMatch(/Animation Time: 555/);
|
|
||||||
const player = driver.players.pop().domPlayer;
|
|
||||||
getDOM().dispatchEvent(player, getDOM().createEvent('finish'));
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
text = getDOM().getText(el);
|
assertStatus('started');
|
||||||
expect(text).toMatch(/Animation Status: done/);
|
assertTime(555);
|
||||||
expect(text).toMatch(/Animation Time: 555/);
|
const player = driver.players.pop();
|
||||||
asyncDone();
|
finishAnimation(player, () => {
|
||||||
|
assertStatus('done');
|
||||||
|
assertTime(555);
|
||||||
|
asyncDone();
|
||||||
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not run change detection for an animation that contains multiple steps until a callback is fired',
|
||||||
|
(asyncDone: Function) => {
|
||||||
|
bootstrap(AnimationAppCmp, testProviders).then(ref => {
|
||||||
|
const appRef = <ApplicationRef>ref.injector.get(ApplicationRef);
|
||||||
|
const appCmpDetails: any =
|
||||||
|
appRef.components.find(cmp => cmp.componentType === AnimationAppCmp);
|
||||||
|
const appCD = appCmpDetails.changeDetectorRef;
|
||||||
|
const appCmp: AnimationAppCmp = appCmpDetails.instance;
|
||||||
|
const driver: ExtendedWebAnimationsDriver = ref.injector.get(AnimationDriver);
|
||||||
|
const zone: NgZone = ref.injector.get(NgZone);
|
||||||
|
|
||||||
|
let player: WebAnimationsPlayer;
|
||||||
|
let onDoneCalls: string[] = [];
|
||||||
|
function onDoneFn(value: string) {
|
||||||
|
return () => {
|
||||||
|
NgZone.assertNotInAngularZone();
|
||||||
|
onDoneCalls.push(value);
|
||||||
|
appCmp.status = value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
zone.run(() => {
|
||||||
|
assertStatus('pending');
|
||||||
|
appCmp.animationWithSteps = 'on';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(driver.players.length).toEqual(3);
|
||||||
|
assertStatus('started');
|
||||||
|
|
||||||
|
zone.runOutsideAngular(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
assertStatus('started');
|
||||||
|
player = driver.players.shift();
|
||||||
|
player.onDone(onDoneFn('1'));
|
||||||
|
|
||||||
|
// step 1 => 2
|
||||||
|
finishAnimation(player, () => {
|
||||||
|
assertStatus('started');
|
||||||
|
player = driver.players.shift();
|
||||||
|
player.onDone(onDoneFn('2'));
|
||||||
|
|
||||||
|
// step 2 => 3
|
||||||
|
finishAnimation(player, () => {
|
||||||
|
assertStatus('started');
|
||||||
|
player = driver.players.shift();
|
||||||
|
player.onDone(onDoneFn('3'));
|
||||||
|
|
||||||
|
// step 3 => done
|
||||||
|
finishAnimation(player, () => {
|
||||||
|
assertStatus('done');
|
||||||
|
asyncDone();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -2295,7 +2400,17 @@ class _NaiveElementSchema extends DomElementSchemaRegistry {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'animation-app',
|
selector: 'animation-app',
|
||||||
animations: [trigger('animationStatus', [transition('off => on', animate(555))])],
|
animations: [
|
||||||
|
trigger('animationStatus', [transition('off => on', animate(555))]),
|
||||||
|
trigger(
|
||||||
|
'animationWithSteps',
|
||||||
|
[transition(
|
||||||
|
'* => on',
|
||||||
|
[
|
||||||
|
style({height: '0px'}), animate(100, style({height: '100px'})),
|
||||||
|
animate(100, style({height: '200px'})), animate(100, style({height: '300px'}))
|
||||||
|
])])
|
||||||
|
],
|
||||||
template: `
|
template: `
|
||||||
Animation Time: {{ time }}
|
Animation Time: {{ time }}
|
||||||
Animation Status: {{ status }}
|
Animation Status: {{ status }}
|
||||||
@ -2309,7 +2424,7 @@ class AnimationAppCmp {
|
|||||||
animationStatus = 'off';
|
animationStatus = 'off';
|
||||||
|
|
||||||
@HostListener('@animationStatus.start', ['$event'])
|
@HostListener('@animationStatus.start', ['$event'])
|
||||||
onStart(event: AnimationTransitionEvent) {
|
onAnimationStartDone(event: AnimationTransitionEvent) {
|
||||||
if (event.toState == 'on') {
|
if (event.toState == 'on') {
|
||||||
this.time = event.totalTime;
|
this.time = event.totalTime;
|
||||||
this.status = 'started';
|
this.status = 'started';
|
||||||
@ -2317,7 +2432,26 @@ class AnimationAppCmp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('@animationStatus.done', ['$event'])
|
@HostListener('@animationStatus.done', ['$event'])
|
||||||
onDone(event: AnimationTransitionEvent) {
|
onAnimationStatusDone(event: AnimationTransitionEvent) {
|
||||||
|
if (event.toState == 'on') {
|
||||||
|
this.time = event.totalTime;
|
||||||
|
this.status = 'done';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostBinding('@animationWithSteps')
|
||||||
|
animationWithSteps = 'off';
|
||||||
|
|
||||||
|
@HostListener('@animationWithSteps.start', ['$event'])
|
||||||
|
onAnimationWithStepsStart(event: AnimationTransitionEvent) {
|
||||||
|
if (event.toState == 'on') {
|
||||||
|
this.time = event.totalTime;
|
||||||
|
this.status = 'started';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('@animationWithSteps.done', ['$event'])
|
||||||
|
onAnimationWithStepsDone(event: AnimationTransitionEvent) {
|
||||||
if (event.toState == 'on') {
|
if (event.toState == 'on') {
|
||||||
this.time = event.totalTime;
|
this.time = event.totalTime;
|
||||||
this.status = 'done';
|
this.status = 'done';
|
||||||
|
143
modules/@angular/core/test/animation/animation_queue_spec.ts
Normal file
143
modules/@angular/core/test/animation/animation_queue_spec.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import {AnimationQueue} from '@angular/core/src/animation/animation_queue';
|
||||||
|
|
||||||
|
import {NgZone} from '../../src/zone/ng_zone';
|
||||||
|
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
|
||||||
|
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
|
||||||
|
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('AnimationQueue', function() {
|
||||||
|
beforeEach(() => { TestBed.configureTestingModule({declarations: [], imports: []}); });
|
||||||
|
|
||||||
|
it('should queue animation players and run when flushed, but only as the next scheduled microtask',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const zone = TestBed.get(NgZone);
|
||||||
|
const queue = new AnimationQueue(zone);
|
||||||
|
|
||||||
|
const log: string[] = [];
|
||||||
|
const p1 = new MockAnimationPlayer();
|
||||||
|
const p2 = new MockAnimationPlayer();
|
||||||
|
const p3 = new MockAnimationPlayer();
|
||||||
|
|
||||||
|
p1.onStart(() => log.push('1'));
|
||||||
|
p2.onStart(() => log.push('2'));
|
||||||
|
p3.onStart(() => log.push('3'));
|
||||||
|
|
||||||
|
queue.enqueue(p1);
|
||||||
|
queue.enqueue(p2);
|
||||||
|
queue.enqueue(p3);
|
||||||
|
expect(log).toEqual([]);
|
||||||
|
|
||||||
|
queue.flush();
|
||||||
|
expect(log).toEqual([]);
|
||||||
|
|
||||||
|
flushMicrotasks();
|
||||||
|
expect(log).toEqual(['1', '2', '3']);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should always run each of the animation players outside of the angular zone on start',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const zone = TestBed.get(NgZone);
|
||||||
|
const queue = new AnimationQueue(zone);
|
||||||
|
|
||||||
|
const player = new MockAnimationPlayer();
|
||||||
|
let eventHasRun = false;
|
||||||
|
player.onStart(() => {
|
||||||
|
NgZone.assertNotInAngularZone();
|
||||||
|
eventHasRun = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
zone.run(() => {
|
||||||
|
NgZone.assertInAngularZone();
|
||||||
|
queue.enqueue(player);
|
||||||
|
queue.flush();
|
||||||
|
flushMicrotasks();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(eventHasRun).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should always run each of the animation players outside of the angular zone on done',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const zone = TestBed.get(NgZone);
|
||||||
|
const queue = new AnimationQueue(zone);
|
||||||
|
|
||||||
|
const player = new MockAnimationPlayer();
|
||||||
|
let eventHasRun = false;
|
||||||
|
player.onDone(() => {
|
||||||
|
NgZone.assertNotInAngularZone();
|
||||||
|
eventHasRun = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
zone.run(() => {
|
||||||
|
NgZone.assertInAngularZone();
|
||||||
|
queue.enqueue(player);
|
||||||
|
queue.flush();
|
||||||
|
flushMicrotasks();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(eventHasRun).toBe(false);
|
||||||
|
player.finish();
|
||||||
|
expect(eventHasRun).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should not run animations again incase an animation midway fails', fakeAsync(() => {
|
||||||
|
const zone = TestBed.get(NgZone);
|
||||||
|
const queue = new AnimationQueue(zone);
|
||||||
|
|
||||||
|
const log: string[] = [];
|
||||||
|
const p1 = new PlayerThatFails(false);
|
||||||
|
const p2 = new PlayerThatFails(true);
|
||||||
|
const p3 = new PlayerThatFails(false);
|
||||||
|
|
||||||
|
p1.onStart(() => log.push('1'));
|
||||||
|
p2.onStart(() => log.push('2'));
|
||||||
|
p3.onStart(() => log.push('3'));
|
||||||
|
|
||||||
|
queue.enqueue(p1);
|
||||||
|
queue.enqueue(p2);
|
||||||
|
queue.enqueue(p3);
|
||||||
|
|
||||||
|
queue.flush();
|
||||||
|
|
||||||
|
expect(() => flushMicrotasks()).toThrowError();
|
||||||
|
|
||||||
|
expect(log).toEqual(['1', '2']);
|
||||||
|
|
||||||
|
// let's reset this so that it gets triggered again
|
||||||
|
p2.reset();
|
||||||
|
p2.onStart(() => log.push('2'));
|
||||||
|
|
||||||
|
queue.flush();
|
||||||
|
|
||||||
|
expect(() => flushMicrotasks()).not.toThrowError();
|
||||||
|
|
||||||
|
expect(log).toEqual(['1', '2', '3']);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlayerThatFails extends MockAnimationPlayer {
|
||||||
|
private _animationStarted = false;
|
||||||
|
|
||||||
|
constructor(public doFail: boolean) { super(); }
|
||||||
|
|
||||||
|
play() {
|
||||||
|
super.play();
|
||||||
|
this._animationStarted = true;
|
||||||
|
if (this.doFail) {
|
||||||
|
throw new Error('Oh nooooo');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() { this._animationStarted = false; }
|
||||||
|
|
||||||
|
hasStarted() { return this._animationStarted; }
|
||||||
|
}
|
@ -9,53 +9,54 @@
|
|||||||
import {el} from '@angular/platform-browser/testing/browser_util';
|
import {el} from '@angular/platform-browser/testing/browser_util';
|
||||||
|
|
||||||
import {NoOpAnimationPlayer} from '../../src/animation/animation_player';
|
import {NoOpAnimationPlayer} from '../../src/animation/animation_player';
|
||||||
|
import {AnimationQueue} from '../../src/animation/animation_queue';
|
||||||
import {AnimationViewContext} from '../../src/linker/animation_view_context';
|
import {AnimationViewContext} from '../../src/linker/animation_view_context';
|
||||||
import {fakeAsync, flushMicrotasks} from '../../testing';
|
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
|
||||||
import {describe, expect, iit, it} from '../../testing/testing_internal';
|
import {describe, expect, iit, it} from '../../testing/testing_internal';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('AnimationViewContext', function() {
|
describe('AnimationViewContext', function() {
|
||||||
let viewContext: AnimationViewContext;
|
|
||||||
let elm: any;
|
let elm: any;
|
||||||
beforeEach(() => {
|
beforeEach(() => { elm = el('<div></div>'); });
|
||||||
viewContext = new AnimationViewContext();
|
|
||||||
elm = el('<div></div>');
|
|
||||||
});
|
|
||||||
|
|
||||||
function getPlayers() { return viewContext.getAnimationPlayers(elm); }
|
function getPlayers(vc: any) { return vc.getAnimationPlayers(elm); }
|
||||||
|
|
||||||
it('should remove the player from the registry once the animation is complete',
|
it('should remove the player from the registry once the animation is complete',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
const player = new NoOpAnimationPlayer();
|
const player = new NoOpAnimationPlayer();
|
||||||
|
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
|
||||||
|
const vc = new AnimationViewContext(animationQueue);
|
||||||
|
|
||||||
expect(getPlayers().length).toEqual(0);
|
expect(getPlayers(vc).length).toEqual(0);
|
||||||
viewContext.queueAnimation(elm, 'someAnimation', player);
|
vc.queueAnimation(elm, 'someAnimation', player);
|
||||||
expect(getPlayers().length).toEqual(1);
|
expect(getPlayers(vc).length).toEqual(1);
|
||||||
player.finish();
|
player.finish();
|
||||||
expect(getPlayers().length).toEqual(0);
|
expect(getPlayers(vc).length).toEqual(0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not remove a follow-up player from the registry if another player is queued',
|
it('should not remove a follow-up player from the registry if another player is queued',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
const player1 = new NoOpAnimationPlayer();
|
const player1 = new NoOpAnimationPlayer();
|
||||||
const player2 = new NoOpAnimationPlayer();
|
const player2 = new NoOpAnimationPlayer();
|
||||||
|
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
|
||||||
|
const vc = new AnimationViewContext(animationQueue);
|
||||||
|
|
||||||
viewContext.queueAnimation(elm, 'someAnimation', player1);
|
vc.queueAnimation(elm, 'someAnimation', player1);
|
||||||
expect(getPlayers().length).toBe(1);
|
expect(getPlayers(vc).length).toBe(1);
|
||||||
expect(getPlayers()[0]).toBe(player1);
|
expect(getPlayers(vc)[0]).toBe(player1);
|
||||||
|
|
||||||
viewContext.queueAnimation(elm, 'someAnimation', player2);
|
vc.queueAnimation(elm, 'someAnimation', player2);
|
||||||
expect(getPlayers().length).toBe(1);
|
expect(getPlayers(vc).length).toBe(1);
|
||||||
expect(getPlayers()[0]).toBe(player2);
|
expect(getPlayers(vc)[0]).toBe(player2);
|
||||||
|
|
||||||
player1.finish();
|
player1.finish();
|
||||||
|
|
||||||
expect(getPlayers().length).toBe(1);
|
expect(getPlayers(vc).length).toBe(1);
|
||||||
expect(getPlayers()[0]).toBe(player2);
|
expect(getPlayers(vc)[0]).toBe(player2);
|
||||||
|
|
||||||
player2.finish();
|
player2.finish();
|
||||||
|
|
||||||
expect(getPlayers().length).toBe(0);
|
expect(getPlayers(vc).length).toBe(0);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerOptions, Component, Directive, Injector, ModuleWithComponentFactories, NgModule, NgModuleRef, NgZone, OpaqueToken, Pipe, PlatformRef, Provider, SchemaMetadata, Type} from '@angular/core';
|
import {CompilerOptions, Component, Directive, Injector, ModuleWithComponentFactories, NgModule, NgModuleRef, NgZone, OpaqueToken, Pipe, PlatformRef, Provider, ReflectiveInjector, SchemaMetadata, Type} from '@angular/core';
|
||||||
|
|
||||||
import {AsyncTestCompleter} from './async_test_completer';
|
import {AsyncTestCompleter} from './async_test_completer';
|
||||||
import {ComponentFixture} from './component_fixture';
|
import {ComponentFixture} from './component_fixture';
|
||||||
import {stringify} from './facade/lang';
|
import {stringify} from './facade/lang';
|
||||||
@ -268,8 +269,10 @@ export class TestBed implements Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._moduleRef =
|
const ngZone = new NgZone({enableLongStackTrace: true});
|
||||||
this._moduleWithComponentFactories.ngModuleFactory.create(this.platform.injector);
|
const ngZoneInjector = ReflectiveInjector.resolveAndCreate(
|
||||||
|
[{provide: NgZone, useValue: ngZone}], this.platform.injector);
|
||||||
|
this._moduleRef = this._moduleWithComponentFactories.ngModuleFactory.create(ngZoneInjector);
|
||||||
this._instantiated = true;
|
this._instantiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import * as import2 from '@angular/common/src/common_module';
|
import * as import2 from '@angular/common/src/common_module';
|
||||||
import * as import5 from '@angular/common/src/localization';
|
import * as import5 from '@angular/common/src/localization';
|
||||||
|
import * as import34 from '@angular/core/src/animation/animation_queue';
|
||||||
import * as import6 from '@angular/core/src/application_init';
|
import * as import6 from '@angular/core/src/application_init';
|
||||||
import * as import3 from '@angular/core/src/application_module';
|
import * as import3 from '@angular/core/src/application_module';
|
||||||
import * as import8 from '@angular/core/src/application_ref';
|
import * as import8 from '@angular/core/src/application_ref';
|
||||||
@ -70,6 +71,7 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
__SharedStylesHost_26: any;
|
__SharedStylesHost_26: any;
|
||||||
__Title_27: import16.Title;
|
__Title_27: import16.Title;
|
||||||
__TRANSLATIONS_FORMAT_28: any;
|
__TRANSLATIONS_FORMAT_28: any;
|
||||||
|
__AnimationQueue_29: import34.AnimationQueue;
|
||||||
constructor(parent: import17.Injector) {
|
constructor(parent: import17.Injector) {
|
||||||
super(parent, [import18.TreeComponentNgFactory], [import18.TreeComponentNgFactory]);
|
super(parent, [import18.TreeComponentNgFactory], [import18.TreeComponentNgFactory]);
|
||||||
}
|
}
|
||||||
@ -173,10 +175,17 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
}
|
}
|
||||||
get _ViewUtils_23(): import15.ViewUtils {
|
get _ViewUtils_23(): import15.ViewUtils {
|
||||||
if ((this.__ViewUtils_23 == (null as any))) {
|
if ((this.__ViewUtils_23 == (null as any))) {
|
||||||
(this.__ViewUtils_23 = new import15.ViewUtils(this._RootRenderer_20, this._Sanitizer_22));
|
(this.__ViewUtils_23 = new import15.ViewUtils(
|
||||||
|
this._RootRenderer_20, this._Sanitizer_22, this._AnimationQueue_29));
|
||||||
}
|
}
|
||||||
return this.__ViewUtils_23;
|
return this.__ViewUtils_23;
|
||||||
}
|
}
|
||||||
|
get _AnimationQueue_29(): import34.AnimationQueue {
|
||||||
|
if ((this.__AnimationQueue_29 == (null as any))) {
|
||||||
|
(this.__AnimationQueue_29 = new import34.AnimationQueue(this.parent.get(import22.NgZone)));
|
||||||
|
}
|
||||||
|
return this.__AnimationQueue_29;
|
||||||
|
}
|
||||||
get _IterableDiffers_24(): any {
|
get _IterableDiffers_24(): any {
|
||||||
if ((this.__IterableDiffers_24 == (null as any))) {
|
if ((this.__IterableDiffers_24 == (null as any))) {
|
||||||
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
|
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
|
||||||
@ -316,4 +325,4 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
|
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
|
||||||
}
|
}
|
||||||
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
|
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
|
||||||
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);
|
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import * as import2 from '@angular/common/src/common_module';
|
import * as import2 from '@angular/common/src/common_module';
|
||||||
import * as import5 from '@angular/common/src/localization';
|
import * as import5 from '@angular/common/src/localization';
|
||||||
|
import * as import34 from '@angular/core/src/animation/animation_queue';
|
||||||
import * as import6 from '@angular/core/src/application_init';
|
import * as import6 from '@angular/core/src/application_init';
|
||||||
import * as import3 from '@angular/core/src/application_module';
|
import * as import3 from '@angular/core/src/application_module';
|
||||||
import * as import8 from '@angular/core/src/application_ref';
|
import * as import8 from '@angular/core/src/application_ref';
|
||||||
@ -70,6 +71,7 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
__SharedStylesHost_26: any;
|
__SharedStylesHost_26: any;
|
||||||
__Title_27: import16.Title;
|
__Title_27: import16.Title;
|
||||||
__TRANSLATIONS_FORMAT_28: any;
|
__TRANSLATIONS_FORMAT_28: any;
|
||||||
|
__AnimationQueue_29: import34.AnimationQueue;
|
||||||
constructor(parent: import17.Injector) {
|
constructor(parent: import17.Injector) {
|
||||||
super(parent, [import18.TreeRootComponentNgFactory], [import18.TreeRootComponentNgFactory]);
|
super(parent, [import18.TreeRootComponentNgFactory], [import18.TreeRootComponentNgFactory]);
|
||||||
}
|
}
|
||||||
@ -173,10 +175,17 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
}
|
}
|
||||||
get _ViewUtils_23(): import15.ViewUtils {
|
get _ViewUtils_23(): import15.ViewUtils {
|
||||||
if ((this.__ViewUtils_23 == (null as any))) {
|
if ((this.__ViewUtils_23 == (null as any))) {
|
||||||
(this.__ViewUtils_23 = new import15.ViewUtils(this._RootRenderer_20, this._Sanitizer_22));
|
(this.__ViewUtils_23 = new import15.ViewUtils(
|
||||||
|
this._RootRenderer_20, this._Sanitizer_22, this._AnimationQueue_29));
|
||||||
}
|
}
|
||||||
return this.__ViewUtils_23;
|
return this.__ViewUtils_23;
|
||||||
}
|
}
|
||||||
|
get _AnimationQueue_29(): import34.AnimationQueue {
|
||||||
|
if ((this.__AnimationQueue_29 == (null as any))) {
|
||||||
|
(this.__AnimationQueue_29 = new import34.AnimationQueue(this.parent.get(import22.NgZone)));
|
||||||
|
}
|
||||||
|
return this.__AnimationQueue_29;
|
||||||
|
}
|
||||||
get _IterableDiffers_24(): any {
|
get _IterableDiffers_24(): any {
|
||||||
if ((this.__IterableDiffers_24 == (null as any))) {
|
if ((this.__IterableDiffers_24 == (null as any))) {
|
||||||
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
|
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
|
||||||
@ -316,4 +325,4 @@ class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
|
|||||||
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
|
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
|
||||||
}
|
}
|
||||||
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
|
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
|
||||||
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);
|
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);
|
||||||
|
Reference in New Issue
Block a user