Skip to content

Commit

Permalink
feat(animations): add provideAnimations() and `provideNoopAnimation…
Browse files Browse the repository at this point in the history
…s()` functions (#46793)

This commit adds the following functions to the public API:

- provideAnimations
- provideNoopAnimations

The goal of those functions is to return a set of providers required to setup animations in an application. The functions are useful when the `bootstrapApplication` function is used to bootstrap an app. The functions allow to avoid the need to import `BrowserAnimationsModule` and `BrowserNoopAnimationsModule` NgModules.

PR Close #46793
  • Loading branch information
AndrewKushnir authored and thePunderWoman committed Jul 12, 2022
1 parent c0ca3fc commit 55308f2
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 4 deletions.
7 changes: 7 additions & 0 deletions goldens/public-api/platform-browser/animations/index.md
Expand Up @@ -8,6 +8,7 @@ import { ANIMATION_MODULE_TYPE } from '@angular/core';
import * as i0 from '@angular/core';
import * as i1 from '@angular/platform-browser';
import { ModuleWithProviders } from '@angular/core';
import { Provider } from '@angular/core';

export { ANIMATION_MODULE_TYPE }

Expand Down Expand Up @@ -37,6 +38,12 @@ export class NoopAnimationsModule {
static ɵmod: i0.ɵɵNgModuleDeclaration<NoopAnimationsModule, never, never, [typeof i1.BrowserModule]>;
}

// @public
export function provideAnimations(): Provider[];

// @public
export function provideNoopAnimations(): Provider[];

// (No @packageDocumentation comment for this package)

```
2 changes: 1 addition & 1 deletion packages/platform-browser/animations/src/animations.ts
Expand Up @@ -12,6 +12,6 @@
* Entry point for all animation APIs of the animation browser package.
*/
export {ANIMATION_MODULE_TYPE} from '@angular/core';
export {BrowserAnimationsModule, BrowserAnimationsModuleConfig, NoopAnimationsModule} from './module';
export {BrowserAnimationsModule, BrowserAnimationsModuleConfig, NoopAnimationsModule, provideAnimations, provideNoopAnimations} from './module';

export * from './private_export';
59 changes: 58 additions & 1 deletion packages/platform-browser/animations/src/module.ts
Expand Up @@ -5,7 +5,7 @@
* 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 {ModuleWithProviders, NgModule} from '@angular/core';
import {ModuleWithProviders, NgModule, Provider} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';

import {BROWSER_ANIMATIONS_PROVIDERS, BROWSER_NOOP_ANIMATIONS_PROVIDERS} from './providers';
Expand Down Expand Up @@ -58,6 +58,35 @@ export class BrowserAnimationsModule {
}
}

/**
* Returns the set of [dependency-injection providers](guide/glossary#provider)
* to enable animations in an application. See [animations guide](guide/animations)
* to learn more about animations in Angular.
*
* @usageNotes
*
* The function is useful when you want to enable animations in an application
* bootstrapped using the `bootstrapApplication` function. In this scenario there
* is no need to import the `BrowserAnimationsModule` NgModule at all, just add
* providers returned by this function to the `providers` list as show below.
*
* ```typescript
* bootstrapApplication(RootComponent, {
* providers: [
* provideAnimations()
* ]
* });
* ```
*
* @publicApi
* @developerPreview
*/
export function provideAnimations(): Provider[] {
// Return a copy to prevent changes to the original array in case any in-place
// alterations are performed to the `provideAnimations` call results in app code.
return [...BROWSER_ANIMATIONS_PROVIDERS];
}

/**
* A null player that must be imported to allow disabling of animations.
* @publicApi
Expand All @@ -68,3 +97,31 @@ export class BrowserAnimationsModule {
})
export class NoopAnimationsModule {
}

/**
* Returns the set of [dependency-injection providers](guide/glossary#provider)
* to disable animations in an application. See [animations guide](guide/animations)
* to learn more about animations in Angular.
*
* @usageNotes
*
* The function is useful when you want to bootstrap an application using
* the `bootstrapApplication` function, but you need to disable animations
* (for example, when running tests).
*
* ```typescript
* bootstrapApplication(RootComponent, {
* providers: [
* provideNoopAnimations()
* ]
* });
* ```
*
* @publicApi
* @developerPreview
*/
export function provideNoopAnimations(): Provider[] {
// Return a copy to prevent changes to the original array in case any in-place
// alterations are performed to the `provideNoopAnimations` call results in app code.
return [...BROWSER_NOOP_ANIMATIONS_PROVIDERS];
}
Expand Up @@ -9,7 +9,7 @@ import {animate, style, transition, trigger} from '@angular/animations';
import {ɵAnimationEngine} from '@angular/animations/browser';
import {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
import {BrowserAnimationsModule, NoopAnimationsModule, provideNoopAnimations} from '@angular/platform-browser/animations';

describe('NoopAnimationsModule', () => {
beforeEach(() => {
Expand All @@ -28,6 +28,14 @@ describe('BrowserAnimationsModule with disableAnimations = true', () => {
noopAnimationTests();
});

describe('provideNoopAnimations()', () => {
beforeEach(() => {
TestBed.configureTestingModule({providers: [provideNoopAnimations()]});
});

noopAnimationTests();
});


function noopAnimationTests() {
it('should flush and fire callbacks when the zone becomes stable', (async) => {
Expand Down
56 changes: 55 additions & 1 deletion packages/platform-browser/test/browser/bootstrap_spec.ts
Expand Up @@ -6,15 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/

import {animate, state, style, transition, trigger} from '@angular/animations';
import {DOCUMENT, isPlatformBrowser, ɵgetDOM as getDOM} from '@angular/common';
import {APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, InjectionToken, Injector, Input, LOCALE_ID, NgModule, NgModuleRef, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Testability, TestabilityRegistry, Type, VERSION} from '@angular/core';
import {ANIMATION_MODULE_TYPE, APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, inject as _inject, InjectionToken, Injector, Input, LOCALE_ID, NgModule, NgModuleRef, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Testability, TestabilityRegistry, Type, VERSION} from '@angular/core';
import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
import {Console} from '@angular/core/src/console';
import {ComponentRef} from '@angular/core/src/linker/component_factory';
import {inject, TestBed} from '@angular/core/testing';
import {Log} from '@angular/core/testing/src/testing_internal';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {provideAnimations, provideNoopAnimations} from '@angular/platform-browser/animations';
import {expect} from '@angular/platform-browser/testing/src/matchers';

import {bootstrapApplication} from '../../src/browser';
Expand Down Expand Up @@ -314,6 +316,58 @@ function bootstrap(
'make sure it has the `@Component` decorator.';
expect(() => bootstrapApplication(NonAnnotatedClass)).toThrowError(msg);
});

describe('with animations', () => {
@Component({
standalone: true,
selector: 'hello-app',
template: `
<div
@myAnimation
(@myAnimation.start)="onStart($event)">Hello from AnimationCmp!</div>`,
animations: [trigger(
'myAnimation', [transition('void => *', [style({opacity: 1}), animate(5)])])],
})
class AnimationCmp {
renderer = _inject(ANIMATION_MODULE_TYPE, {optional: true}) ?? 'not found';
startEvent?: {};
onStart(event: {}) {
this.startEvent = event;
}
}

it('should enable animations when using provideAnimations()', async () => {
const appRef = await bootstrapApplication(AnimationCmp, {
providers: [provideAnimations()],
});
const cmp = appRef.components[0].instance;

// Wait until animation is completed.
await new Promise(resolve => setTimeout(resolve, 10));

expect(cmp.renderer).toBe('BrowserAnimations');
expect(cmp.startEvent.triggerName).toEqual('myAnimation');
expect(cmp.startEvent.phaseName).toEqual('start');

expect(el.innerText).toBe('Hello from AnimationCmp!');
});

it('should use noop animations renderer when using provideNoopAnimations()', async () => {
const appRef = await bootstrapApplication(AnimationCmp, {
providers: [provideNoopAnimations()],
});
const cmp = appRef.components[0].instance;

// Wait until animation is completed.
await new Promise(resolve => setTimeout(resolve, 10));

expect(cmp.renderer).toBe('NoopAnimations');
expect(cmp.startEvent.triggerName).toEqual('myAnimation');
expect(cmp.startEvent.phaseName).toEqual('start');

expect(el.innerText).toBe('Hello from AnimationCmp!');
});
});
});

it('should throw if bootstrapped Directive is not a Component', done => {
Expand Down

0 comments on commit 55308f2

Please sign in to comment.