refactor(docs-infra): apply prettier formatting to adev (#54625)

Apply prettier formatting to adev code

PR Close #54625
This commit is contained in:
Joey Perrott
2024-02-27 15:28:00 +00:00
committed by Dylan Hunn
parent 83d8c68690
commit 8f0c27ffc3
870 changed files with 6381 additions and 6752 deletions
+1
View File
@@ -7,6 +7,7 @@ export const format: FormatConfig = {
'prettier': {
'matchers': [
'**/*.{yaml,yml}',
'adev/**/*.{js,ts}',
'devtools/**/*.{js,ts}',
'tools/**/*.{js,ts}',
'modules/**/*.{js,ts}',
+11 -7
View File
@@ -21,7 +21,7 @@ module.exports = function (config) {
'/dummy/image': 'src/assets/images/logos/angular/angular.png',
},
client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser
clearContext: false, // leave Jasmine Spec Runner output visible in browser
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
@@ -32,15 +32,12 @@ module.exports = function (config) {
},
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
suppressAll: true, // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/site'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
],
reporters: [{type: 'html'}, {type: 'text-summary'}],
},
reporters: ['progress', 'kjhtml', 'jasmine-seed'],
port: 9876,
@@ -51,7 +48,14 @@ module.exports = function (config) {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
// See /integration/README.md#browser-tests for more info on these args
flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage', '--hide-scrollbars', '--mute-audio'],
flags: [
'--no-sandbox',
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage',
'--hide-scrollbars',
'--mute-audio',
],
},
},
browsers: ['ChromeHeadlessNoSandbox'],
+9 -1
View File
@@ -7,7 +7,15 @@
*/
import {DOCUMENT, isPlatformBrowser} from '@angular/common';
import {Component, inject, NgZone, OnInit, PLATFORM_ID, signal, WritableSignal} from '@angular/core';
import {
Component,
inject,
NgZone,
OnInit,
PLATFORM_ID,
signal,
WritableSignal,
} from '@angular/core';
import {NavigationEnd, NavigationSkipped, Router, RouterLink, RouterOutlet} from '@angular/router';
import {filter, map, skip} from 'rxjs/operators';
import {
@@ -28,12 +28,12 @@ export class ContentLoader implements DocsContentLoader {
this.cache.set(
path,
this.httpClient
.get(`assets/content/${path}`, {
responseType: 'text',
})
.pipe(map((contents) => ({contents, id: path})))
.toPromise()
);
.get(`assets/content/${path}`, {
responseType: 'text',
})
.pipe(map((contents) => ({contents, id: path})))
.toPromise(),
);
} catch {
this.router.navigateByUrl('/404');
}
@@ -16,10 +16,7 @@ import {NodeRuntimeSandbox} from '../node-runtime-sandbox.service';
import {EmbeddedTutorialManager} from '../embedded-tutorial-manager.service';
import {CodeMirrorEditor, EDITOR_CONTENT_CHANGE_DELAY_MILLIES} from './code-mirror-editor.service';
import {
TutorialConfig,
TutorialMetadata,
} from '@angular/docs';
import {TutorialConfig, TutorialMetadata} from '@angular/docs';
class FakeNodeRuntimeSandbox {
async writeFile(path: string, content: string) {}
+1 -2
View File
@@ -13,5 +13,4 @@ export const TUTORIALS_ASSETS_METADATA_DIRECTORY = 'metadata';
export const TUTORIALS_SOURCE_CODE_WEB_PATH = `${TUTORIALS_ASSETS_WEB_PATH}/${TUTORIALS_ASSETS_SOURCE_CODE_DIRECTORY}`;
export const TUTORIALS_METADATA_WEB_PATH = `${TUTORIALS_ASSETS_WEB_PATH}/${TUTORIALS_ASSETS_METADATA_DIRECTORY}`;
export const TUTORIALS_COMMON_DIRECTORY = 'common';
export const TUTORIALS_COMMON_DIRECTORY = 'common';
@@ -245,7 +245,7 @@ describe('EmbeddedTutorialManager', () => {
},
},
};
const metadata: TutorialMetadata = {
tutorialFiles: {'app.js': ''},
openFiles: ['app.js'],
@@ -295,7 +295,6 @@ describe('EmbeddedTutorialManager', () => {
);
});
it('should not set shouldReinstallDependencies if project did not change', async () => {
const fetchMock = spyOn(window, 'fetch');
@@ -325,7 +324,6 @@ describe('EmbeddedTutorialManager', () => {
it('should trigger shouldReInstallDependencies if new metadata has different dependencies', async () => {
const fetchMock = spyOn(window, 'fetch');
fetchMock
.withArgs(`${TUTORIALS_ASSETS_WEB_PATH}/${tutorial}/source-code.json`)
.and.returnValues(Promise.resolve(new Response('{}', {status: 200})));
@@ -11,10 +11,7 @@ import {FileSystemTree} from '@webcontainer/api';
import {BehaviorSubject} from 'rxjs';
import {TutorialMetadata} from '@angular/docs';
import {
TUTORIALS_COMMON_DIRECTORY,
TUTORIALS_ASSETS_WEB_PATH
} from './constants';
import {TUTORIALS_COMMON_DIRECTORY, TUTORIALS_ASSETS_WEB_PATH} from './constants';
/**
* A service responsible for the current tutorial, retrieving and providing
@@ -140,7 +137,9 @@ export class EmbeddedTutorialManager {
}
private async fetchTutorialSourceCode(tutorial: string): Promise<FileSystemTree> {
const tutorialSourceCode = await fetch(`${TUTORIALS_ASSETS_WEB_PATH}/${tutorial}/source-code.json`);
const tutorialSourceCode = await fetch(
`${TUTORIALS_ASSETS_WEB_PATH}/${tutorial}/source-code.json`,
);
if (!tutorialSourceCode.ok) throw new Error(`Missing source code for tutorial ${tutorial}`);
@@ -148,7 +147,9 @@ export class EmbeddedTutorialManager {
}
private async fetchTutorialMetadata(tutorial: string): Promise<TutorialMetadata> {
const tutorialSourceCode = await fetch(`${TUTORIALS_ASSETS_WEB_PATH}/${tutorial}/metadata.json`);
const tutorialSourceCode = await fetch(
`${TUTORIALS_ASSETS_WEB_PATH}/${tutorial}/metadata.json`,
);
if (!tutorialSourceCode.ok) throw new Error(`Missing metadata for ${tutorial}`);
+5 -6
View File
@@ -1,8 +1,7 @@
export { EmbeddedTutorialManager } from './embedded-tutorial-manager.service'
export { LoadingStep } from './enums/loading-steps'
export { NodeRuntimeState } from './node-runtime-state.service'
export {EmbeddedTutorialManager} from './embedded-tutorial-manager.service';
export {LoadingStep} from './enums/loading-steps';
export {NodeRuntimeState} from './node-runtime-state.service';
export { NodeRuntimeSandbox } from './node-runtime-sandbox.service'
export {EmbeddedEditor, EMBEDDED_EDITOR_SELECTOR} from './embedded-editor.component'
export {NodeRuntimeSandbox} from './node-runtime-sandbox.service';
export {EmbeddedEditor, EMBEDDED_EDITOR_SELECTOR} from './embedded-editor.component';
@@ -12,10 +12,7 @@ import {BehaviorSubject, of as observableOf} from 'rxjs';
import {signal} from '@angular/core';
import {WebContainer} from '@webcontainer/api';
import {TutorialType} from '@angular/docs';
import {
FakeWebContainer,
FakeWebContainerProcess,
} from '@angular/docs/testing';
import {FakeWebContainer, FakeWebContainerProcess} from '@angular/docs/testing';
import {AlertManager} from './alert-manager.service';
import {EmbeddedTutorialManager} from './embedded-tutorial-manager.service';
import {LoadingStep} from './enums/loading-steps';
@@ -16,7 +16,7 @@ import {
} from '@angular/core';
import {injectAsync} from '../../../core/services/inject-async';
import { EmbeddedEditor, EmbeddedTutorialManager } from '../../../editor';
import {EmbeddedEditor, EmbeddedTutorialManager} from '../../../editor';
@Component({
selector: 'adev-code-editor',
@@ -39,9 +39,7 @@ export class CodeEditorComponent implements OnInit {
private async loadEmbeddedEditor() {
const nodeRuntimeSandbox = await injectAsync(this.environmentInjector, () =>
import('../../../editor/index').then(
(c) => c.NodeRuntimeSandbox,
),
import('../../../editor/index').then((c) => c.NodeRuntimeSandbox),
);
await this.embeddedTutorialManager.fetchAndSetTutorialFiles(this.tutorialFiles);
@@ -31,7 +31,10 @@ export class BuildText extends View {
/**
* Create the build text.
*/
constructor(private readonly gl: OGLRenderingContext, private readonly document: Document) {
constructor(
private readonly gl: OGLRenderingContext,
private readonly document: Document,
) {
super();
this.userData['x'] = 0;
@@ -27,7 +27,10 @@ export class BuildView extends View {
/**
* Create the build view.
*/
constructor(private readonly gl: OGLRenderingContext, private readonly document: Document) {
constructor(
private readonly gl: OGLRenderingContext,
private readonly document: Document,
) {
super();
this.visible = false;
@@ -34,7 +34,10 @@ export class Lines extends View {
/**
* Create the container view.
*/
constructor(private readonly gl: OGLRenderingContext, private readonly divisions: number) {
constructor(
private readonly gl: OGLRenderingContext,
private readonly divisions: number,
) {
super();
this.userData['x'] = 0;
@@ -23,7 +23,7 @@ import {RouterLink} from '@angular/router';
import {PlaygroundTemplate} from '@angular/docs';
import {ClickOutside, NavigationList} from '@angular/docs';
import {injectAsync} from '../../core/services/inject-async';
import {EmbeddedTutorialManager} from '../../editor/index';
import {EmbeddedTutorialManager} from '../../editor/index';
import PLAYGROUND_ROUTE_DATA_JSON from '../../../../src/assets/tutorials/playground/routes.json';
import {CdkMenu, CdkMenuItem, CdkMenuTrigger} from '@angular/cdk/menu';
@@ -69,9 +69,7 @@ export default class PlaygroundComponent implements AfterViewInit {
const [embeddedEditorComponent, nodeRuntimeSandbox] = await Promise.all([
import('../../editor/index').then((c) => c.EmbeddedEditor),
injectAsync(this.environmentInjector, () =>
import('../../editor/index').then(
(c) => c.NodeRuntimeSandbox,
),
import('../../editor/index').then((c) => c.NodeRuntimeSandbox),
),
]);
@@ -59,7 +59,7 @@ export default class CliReferenceDetailsPage implements OnInit {
private setPageContent(): void {
this.activatedRoute.data
.pipe(
map(data => data['docContent']),
map((data) => data['docContent']),
takeUntilDestroyed(this.destroyRef),
)
.subscribe((doc: DocContent | undefined) => {
@@ -18,12 +18,12 @@ import {
EMBEDDED_EDITOR_SELECTOR,
EmbeddedEditor,
EmbeddedTutorialManager,
NodeRuntimeSandbox
NodeRuntimeSandbox,
} from '../../editor';
import {mockAsyncProvider} from '../../core/services/inject-async';
import Tutorial from './tutorial.component';
import {TutorialConfig, TutorialType} from '@angular/docs'
import {TutorialConfig, TutorialType} from '@angular/docs';
@Component({
selector: EMBEDDED_EDITOR_SELECTOR,
@@ -38,11 +38,11 @@ import {
EmbeddedTutorialManager,
LoadingStep,
NodeRuntimeState,
EmbeddedEditor
EmbeddedEditor,
} from '../../editor/index';
import {SplitResizerHandler} from './split-resizer-handler.service';
import { TutorialType } from '@angular/docs';
import { TutorialNavigationData, TutorialNavigationItem, } from '@angular/docs'
import {TutorialType} from '@angular/docs';
import {TutorialNavigationData, TutorialNavigationItem} from '@angular/docs';
const INTRODUCTION_LABEL = 'Introduction';
@@ -138,9 +138,7 @@ export default class Tutorial implements AfterViewInit {
this.embeddedTutorialManager.revealAnswer();
const nodeRuntimeSandbox = await injectAsync(this.environmentInjector, () =>
import('../../editor/index').then(
(s) => s.NodeRuntimeSandbox,
),
import('../../editor/index').then((s) => s.NodeRuntimeSandbox),
);
await Promise.all(
@@ -213,16 +211,10 @@ export default class Tutorial implements AfterViewInit {
this.shouldRenderContent.set(routeData.type !== TutorialType.EDITOR_ONLY);
this.nextStepPath = routeData.nextStep
? `/${routeData.nextStep}`
: undefined;
this.previousStepPath = routeData.previousStep
? `/${routeData.previousStep}`
: undefined;
this.nextStepPath = routeData.nextStep ? `/${routeData.nextStep}` : undefined;
this.previousStepPath = routeData.previousStep ? `/${routeData.previousStep}` : undefined;
this.nextTutorialPath.set(
routeData.nextTutorial ? `/${routeData.nextTutorial}` : null,
);
this.nextTutorialPath.set(routeData.nextTutorial ? `/${routeData.nextTutorial}` : null);
}
/**
+2 -6
View File
@@ -6,11 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {
contentResolver,
flatNavigationData,
mapNavigationItemsToRoutes,
} from '@angular/docs';
import {contentResolver, flatNavigationData, mapNavigationItemsToRoutes} from '@angular/docs';
import {Route} from '@angular/router';
import {DefaultPage, PagePrefix} from './core/enums/pages';
@@ -125,7 +121,7 @@ export const routes: Route[] = [
{
path: '',
loadComponent: () => import('./features/home/home.component'),
data: {label: 'Home'}
data: {label: 'Home'},
},
{
path: PagePrefix.DOCS,
+1 -1
View File
@@ -943,7 +943,7 @@ export const TUTORIALS_SUB_NAVIGATION_DATA: NavigationItem[] = [
{
path: DefaultPage.TUTORIALS,
contentPath: 'tutorials/home',
label: 'Tutorials'
label: 'Tutorials',
},
];
+1 -2
View File
@@ -18,5 +18,4 @@ import {Type} from '@angular/core';
* Map of the previews components, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component.
* Keys has to be equal to paths written down in the docs markdown files.
*/
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {
};
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {};
@@ -82,7 +82,10 @@ export class NgComponentOutletCompleteExample implements OnInit {
@ViewChild('svet', {static: true}) svetTemplateRef!: TemplateRef<any>;
myContent?: any[][];
constructor(injector: Injector, private vcr: ViewContainerRef) {
constructor(
injector: Injector,
private vcr: ViewContainerRef,
) {
this.myInjector = Injector.create({
providers: [{provide: Greeter, deps: []}],
parent: injector,
@@ -51,7 +51,10 @@ class DataListProvider {
`,
})
class GiantList {
constructor(private ref: ChangeDetectorRef, public dataProvider: DataListProvider) {
constructor(
private ref: ChangeDetectorRef,
public dataProvider: DataListProvider,
) {
ref.detach();
setInterval(() => {
this.ref.detectChanges();
@@ -81,7 +84,10 @@ class DataProvider {
@Component({selector: 'live-data', inputs: ['live'], template: 'Data: {{dataProvider.data}}'})
class LiveData {
constructor(private ref: ChangeDetectorRef, public dataProvider: DataProvider) {}
constructor(
private ref: ChangeDetectorRef,
public dataProvider: DataProvider,
) {}
@Input()
set live(value: boolean) {
@@ -70,7 +70,10 @@ describe('navigate for test examples', () => {
`,
})
class SearchCmp {
constructor(readonly route: ActivatedRoute, readonly router: Router) {}
constructor(
readonly route: ActivatedRoute,
readonly router: Router,
) {}
async searchFor(thing: string) {
await this.router.navigate([], {queryParams: {query: thing}});
@@ -1,7 +1,6 @@
import { browser, element, by } from 'protractor';
import {browser, element, by} from 'protractor';
describe('Accessibility example e2e tests', () => {
beforeEach(() => browser.get(''));
it('should display Accessibility Example', async () => {
@@ -13,5 +12,4 @@ describe('Accessibility example e2e tests', () => {
expect(await element(by.css('input')).getAttribute('value')).toEqual('16');
expect(await element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');
});
});
@@ -1,5 +1,5 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
import {AppPage} from './app.po';
import {browser, logging} from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
@@ -13,8 +13,10 @@ describe('workspace-project App', () => {
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
expect(logs).not.toContain(
jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry),
);
});
});
@@ -1,12 +1,10 @@
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {TestBed} from '@angular/core/testing';
import {AppComponent} from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
declarations: [AppComponent],
}).compileComponents();
});
@@ -1,5 +1,5 @@
import { browser } from 'protractor';
import { logging } from 'selenium-webdriver';
import {browser} from 'protractor';
import {logging} from 'selenium-webdriver';
import * as openClose from './open-close.po';
import * as statusSlider from './status-slider.po';
import * as toggle from './toggle.po';
@@ -7,8 +7,8 @@ import * as enterLeave from './enter-leave.po';
import * as auto from './auto.po';
import * as filterStagger from './filter-stagger.po';
import * as heroGroups from './hero-groups';
import { getLinkById, sleepFor } from './util';
import { getComponentSection, getToggleButton } from './querying.po';
import {getLinkById, sleepFor} from './util';
import {getComponentSection, getToggleButton} from './querying.po';
describe('Animation Tests', () => {
const routingAnimationDuration = 350;
@@ -42,7 +42,10 @@ describe('Animation Tests', () => {
if (text.includes('Closed')) {
await toggleButton.click();
await browser.wait(async () => await container.getCssValue('height') === openHeight, 2000);
await browser.wait(
async () => (await container.getCssValue('height')) === openHeight,
2000,
);
}
text = await container.getText();
@@ -59,7 +62,10 @@ describe('Animation Tests', () => {
if (text.includes('Open')) {
await toggleButton.click();
await browser.wait(async () => await container.getCssValue('height') === closedHeight, 2000);
await browser.wait(
async () => (await container.getCssValue('height')) === closedHeight,
2000,
);
}
text = await container.getText();
@@ -76,7 +82,7 @@ describe('Animation Tests', () => {
await toggleButton.click();
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const animationMessages = logs.filter(({ message }) => message.includes('Animation'));
const animationMessages = logs.filter(({message}) => message.includes('Animation'));
expect(animationMessages.length).toBeGreaterThan(0);
});
@@ -98,7 +104,10 @@ describe('Animation Tests', () => {
if (text === 'Active') {
await toggleButton.click();
await browser.wait(async () => await container.getCssValue('backgroundColor') === inactiveColor, 3000);
await browser.wait(
async () => (await container.getCssValue('backgroundColor')) === inactiveColor,
3000,
);
}
text = await container.getText();
@@ -115,7 +124,10 @@ describe('Animation Tests', () => {
if (text === 'Inactive') {
await toggleButton.click();
await browser.wait(async () => await container.getCssValue('backgroundColor') === activeColor, 3000);
await browser.wait(
async () => (await container.getCssValue('backgroundColor')) === activeColor,
3000,
);
}
text = await container.getText();
@@ -166,7 +178,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0);
await hero.click();
await browser.wait(async () => await heroesList.count() < total, 2000);
await browser.wait(async () => (await heroesList.count()) < total, 2000);
});
});
@@ -190,7 +202,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0);
await hero.click();
await browser.wait(async () => await heroesList.count() < total, 2000);
await browser.wait(async () => (await heroesList.count()) < total, 2000);
});
});
@@ -214,7 +226,7 @@ describe('Animation Tests', () => {
const input = filterStagger.getInput();
await input.sendKeys('Mag');
await browser.wait(async () => await heroesList.count() === 2, 2000);
await browser.wait(async () => (await heroesList.count()) === 2, 2000);
const newTotal = await heroesList.count();
expect(newTotal).toBeLessThan(total);
@@ -245,7 +257,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0);
await hero.click();
await browser.wait(async () => await heroesList.count() < total, 2000);
await browser.wait(async () => (await heroesList.count()) < total, 2000);
});
});
@@ -291,6 +303,5 @@ describe('Animation Tests', () => {
await newPageSleepFor(queryingAnimationDuration);
expect(await toggleButton.isEnabled()).toBe(true);
});
});
});
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-auto-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-enter-leave-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-hero-list-groups-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-open-close-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getComponent() {
return by.css('app-querying');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-status-slider-page');
@@ -1,5 +1,5 @@
import { by } from 'protractor';
import { locate } from './util';
import {by} from 'protractor';
import {locate} from './util';
export function getPage() {
return by.css('app-toggle-animations-child-page');
@@ -1,4 +1,4 @@
import { Locator, ElementFinder, browser, by, element } from 'protractor';
import {Locator, ElementFinder, browser, by, element} from 'protractor';
/**
*
@@ -6,8 +6,9 @@ import { Locator, ElementFinder, browser, by, element } from 'protractor';
*/
export function locate(locator: Locator, ...locators: Locator[]) {
return locators.reduce(
(current: ElementFinder, next: Locator) => current.element(next),
element(locator)) as ElementFinder;
(current: ElementFinder, next: Locator) => current.element(next),
element(locator),
) as ElementFinder;
}
export async function sleepFor(time = 1000) {
@@ -1,9 +1,9 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
standalone: true,
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
styleUrls: ['./about.component.css'],
})
export class AboutComponent {}
@@ -1,15 +1,15 @@
// #docplaster
// #docregion animation-const, trigger-const
import { animation, style, animate, trigger, transition, useAnimation } from '@angular/animations';
import {animation, style, animate, trigger, transition, useAnimation} from '@angular/animations';
// #enddocregion trigger-const
export const transitionAnimation = animation([
style({
height: '{{ height }}',
opacity: '{{ opacity }}',
backgroundColor: '{{ backgroundColor }}'
backgroundColor: '{{ backgroundColor }}',
}),
animate('{{ time }}')
animate('{{ time }}'),
]);
// #enddocregion animation-const
@@ -21,9 +21,9 @@ export const triggerAnimation = trigger('openClose', [
height: 0,
opacity: 1,
backgroundColor: 'red',
time: '1s'
}
})
])
time: '1s',
},
}),
]),
]);
// #enddocregion trigger-const
@@ -1,71 +1,71 @@
import {
animation, trigger, animateChild, group,
transition, animate, style, query
animation,
trigger,
animateChild,
group,
transition,
animate,
style,
query,
} from '@angular/animations';
export const transitionAnimation = animation([
style({
height: '{{ height }}',
opacity: '{{ opacity }}',
backgroundColor: '{{ backgroundColor }}'
backgroundColor: '{{ backgroundColor }}',
}),
animate('{{ time }}')
animate('{{ time }}'),
]);
// Routable animations
// #docregion route-animations
export const slideInAnimation =
// #docregion style-view
// #docregion style-view
trigger('routeAnimations', [
transition('HomePage <=> AboutPage', [
style({ position: 'relative' }),
style({position: 'relative'}),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
width: '100%',
}),
]),
// #enddocregion style-view
// #docregion query
query(':enter', [
style({ left: '-100%' })
], { optional: true }),
query(':leave', animateChild(), { optional: true }),
// #enddocregion style-view
// #docregion query
query(':enter', [style({left: '-100%'})], {optional: true}),
query(':leave', animateChild(), {optional: true}),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
], { optional: true }),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
], { optional: true }),
query(':leave', [animate('300ms ease-out', style({left: '100%'}))], {optional: true}),
query(':enter', [animate('300ms ease-out', style({left: '0%'}))], {optional: true}),
]),
]),
transition('* <=> *', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
], { optional: true }),
query(':enter', [
style({ left: '-100%' })
], { optional: true }),
query(':leave', animateChild(), { optional: true }),
style({position: 'relative'}),
query(
':enter, :leave',
[
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
}),
],
{optional: true},
),
query(':enter', [style({left: '-100%'})], {optional: true}),
query(':leave', animateChild(), {optional: true}),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
], { optional: true }),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
], { optional: true }),
query('@*', animateChild(), { optional: true })
query(':leave', [animate('200ms ease-out', style({left: '100%', opacity: 0}))], {
optional: true,
}),
query(':enter', [animate('300ms ease-out', style({left: '0%'}))], {optional: true}),
query('@*', animateChild(), {optional: true}),
]),
])
]),
// #enddocregion query
]);
// #enddocregion route-animations
// #enddocregion route-animations
@@ -1,6 +1,6 @@
// #docplaster
// #docregion imports
import { Component, HostBinding } from '@angular/core';
import {Component, HostBinding} from '@angular/core';
import {
trigger,
state,
@@ -11,8 +11,8 @@ import {
} from '@angular/animations';
// #enddocregion imports
import { ChildrenOutletContexts, RouterLink, RouterOutlet } from '@angular/router';
import { slideInAnimation } from './animations';
import {ChildrenOutletContexts, RouterLink, RouterOutlet} from '@angular/router';
import {slideInAnimation} from './animations';
// #docregion decorator, toggle-app-animations, define
@Component({
@@ -22,31 +22,31 @@ import { slideInAnimation } from './animations';
styleUrls: ['app.component.css'],
imports: [RouterLink, RouterOutlet],
animations: [
// #enddocregion decorator
slideInAnimation
// #docregion decorator
// #enddocregion toggle-app-animations, define
// #enddocregion decorator
slideInAnimation,
// #docregion decorator
// #enddocregion toggle-app-animations, define
// animation triggers go here
// #docregion toggle-app-animations, define
]
// #docregion toggle-app-animations, define
],
})
// #enddocregion decorator, define
export class AppComponent {
@HostBinding('@.disabled')
public animationsDisabled = false;
// #enddocregion toggle-app-animations
// #enddocregion toggle-app-animations
// #docregion get-route-animations-data
// #docregion get-route-animations-data
constructor(private contexts: ChildrenOutletContexts) {}
getRouteAnimationData() {
return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
}
// #enddocregion get-route-animations-data
// #enddocregion get-route-animations-data
toggleAnimations() {
this.animationsDisabled = !this.animationsDisabled;
}
// #docregion toggle-app-animations
// #docregion toggle-app-animations
}
// #enddocregion toggle-app-animations
@@ -1,15 +1,14 @@
import { ApplicationConfig } from '@angular/core';
import { routes } from './app.routes';
import { provideRouter } from '@angular/router';
import { provideProtractorTestingSupport } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import {ApplicationConfig} from '@angular/core';
import {routes} from './app.routes';
import {provideRouter} from '@angular/router';
import {provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideAnimations} from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
// needed for supporting e2e tests
provideProtractorTestingSupport(),
provideRouter(routes),
provideAnimations(),
]
providers: [
// needed for supporting e2e tests
provideProtractorTestingSupport(),
provideRouter(routes),
provideAnimations(),
],
};
@@ -1,13 +1,10 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule
],
declarations: [ ],
bootstrap: [ ]
imports: [BrowserModule, BrowserAnimationsModule],
declarations: [],
bootstrap: [],
})
export class AppModule { }
export class AppModule {}
@@ -1,73 +1,73 @@
import { Routes } from '@angular/router';
import { OpenClosePageComponent } from './open-close-page.component';
import { StatusSliderPageComponent } from './status-slider-page.component';
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
import { HeroListPageComponent } from './hero-list-page.component';
import { HeroListGroupPageComponent } from './hero-list-group-page.component';
import { HeroListEnterLeavePageComponent } from './hero-list-enter-leave-page.component';
import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component';
import { InsertRemoveComponent } from './insert-remove.component';
import { QueryingComponent } from './querying.component';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
import {Routes} from '@angular/router';
import {OpenClosePageComponent} from './open-close-page.component';
import {StatusSliderPageComponent} from './status-slider-page.component';
import {ToggleAnimationsPageComponent} from './toggle-animations-page.component';
import {HeroListPageComponent} from './hero-list-page.component';
import {HeroListGroupPageComponent} from './hero-list-group-page.component';
import {HeroListEnterLeavePageComponent} from './hero-list-enter-leave-page.component';
import {HeroListAutoCalcPageComponent} from './hero-list-auto-page.component';
import {InsertRemoveComponent} from './insert-remove.component';
import {QueryingComponent} from './querying.component';
import {HomeComponent} from './home.component';
import {AboutComponent} from './about.component';
// #docregion route-animation-data
export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
{
path: 'open-close',
component: OpenClosePageComponent,
data: { animation: 'openClosePage' }
},
{
path: 'status',
component: StatusSliderPageComponent,
data: { animation: 'statusPage' }
},
{
path: 'toggle',
component: ToggleAnimationsPageComponent,
data: { animation: 'togglePage' }
},
{
path: 'heroes',
component: HeroListPageComponent,
data: { animation: 'filterPage' }
},
{
path: 'hero-groups',
component: HeroListGroupPageComponent,
data: { animation: 'heroGroupPage' }
},
{
path: 'enter-leave',
component: HeroListEnterLeavePageComponent,
data: { animation: 'enterLeavePage' }
},
{
path: 'auto',
component: HeroListAutoCalcPageComponent,
data: { animation: 'autoPage' }
},
{
path: 'insert-remove',
component: InsertRemoveComponent,
data: { animation: 'insertRemovePage' }
},
{
path: 'querying',
component: QueryingComponent,
data: { animation: 'queryingPage' }
},
{
path: 'home',
component: HomeComponent,
data: { animation: 'HomePage' }
},
{
path: 'about',
component: AboutComponent,
data: { animation: 'AboutPage' }
},
{path: '', pathMatch: 'full', redirectTo: '/enter-leave'},
{
path: 'open-close',
component: OpenClosePageComponent,
data: {animation: 'openClosePage'},
},
{
path: 'status',
component: StatusSliderPageComponent,
data: {animation: 'statusPage'},
},
{
path: 'toggle',
component: ToggleAnimationsPageComponent,
data: {animation: 'togglePage'},
},
{
path: 'heroes',
component: HeroListPageComponent,
data: {animation: 'filterPage'},
},
{
path: 'hero-groups',
component: HeroListGroupPageComponent,
data: {animation: 'heroGroupPage'},
},
{
path: 'enter-leave',
component: HeroListEnterLeavePageComponent,
data: {animation: 'enterLeavePage'},
},
{
path: 'auto',
component: HeroListAutoCalcPageComponent,
data: {animation: 'autoPage'},
},
{
path: 'insert-remove',
component: InsertRemoveComponent,
data: {animation: 'insertRemovePage'},
},
{
path: 'querying',
component: QueryingComponent,
data: {animation: 'queryingPage'},
},
{
path: 'home',
component: HomeComponent,
data: {animation: 'HomePage'},
},
{
path: 'about',
component: AboutComponent,
data: {animation: 'AboutPage'},
},
];
// #enddocregion route-animation-data
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListAutoComponent } from './hero-list-auto.component';
import {Component} from '@angular/core';
import {HEROES} from './mock-heroes';
import {HeroListAutoComponent} from './hero-list-auto.component';
@Component({
standalone: true,
@@ -12,12 +12,12 @@ import { HeroListAutoComponent } from './hero-list-auto.component';
<app-hero-list-auto [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-auto>
</section>
`,
imports: [HeroListAutoComponent]
imports: [HeroListAutoComponent],
})
export class HeroListAutoCalcPageComponent {
heroes = HEROES.slice();
onRemove(id: number) {
this.heroes = this.heroes.filter(hero => hero.id !== id);
this.heroes = this.heroes.filter((hero) => hero.id !== id);
}
}
@@ -1,19 +1,8 @@
import {
Component,
Input,
Output,
EventEmitter
} from '@angular/core';
import {
trigger,
state,
style,
animate,
transition
} from '@angular/animations';
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {trigger, state, style, animate, transition} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
import {Hero} from './hero';
import {NgFor} from '@angular/common';
@Component({
standalone: true,
@@ -24,21 +13,18 @@ import { NgFor } from '@angular/common';
// #docregion auto-calc
animations: [
trigger('shrinkOut', [
state('in', style({ height: '*' })),
transition('* => void', [
style({ height: '*' }),
animate(250, style({ height: 0 }))
])
])
]
state('in', style({height: '*'})),
transition('* => void', [style({height: '*'}), animate(250, style({height: 0}))]),
]),
],
// #enddocregion auto-calc
})
export class HeroListAutoComponent {
@Input() heroes: Hero[] = [];
@Input() heroes: Hero[] = [];
@Output() remove = new EventEmitter<number>();
@Output() remove = new EventEmitter<number>();
removeHero(id: number) {
this.remove.emit(id);
}
removeHero(id: number) {
this.remove.emit(id);
}
}
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
import {Component} from '@angular/core';
import {HEROES} from './mock-heroes';
import {HeroListEnterLeaveComponent} from './hero-list-enter-leave.component';
@Component({
standalone: true,
@@ -12,12 +12,12 @@ import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
<app-hero-list-enter-leave [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-enter-leave>
</section>
`,
imports: [HeroListEnterLeaveComponent]
imports: [HeroListEnterLeaveComponent],
})
export class HeroListEnterLeavePageComponent {
heroes = HEROES.slice();
onRemove(id: number) {
this.heroes = this.heroes.filter(hero => hero.id !== id);
this.heroes = this.heroes.filter((hero) => hero.id !== id);
}
}
@@ -1,19 +1,8 @@
import {
Component,
Input,
Output,
EventEmitter
} from '@angular/core';
import {
trigger,
state,
style,
animate,
transition
} from '@angular/animations';
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {trigger, state, style, animate, transition} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
import {Hero} from './hero';
import {NgFor} from '@angular/common';
@Component({
standalone: true,
@@ -35,16 +24,11 @@ import { NgFor } from '@angular/common';
// #docregion animationdef
animations: [
trigger('flyInOut', [
state('in', style({ transform: 'translateX(0)' })),
transition('void => *', [
style({ transform: 'translateX(-100%)' }),
animate(100)
]),
transition('* => void', [
animate(100, style({ transform: 'translateX(100%)' }))
])
])
]
state('in', style({transform: 'translateX(0)'})),
transition('void => *', [style({transform: 'translateX(-100%)'}), animate(100)]),
transition('* => void', [animate(100, style({transform: 'translateX(100%)'}))]),
]),
],
// #enddocregion animationdef
})
export class HeroListEnterLeaveComponent {
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListGroupsComponent } from './hero-list-groups.component';
import {Component} from '@angular/core';
import {HEROES} from './mock-heroes';
import {HeroListGroupsComponent} from './hero-list-groups.component';
@Component({
standalone: true,
@@ -12,12 +12,12 @@ import { HeroListGroupsComponent } from './hero-list-groups.component';
<app-hero-list-groups [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-groups>
</section>
`,
imports: [HeroListGroupsComponent]
imports: [HeroListGroupsComponent],
})
export class HeroListGroupPageComponent {
heroes = HEROES.slice();
onRemove(id: number) {
this.heroes = this.heroes.filter(hero => hero.id !== id);
this.heroes = this.heroes.filter((hero) => hero.id !== id);
}
}
@@ -1,20 +1,8 @@
import {
Component,
Input,
Output,
EventEmitter
} from '@angular/core';
import {
trigger,
state,
style,
animate,
transition,
group
} from '@angular/animations';
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {trigger, state, style, animate, transition, group} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
import {Hero} from './hero';
import {NgFor} from '@angular/common';
@Component({
standalone: true,
@@ -36,43 +24,59 @@ import { NgFor } from '@angular/common';
// #docregion animationdef
animations: [
trigger('flyInOut', [
state('in', style({
width: '*',
transform: 'translateX(0)', opacity: 1
})),
state(
'in',
style({
width: '*',
transform: 'translateX(0)',
opacity: 1,
}),
),
transition(':enter', [
style({ width: 10, transform: 'translateX(50px)', opacity: 0 }),
style({width: 10, transform: 'translateX(50px)', opacity: 0}),
group([
animate('0.3s 0.1s ease', style({
transform: 'translateX(0)',
width: '*'
})),
animate('0.3s ease', style({
opacity: 1
}))
])
animate(
'0.3s 0.1s ease',
style({
transform: 'translateX(0)',
width: '*',
}),
),
animate(
'0.3s ease',
style({
opacity: 1,
}),
),
]),
]),
transition(':leave', [
group([
animate('0.3s ease', style({
transform: 'translateX(50px)',
width: 10
})),
animate('0.3s 0.2s ease', style({
opacity: 0
}))
])
])
])
]
animate(
'0.3s ease',
style({
transform: 'translateX(50px)',
width: 10,
}),
),
animate(
'0.3s 0.2s ease',
style({
opacity: 0,
}),
),
]),
]),
]),
],
// #enddocregion animationdef
})
export class HeroListGroupsComponent {
@Input() heroes: Hero[] = [];
@Input() heroes: Hero[] = [];
@Output() remove = new EventEmitter<number>();
@Output() remove = new EventEmitter<number>();
removeHero(id: number) {
this.remove.emit(id);
}
removeHero(id: number) {
this.remove.emit(id);
}
}
@@ -1,66 +1,65 @@
// #docplaster
// #docregion
import { Component, HostBinding, OnInit } from '@angular/core';
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
import { HEROES } from './mock-heroes';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
import {Component, HostBinding, OnInit} from '@angular/core';
import {trigger, transition, animate, style, query, stagger} from '@angular/animations';
import {HEROES} from './mock-heroes';
import {Hero} from './hero';
import {NgFor} from '@angular/common';
// #docregion filter-animations
@Component({
// #enddocregion filter-animations
// #enddocregion filter-animations
standalone: true,
imports: [NgFor],
selector: 'app-hero-list-page',
templateUrl: 'hero-list-page.component.html',
styleUrls: ['hero-list-page.component.css'],
// #docregion page-animations, filter-animations
// #docregion page-animations, filter-animations
animations: [
// #enddocregion filter-animations
// #enddocregion filter-animations
trigger('pageAnimations', [
transition(':enter', [
query('.hero', [
style({opacity: 0, transform: 'translateY(-100px)'}),
stagger(30, [
animate('500ms cubic-bezier(0.35, 0, 0.25, 1)',
style({ opacity: 1, transform: 'none' }))
])
])
])
animate('500ms cubic-bezier(0.35, 0, 0.25, 1)', style({opacity: 1, transform: 'none'})),
]),
]),
]),
]),
// #enddocregion page-animations
// #docregion increment
// #docregion filter-animations
// #enddocregion page-animations
// #docregion increment
// #docregion filter-animations
trigger('filterAnimation', [
transition(':enter, * => 0, * => -1', []),
transition(':increment', [
query(':enter', [
style({ opacity: 0, width: 0 }),
stagger(50, [
animate('300ms ease-out', style({ opacity: 1, width: '*' })),
]),
], { optional: true })
query(
':enter',
[
style({opacity: 0, width: 0}),
stagger(50, [animate('300ms ease-out', style({opacity: 1, width: '*'}))]),
],
{optional: true},
),
]),
transition(':decrement', [
query(':leave', [
stagger(50, [
animate('300ms ease-out', style({ opacity: 0, width: 0 })),
]),
])
query(':leave', [stagger(50, [animate('300ms ease-out', style({opacity: 0, width: 0}))])]),
]),
]),
// #enddocregion increment
]
// #enddocregion increment
],
})
export class HeroListPageComponent implements OnInit {
// #enddocregion filter-animations
// #enddocregion filter-animations
@HostBinding('@pageAnimations')
public animatePage = true;
// #docregion filter-animations
// #docregion filter-animations
heroesTotal = -1;
get heroes() { return this._heroes; }
get heroes() {
return this._heroes;
}
private _heroes: Hero[] = [];
ngOnInit() {
@@ -70,7 +69,9 @@ export class HeroListPageComponent implements OnInit {
updateCriteria(criteria: string) {
criteria = criteria ? criteria.trim() : '';
this._heroes = HEROES.filter(hero => hero.name.toLowerCase().includes(criteria.toLowerCase()));
this._heroes = HEROES.filter((hero) =>
hero.name.toLowerCase().includes(criteria.toLowerCase()),
);
const newTotal = this.heroes.length;
if (this.heroesTotal !== newTotal) {
@@ -1,9 +1,9 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
standalone: true,
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
styleUrls: ['./home.component.css'],
})
export class HomeComponent {}
@@ -1,27 +1,22 @@
// #docplaster
import { Component } from '@angular/core';
import { trigger, transition, animate, style } from '@angular/animations';
import { NgIf } from '@angular/common';
import {Component} from '@angular/core';
import {trigger, transition, animate, style} from '@angular/animations';
import {NgIf} from '@angular/common';
@Component({
standalone: true,
selector: 'app-insert-remove',
imports: [NgIf],
animations: [
// #docregion enter-leave-trigger
// #docregion enter-leave-trigger
trigger('myInsertRemoveTrigger', [
transition(':enter', [
style({ opacity: 0 }),
animate('100ms', style({ opacity: 1 })),
]),
transition(':leave', [
animate('100ms', style({ opacity: 0 }))
])
transition(':enter', [style({opacity: 0}), animate('100ms', style({opacity: 1}))]),
transition(':leave', [animate('100ms', style({opacity: 0}))]),
]),
// #enddocregion enter-leave-trigger
// #enddocregion enter-leave-trigger
],
templateUrl: 'insert-remove.component.html',
styleUrls: ['insert-remove.component.css']
styleUrls: ['insert-remove.component.css'],
})
export class InsertRemoveComponent {
isShown = false;
@@ -1,14 +1,14 @@
// #docregion
import { Hero } from './hero';
import {Hero} from './hero';
export const HEROES: Hero[] = [
{ id: 12, name: 'Dr. Nice' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr. IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
{id: 12, name: 'Dr. Nice'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr. IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'},
];
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { OpenCloseComponent } from './open-close.component';
import {Component} from '@angular/core';
import {OpenCloseComponent} from './open-close.component';
@Component({
standalone: true,
@@ -13,7 +13,7 @@ import { OpenCloseComponent } from './open-close.component';
<app-open-close [logging]="logging"></app-open-close>
</section>
`,
imports: [OpenCloseComponent]
imports: [OpenCloseComponent],
})
export class OpenClosePageComponent {
logging = false;
@@ -1,36 +1,53 @@
import { Component, Input } from '@angular/core';
import { trigger, transition, state, animate, style, keyframes, AnimationEvent } from '@angular/animations';
import {Component, Input} from '@angular/core';
import {
trigger,
transition,
state,
animate,
style,
keyframes,
AnimationEvent,
} from '@angular/animations';
@Component({
standalone: true,
selector: 'app-open-close',
animations: [
// #docregion trigger
// #docregion trigger
trigger('openClose', [
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('close', style({
height: '100px',
opacity: 0.5,
backgroundColor: 'green'
})),
state(
'open',
style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow',
}),
),
state(
'close',
style({
height: '100px',
opacity: 0.5,
backgroundColor: 'green',
}),
),
// ...
transition('* => *', [
animate('1s', keyframes ( [
style({ opacity: 0.1, offset: 0.1 }),
style({ opacity: 0.6, offset: 0.2 }),
style({ opacity: 1, offset: 0.5 }),
style({ opacity: 0.2, offset: 0.7 })
]))
])
])
// #enddocregion trigger
animate(
'1s',
keyframes([
style({opacity: 0.1, offset: 0.1}),
style({opacity: 0.6, offset: 0.2}),
style({opacity: 1, offset: 0.5}),
style({opacity: 0.2, offset: 0.7}),
]),
),
]),
]),
// #enddocregion trigger
],
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
styleUrls: ['open-close.component.css'],
})
export class OpenCloseKeyframeComponent {
isOpen = false;
@@ -1,20 +1,20 @@
import { Component } from '@angular/core';
import { trigger, transition, state, animate, style } from '@angular/animations';
import {Component} from '@angular/core';
import {trigger, transition, state, animate, style} from '@angular/animations';
@Component({
standalone: true,
selector: 'app-open-close-boolean',
// #docregion trigger-boolean
// #docregion trigger-boolean
animations: [
trigger('openClose', [
state('true', style({ height: '*' })),
state('false', style({ height: '0px' })),
transition('false <=> true', animate(500))
])
state('true', style({height: '*'})),
state('false', style({height: '0px'})),
transition('false <=> true', animate(500)),
]),
],
// #enddocregion trigger-boolean
// #enddocregion trigger-boolean
templateUrl: 'open-close.component.2.html',
styleUrls: ['open-close.component.css']
styleUrls: ['open-close.component.css'],
})
export class OpenCloseBooleanComponent {
isOpen = false;
@@ -1,8 +1,8 @@
// #docplaster
// #docregion reusable
import { Component, Input } from '@angular/core';
import { transition, trigger, useAnimation, AnimationEvent } from '@angular/animations';
import { transitionAnimation } from './animations';
import {Component, Input} from '@angular/core';
import {transition, trigger, useAnimation, AnimationEvent} from '@angular/animations';
import {transitionAnimation} from './animations';
@Component({
standalone: true,
@@ -15,14 +15,14 @@ import { transitionAnimation } from './animations';
height: 0,
opacity: 1,
backgroundColor: 'red',
time: '1s'
}
})
])
])
time: '1s',
},
}),
]),
]),
],
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
styleUrls: ['open-close.component.css'],
})
// #enddocregion reusable
export class OpenCloseBooleanComponent {
@@ -38,4 +38,4 @@ export class OpenCloseBooleanComponent {
return;
}
}
}
}
@@ -1,11 +1,11 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { trigger, transition, state, animate, style } from '@angular/animations';
import {Component} from '@angular/core';
import {trigger, transition, state, animate, style} from '@angular/animations';
// #docregion toggle-animation
@Component({
// #enddocregion toggle-animation
// #enddocregion toggle-animation
standalone: true,
selector: 'app-open-close-toggle',
templateUrl: 'open-close.component.4.html',
@@ -14,28 +14,32 @@ import { trigger, transition, state, animate, style } from '@angular/animations'
animations: [
trigger('childAnimation', [
// ...
// #enddocregion toggle-animation
state('open', style({
width: '250px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('closed', style({
width: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
transition('* => *', [
animate('1s')
]),
// #docregion toggle-animation
// #enddocregion toggle-animation
state(
'open',
style({
width: '250px',
opacity: 1,
backgroundColor: 'yellow',
}),
),
state(
'closed',
style({
width: '100px',
opacity: 0.8,
backgroundColor: 'blue',
}),
),
transition('* => *', [animate('1s')]),
// #docregion toggle-animation
]),
],
})
export class OpenCloseChildComponent {
isDisabled = false;
isOpen = false;
// #enddocregion toggle-animation
// #enddocregion toggle-animation
toggleAnimations() {
this.isDisabled = !this.isDisabled;
}
@@ -43,6 +47,6 @@ export class OpenCloseChildComponent {
toggle() {
this.isOpen = !this.isOpen;
}
// #docregion toggle-animation
// #docregion toggle-animation
}
// #enddocregion toggle-animation
@@ -1,90 +1,80 @@
// #docplaster
import { Component, Input } from '@angular/core';
import { trigger, transition, state, animate, style, AnimationEvent } from '@angular/animations';
import {Component, Input} from '@angular/core';
import {trigger, transition, state, animate, style, AnimationEvent} from '@angular/animations';
// #docregion component, events1
@Component({
standalone: true,
selector: 'app-open-close',
// #docregion trigger-wildcard1, trigger-transition
// #docregion trigger-wildcard1, trigger-transition
animations: [
trigger('openClose', [
// #docregion state1
// #docregion state1
// ...
// #enddocregion events1
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
// #enddocregion state1
// #docregion state2
state('closed', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
// #enddocregion state2, trigger-wildcard1
// #docregion transition1
transition('open => closed', [
animate('1s')
]),
// #enddocregion transition1
// #docregion transition2
transition('closed => open', [
animate('0.5s')
]),
// #enddocregion transition2, component
// #docregion trigger-wildcard1
transition('* => closed', [
animate('1s')
]),
transition('* => open', [
animate('0.5s')
]),
// #enddocregion trigger-wildcard1
// #docregion trigger-wildcard2
transition('open <=> closed', [
animate('0.5s')
]),
// #enddocregion trigger-wildcard2
// #docregion transition4
transition ('* => open', [
animate ('1s',
style ({ opacity: '*' }),
),
]),
// #enddocregion transition4
transition('* => *', [
animate('1s')
]),
// #enddocregion trigger-transition
// #docregion component, trigger-wildcard1, events1
// #enddocregion events1
state(
'open',
style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow',
}),
),
// #enddocregion state1
// #docregion state2
state(
'closed',
style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue',
}),
),
// #enddocregion state2, trigger-wildcard1
// #docregion transition1
transition('open => closed', [animate('1s')]),
// #enddocregion transition1
// #docregion transition2
transition('closed => open', [animate('0.5s')]),
// #enddocregion transition2, component
// #docregion trigger-wildcard1
transition('* => closed', [animate('1s')]),
transition('* => open', [animate('0.5s')]),
// #enddocregion trigger-wildcard1
// #docregion trigger-wildcard2
transition('open <=> closed', [animate('0.5s')]),
// #enddocregion trigger-wildcard2
// #docregion transition4
transition('* => open', [animate('1s', style({opacity: '*'}))]),
// #enddocregion transition4
transition('* => *', [animate('1s')]),
// #enddocregion trigger-transition
// #docregion component, trigger-wildcard1, events1
]),
],
// #enddocregion trigger-wildcard1
// #enddocregion trigger-wildcard1
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
styleUrls: ['open-close.component.css'],
})
// #docregion events
export class OpenCloseComponent {
// #enddocregion events1, events, component
// #enddocregion events1, events, component
@Input() logging = false;
// #docregion component
// #docregion component
isOpen = true;
toggle() {
this.isOpen = !this.isOpen;
}
// #enddocregion component
// #docregion events1, events
// #enddocregion component
// #docregion events1, events
onAnimationEvent(event: AnimationEvent) {
// #enddocregion events1, events
// #enddocregion events1, events
if (!this.logging) {
return;
}
// #docregion events
// #docregion events
// openClose is trigger name in this example
console.warn(`Animation Trigger: ${event.triggerName}`);
@@ -102,8 +92,8 @@ export class OpenCloseComponent {
// the HTML element itself, the button in this case
console.warn(`Element: ${event.element}`);
// #docregion events1
// #docregion events1
}
// #docregion component
// #docregion component
}
// #enddocregion component
@@ -1,6 +1,4 @@
import {
Component,
} from '@angular/core';
import {Component} from '@angular/core';
import {
trigger,
style,
@@ -9,11 +7,11 @@ import {
group,
query,
animateChild,
keyframes
keyframes,
} from '@angular/animations';
import { HEROES } from './mock-heroes';
import { NgIf } from '@angular/common';
import {HEROES} from './mock-heroes';
import {NgIf} from '@angular/common';
@Component({
standalone: true,
@@ -41,44 +39,50 @@ import { NgIf } from '@angular/common';
animations: [
trigger('query', [
transition(':enter', [
style({ height: 0 }),
style({height: 0}),
group([
animate(500, style({ height: '*' })),
animate(500, style({height: '*'})),
query(':enter', [
style({ opacity: 0, transform: 'scale(0)'}),
animate(2000, style({ opacity: 1, transform: 'scale(1)' }))
style({opacity: 0, transform: 'scale(0)'}),
animate(2000, style({opacity: 1, transform: 'scale(1)'})),
]),
query('.hero', [
style({ transform: 'translateX(-100%)'}),
animate('.7s 500ms ease-in', style({ transform: 'translateX(0)' }))
style({transform: 'translateX(-100%)'}),
animate('.7s 500ms ease-in', style({transform: 'translateX(0)'})),
]),
]),
query('@animateMe', animateChild()),
]),
transition(':leave', [
style({ height: '*' }),
style({height: '*'}),
query('@animateMe', animateChild()),
group([
animate('500ms 500ms', style({ height: '0', padding: '0' })),
animate('500ms 500ms', style({height: '0', padding: '0'})),
query(':leave', [
style({ opacity: 1, transform: 'scale(1)'}),
animate('1s', style({ opacity: 0, transform: 'scale(0)' }))
style({opacity: 1, transform: 'scale(1)'}),
animate('1s', style({opacity: 0, transform: 'scale(0)'})),
]),
query('.hero', [
style({ transform: 'translateX(0)'}),
animate('.7s ease-out', style({ transform: 'translateX(-100%)' }))
style({transform: 'translateX(0)'}),
animate('.7s ease-out', style({transform: 'translateX(-100%)'})),
]),
]),
]),
]),
trigger('animateMe', [
transition('* <=> *', animate('500ms cubic-bezier(.68,-0.73,.26,1.65)', keyframes([
style({ backgroundColor: 'transparent', color: '*', offset: 0 }),
style({ backgroundColor: 'blue', color: 'white', offset: 0.2 }),
style({ backgroundColor: 'transparent', color: '*', offset: 1 })
])))
transition(
'* <=> *',
animate(
'500ms cubic-bezier(.68,-0.73,.26,1.65)',
keyframes([
style({backgroundColor: 'transparent', color: '*', offset: 0}),
style({backgroundColor: 'blue', color: 'white', offset: 0.2}),
style({backgroundColor: 'transparent', color: '*', offset: 1}),
]),
),
),
]),
]
],
})
export class QueryingComponent {
toggleDisabled = false;
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { StatusSliderComponent } from './status-slider.component';
import {Component} from '@angular/core';
import {StatusSliderComponent} from './status-slider.component';
@Component({
standalone: true,
@@ -10,6 +10,6 @@ import { StatusSliderComponent } from './status-slider.component';
<app-status-slider></app-status-slider>
</section>
`,
imports: [StatusSliderComponent]
imports: [StatusSliderComponent],
})
export class StatusSliderPageComponent {}
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { trigger, transition, state, animate, style, keyframes } from '@angular/animations';
import {Component} from '@angular/core';
import {trigger, transition, state, animate, style, keyframes} from '@angular/animations';
@Component({
standalone: true,
@@ -8,37 +8,46 @@ import { trigger, transition, state, animate, style, keyframes } from '@angular/
styleUrls: ['status-slider.component.css'],
animations: [
trigger('slideStatus', [
state('inactive', style({ backgroundColor: 'blue' })),
state('active', style({ backgroundColor: '#754600' })),
state('inactive', style({backgroundColor: 'blue'})),
state('active', style({backgroundColor: '#754600'})),
// #docregion keyframesWithOffsets
// #docregion keyframesWithOffsets
transition('* => active', [
animate('2s', keyframes([
style({ backgroundColor: 'blue', offset: 0}),
style({ backgroundColor: 'red', offset: 0.8}),
style({ backgroundColor: '#754600', offset: 1.0})
])),
animate(
'2s',
keyframes([
style({backgroundColor: 'blue', offset: 0}),
style({backgroundColor: 'red', offset: 0.8}),
style({backgroundColor: '#754600', offset: 1.0}),
]),
),
]),
transition('* => inactive', [
animate('2s', keyframes([
style({ backgroundColor: '#754600', offset: 0}),
style({ backgroundColor: 'red', offset: 0.2}),
style({ backgroundColor: 'blue', offset: 1.0})
]))
animate(
'2s',
keyframes([
style({backgroundColor: '#754600', offset: 0}),
style({backgroundColor: 'red', offset: 0.2}),
style({backgroundColor: 'blue', offset: 1.0}),
]),
),
]),
// #enddocregion keyframesWithOffsets
// #enddocregion keyframesWithOffsets
// #docregion keyframes
// #docregion keyframes
transition('* => active', [
animate('2s', keyframes([
style({ backgroundColor: 'blue' }),
style({ backgroundColor: 'red' }),
style({ backgroundColor: 'orange' })
]))
// #enddocregion keyframes
animate(
'2s',
keyframes([
style({backgroundColor: 'blue'}),
style({backgroundColor: 'red'}),
style({backgroundColor: 'orange'}),
]),
),
// #enddocregion keyframes
]),
])
]
]),
],
})
export class StatusSliderComponent {
status: 'active' | 'inactive' = 'inactive';
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { OpenCloseChildComponent } from './open-close.component.4';
import {Component} from '@angular/core';
import {OpenCloseChildComponent} from './open-close.component.4';
@Component({
standalone: true,
@@ -11,6 +11,6 @@ import { OpenCloseChildComponent } from './open-close.component.4';
<app-open-close-toggle></app-open-close-toggle>
</section>
`,
imports: [OpenCloseChildComponent]
imports: [OpenCloseChildComponent],
})
export class ToggleAnimationsPageComponent {}
@@ -1,5 +1,5 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {appConfig} from './app/app.config';
bootstrapApplication(AppComponent, appConfig);
@@ -1,4 +1,4 @@
import { protractor, browser, element, by, ElementFinder } from 'protractor';
import {protractor, browser, element, by, ElementFinder} from 'protractor';
const nameSuffix = 'X';
@@ -8,7 +8,6 @@ interface Hero {
}
describe('Architecture', () => {
const expectedTitle = 'Architecture of Angular';
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
@@ -28,8 +27,7 @@ describe('Architecture', () => {
});
function heroTests() {
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
const targetHero: Hero = {id: 2, name: 'Dr Nice'};
it('has the right number of heroes', async () => {
const page = getPageElts();
@@ -80,7 +78,7 @@ function getPageElts() {
heroes: element.all(by.css('app-root li')),
heroDetail: element(by.css('app-root app-hero-detail')),
salesTaxAmountInput: element(by.css('app-root app-sales-tax input')),
salesTaxDetail: element(by.css('app-root app-sales-tax div'))
salesTaxDetail: element(by.css('app-root app-sales-tax div')),
};
}
@@ -1,5 +1,5 @@
// #docregion import
import { Component } from '@angular/core';
import {Component} from '@angular/core';
// #enddocregion import
@Component({
@@ -8,6 +8,6 @@ import { Component } from '@angular/core';
<h1>Architecture Example</h1>
<app-hero-list></app-hero-list>
<app-sales-tax></app-sales-tax>
`
`,
})
export class AppComponent { }
export class AppComponent {}
@@ -1,34 +1,22 @@
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
// #docregion imports
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
// #enddocregion imports
import { HeroDetailComponent } from './hero-detail.component';
import { HeroListComponent } from './hero-list.component';
import { SalesTaxComponent } from './sales-tax.component';
import { HeroService } from './hero.service';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroListComponent} from './hero-list.component';
import {SalesTaxComponent} from './sales-tax.component';
import {HeroService} from './hero.service';
import {BackendService} from './backend.service';
import {Logger} from './logger.service';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
HeroDetailComponent,
HeroListComponent,
SalesTaxComponent
],
providers: [
BackendService,
HeroService,
Logger
],
bootstrap: [ AppComponent ]
imports: [BrowserModule, FormsModule],
declarations: [AppComponent, HeroDetailComponent, HeroListComponent, SalesTaxComponent],
providers: [BackendService, HeroService, Logger],
bootstrap: [AppComponent],
})
// #docregion export
export class AppModule { }
export class AppModule {}
// #enddocregion export
@@ -1,13 +1,13 @@
import { Injectable, Type } from '@angular/core';
import {Injectable, Type} from '@angular/core';
import { Logger } from './logger.service';
import { Hero } from './hero';
import {Logger} from './logger.service';
import {Hero} from './hero';
const HEROES = [
new Hero('Windstorm', 'Weather mastery'),
new Hero('Dr Nice', 'Killing them with kindness'),
new Hero('Magneta', 'Manipulates metallic objects')
];
new Hero('Windstorm', 'Weather mastery'),
new Hero('Dr Nice', 'Killing them with kindness'),
new Hero('Magneta', 'Manipulates metallic objects'),
];
@Injectable()
export class BackendService {
@@ -1,10 +1,10 @@
import { Component, Input } from '@angular/core';
import {Component, Input} from '@angular/core';
import { Hero } from './hero';
import {Hero} from './hero';
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html'
templateUrl: './hero-detail.component.html',
})
export class HeroDetailComponent {
@Input() hero!: Hero;
@@ -1,13 +1,13 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit} from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import {Hero} from './hero';
import {HeroService} from './hero.service';
// #docregion metadata, providers
@Component({
selector: 'app-hero-list',
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
providers: [HeroService],
})
// #enddocregion providers
// #docregion class
@@ -17,13 +17,15 @@ export class HeroListComponent implements OnInit {
selectedHero: Hero | undefined;
// #docregion ctor
constructor(private service: HeroService) { }
constructor(private service: HeroService) {}
// #enddocregion ctor
ngOnInit() {
this.heroes = this.service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
selectHero(hero: Hero) {
this.selectedHero = hero;
}
// #docregion metadata
}
@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import { Hero } from './hero';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
import {Hero} from './hero';
import {BackendService} from './backend.service';
import {Logger} from './logger.service';
@Injectable()
// #docregion class
@@ -11,10 +11,11 @@ export class HeroService {
constructor(
private backend: BackendService,
private logger: Logger) { }
private logger: Logger,
) {}
getHeroes() {
this.backend.getAll(Hero).then( (heroes: Hero[]) => {
this.backend.getAll(Hero).then((heroes: Hero[]) => {
this.logger.log(`Fetched ${heroes.length} heroes.`);
this.heroes.push(...heroes); // fill cache
});
@@ -4,7 +4,8 @@ export class Hero {
id: number;
constructor(
public name: string,
public power?: string) {
this.id = nextId++;
}
public power?: string,
) {
this.id = nextId++;
}
}
@@ -1,9 +1,15 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
@Injectable()
// #docregion class
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
log(msg: any) {
console.log(msg);
}
error(msg: any) {
console.error(msg);
}
warn(msg: any) {
console.warn(msg);
}
}
@@ -1,17 +1,19 @@
// #docplaster
// A mini-application
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
@Injectable()
export class Logger {
log(message: string) { console.log(message); }
log(message: string) {
console.log(message);
}
}
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
template: 'Welcome to Angular'
selector: 'app-root',
template: 'Welcome to Angular',
})
export class AppComponent {
constructor(logger: Logger) {
@@ -20,22 +22,22 @@ export class AppComponent {
}
// #docregion module
import { NgModule } from '@angular/core';
import {NgModule} from '@angular/core';
// #docregion import-browser-module
import { BrowserModule } from '@angular/platform-browser';
import {BrowserModule} from '@angular/platform-browser';
// #enddocregion import-browser-module
@NgModule({
// #docregion ngmodule-imports
imports: [ BrowserModule ],
// #enddocregion ngmodule-imports
providers: [ Logger ],
declarations: [ AppComponent ],
exports: [ AppComponent ],
bootstrap: [ AppComponent ]
// #docregion ngmodule-imports
imports: [BrowserModule],
// #enddocregion ngmodule-imports
providers: [Logger],
declarations: [AppComponent],
exports: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}
// #enddocregion module
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
platformBrowserDynamic().bootstrapModule(AppModule);
@@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
import { SalesTaxService } from './sales-tax.service';
import { TaxRateService } from './tax-rate.service';
import {SalesTaxService} from './sales-tax.service';
import {TaxRateService} from './tax-rate.service';
@Component({
selector: 'app-sales-tax',
selector: 'app-sales-tax',
template: `
<h2>Sales Tax Calculator</h2>
<p><em>Enter a number and press enter to calculate tax.</em></p>
@@ -15,10 +15,10 @@ import { TaxRateService } from './tax-rate.service';
{{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }}</p>
</div>
`,
providers: [SalesTaxService, TaxRateService]
providers: [SalesTaxService, TaxRateService],
})
export class SalesTaxComponent {
constructor(private salesTaxService: SalesTaxService) { }
constructor(private salesTaxService: SalesTaxService) {}
getTax(value: string | number) {
return this.salesTaxService.getVAT(value);
@@ -1,14 +1,13 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import { TaxRateService } from './tax-rate.service';
import {TaxRateService} from './tax-rate.service';
@Injectable()
export class SalesTaxService {
constructor(private rateService: TaxRateService) { }
constructor(private rateService: TaxRateService) {}
getVAT(value: string | number) {
const amount = (typeof value === 'string') ?
parseFloat(value) : value;
const amount = typeof value === 'string' ? parseFloat(value) : value;
return (amount || 0) * this.rateService.getRate('VAT');
}
}
@@ -1,6 +1,8 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
@Injectable()
export class TaxRateService {
getRate(rateName: string) { return 0.10; } // 10% everywhere
getRate(rateName: string) {
return 0.1;
} // 10% everywhere
}
@@ -1,7 +1,8 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import {AppModule} from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
@@ -1,7 +1,6 @@
import { browser, element, by } from 'protractor';
import {browser, element, by} from 'protractor';
describe('Attribute binding example', () => {
beforeEach(() => browser.get(''));
it('should display Property Binding with Angular', async () => {
@@ -13,7 +12,9 @@ describe('Attribute binding example', () => {
});
it('should display an Aria button', async () => {
expect(await element.all(by.css('button')).get(0).getText()).toBe('Create and set an attribute with Aria');
expect(await element.all(by.css('button')).get(0).getText()).toBe(
'Create and set an attribute with Aria',
);
});
it('should display a black background on div', async () => {
@@ -31,5 +32,4 @@ describe('Attribute binding example', () => {
expect(await div.getAttribute('class')).toContain('special');
expect(await div.getAttribute('class')).toContain('clearance');
});
});
@@ -1,4 +1,4 @@
import { Component } from "@angular/core";
import {Component} from '@angular/core';
@Component({
standalone: true,
@@ -1,7 +1,6 @@
import { browser, element, by } from 'protractor';
import {browser, element, by} from 'protractor';
describe('Attribute directives', () => {
const title = 'My First Attribute Directive';
beforeAll(() => browser.get(''));
@@ -23,6 +22,6 @@ describe('Attribute directives', () => {
// Wait for up to 4s for the background color to be updated,
// to account for slow environments (e.g. CI).
await browser.wait(async () => await getBgColor() === lightGreen, 4000);
await browser.wait(async () => (await getBgColor()) === lightGreen, 4000);
});
});
@@ -1,5 +1,5 @@
import {Component} from '@angular/core';
import { HighlightDirective } from './highlight.directive';
import {HighlightDirective} from './highlight.directive';
@Component({
standalone: true,
@@ -1,19 +1,16 @@
import { browser, element, by } from 'protractor';
import { logging } from 'selenium-webdriver';
import {browser, element, by} from 'protractor';
import {logging} from 'selenium-webdriver';
describe('Binding syntax e2e tests', () => {
beforeEach(() => browser.get(''));
// helper function used to test what's logged to the console
async function logChecker(contents: string) {
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const messages = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
const messages = logs.filter(({message}) => (message.indexOf(contents) !== -1 ? true : false));
expect(messages.length).toBeGreaterThan(0);
}
it('should display Binding syntax', async () => {
expect(await element(by.css('h1')).getText()).toEqual('Binding syntax');
});
@@ -23,7 +20,9 @@ describe('Binding syntax e2e tests', () => {
});
it('should display HTML attributes and DOM properties', async () => {
expect(await element.all(by.css('h2')).get(1).getText()).toBe('HTML attributes and DOM properties');
expect(await element.all(by.css('h2')).get(1).getText()).toBe(
'HTML attributes and DOM properties',
);
});
it('should display 1. Use the inspector...', async () => {
@@ -31,10 +30,11 @@ describe('Binding syntax e2e tests', () => {
});
it('should display Disabled property vs. attribute', async () => {
expect(await element.all(by.css('h3')).get(0).getText()).toBe('Disabled property vs. attribute');
expect(await element.all(by.css('h3')).get(0).getText()).toBe(
'Disabled property vs. attribute',
);
});
it('should log a message including Sarah', async () => {
const attributeButton = element.all(by.css('button')).get(1);
await attributeButton.click();
@@ -1,4 +1,4 @@
import { AppPage } from './app.po';
import {AppPage} from './app.po';
describe('feature-modules App', () => {
let page: AppPage;
@@ -1,9 +1,9 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'app works!';
@@ -1,32 +1,24 @@
// #docplaster
// imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import { AppComponent } from './app.component';
import {AppComponent} from './app.component';
// #docregion directive-import
import { ItemDirective } from './item.directive';
import {ItemDirective} from './item.directive';
// #enddocregion directive-import
// @NgModule decorator with its metadata
@NgModule({
// #docregion declarations
declarations: [
AppComponent,
ItemDirective
],
// #docregion declarations
declarations: [AppComponent, ItemDirective],
// #enddocregion declarations
// #docregion imports
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
imports: [BrowserModule, FormsModule, HttpClientModule],
// #enddocregion imports
providers: [],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}
@@ -1,15 +1,13 @@
// #docplaster
// #docregion directive
import { Directive } from '@angular/core';
import {Directive} from '@angular/core';
@Directive({
selector: '[appItem]'
selector: '[appItem]',
})
export class ItemDirective {
// code goes here
constructor() { }
// code goes here
constructor() {}
}
// #enddocregion directive
@@ -1,6 +1,7 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import {AppModule} from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
@@ -1,7 +1,6 @@
import { browser, element, by } from 'protractor';
import {browser, element, by} from 'protractor';
describe('Built-in Directives', () => {
beforeAll(() => browser.get(''));
it('should have title Built-in Directives', async () => {
@@ -18,7 +17,6 @@ describe('Built-in Directives', () => {
expect(await firstLabel.getText()).toEqual('Current item name: Teapotabc');
});
it('should modify sentence when modified checkbox checked', async () => {
const modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
const modifiedSentence = element.all(by.css('div')).get(1);
@@ -68,6 +66,4 @@ describe('Built-in Directives', () => {
await fishbowlRadioButton.click();
expect(await fishbowlDiv.getText()).toContain('mysterious');
});
});
@@ -2,25 +2,20 @@ export class Item {
static nextId = 0;
static items: Item[] = [
new Item(
0,
'Teapot',
'stout'
),
new Item(0, 'Teapot', 'stout'),
new Item(1, 'Lamp', 'bright'),
new Item(2, 'Phone', 'slim' ),
new Item(3, 'Television', 'vintage' ),
new Item(4, 'Fishbowl')
new Item(2, 'Phone', 'slim'),
new Item(3, 'Television', 'vintage'),
new Item(4, 'Fishbowl'),
];
constructor(
public id: number,
public name?: string,
public feature?: string,
public url?: string,
public rate = 100,
) {
) {
this.id = id ? id : Item.nextId++;
}
@@ -1,4 +1,4 @@
import { browser, element, by } from 'protractor';
import {browser, element, by} from 'protractor';
describe('Built Template Functions Example', () => {
beforeAll(() => browser.get(''));
@@ -12,5 +12,4 @@ describe('Built Template Functions Example', () => {
const header = element(by.css('h2'));
expect(await header.getText()).toContain('$any( )');
});
});
@@ -1,9 +1,9 @@
// #docregion
import { Architect } from '@angular-devkit/architect';
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
import { schema } from '@angular-devkit/core';
import { promises as fs } from 'fs';
import { join } from 'path';
import {Architect} from '@angular-devkit/architect';
import {TestingArchitectHost} from '@angular-devkit/architect/testing';
import {schema} from '@angular-devkit/core';
import {promises as fs} from 'fs';
import {join} from 'path';
describe('Copy File Builder', () => {
let architect: Architect;
@@ -1,9 +1,9 @@
// #docplaster
// #docregion builder, builder-skeleton
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import {BuilderContext, BuilderOutput, createBuilder} from '@angular-devkit/architect';
import {JsonObject} from '@angular-devkit/core';
// #enddocregion builder-skeleton
import { promises as fs } from 'fs';
import {promises as fs} from 'fs';
// #docregion builder-skeleton
interface Options extends JsonObject {
@@ -13,10 +13,7 @@ interface Options extends JsonObject {
export default createBuilder(copyFileBuilder);
async function copyFileBuilder(
options: Options,
context: BuilderContext,
): Promise<BuilderOutput> {
async function copyFileBuilder(options: Options, context: BuilderContext): Promise<BuilderOutput> {
// #enddocregion builder, builder-skeleton
// #docregion progress-reporting
context.reportStatus(`Copying ${options.source} to ${options.destination}.`);
@@ -38,7 +35,7 @@ async function copyFileBuilder(
context.reportStatus('Done.');
// #docregion builder
return { success: true };
return {success: true};
// #enddocregion progress-reporting
// #docregion builder-skeleton
}
@@ -1,7 +1,6 @@
import { browser, by, element } from 'protractor';
import {browser, by, element} from 'protractor';
describe('Component Communication Cookbook Tests', () => {
beforeEach(() => browser.get(browser.baseUrl));
describe('Parent-to-child communication', () => {
@@ -101,7 +100,7 @@ describe('Component Communication Cookbook Tests', () => {
async function getActual() {
const versionTag = element(by.tagName('app-version-child'));
const label = await versionTag.element(by.tagName('h3')).getText();
const ul = versionTag.element((by.tagName('ul')));
const ul = versionTag.element(by.tagName('ul'));
const logs = ul.all(by.tagName('li'));
return {
@@ -124,8 +123,11 @@ describe('Component Communication Cookbook Tests', () => {
it('should process Agree vote', async () => {
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
const agreeButton1 = element.all(by.tagName('app-voter')).get(0)
.all(by.tagName('button')).get(0);
const agreeButton1 = element
.all(by.tagName('app-voter'))
.get(0)
.all(by.tagName('button'))
.get(0);
await agreeButton1.click();
@@ -134,8 +136,11 @@ describe('Component Communication Cookbook Tests', () => {
it('should process Disagree vote', async () => {
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
const agreeButton1 = element.all(by.tagName('app-voter')).get(1)
.all(by.tagName('button')).get(1);
const agreeButton1 = element
.all(by.tagName('app-voter'))
.get(1)
.all(by.tagName('button'))
.get(1);
await agreeButton1.click();
@@ -235,5 +240,4 @@ describe('Component Communication Cookbook Tests', () => {
// ...
// #enddocregion bidirectional-service
});
});
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
templateUrl: './app.component.html',
})
export class AppComponent { }
export class AppComponent {}
@@ -1,25 +1,25 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AstronautComponent } from './astronaut.component';
import { CountdownLocalVarParentComponent, CountdownViewChildParentComponent } from './countdown-parent.component';
import { CountdownTimerComponent } from './countdown-timer.component';
import { HeroChildComponent } from './hero-child.component';
import { HeroParentComponent } from './hero-parent.component';
import { MissionControlComponent } from './missioncontrol.component';
import { NameChildComponent } from './name-child.component';
import { NameParentComponent } from './name-parent.component';
import { VersionChildComponent } from './version-child.component';
import { VersionParentComponent } from './version-parent.component';
import { VoterComponent } from './voter.component';
import { VoteTakerComponent } from './votetaker.component';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
import {AstronautComponent} from './astronaut.component';
import {
CountdownLocalVarParentComponent,
CountdownViewChildParentComponent,
} from './countdown-parent.component';
import {CountdownTimerComponent} from './countdown-timer.component';
import {HeroChildComponent} from './hero-child.component';
import {HeroParentComponent} from './hero-parent.component';
import {MissionControlComponent} from './missioncontrol.component';
import {NameChildComponent} from './name-child.component';
import {NameParentComponent} from './name-parent.component';
import {VersionChildComponent} from './version-child.component';
import {VersionParentComponent} from './version-parent.component';
import {VoterComponent} from './voter.component';
import {VoteTakerComponent} from './votetaker.component';
@NgModule({
imports: [
BrowserModule,
],
imports: [BrowserModule],
declarations: [
AppComponent,
AstronautComponent,
@@ -36,6 +36,6 @@ import { VoteTakerComponent } from './votetaker.component';
VoterComponent,
VoteTakerComponent,
],
bootstrap: [ AppComponent ],
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}
@@ -1,8 +1,8 @@
// #docregion
import { Component, Input, OnDestroy } from '@angular/core';
import {Component, Input, OnDestroy} from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs';
import {MissionService} from './mission.service';
import {Subscription} from 'rxjs';
@Component({
selector: 'app-astronaut',
@@ -16,7 +16,7 @@ import { Subscription } from 'rxjs';
Confirm
</button>
</p>
`
`,
})
export class AstronautComponent implements OnDestroy {
@Input() astronaut = '';
@@ -26,11 +26,10 @@ export class AstronautComponent implements OnDestroy {
subscription: Subscription;
constructor(private missionService: MissionService) {
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
this.subscription = missionService.missionAnnounced$.subscribe((mission) => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
});
}
@@ -1,9 +1,9 @@
// #docplaster
// #docregion vc
import { AfterViewInit, ViewChild } from '@angular/core';
import {AfterViewInit, ViewChild} from '@angular/core';
// #docregion lv
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
import {Component} from '@angular/core';
import {CountdownTimerComponent} from './countdown-timer.component';
// #enddocregion lv
// #enddocregion vc
@@ -19,9 +19,9 @@ import { CountdownTimerComponent } from './countdown-timer.component';
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
`,
styleUrls: ['../assets/demo.css']
styleUrls: ['../assets/demo.css'],
})
export class CountdownLocalVarParentComponent { }
export class CountdownLocalVarParentComponent {}
// #enddocregion lv
//// View Child version
@@ -35,23 +35,28 @@ export class CountdownLocalVarParentComponent { }
<div class="seconds">{{ seconds() }}</div>
<app-countdown-timer></app-countdown-timer>
`,
styleUrls: ['../assets/demo.css']
styleUrls: ['../assets/demo.css'],
})
export class CountdownViewChildParentComponent implements AfterViewInit {
@ViewChild(CountdownTimerComponent)
private timerComponent!: CountdownTimerComponent;
seconds() { return 0; }
seconds() {
return 0;
}
ngAfterViewInit() {
// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...
// but wait a tick first to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
setTimeout(() => (this.seconds = () => this.timerComponent.seconds), 0);
}
start() { this.timerComponent.start(); }
stop() { this.timerComponent.stop(); }
start() {
this.timerComponent.start();
}
stop() {
this.timerComponent.stop();
}
}
// #enddocregion vc
@@ -1,18 +1,22 @@
// #docregion
import { Component, OnDestroy } from '@angular/core';
import {Component, OnDestroy} from '@angular/core';
@Component({
selector: 'app-countdown-timer',
template: '<p>{{message}}</p>'
template: '<p>{{message}}</p>',
})
export class CountdownTimerComponent implements OnDestroy {
message = '';
seconds = 11;
ngOnDestroy() { this.clearTimer?.(); }
ngOnDestroy() {
this.clearTimer?.();
}
start() { this.countDown(); }
stop() {
start() {
this.countDown();
}
stop() {
this.clearTimer?.();
this.message = `Holding at T-${this.seconds} seconds`;
}
@@ -26,7 +30,9 @@ export class CountdownTimerComponent implements OnDestroy {
if (this.seconds === 0) {
this.message = 'Blast off!';
} else {
if (this.seconds < 0) { this.seconds = 10; } // reset
if (this.seconds < 0) {
this.seconds = 10;
} // reset
this.message = `T-${this.seconds} seconds and counting`;
}
}, 1000);

Some files were not shown because too many files have changed in this diff Show More