diff --git a/adev-es/src/app/core/constants/links.ts b/adev-es/src/app/core/constants/links.ts new file mode 100644 index 0000000..0dd19ee --- /dev/null +++ b/adev-es/src/app/core/constants/links.ts @@ -0,0 +1,5 @@ +export const GITHUB = 'https://github.com/angular-hispano/angular-docs-es'; +export const X = 'https://x.com/AngularHispana'; +export const DISCORD = 'https://discord.com/invite/4cWb6SKUcb'; +export const MEDIUM = ''; +export const YOUTUBE = ''; \ No newline at end of file diff --git a/adev-es/src/app/core/layout/footer/footer.component.html b/adev-es/src/app/core/layout/footer/footer.component.html new file mode 100644 index 0000000..1fa7444 --- /dev/null +++ b/adev-es/src/app/core/layout/footer/footer.component.html @@ -0,0 +1,71 @@ + + \ No newline at end of file diff --git a/adev-es/src/app/core/layout/footer/footer.component.ts b/adev-es/src/app/core/layout/footer/footer.component.ts new file mode 100644 index 0000000..80379a1 --- /dev/null +++ b/adev-es/src/app/core/layout/footer/footer.component.ts @@ -0,0 +1,19 @@ +import {CommonModule} from '@angular/common'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {ExternalLink} from '@angular/docs'; +import {RouterLink} from '@angular/router'; +import {DISCORD, GITHUB, X} from './../../constants/links'; + +@Component({ + selector: 'footer[adev-footer]', + standalone: true, + imports: [CommonModule, ExternalLink, RouterLink], + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class Footer { + readonly GITHUB = GITHUB; + readonly X = X; + readonly DISCORD = DISCORD; +} diff --git a/adev-es/src/app/core/layout/navigation/navigation.component.html b/adev-es/src/app/core/layout/navigation/navigation.component.html new file mode 100644 index 0000000..73f5c45 --- /dev/null +++ b/adev-es/src/app/core/layout/navigation/navigation.component.html @@ -0,0 +1,397 @@ + +
+ +
+ + +
+ + + + + @if (activeRouteItem() === DOCS_ROUTE || activeRouteItem() === REFERENCE_ROUTE) { +
+ +
+ } +
diff --git a/adev-es/src/app/features/home/home.component.html b/adev-es/src/app/features/home/home.component.html new file mode 100644 index 0000000..a71f8c8 --- /dev/null +++ b/adev-es/src/app/features/home/home.component.html @@ -0,0 +1,153 @@ +
+
+
+ +
+
+
+ +
+
+
+
+

Trabaja a cualquier escala

+

+ Angular te permite empezar poco a poco en un camino bien iluminado y + te apoya a medida que tu equipo y tus aplicaciones crecen. +

+
+
+
+
+
+
+
+
+

Amado por millones

+

+ Únete a los millones de desarrolladores de todo el mundo que + construyen con Angular en una comunidad próspera y amigable. +

+
+
+
+
+
+
+
+
+

+ Construir para todos + +

+

+ Confía en el soporte integrado de hidratación, internacionalización, + seguridad y accesibilidad de Angular para construir para todos en + todo el mundo. +

+
+
+
+ +
+
+
+
+ @defer (on viewport(buildForEveryone); prefetch on + viewport(lovedByMillions)) { + + } @loading { + Code editor + } +
+
+
+ + + +
diff --git a/adev-es/src/app/sub-navigation-data.ts b/adev-es/src/app/sub-navigation-data.ts index ed93a1f..b75a150 100644 --- a/adev-es/src/app/sub-navigation-data.ts +++ b/adev-es/src/app/sub-navigation-data.ts @@ -8,6 +8,7 @@ import {NavigationItem} from '@angular/docs'; +// These 2 imports are expected to be red because they are generated a build time import FIRST_APP_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/first-app/routes.json'; import LEARN_ANGULAR_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/learn-angular/routes.json'; @@ -639,6 +640,12 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ }, ], }, + { + label: 'Experimental features', + children: [ + {label: 'Zoneless', path: 'guide/experimental/zoneless', contentPath: 'guide/zoneless'}, + ], + }, ], }, { @@ -678,9 +685,9 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ contentPath: 'tools/cli/end-to-end', }, { - label: 'ESBuild', - path: 'tools/cli/esbuild', - contentPath: 'tools/cli/esbuild', + label: 'Migrating to new build system', + path: 'tools/cli/build-system-migration', + contentPath: 'tools/cli/build-system-migration', }, { label: 'Build environments', @@ -931,7 +938,28 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ }, { label: 'ng analytics', - path: 'cli/analytics', + children: [ + { + label: 'Overview', + path: 'cli/analytics', + }, + { + label: 'disable', + path: 'cli/analytics/disable', + }, + { + label: 'enable', + path: 'cli/analytics/enable', + }, + { + label: 'info', + path: 'cli/analytics/info', + }, + { + label: 'prompt', + path: 'cli/analytics/prompt', + }, + ], }, { label: 'ng build', @@ -939,11 +967,41 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ }, { label: 'ng cache', - path: 'cli/cache', + children: [ + { + label: 'Overview', + path: 'cli/cache', + }, + { + label: 'clear', + path: 'cli/cache/clean', + }, + { + label: 'disable', + path: 'cli/cache/disable', + }, + { + label: 'enable', + path: 'cli/cache/enable', + }, + { + label: 'info', + path: 'cli/cache/info', + }, + ], }, { label: 'ng completion', - path: 'cli/completion', + children: [ + { + label: 'Overview', + path: 'cli/completion', + }, + { + label: 'script', + path: 'cli/completion/script', + }, + ], }, { label: 'ng config', @@ -953,10 +1011,6 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ label: 'ng deploy', path: 'cli/deploy', }, - { - label: 'ng doc', - path: 'cli/doc', - }, { label: 'ng e2e', path: 'cli/e2e', @@ -967,7 +1021,80 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ }, { label: 'ng generate', - path: 'cli/generate', + children: [ + { + label: 'Overview', + path: 'cli/generate', + }, + { + label: 'app-shell', + path: 'cli/generate/app-shell', + }, + { + label: 'application', + path: 'cli/generate/application', + }, + { + label: 'class', + path: 'cli/generate/class', + }, + { + label: 'component', + path: 'cli/generate/component', + }, + { + label: 'config', + path: 'cli/generate/config', + }, + { + label: 'enum', + path: 'cli/generate/enum', + }, + { + label: 'environments', + path: 'cli/generate/environments', + }, + { + label: 'guard', + path: 'cli/generate/guard', + }, + { + label: 'interceptor', + path: 'cli/generate/interceptor', + }, + { + label: 'interface', + path: 'cli/generate/interface', + }, + { + label: 'library', + path: 'cli/generate/library', + }, + { + label: 'module', + path: 'cli/generate/module', + }, + { + label: 'pipe', + path: 'cli/generate/pipe', + }, + { + label: 'resolver', + path: 'cli/generate/resolver', + }, + { + label: 'service-worker', + path: 'cli/generate/service-worker', + }, + { + label: 'service', + path: 'cli/generate/service', + }, + { + label: 'web-worker', + path: 'cli/generate/web-worker', + }, + ], }, { label: 'ng lint', @@ -1112,6 +1239,11 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'errors/NG0507', contentPath: 'reference/errors/NG0507', }, + { + label: 'NG0602: HTML content was altered after server-side rendering', + path: 'errors/NG0602', + contentPath: 'reference/errors/NG0602', + }, { label: 'NG05104: Root element was not found', path: 'errors/NG05104', @@ -1127,6 +1259,26 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'errors/NG0912', contentPath: 'reference/errors/NG0912', }, + { + label: 'NG0950: Required input is accessed before a value is set.', + path: 'errors/NG0950', + contentPath: 'reference/errors/NG0950', + }, + { + label: 'NG0951: Child query result is required but no value is available.', + path: 'errors/NG0951', + contentPath: 'reference/errors/NG0951', + }, + { + label: 'NG0955: Track expression resulted in duplicated keys for a given collection', + path: 'errors/NG0955', + contentPath: 'reference/errors/NG0955', + }, + { + label: 'NG0956: Tracking expression caused re-creation of the DOM structure', + path: 'errors/NG0956', + contentPath: 'reference/errors/NG0956', + }, { label: 'NG1001: Argument Not Literal', path: 'errors/NG1001', @@ -1148,9 +1300,9 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ contentPath: 'reference/errors/NG3003', }, { - label: 'NG5000: Hydration with unsupported Zone.js instance.', - path: 'errors/NG5000', - contentPath: 'reference/errors/NG5000', + label: 'NG05000: Hydration with unsupported Zone.js instance.', + path: 'errors/NG05000', + contentPath: 'reference/errors/NG05000', }, { label: 'NG6100: NgModule.id Set to module.id anti-pattern', @@ -1239,6 +1391,10 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'reference/versions', contentPath: 'reference/versions', }, + { + label: 'Update guide', + path: 'update-guide', + }, { label: 'Configurations', children: [ diff --git a/adev-es/src/content/best-practices/a11y.md b/adev-es/src/content/best-practices/a11y.md index 7d030c2..ac68f5d 100644 --- a/adev-es/src/content/best-practices/a11y.md +++ b/adev-es/src/content/best-practices/a11y.md @@ -76,15 +76,15 @@ The following example shows how to make a progress bar accessible by using host The ARIA attribute `aria-valuenow` is bound to the user's input. * In the template, the `aria-label` attribute ensures that the control is accessible to screen readers. - + diff --git a/adev-es/src/content/best-practices/runtime-performance/skipping-subtrees.md b/adev-es/src/content/best-practices/runtime-performance/skipping-subtrees.md index 37a2eda..86e608f 100644 --- a/adev-es/src/content/best-practices/runtime-performance/skipping-subtrees.md +++ b/adev-es/src/content/best-practices/runtime-performance/skipping-subtrees.md @@ -59,8 +59,6 @@ If Angular handles an event within a component with OnPush strategy, the framewo As an example, if Angular handles an event within `MainComponent`, the framework will run change detection in the entire component tree. Angular will ignore the subtree with root `LoginComponent` because it has `OnPush` and the event happened outside of its scope. -Change detection propagation from OnPush component - ```mermaid graph TD; app[AppComponent] --- header[HeaderComponent]; diff --git a/adev-es/src/content/best-practices/runtime-performance/slow-computations.md b/adev-es/src/content/best-practices/runtime-performance/slow-computations.md index e079717..38f8aab 100644 --- a/adev-es/src/content/best-practices/runtime-performance/slow-computations.md +++ b/adev-es/src/content/best-practices/runtime-performance/slow-computations.md @@ -19,7 +19,7 @@ For example, in the preceding screenshot, the second recorded change detection c Here are several techniques to remove slow computations: * **Optimizing the underlying algorithm**. This is the recommended approach. If you can speed up the algorithm that is causing the problem, you can speed up the entire change detection mechanism. -* **Caching using pure pipes**. You can move the heavy computation to a pure [pipe](/guide/pipes). Angular reevaluates a pure pipe only if it detects that its inputs have changed, compared to the previous time Angular called it. +* **Caching using pure pipes**. You can move the heavy computation to a pure [pipe](guide/pipes). Angular reevaluates a pure pipe only if it detects that its inputs have changed, compared to the previous time Angular called it. * **Using memoization**. [Memoization](https://en.wikipedia.org/wiki/Memoization) is a similar technique to pure pipes, with the difference that pure pipes preserve only the last result from the computation where memoization could store multiple results. * **Avoid repaints/reflows in lifecycle hooks**. Certain [operations](https://web.dev/avoid-large-complex-layouts-and-layout-thrashing/) cause the browser to either synchronously recalculate the layout of the page or re-render it. Since reflows and repaints are generally slow, you want to avoid performing them in every change detection cycle. diff --git a/adev-es/src/content/best-practices/runtime-performance/zone-pollution.md b/adev-es/src/content/best-practices/runtime-performance/zone-pollution.md index 8e7326d..27b22fc 100644 --- a/adev-es/src/content/best-practices/runtime-performance/zone-pollution.md +++ b/adev-es/src/content/best-practices/runtime-performance/zone-pollution.md @@ -35,7 +35,7 @@ class AppComponent implements OnInit { The preceding snippet instructs Angular to call `setInterval` outside the Angular Zone and skip running change detection after `pollForUpdates` runs. -Third-party libraries commonly trigger unnecessary change detection cycles because they weren't authored with Zone.js in mind. Avoid these extra cycles by calling library APIs outside the Angular zone: +Third-party libraries commonly trigger unnecessary change detection cycles when their APIs are invoked within the Angular zone. This phenomenon particularly affects libraries that setup event listeners or initiate other tasks (such as timers, XHR requests, etc.). Avoid these extra cycles by calling library APIs outside the Angular zone: import { Component, NgZone, OnInit } from '@angular/core'; @@ -57,3 +57,67 @@ class AppComponent implements OnInit { Running `Plotly.newPlot('chart', data);` within `runOutsideAngular` instructs the framework that it shouldn’t run change detection after the execution of tasks scheduled by the initialization logic. For example, if `Plotly.newPlot('chart', data)` adds event listeners to a DOM element, Angular does not run change detection after the execution of their handlers. + +But sometimes, you may need to listen to events dispatched by third-party APIs. In such cases, it's important to remember that those event listeners will also execute outside of the Angular zone if the initialization logic was done there: + + +import { Component, NgZone, OnInit, output } from '@angular/core'; +import * as Plotly from 'plotly.js-dist-min'; + +@Component(...) +class AppComponent implements OnInit { + plotlyClick = output(); + + constructor(private ngZone: NgZone) {} + + ngOnInit() { + this.ngZone.runOutsideAngular(() => { + this.createPlotly(); + }); + } + + private async createPlotly() { + const plotly = await Plotly.newPlot('chart', data); + + plotly.on('plotly_click', (event: Plotly.PlotMouseEvent) => { + // This handler will be called outside of the Angular zone because + // the initialization logic is also called outside of the zone. To check + // whether we're in the Angular zone, we can call the following: + console.log(NgZone.isInAngularZone()); + this.plotlyClick.emit(event); + }); + } +} + + +If you need to dispatch events to parent components and execute specific view update logic, you should consider re-entering the Angular zone to instruct the framework to run change detection or run change detection manually: + + +import { Component, NgZone, OnInit, output } from '@angular/core'; +import * as Plotly from 'plotly.js-dist-min'; + +@Component(...) +class AppComponent implements OnInit { + plotlyClick = output(); + + constructor(private ngZone: NgZone) {} + + ngOnInit() { + this.ngZone.runOutsideAngular(() => { + this.createPlotly(); + }); + } + + private async createPlotly() { + const plotly = await Plotly.newPlot('chart', data); + + plotly.on('plotly_click', (event: Plotly.PlotMouseEvent) => { + this.ngZone.run(() => { + this.plotlyClick.emit(event); + }); + }); + } +} + + +The scenario of dispatching events outside of the Angular zone may also arise. It's important to remember that triggering change detection (for example, manually) may result to the creation/update of views outside of the Angular zone. \ No newline at end of file diff --git a/adev-es/src/content/best-practices/style-guide.md b/adev-es/src/content/best-practices/style-guide.md index ce209b4..28219b3 100644 --- a/adev-es/src/content/best-practices/style-guide.md +++ b/adev-es/src/content/best-practices/style-guide.md @@ -730,7 +730,7 @@ If the property is hard to construct a default value for, use `?` to explicitly You may want to have a required `@Input` field, meaning all your component users are required to pass that attribute. In such cases, use a default value. -Just suppressing the TypeScript error with `!` is insufficient and should be avoided because it will prevent the type checker ensure the input value is provided. +Just suppressing the TypeScript error with `!` is insufficient and should be avoided because it will prevent the type checker from ensuring the input value is provided. diff --git a/adev-es/src/content/best-practices/update.md b/adev-es/src/content/best-practices/update.md index 55db2f1..f4c8e4f 100644 --- a/adev-es/src/content/best-practices/update.md +++ b/adev-es/src/content/best-practices/update.md @@ -13,11 +13,11 @@ HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](ht ## Getting notified of new releases -To be notified when new releases are available, follow [@angular](https://twitter.com/angular "@angular on Twitter") on Twitter or subscribe to the [Angular blog](https://blog.angular.io "Angular blog"). +To be notified when new releases are available, follow [@angular](https://twitter.com/angular "@angular on Twitter") on Twitter or subscribe to the [Angular blog](https://blog.angular.dev "Angular blog"). ## Learning about new features -What's new? What's changed? We share the most important things you need to know on the Angular blog in [release announcements]( https://blog.angular.io/ "Angular blog - release announcements"). +What's new? What's changed? We share the most important things you need to know on the Angular blog in [release announcements]( https://blog.angular.dev/ "Angular blog - release announcements"). To review a complete list of changes, organized by version, see the [Angular change log](https://github.com/angular/angular/blob/main/CHANGELOG.md "Angular change log"). @@ -49,7 +49,7 @@ It also describes supported update paths. ## Resource summary * Release announcements: - [Angular blog - release announcements](https://blog.angular.io/ "Angular blog announcements about recent releases") + [Angular blog - release announcements](https://blog.angular.dev/ "Angular blog announcements about recent releases") * Release details: [Angular change log](https://github.com/angular/angular/blob/main/CHANGELOG.md "Angular change log") diff --git a/adev-es/src/content/ecosystem/service-workers/app-shell.md b/adev-es/src/content/ecosystem/service-workers/app-shell.md index 20c2384..c79e3a6 100644 --- a/adev-es/src/content/ecosystem/service-workers/app-shell.md +++ b/adev-es/src/content/ecosystem/service-workers/app-shell.md @@ -5,6 +5,8 @@ It can improve the user experience by quickly launching a static rendered page ( This gives users a meaningful first paint of your application that appears quickly because the browser can render the HTML and CSS without the need to initialize any JavaScript. +Learn more in [The App Shell Model](https://developers.google.com/web/fundamentals/architecture/app-shell). + Do this with the following Angular CLI command: @@ -15,7 +17,7 @@ ng new my-app --routing -For an existing application, you have to manually add the `RouterModule` and defining a `` within your application. +For an existing application, you have to manually add the `Router` and defining a `` within your application. Use the Angular CLI to automatically create the application shell. @@ -28,57 +30,24 @@ ng generate app-shell For more information about this command, see [App shell command](cli/generate#app-shell-command). -After running this command you can see that the `angular.json` configuration file has been updated to add two new targets, with a few other changes. - - - -"server": { - "builder": "@angular-devkit/build-angular:server", - "defaultConfiguration": "production", - "options": { - "outputPath": "dist/my-app/server", - "main": "src/main.server.ts", - "tsConfig": "tsconfig.server.json" - }, - "configurations": { - "development": { - "outputHashing": "none", - }, - "production": { - "outputHashing": "media", - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "sourceMap": false, - "optimization": true - } - } -}, -"app-shell": { - "builder": "@angular-devkit/build-angular:app-shell", - "defaultConfiguration": "production", - "options": { - "route": "shell" - }, - "configurations": { - "development": { - "browserTarget": "my-app:build:development", - "serverTarget": "my-app:server:development", - }, - "production": { - "browserTarget": "my-app:build:production", - "serverTarget": "my-app:server:production" - } - } -} +The command updates the application code and adds extra files to the project structure. + + + + src + ├── app + │ ├── app.config.server.ts # server application configuration + │ └── app-shell # app-shell component + │ ├── app-shell.component.html + │ ├── app-shell.component.scss + │ ├── app-shell.component.spec.ts + │ └── app-shell.component.ts + └── main.server.ts # main server application bootstrapping + + + - - -Use the Angular CLI to build the `app-shell` target. diff --git a/adev-es/src/content/guide/animations/complex-sequences.md b/adev-es/src/content/guide/animations/complex-sequences.md index 6eba081..1f5e452 100644 --- a/adev-es/src/content/guide/animations/complex-sequences.md +++ b/adev-es/src/content/guide/animations/complex-sequences.md @@ -120,7 +120,7 @@ If you need to animate the items of an `*ngFor` list and there is a possibility ## Animations and Component View Encapsulation -Angular animations are based on the components DOM structure and do not directly take [View Encapsulation](/guide/components/styling#style-scoping) into account, this means that components using `ViewEncapsulation.Emulated` behave exactly as if they were using `ViewEncapsulation.None` (`ViewEncapsulation.ShadowDom` behaves differently as we'll discuss shortly). +Angular animations are based on the components DOM structure and do not directly take [View Encapsulation](guide/components/styling#style-scoping) into account, this means that components using `ViewEncapsulation.Emulated` behave exactly as if they were using `ViewEncapsulation.None` (`ViewEncapsulation.ShadowDom` behaves differently as we'll discuss shortly). For example if the `query()` function (which you'll see more of in the rest of the Animations guide) were to be applied at the top of a tree of components using the emulated view encapsulation, such query would be able to identify (and thus animate) DOM elements on any depth of the tree. diff --git a/adev-es/src/content/guide/animations/overview.md b/adev-es/src/content/guide/animations/overview.md index 70cc93a..8ea7b23 100644 --- a/adev-es/src/content/guide/animations/overview.md +++ b/adev-es/src/content/guide/animations/overview.md @@ -266,7 +266,7 @@ Learn about more advanced features in Angular animations under the Animation sec ## Animations API summary The functional API provided by the `@angular/animations` module provides a domain-specific language \(DSL\) for creating and controlling animations in Angular applications. -See the [API reference](api/animations) for a complete listing and syntax details of the core functions and related data structures. +See the [API reference](api#animations) for a complete listing and syntax details of the core functions and related data structures. | Function name | What it does | |:--- |:--- | diff --git a/adev-es/src/content/guide/components/dom-apis.md b/adev-es/src/content/guide/components/dom-apis.md index 8bf8673..875007a 100644 --- a/adev-es/src/content/guide/components/dom-apis.md +++ b/adev-es/src/content/guide/components/dom-apis.md @@ -80,4 +80,4 @@ Avoid inserting, removing, and modifying DOM elements. In particular, **never di element's `innerHTML` property**, which can make your application vulnerable to [cross-site scripting (XSS) exploits](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting). Angular's template bindings, including bindings for `innerHTML`, include safeguards that help -protect against XSS attacks. See the [Security guide](guide/security) for details. +protect against XSS attacks. See the [Security guide](best-practices/security) for details. diff --git a/adev-es/src/content/guide/components/output-function.md b/adev-es/src/content/guide/components/output-function.md index 2bb38de..7723178 100644 --- a/adev-es/src/content/guide/components/output-function.md +++ b/adev-es/src/content/guide/components/output-function.md @@ -3,7 +3,7 @@ The `output()` function declares an output in a directive or component. Outputs allow you to emit values to parent components. -HELPFUL: The `output()` function is currently in [developer preview](/guide/releases#developer-preview). +HELPFUL: The `output()` function is currently in [developer preview](/reference/releases#developer-preview). import {Component, output} from '@angular/core'; diff --git a/adev-es/src/content/guide/components/styling.md b/adev-es/src/content/guide/components/styling.md index 9a75281..afb87a0 100644 --- a/adev-es/src/content/guide/components/styling.md +++ b/adev-es/src/content/guide/components/styling.md @@ -60,10 +60,11 @@ emulated encapsulation. In emulated mode, Angular supports the [`:host`](https://developer.mozilla.org/en-US/docs/Web/CSS/:host) -and [`:host-context`](https://developer.mozilla.org/en-US/docs/Web/CSS/:host-context) pseudo +and [`:host-context()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:host-context) pseudo classes without using [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). -During compilation, the framework transforms these pseudo classes into attributes. Angular's +During compilation, the framework transforms these pseudo classes into attributes so it doesn't +comply with these native pseudo classes' rules at runtime (e.g. browser compatibility, specificity). Angular's emulated encapsulation mode does not support any other pseudo classes related to Shadow DOM, such as `::shadow` or `::part`. diff --git a/adev-es/src/content/guide/di/creating-injectable-service.md b/adev-es/src/content/guide/di/creating-injectable-service.md index 388fcb5..eaea5fc 100644 --- a/adev-es/src/content/guide/di/creating-injectable-service.md +++ b/adev-es/src/content/guide/di/creating-injectable-service.md @@ -19,7 +19,7 @@ Angular helps you follow these principles by making it easy to factor your appli ## Service examples -Here's an example of a service class that logs to the browser console. +Here's an example of a service class that logs to the browser console: export class Logger { @@ -31,7 +31,7 @@ export class Logger { Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. -That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server. +That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server: @@ -54,7 +54,7 @@ export class HeroService { ## Creating an injectable service -Angular CLI provides a command to create a new service. In the following example, you add a new service to your application, which was created earlier with the `ng new` command. +The Angular CLI provides a command to create a new service. In the following example, you add a new service to an existing application. To generate a new `HeroService` class in the `src/app/heroes` folder, follow these steps: @@ -64,7 +64,7 @@ To generate a new `HeroService` class in the `src/app/heroes` folder, follow the ng generate service heroes/hero -This command creates the following default `HeroService`. +This command creates the following default `HeroService`: import { Injectable } from '@angular/core'; @@ -100,11 +100,11 @@ For clarity and maintainability, it is recommended that you define components an ## Injecting services -To inject a service as a dependency into a component, you can use component's `constructor()` and supply a constructor argument with the dependency type. +To inject a service as a dependency into a component, you can use the component's `constructor()` and supply a constructor argument with the dependency type. The following example specifies the `HeroService` in the `HeroListComponent` constructor. -The type of the `heroService` is `HeroService`. -Angular recognizes the `HeroService` type as a dependency, since that class was previously annotated with the `@Injectable` decorator. +The type of `heroService` is `HeroService`. +Angular recognizes the `HeroService` type as a dependency, since that class was previously annotated with the `@Injectable` decorator: constructor(heroService: HeroService) @@ -113,10 +113,7 @@ Angular recognizes the `HeroService` type as a dependency, since that class was ## Injecting services in other services When a service depends on another service, follow the same pattern as injecting into a component. -In the following example `HeroService` depends on a `Logger` service to report its activities. - -1. Import the `Logger` service. -2. Then inject the `Logger` service in the `HeroService` `constructor()` by specifying `private logger: Logger`. +In the following example, `HeroService` depends on a `Logger` service to report its activities: @@ -142,6 +139,6 @@ In this example, the `getHeroes()` method uses the `Logger` service by logging a ## What's next - + diff --git a/adev-es/src/content/guide/di/dependency-injection-context.md b/adev-es/src/content/guide/di/dependency-injection-context.md index ec792f7..415556f 100644 --- a/adev-es/src/content/guide/di/dependency-injection-context.md +++ b/adev-es/src/content/guide/di/dependency-injection-context.md @@ -1,21 +1,21 @@ # Injection context The dependency injection (DI) system relies internally on a runtime context where the current injector is available. -This means that injectors can only work when code is executed in this context. +This means that injectors can only work when code is executed in such a context. The injection context is available in these situations: -* Construction (via the `constructor`) of a class being instantiated by the DI system, such as an `@Injectable` or `@Component`. +* During construction (via the `constructor`) of a class being instantiated by the DI system, such as an `@Injectable` or `@Component`. * In the initializer for fields of such classes. * In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`. * In the `factory` function specified for an `InjectionToken`. -* Within a stack frame that is run in a injection context. +* Within a stack frame that runs in an injection context. -Knowing when you are in an injection context, will allow you to use the [`inject`](api/core/inject) function to inject instances. +Knowing when you are in an injection context will allow you to use the [`inject`](api/core/inject) function to inject instances. ## Class constructors -Everytime the DI system instantiates a class, this is done in an injection context. This is being handled by the framework itself. The constructor of the class is executed in that runtime context thus allowing to inject a token using the [`inject`](api/core/inject) function. +Every time the DI system instantiates a class, it does so in an injection context. This is handled by the framework itself. The constructor of the class is executed in that runtime context, which also allows injection of a token using the [`inject`](api/core/inject) function. class MyComponent { @@ -30,7 +30,7 @@ class MyComponent { ## Stack frame in context -Some APIs are designed to be run in an injection context. This is the case, for example, of the router guards. It allows the use of [`inject`](api/core/inject) to access a service within the guard function. +Some APIs are designed to be run in an injection context. This is the case, for example, with router guards. This allows the use of [`inject`](api/core/inject) within the guard function to access a service. Here is an example for `CanActivateFn` @@ -43,8 +43,8 @@ const canActivateTeam: CanActivateFn = ## Run within an injection context -When you want to run a given function in an injection context without being in one, you can do it with `runInInjectionContext`. -This requires to have access to a given injector like the `EnvironmentInjector` for example. +When you want to run a given function in an injection context without already being in one, you can do so with `runInInjectionContext`. +This requires access to a given injector, like the `EnvironmentInjector`, for example: @@ -66,7 +66,7 @@ Note that `inject` will return an instance only if the injector can resolve the ## Asserts the context -Angular provides `assertInInjectionContext` helper function to assert that the current context is an injection context. +Angular provides the `assertInInjectionContext` helper function to assert that the current context is an injection context. ## Using DI outside of a context diff --git a/adev-es/src/content/guide/di/dependency-injection-providers.md b/adev-es/src/content/guide/di/dependency-injection-providers.md index 2f7ce54..3e67bb6 100644 --- a/adev-es/src/content/guide/di/dependency-injection-providers.md +++ b/adev-es/src/content/guide/di/dependency-injection-providers.md @@ -8,7 +8,7 @@ Angular provides the necessary APIs to make the dependency configuration flexibl If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class using the `new` operator. -In the following example, the app component provides a `Logger` instance. +In the following example, the app component provides a `Logger` instance: providers: [Logger], @@ -33,7 +33,7 @@ The expanded provider configuration is an object literal with two properties: - `useFactory` - allows you to define a function that constructs a dependency. - `useValue` - provides a static value that should be used as a dependency. -The section below describes how to use the different provider definitions. +The sections below describe how to use the different provider definitions. ### Class providers: useClass @@ -42,13 +42,13 @@ The `useClass` provider key lets you create and return a new instance of the spe You can use this type of provider to substitute an alternative implementation for a common or default class. The alternative implementation can, for example, implement a different strategy, extend the default class, or emulate the behavior of the real class in a test case. -In the following example, `BetterLogger` would be instantiated when the `Logger` dependency is requested in a component or any other class. +In the following example, `BetterLogger` would be instantiated when the `Logger` dependency is requested in a component or any other class: [{ provide: Logger, useClass: BetterLogger }] -If the alternative class providers have their own dependencies, specify both providers in the providers metadata property of the parent module or component. +If the alternative class providers have their own dependencies, specify both providers in the providers metadata property of the parent module or component: [ @@ -57,7 +57,7 @@ If the alternative class providers have their own dependencies, specify both pro ] -In this example, `EvenBetterLogger` displays the user name in the log message. This logger gets the user from an injected `UserService` instance. +In this example, `EvenBetterLogger` displays the user name in the log message. This logger gets the user from an injected `UserService` instance: @@ -79,7 +79,7 @@ Angular DI knows how to construct the `UserService` dependency, since it has bee The `useExisting` provider key lets you map one token to another. In effect, the first token is an alias for the service associated with the second token, creating two ways to access the same service object. -In the following example, the injector injects the singleton instance of `NewLogger` when the component asks for either the new or the old logger. +In the following example, the injector injects the singleton instance of `NewLogger` when the component asks for either the new or the old logger: In this way, `OldLogger` is an alias for `NewLogger`. @@ -95,12 +95,12 @@ Note: Ensure you do not alias `OldLogger` to `NewLogger` with `useClass`, as thi ### Factory providers: useFactory The `useFactory` provider key lets you create a dependency object by calling a factory function. -With this approach you can create a dynamic value based on information available in the DI and elsewhere in the app. +With this approach, you can create a dynamic value based on information available in the DI and elsewhere in the app. In the following example, only authorized users should see secret heroes in the `HeroService`. Authorization can change during the course of a single application session, as when a different user logs in . -To keep security-sensitive information in `UserService` and out of `HeroService`, give the `HeroService` constructor a boolean flag to control display of secret heroes. +To keep security-sensitive information in `UserService` and out of `HeroService`, give the `HeroService` constructor a boolean flag to control display of secret heroes: @@ -118,7 +118,7 @@ class HeroService { To implement the `isAuthorized` flag, use a factory provider to create a new logger instance for `HeroService`. -This is necessary as we need to manually pass `Logger` when constructing the hero service. +This is necessary as we need to manually pass `Logger` when constructing the hero service: const heroServiceFactory = (logger: Logger, userService: UserService) => @@ -126,7 +126,7 @@ const heroServiceFactory = (logger: Logger, userService: UserService) => The factory function has access to `UserService`. -You inject both `Logger` and `UserService` into the factory provider so the injector can pass them along to the factory function. +You inject both `Logger` and `UserService` into the factory provider so the injector can pass them along to the factory function: @@ -156,7 +156,7 @@ The next section provides more information about the `useValue` key. ## Using an `InjectionToken` object Use an `InjectionToken` object as provider token for non-class dependencies. -The following example defines a token, `APP_CONFIG` of the type `InjectionToken`. +The following example defines a token, `APP_CONFIG`. of the type `InjectionToken`: import { InjectionToken } from '@angular/core'; @@ -166,13 +166,13 @@ export const APP_CONFIG = new InjectionToken('app.config description' The optional type parameter, ``, and the token description, `app.config description`, specify the token's purpose. -Next, register the dependency provider in the component using the `InjectionToken` object of `APP_CONFIG`. +Next, register the dependency provider in the component using the `InjectionToken` object of `APP_CONFIG`: providers: [{ provide: APP_CONFIG, useValue: MY_APP_CONFIG_VARIABLE }] -Now, inject the configuration object into the constructor with `@Inject()` parameter decorator. +Now, inject the configuration object into the constructor with the `@Inject()` parameter decorator: export class AppComponent { @@ -187,8 +187,8 @@ export class AppComponent { Though the TypeScript `AppConfig` interface supports typing within the class, the `AppConfig` interface plays no role in DI. In TypeScript, an interface is a design-time artifact, and does not have a runtime representation, or token, that the DI framework can use. -When the transpiler changes TypeScript to JavaScript, the interface disappears because JavaScript doesn't have interfaces. -Because there is no interface for Angular to find at runtime, the interface cannot be a token, nor can you inject it. +When the TypeScript transpiles to JavaScript, the interface disappears because JavaScript doesn't have interfaces. +Because there is no interface for Angular to find at runtime, the interface cannot be a token, nor can you inject it: // Can't use interface as provider token diff --git a/adev-es/src/content/guide/di/dependency-injection.md b/adev-es/src/content/guide/di/dependency-injection.md index 19ff004..b35e72b 100644 --- a/adev-es/src/content/guide/di/dependency-injection.md +++ b/adev-es/src/content/guide/di/dependency-injection.md @@ -4,13 +4,13 @@ Dependency injection, or DI, is one of the fundamental concepts in Angular. DI i Two main roles exist in the DI system: dependency consumer and dependency provider. -Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called `Injector`. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers. +Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called `Injector`. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as the "root" injector) during the application bootstrap process. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers. -This topic covers basic scenarios of how a class can act as a dependency. Angular also allows you to use functions, objects, primitive types such as string or Boolean, or any other types as dependencies. For more information, see [Dependency providers](/guide/di/dependency-injection-providers). +This topic covers basic scenarios of how a class can act as a dependency. Angular also allows you to use functions, objects, primitive types such as string or Boolean, or any other types as dependencies. For more information, see [Dependency providers](guide/di/dependency-injection-providers). -## Providing dependency +## Providing a dependency -Consider there is a class called `HeroService` that needs to act as a dependency in a component. +Consider a class called `HeroService` that needs to act as a dependency in a component. The first step is to add the `@Injectable` decorator to show that the class can be injected. @@ -24,7 +24,7 @@ A dependency can be provided in multiple places: * [**Preferred**: At the application root level using `providedIn`.](#preferred-at-the-application-root-level-using-providedin) * [At the Component level.](#at-the-component-level) -* [At application root level using `ApplicationConfig`.](#at-application-root-level-using-applicationconfig) +* [At the application root level using `ApplicationConfig`.](#at-the-application-root-level-using-applicationconfig) * [`NgModule` based applications.](#ngmodule-based-applications) ### **Preferred**: At the application root level using `providedIn` @@ -64,11 +64,11 @@ When you register a provider at the component level, you get a new instance of t Note: Declaring a service like this causes `HeroService` to always be included in your application— even if the service is unused. -### At application root level using `ApplicationConfig` +### At the application root level using `ApplicationConfig` You can use the `providers` field of the `ApplicationConfig` (passed to the `bootstrapApplication` function) to provide a service or other `Injectable` at the application level. -In the example below, the `HeroService` is available to all components, directives, and pipes. +In the example below, the `HeroService` is available to all components, directives, and pipes: export const appConfig: ApplicationConfig = { @@ -91,7 +91,7 @@ Note: Declaring a service like this causes `HeroService` to always be included i `@NgModule`-based applications use the `providers` field of the `@NgModule` decorator to provide a service or other `Injectable` available at the application level. A service provided in a module is available to all declarations of the module, or to any other modules which share the same `ModuleInjector`. -To understand all edge-cases, see [Hierarchical injectors](/guide/di/hierarchical-dependency-injection). +To understand all edge-cases, see [Hierarchical injectors](guide/di/hierarchical-dependency-injection). Note: Declaring a service using `providers` causes the service to be included in your application— even if the service is unused. @@ -136,5 +136,5 @@ style componentConstructor text-align: left ## What's next - + diff --git a/adev-es/src/content/guide/di/di-in-action.md b/adev-es/src/content/guide/di/di-in-action.md index 57eee60..19ef9a4 100644 --- a/adev-es/src/content/guide/di/di-in-action.md +++ b/adev-es/src/content/guide/di/di-in-action.md @@ -5,7 +5,7 @@ This guide explores additional features of dependency injection in Angular. ## Custom providers with `@Inject` Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. -The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`. +The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`: @@ -32,8 +32,8 @@ export class BrowserStorageService { } -The `factory` function returns the `localStorage` property that is attached to the browser window object. -The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency. +The `factory` function returns the `localStorage` property that is attached to the browser's window object. +The `Inject` decorator is applied to the `storage` constructor parameter and specifies a custom provider of the dependency. This custom provider can now be overridden during testing with a mock API of `localStorage` instead of interacting with real browser APIs. @@ -42,7 +42,7 @@ This custom provider can now be overridden during testing with a mock API of `lo Although developers strive to avoid it, some visual effects and third-party tools require direct DOM access. As a result, you might need to access a component's DOM element. -Angular exposes the underlying element of a `@Component` or `@Directive` via injection using the `ElementRef` injection token. +Angular exposes the underlying element of a `@Component` or `@Directive` via injection using the `ElementRef` injection token: import { Directive, ElementRef } from '@angular/core'; @@ -66,14 +66,13 @@ You can't refer directly to a class until it's been defined. This isn't usually a problem, especially if you adhere to the recommended *one class per file* rule. But sometimes circular references are unavoidable. -For example, when class 'A' refers to class 'B' and 'B' refers to 'A'. -One of them has to be defined first. +For example, when class 'A' refers to class 'B' and 'B' refers to 'A', one of them has to be defined first. The Angular `forwardRef()` function creates an *indirect* reference that Angular can resolve later. You face a similar problem when a class makes *a reference to itself*. -For example in its `providers` array. -The `providers` array is a property of the `@Component()` decorator function which must appear before the class definition. +For example, in its `providers` array. +The `providers` array is a property of the `@Component()` decorator function, which must appear before the class definition. You can break such circular references by using `forwardRef`. diff --git a/adev-es/src/content/guide/di/hierarchical-dependency-injection.md b/adev-es/src/content/guide/di/hierarchical-dependency-injection.md index cee8e46..75465ed 100644 --- a/adev-es/src/content/guide/di/hierarchical-dependency-injection.md +++ b/adev-es/src/content/guide/di/hierarchical-dependency-injection.md @@ -113,7 +113,7 @@ All requests forward up to the root injector, whether you configured it with the If you configure an app-wide provider in the `ApplicationConfig` of `bootstrapApplication`, it overrides one configured for `root` in the `@Injectable()` metadata. You can do this to configure a non-default provider of a service that is shared with multiple applications. -Here is an example of the case where the component router configuration includes a non-default [location strategy](/guide/routing#location-strategy) by listing its provider in the `providers` list of the `ApplicationConfig`. +Here is an example of the case where the component router configuration includes a non-default [location strategy](guide/routing#location-strategy) by listing its provider in the `providers` list of the `ApplicationConfig`. ```ts providers: [ diff --git a/adev-es/src/content/guide/di/lightweight-injection-tokens.md b/adev-es/src/content/guide/di/lightweight-injection-tokens.md index 3d65e9a..b20c8e3 100644 --- a/adev-es/src/content/guide/di/lightweight-injection-tokens.md +++ b/adev-es/src/content/guide/di/lightweight-injection-tokens.md @@ -7,7 +7,7 @@ You can manage the dependency structure among your components and injectable ser This normally ensures that if a provided component or service is never actually used by the application, the compiler can remove its code from the bundle. Due to the way Angular stores injection tokens, it is possible that such an unused component or service can end up in the bundle anyway. -This page describes a dependency-injection design pattern that supports proper tree-shaking by using lightweight injection tokens. +This page describes a dependency injection design pattern that supports proper tree-shaking by using lightweight injection tokens. The lightweight injection token design pattern is especially important for library developers. It ensures that when an application uses only some of your library's capabilities, the unused code can be eliminated from the client's application bundle. @@ -20,7 +20,7 @@ To prevent the retention of unused components, your library should use the light ## When tokens are retained To better explain the condition under which token retention occurs, consider a library that provides a library-card component. -This component contains a body and can contain an optional header. +This component contains a body and can contain an optional header: @@ -30,7 +30,7 @@ This component contains a body and can contain an optional header. -In a likely implementation, the `` component uses `@ContentChild()` or `@ContentChildren()` to get `` and ``, as in the following. +In a likely implementation, the `` component uses `@ContentChild()` or `@ContentChildren()` to get `` and ``, as in the following: @Component({ @@ -51,7 +51,7 @@ class LibCardComponent { Because `` is optional, the element can appear in the template in its minimal form, ``. In this case, `` is not used and you would expect it to be tree-shaken, but that is not what happens. -This is because `LibCardComponent` actually contains two references to the `LibHeaderComponent`. +This is because `LibCardComponent` actually contains two references to the `LibHeaderComponent`: @ContentChild(LibHeaderComponent) header: LibHeaderComponent; @@ -60,24 +60,24 @@ This is because `LibCardComponent` actually contains two references to the `LibH * One of these reference is in the *type position*-- that is, it specifies `LibHeaderComponent` as a type: `header: LibHeaderComponent;`. * The other reference is in the *value position*-- that is, LibHeaderComponent is the value of the `@ContentChild()` parameter decorator: `@ContentChild(LibHeaderComponent)`. -The compiler handles token references in these positions differently. +The compiler handles token references in these positions differently: * The compiler erases *type position* references after conversion from TypeScript, so they have no impact on tree-shaking. * The compiler must keep *value position* references at runtime, which **prevents** the component from being tree-shaken. In the example, the compiler retains the `LibHeaderComponent` token that occurs in the value position. This prevents the referenced component from being tree-shaken, even if the application does not actually use `` anywhere. -If `LibHeaderComponent` 's code, template, and styles combined becomes too large, including it unnecessarily can significantly increase the size of the client application. +If `LibHeaderComponent` 's code, template, and styles combine to become too large, including it unnecessarily can significantly increase the size of the client application. ## When to use the lightweight injection token pattern The tree-shaking problem arises when a component is used as an injection token. -There are two cases when that can happen. +There are two cases when that can happen: -* The token is used in the value position of a [content query](/guide/components/queries#content-queries). +* The token is used in the value position of a [content query](guide/components/queries#content-queries). * The token is used as a type specifier for constructor injection. -In the following example, both uses of the `OtherComponent` token cause retention of `OtherComponent`, preventing it from being tree-shaken when it is not used. +In the following example, both uses of the `OtherComponent` token cause retention of `OtherComponent`, preventing it from being tree-shaken when it is not used: class MyComponent { @@ -89,16 +89,16 @@ class MyComponent { Although tokens used only as type specifiers are removed when converted to JavaScript, all tokens used for dependency injection are needed at runtime. These effectively change `constructor(@Optional() other: OtherComponent)` to `constructor(@Optional() @Inject(OtherComponent) other)`. -The token is now in a value position, and causes the tree shaker to keep the reference. +The token is now in a value position, which causes the tree-shaker to keep the reference. -HELPFUL: For all services, a library should use [tree-shakable providers](/guide/di/dependency-injection#providing-dependency), providing dependencies at the root level rather than in components or modules. +HELPFUL: Libraries should use [tree-shakable providers](guide/di/dependency-injection#providing-dependency) for all services, providing dependencies at the root level rather than in components or modules. ## Using lightweight injection tokens The lightweight injection token design pattern consists of using a small abstract class as an injection token, and providing the actual implementation at a later stage. The abstract class is retained, not tree-shaken, but it is small and has no material impact on the application size. -The following example shows how this works for the `LibHeaderComponent`. +The following example shows how this works for the `LibHeaderComponent`: abstract class LibHeaderToken {} @@ -122,14 +122,14 @@ class LibCardComponent { In this example, the `LibCardComponent` implementation no longer refers to `LibHeaderComponent` in either the type position or the value position. -This lets full tree shaking of `LibHeaderComponent` take place. +This lets full tree-shaking of `LibHeaderComponent` take place. The `LibHeaderToken` is retained, but it is only a class declaration, with no concrete implementation. It is small and does not materially impact the application size when retained after compilation. Instead, `LibHeaderComponent` itself implements the abstract `LibHeaderToken` class. You can safely use that token as the provider in the component definition, allowing Angular to correctly inject the concrete type. -To summarize, the lightweight injection token pattern consists of the following. +To summarize, the lightweight injection token pattern consists of the following: 1. A lightweight injection token that is represented as an abstract class. 1. A component definition that implements the abstract class. @@ -144,7 +144,7 @@ The implementation of the method, with all its code overhead, resides in the inj This lets the parent communicate with the child, if it is present, in a type-safe manner. For example, the `LibCardComponent` now queries `LibHeaderToken` rather than `LibHeaderComponent`. -The following example shows how the pattern lets `LibCardComponent` communicate with the `LibHeaderComponent` without actually referring to `LibHeaderComponent`. +The following example shows how the pattern lets `LibCardComponent` communicate with the `LibHeaderComponent` without actually referring to `LibHeaderComponent`: abstract class LibHeaderToken { @@ -179,7 +179,7 @@ class LibCardComponent implement AfterContentInit { } -In this example the parent queries the token to get the child component, and stores the resulting component reference if it is present. +In this example, the parent queries the token to get the child component, and stores the resulting component reference if it is present. Before calling a method in the child, the parent component checks to see if the child component is present. If the child component has been tree-shaken, there is no runtime reference to it, and no call to its method. diff --git a/adev-es/src/content/guide/directives/directive-composition-api.md b/adev-es/src/content/guide/directives/directive-composition-api.md index d2a7196..11b870b 100644 --- a/adev-es/src/content/guide/directives/directive-composition-api.md +++ b/adev-es/src/content/guide/directives/directive-composition-api.md @@ -195,33 +195,3 @@ providers. If a component or directive with `hostDirectives` and those host directives both provide the same injection token, the providers defined by class with `hostDirectives` take precedence over providers defined by the host directives. - -### Performance - -While the directive composition API offers a powerful tool for reusing common behaviors, excessive -use of host directives can impact your application's memory use. If you create components or -directives that use *many* host directives, you may inadvertently balloon the memory used by your -application. - -The following example shows a component that applies several host directives. - -```typescript -@Component({ - standalone: true, - hostDirectives: [ - DisabledState, - RequiredState, - ValidationState, - ColorState, - RippleBehavior, - ], -}) -export class CustomCheckbox { } -``` - -This example declares a custom checkbox component that includes five host directives. This -means that Angular will create six objects each time a `CustomCheckbox` renders— one for the -component and one for each host directive. For a few checkboxes on a page, this won't pose any -significant issues. However, if your page renders *hundreds* of checkboxes, such as in a table, then -you could start to see an impact of the additional object allocations. Always be sure to profile -your application to determine the right composition pattern for your use case. diff --git a/adev-es/src/content/guide/directives/overview.md b/adev-es/src/content/guide/directives/overview.md index db4622e..43f52ee 100644 --- a/adev-es/src/content/guide/directives/overview.md +++ b/adev-es/src/content/guide/directives/overview.md @@ -63,8 +63,8 @@ Because `isSpecial` is true, `ngClass` applies the class of `special` to the ` -For this use case, Angular applies the classes on initialization and in case of changes. -The full example calls `setCurrentClasses()` initially with `ngOnInit()` and when the dependent properties change through a button click. +For this use case, Angular applies the classes on initialization and in case of changes caused by reassigning the `currentClasses` object. +The full example calls `setCurrentClasses()` initially with `ngOnInit()` when the user clicks on the `Refresh currentClasses` button. These steps are not necessary to implement `ngClass`. ## Setting inline styles with `NgStyle` diff --git a/adev-es/src/content/guide/http/making-requests.md b/adev-es/src/content/guide/http/making-requests.md index 5d2b85a..138b4af 100644 --- a/adev-es/src/content/guide/http/making-requests.md +++ b/adev-es/src/content/guide/http/making-requests.md @@ -39,7 +39,7 @@ For example, you can ask `HttpClient` to download the raw bytes of a `.jpeg` ima http.get('/images/dog.jpg', {responseType: 'arraybuffer'}).subscribe(buffer => { - console.log('The image is ' + buffer.length + ' bytes large'); + console.log('The image is ' + buffer.byteLength + ' bytes large'); }); @@ -242,15 +242,18 @@ export class UserService { } -Within a component, you can combine `NgIf` with the `async` pipe to render the UI for the data only after it's finished loading: +Within a component, you can combine `@if` with the `async` pipe to render the UI for the data only after it's finished loading: +import { AsyncPipe } from '@angular/common'; @Component({ + standalone: true, + imports: [AsyncPipe], template: ` - + @if (user$ | async; as user) {

Name: {{ user.name }}

Biography: {{ user.biography }}

-
+ } `, }) export class UserProfileComponent { diff --git a/adev-es/src/content/guide/hydration.md b/adev-es/src/content/guide/hydration.md index b982aef..53cf9dd 100644 --- a/adev-es/src/content/guide/hydration.md +++ b/adev-es/src/content/guide/hydration.md @@ -12,7 +12,7 @@ Without hydration enabled, server-side rendered Angular applications will destro ## How do you enable hydration in Angular -Before you can get started with hydration, you must have a server-side rendered (SSR) application. Follow the [Angular SSR Guide](/guide/ssr) to enable server-side rendering first. Once you have SSR working with your application, you can enable hydration by visiting your main app component or module and importing `provideClientHydration` from `@angular/platform-browser`. You'll then add that provider to your app's bootstrapping providers list. +Before you can get started with hydration, you must have a server-side rendered (SSR) application. Follow the [Angular SSR Guide](guide/ssr) to enable server-side rendering first. Once you have SSR working with your application, you can enable hydration by visiting your main app component or module and importing `provideClientHydration` from `@angular/platform-browser`. You'll then add that provider to your app's bootstrapping providers list. ```typescript import { @@ -128,9 +128,22 @@ Keep in mind that adding the `ngSkipHydration` attribute to your root applicatio ## I18N -We don't yet support internationalization with hydration, but support is coming. -Currently, Angular would skip hydration for components that use i18n blocks, effectively -re-rendering those components from scratch. +HELPFUL: Support for internationalization with hydration is currently in [developer preview](/reference/releases#developer-preview). By default, Angular will skip hydration for components that use i18n blocks, effectively re-rendering those components from scratch. + +To enable hydration for i18n blocks, you can add [`withI18nSupport`](/api/platform-browser/withI18nSupport) to your `provideClientHydration` call. + +```typescript +import { + bootstrapApplication, + provideClientHydration, + withI18nSupport, +} from '@angular/platform-browser'; +... + +bootstrapApplication(AppComponent, { + providers: [provideClientHydration(withI18nSupport())] +}); +``` ## Third Party Libraries with DOM Manipulation diff --git a/adev-es/src/content/guide/image-optimization.md b/adev-es/src/content/guide/image-optimization.md index 41704ca..51d8847 100644 --- a/adev-es/src/content/guide/image-optimization.md +++ b/adev-es/src/content/guide/image-optimization.md @@ -71,7 +71,7 @@ Marking an image as `priority` applies the following optimizations: * Sets `fetchpriority=high` (read more about priority hints [here](https://web.dev/priority-hints)) * Sets `loading=eager` (read more about native lazy loading [here](https://web.dev/browser-level-image-lazy-loading)) -* Automatically generates a [preload link element](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload) if [rendering on the server](/guide/ssr). +* Automatically generates a [preload link element](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload) if [rendering on the server](guide/ssr). Angular displays a warning during development if the LCP element is an image that does not have the `priority` attribute. A page’s LCP element can vary based on a number of factors - such as the dimensions of a user's screen, so a page may have multiple images that should be marked `priority`. See [CSS for Web Vitals](https://web.dev/css-web-vitals/#images-and-largest-contentful-paint-lcp) for more details.
diff --git a/adev-es/src/content/guide/ngmodules/api.md b/adev-es/src/content/guide/ngmodules/api.md index 11c1b52..b2c00b3 100644 --- a/adev-es/src/content/guide/ngmodules/api.md +++ b/adev-es/src/content/guide/ngmodules/api.md @@ -31,10 +31,10 @@ The following table summarizes the `@NgModule` metadata properties. | Property | Details | |:--- |:--- | -| `declarations` | A list of [declarable](/guide/ngmodules/faq#what-is-a-declarable?) classes (*components*, *directives*, and *pipes*) that *belong to this module*.
  1. When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives.
  2. The template is compiled within the context of an NgModule —the NgModule within which the template's component is declared— which determines the set of selectors using the following rules:
    • All selectors of directives listed in `declarations`.
    • All selectors of directives exported from imported NgModules.
Components, directives, and pipes must belong to *exactly* one module. The compiler emits an error if you try to declare the same class in more than one module. Be careful not to re-declare a class that is imported directly or indirectly from another module. | -| `providers` | A list of dependency-injection providers.
Angular registers these providers with the NgModule's injector. If it is the NgModule used for bootstrapping then it is the root injector.
These services become available for injection into any component, directive, pipe or service which is a child of this injector.
A lazy-loaded module has its own injector which is typically a child of the application root injector.
Lazy-loaded services are scoped to the lazy module's injector. If a lazy-loaded module also provides the `UserService`, any component created within that module's context (such as by router navigation) gets the local instance of the service, not the instance in the root application injector.
Components in external modules continue to receive the instance provided by their injectors.
For more information on injector hierarchy and scoping, see [Providers](/guide/ngmodules/providers) and the [DI Guide](/guide/di). | -| `imports` | A list of modules which should be folded into this module. Folded means it is as if all the imported NgModule's exported properties were declared here.
Specifically, it is as if the list of modules whose exported components, directives, or pipes are referenced by the component templates were declared in this module.
A component template can [reference](/guide/ngmodules/faq#how-does-angular-find-components,-directives,-and-pipes-in-a-template?-what-is-a-template-reference?) another component, directive, or pipe when the reference is declared in this module or if the imported module has exported it. For example, a component can use the `NgIf` and `NgFor` directives only if the module has imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`).
You can import many standard directives from the `CommonModule` but some familiar directives belong to other modules. For example, you can use `[(ngModel)]` only after importing the Angular `FormsModule`. | -| `exports` | A list of declarations —*component*, *directive*, and *pipe* classes— that an importing module can use.
Exported declarations are the module's *public API*. A component in another module can use *this* module's `UserComponent` if it imports this module and this module exports `UserComponent`.
Declarations are private by default. If this module does *not* export `UserComponent`, then only the components within *this* module can use `UserComponent`.
Importing a module does *not* automatically re-export the imported module's imports. Module 'B' can't use `ngIf` just because it imported module 'A' which imported `CommonModule`. Module 'B' must import `CommonModule` itself.
A module can list another module among its `exports`, in which case all of that module's public components, directives, and pipes are exported.
[Re-export](/guide/ngmodules/faq#what-should-i-export?) makes module transitivity explicit. If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. | +| `declarations` | A list of [declarable](guide/ngmodules/faq#what-is-a-declarable?) classes (*components*, *directives*, and *pipes*) that *belong to this module*.
  1. When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives.
  2. The template is compiled within the context of an NgModule —the NgModule within which the template's component is declared— which determines the set of selectors using the following rules:
    • All selectors of directives listed in `declarations`.
    • All selectors of directives exported from imported NgModules.
Components, directives, and pipes must belong to *exactly* one module. The compiler emits an error if you try to declare the same class in more than one module. Be careful not to re-declare a class that is imported directly or indirectly from another module. | +| `providers` | A list of dependency-injection providers.
Angular registers these providers with the NgModule's injector. If it is the NgModule used for bootstrapping then it is the root injector.
These services become available for injection into any component, directive, pipe or service which is a child of this injector.
A lazy-loaded module has its own injector which is typically a child of the application root injector.
Lazy-loaded services are scoped to the lazy module's injector. If a lazy-loaded module also provides the `UserService`, any component created within that module's context (such as by router navigation) gets the local instance of the service, not the instance in the root application injector.
Components in external modules continue to receive the instance provided by their injectors.
For more information on injector hierarchy and scoping, see [Providers](guide/ngmodules/providers) and the [DI Guide](guide/di). | +| `imports` | A list of modules which should be folded into this module. Folded means it is as if all the imported NgModule's exported properties were declared here.
Specifically, it is as if the list of modules whose exported components, directives, or pipes are referenced by the component templates were declared in this module.
A component template can [reference](guide/ngmodules/faq#how-does-angular-find-components,-directives,-and-pipes-in-a-template?-what-is-a-template-reference?) another component, directive, or pipe when the reference is declared in this module or if the imported module has exported it. For example, a component can use the `NgIf` and `NgFor` directives only if the module has imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`).
You can import many standard directives from the `CommonModule` but some familiar directives belong to other modules. For example, you can use `[(ngModel)]` only after importing the Angular `FormsModule`. | +| `exports` | A list of declarations —*component*, *directive*, and *pipe* classes— that an importing module can use.
Exported declarations are the module's *public API*. A component in another module can use *this* module's `UserComponent` if it imports this module and this module exports `UserComponent`.
Declarations are private by default. If this module does *not* export `UserComponent`, then only the components within *this* module can use `UserComponent`.
Importing a module does *not* automatically re-export the imported module's imports. Module 'B' can't use `ngIf` just because it imported module 'A' which imported `CommonModule`. Module 'B' must import `CommonModule` itself.
A module can list another module among its `exports`, in which case all of that module's public components, directives, and pipes are exported.
[Re-export](guide/ngmodules/faq#what-should-i-export?) makes module transitivity explicit. If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. | | `bootstrap` | A list of components that are automatically bootstrapped.
Usually there's only one component in this list, the *root component* of the application.
Angular can launch with multiple bootstrap components, each with its own location in the host web page. | ## More on NgModules diff --git a/adev-es/src/content/guide/ngmodules/bootstrapping.md b/adev-es/src/content/guide/ngmodules/bootstrapping.md index 88ec24e..41fcf18 100644 --- a/adev-es/src/content/guide/ngmodules/bootstrapping.md +++ b/adev-es/src/content/guide/ngmodules/bootstrapping.md @@ -42,7 +42,7 @@ The module's `declarations` array tells Angular which components belong to that As you create more components, add them to `declarations`. The `declarations` array only takes declarables. -Declarables are [components](/guide/components), [directives](/guide/directives), and [pipes](/guide/pipes). +Declarables are [components](guide/components), [directives](guide/directives), and [pipes](guide/pipes). All of a module's declarables must be in the `declarations` array. Declarables must belong to exactly one module. The compiler returns an error if declare the same class in multiple modules. @@ -102,8 +102,8 @@ And in the same file, add it to the `@NgModule` `declarations` array: Now you can use `ItemDirective` in a component. This example uses `AppModule`, but you would follow the same steps for a feature module. -For more about directives, see [Attribute Directives](/guide/directives/attribute-directives) and [Structural Directives](/guide/directives/structural-directives). -You'd also use the same technique for [pipes](/guide/pipes) and [components](/guide/components). +For more about directives, see [Attribute Directives](guide/directives/attribute-directives) and [Structural Directives](guide/directives/structural-directives). +You'd also use the same technique for [pipes](guide/pipes) and [components](guide/components). Remember, components, directives, and pipes belong to one module only. You only need to declare them once in your application because you share them by importing the necessary modules. @@ -131,7 +131,7 @@ A component template can reference another component, directive, or pipe when th The providers array is where you list the services the application needs. When you list services here, they are available app-wide. You can scope them when using feature modules and lazy loading. -For more information, see [Providers in modules](/guide/ngmodules/providers). +For more information, see [Providers in modules](guide/ngmodules/providers). ## The `bootstrap` array diff --git a/adev-es/src/content/guide/ngmodules/faq.md b/adev-es/src/content/guide/ngmodules/faq.md index ad8d22b..8e7d4f4 100644 --- a/adev-es/src/content/guide/ngmodules/faq.md +++ b/adev-es/src/content/guide/ngmodules/faq.md @@ -6,7 +6,7 @@ This page answers the questions many developers ask about NgModule design and im ## What classes should I add to the `declarations` array? -Add [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes —components, directives, and pipes— to a `declarations` list. +Add [declarable](guide/ngmodules/bootstrapping#the-declarations-array) classes —components, directives, and pipes— to a `declarations` list. Declare these classes in *exactly one* module of the application. Declare them in a module if they belong to that particular module. @@ -18,7 +18,7 @@ They're the only classes that you can add to `declarations`. ## What classes should I *not* add to `declarations`? -Add only [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes to an NgModule's `declarations` list. +Add only [declarable](guide/ngmodules/bootstrapping#the-declarations-array) classes to an NgModule's `declarations` list. Do *not* declare the following: @@ -51,7 +51,7 @@ The "x" class isn't visible to other modules until you add it to the `exports` l ## What should I import? -Import NgModules whose public (exported) [declarable classes](/guide/ngmodules/bootstrapping#the-declarations-array) +Import NgModules whose public (exported) [declarable classes](guide/ngmodules/bootstrapping#the-declarations-array) you need to reference in this module's component templates. This always means importing `CommonModule` from `@angular/common` for access to @@ -93,7 +93,7 @@ Angular doesn't like NgModules with circular references, so don't let Module 'A' ## What should I export? -Export [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes that components in *other* NgModules should be able to use in their templates. +Export [declarable](guide/ngmodules/bootstrapping#the-declarations-array) classes that components in *other* NgModules should be able to use in their templates. These are your *public* classes. If you don't export a declarable class, it stays *private*, visible only to other components declared in this NgModule. @@ -137,7 +137,7 @@ exports: [CommonModule, ApplicationModule] An NgModule can export a combination of its own declarations, selected imported classes, and imported NgModules. Don't bother re-exporting pure service modules. -Pure service modules don't export [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes that another NgModule could use. +Pure service modules don't export [declarable](guide/ngmodules/bootstrapping#the-declarations-array) classes that another NgModule could use. For example, there's no point in re-exporting `HttpClientModule` because it doesn't export anything. Its only purpose is to add http service providers to the application as a whole. @@ -146,7 +146,7 @@ Its only purpose is to add http service providers to the application as a whole. The `forRoot()` static method is a convention that makes it easy for developers to configure services and providers that are intended to be singletons. A good example of `forRoot()` is the `RouterModule.forRoot()` method. -For more information on `forRoot()` see [the `forRoot()` pattern](/guide/ngmodules/singleton-services#the-forroot()-pattern) section of the [Singleton Services](/guide/ngmodules/singleton-services) guide. +For more information on `forRoot()` see [the `forRoot()` pattern](guide/ngmodules/singleton-services#the-forroot()-pattern) section of the [Singleton Services](guide/ngmodules/singleton-services) guide. ## Why is a service provided in a feature module visible everywhere? @@ -380,7 +380,7 @@ They support your application by containing a particular feature, such as routes To conceptualize what a feature module might be in your app, consider that if you would put the files related to a certain functionality, like a search, in one folder, that the contents of that folder would be a feature module that you might call your `SearchModule`. It would contain all of the components, routing, and templates that would make up the search functionality. -For more information, see [Feature Modules](/guide/ngmodules/feature-modules) and [Module Types](/guide/ngmodules/module-types) +For more information, see [Feature Modules](guide/ngmodules/feature-modules) and [Module Types](guide/ngmodules/module-types) ## What's the difference between NgModules and JavaScript Modules? diff --git a/adev-es/src/content/guide/ngmodules/frequent.md b/adev-es/src/content/guide/ngmodules/frequent.md index 33d8fcc..3b68932 100644 --- a/adev-es/src/content/guide/ngmodules/frequent.md +++ b/adev-es/src/content/guide/ngmodules/frequent.md @@ -41,7 +41,7 @@ export class AppModule { }
The imports at the top of the array are JavaScript import statements while the `imports` array within `@NgModule` is Angular specific. -For more information on the difference, see [JavaScript Modules vs. NgModules](/guide/ngmodules/vs-jsmodule). +For more information on the difference, see [JavaScript Modules vs. NgModules](guide/ngmodules/vs-jsmodule). ## `BrowserModule` and `CommonModule` diff --git a/adev-es/src/content/guide/ngmodules/lazy-loading.md b/adev-es/src/content/guide/ngmodules/lazy-loading.md index 70b0eb7..1cd88f6 100644 --- a/adev-es/src/content/guide/ngmodules/lazy-loading.md +++ b/adev-es/src/content/guide/ngmodules/lazy-loading.md @@ -440,7 +440,7 @@ If `ng generate module` with the `--route` parameter returns an error, but runs Remember, many common Angular modules should be imported at the base of your application. -For more information on Angular Modules, see [NgModules](/guide/ngmodules). +For more information on Angular Modules, see [NgModules](guide/ngmodules). ## More on NgModules and routing diff --git a/adev-es/src/content/guide/ngmodules/module-types.md b/adev-es/src/content/guide/ngmodules/module-types.md index 9f7f05e..77ccb28 100644 --- a/adev-es/src/content/guide/ngmodules/module-types.md +++ b/adev-es/src/content/guide/ngmodules/module-types.md @@ -10,7 +10,7 @@ Focus each block on a feature or business domain, a workflow or navigation flow, ## Summary of NgModule categories -All applications start by [bootstrapping a root NgModule](/guide/ngmodules/bootstrapping "Launching an app with a root NgModule"). +All applications start by [bootstrapping a root NgModule](guide/ngmodules/bootstrapping "Launching an app with a root NgModule"). You can organize your other NgModules any way you want. This topic provides some guidelines for the following general categories of NgModules: @@ -52,7 +52,7 @@ If you do, the lifetime of the provided services should be the same as the lifet Use a routing NgModule to provide the routing configuration for a domain NgModule, thereby separating routing concerns from its companion domain NgModule. -HELPFUL: For an overview and details about routing, see [In-app navigation: routing to views](/guide/routing "In-app navigation: routing to views"). +HELPFUL: For an overview and details about routing, see [In-app navigation: routing to views](guide/routing "In-app navigation: routing to views"). Use a routing NgModule to do the following tasks: @@ -92,16 +92,16 @@ It would rarely have providers. ## Shared NgModules Put commonly used directives, pipes, and components into one NgModule, typically named `SharedModule`, and then import just that NgModule wherever you need it in other parts of your application. -You can import the shared NgModule in your domain NgModules, including [lazy-loaded NgModules](/guide/ngmodules/lazy-loading "Lazy-loading an NgModule"). +You can import the shared NgModule in your domain NgModules, including [lazy-loaded NgModules](guide/ngmodules/lazy-loading "Lazy-loading an NgModule"). Note: Shared NgModules should not include providers, nor should any of its imported or re-exported NgModules include providers. -To learn how to use shared modules to organize and streamline your code, see [Sharing NgModules in an app](/guide/ngmodules/sharing "Sharing NgModules in an app"). +To learn how to use shared modules to organize and streamline your code, see [Sharing NgModules in an app](guide/ngmodules/sharing "Sharing NgModules in an app"). ## Next steps If you want to manage NgModule loading and the use of dependencies and services, see the following: -* To learn about loading NgModules eagerly when the application starts, or lazy-loading NgModules asynchronously by the router, see [Lazy-loading feature modules](/guide/ngmodules/lazy-loading) -* To understand how to provide a service or other dependency for your app, see [Providing Dependencies for an NgModule](/guide/ngmodules/providers "Providing Dependencies for an NgModule") -* To learn how to create a singleton service to use in NgModules, see [Making a service a singleton](/guide/ngmodules/singleton-services "Making a service a singleton") +* To learn about loading NgModules eagerly when the application starts, or lazy-loading NgModules asynchronously by the router, see [Lazy-loading feature modules](guide/ngmodules/lazy-loading) +* To understand how to provide a service or other dependency for your app, see [Providing Dependencies for an NgModule](guide/ngmodules/providers "Providing Dependencies for an NgModule") +* To learn how to create a singleton service to use in NgModules, see [Making a service a singleton](guide/ngmodules/singleton-services "Making a service a singleton") diff --git a/adev-es/src/content/guide/ngmodules/overview.md b/adev-es/src/content/guide/ngmodules/overview.md index 2698e65..b1f10dd 100644 --- a/adev-es/src/content/guide/ngmodules/overview.md +++ b/adev-es/src/content/guide/ngmodules/overview.md @@ -29,10 +29,10 @@ NgModule metadata does the following: * Provides services that other application components can use Every Angular application has at least one module, the root module. -You [bootstrap](/guide/ngmodules/bootstrapping) that module to launch the application. +You [bootstrap](guide/ngmodules/bootstrapping) that module to launch the application. The root module is all you need in an application with few components. -As the application grows, you refactor the root module into [feature modules](/guide/ngmodules/feature-modules) that represent collections of related functionality. +As the application grows, you refactor the root module into [feature modules](guide/ngmodules/feature-modules) that represent collections of related functionality. You then import these modules into the root module. ## The basic NgModule @@ -56,7 +56,7 @@ export class AppModule {} At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). -For more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](/guide/ngmodules/bootstrapping). +For more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/ngmodules/bootstrapping). ## More on NgModules diff --git a/adev-es/src/content/guide/ngmodules/providers.md b/adev-es/src/content/guide/ngmodules/providers.md index 80d8c33..b945027 100644 --- a/adev-es/src/content/guide/ngmodules/providers.md +++ b/adev-es/src/content/guide/ngmodules/providers.md @@ -1,6 +1,6 @@ # Providing dependencies in modules -A provider is an instruction to the [Dependency Injection](/guide/di) system on how to obtain a value for a dependency. +A provider is an instruction to the [Dependency Injection](guide/di) system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide. ## Providing a service @@ -57,7 +57,7 @@ When the Angular router lazy-loads a module, it creates a new injector. This injector is a child of the root application injector. Imagine a tree of injectors; there is a single root injector and then a child injector for each lazy loaded module. This child injector gets populated with all the module-specific providers, if any. -Look up resolution for every provider follows the [rules of dependency injection hierarchy](/guide/di/hierarchical-dependency-injection#resolution-rules). +Look up resolution for every provider follows the [rules of dependency injection hierarchy](guide/di/hierarchical-dependency-injection#resolution-rules). Any component created within a lazy loaded module's context, such as by router navigation, gets its own local instance of child provided services, not the instance in the root application injector. Components in external modules continue to receive the instances created for the application root injector. @@ -114,7 +114,7 @@ Then each new instance of the `UserEditorComponent` gets its own cached service Services are singletons within the scope of an injector, which means there is at most one instance of a service in a given injector. -Angular DI has a [hierarchical injection system](/guide/di/hierarchical-dependency-injection), which means that nested injectors can create their own service instances. +Angular DI has a [hierarchical injection system](guide/di/hierarchical-dependency-injection), which means that nested injectors can create their own service instances. Whenever Angular creates a new instance of a component that has `providers` specified in `@Component()`, it also creates a new child injector for that instance. Similarly, when a new NgModule is lazy-loaded at run time, Angular can create an injector for it with its own providers. diff --git a/adev-es/src/content/guide/ngmodules/vs-jsmodule.md b/adev-es/src/content/guide/ngmodules/vs-jsmodule.md index b524109..6409fc2 100644 --- a/adev-es/src/content/guide/ngmodules/vs-jsmodule.md +++ b/adev-es/src/content/guide/ngmodules/vs-jsmodule.md @@ -44,7 +44,7 @@ An NgModule can export only the declarable classes it owns or imports from other It doesn't declare or export any other kind of class. Declarables are the only classes that matter to the Angular compilation process. -For a complete description of the NgModule metadata properties, see [Using the NgModule metadata](/guide/ngmodules/api "Using the NgModule metadata"). +For a complete description of the NgModule metadata properties, see [Using the NgModule metadata](guide/ngmodules/api "Using the NgModule metadata"). ## An example that uses both @@ -82,5 +82,5 @@ It then configures the `@NgModule` with the following arrays: ## Next steps -* To learn more about the root NgModule, see [Launching an app with a root NgModule](/guide/ngmodules/bootstrapping "Launching an app with a root NgModule"). -* To learn about frequently used Angular NgModules and how to import them into your app, see [Frequently-used modules](/guide/ngmodules/frequent "Frequently-used modules"). +* To learn more about the root NgModule, see [Launching an app with a root NgModule](guide/ngmodules/bootstrapping "Launching an app with a root NgModule"). +* To learn about frequently used Angular NgModules and how to import them into your app, see [Frequently-used modules](guide/ngmodules/frequent "Frequently-used modules"). diff --git a/adev-es/src/content/guide/pipes/change-detection.md b/adev-es/src/content/guide/pipes/change-detection.md index 28b5b84..6edabce 100644 --- a/adev-es/src/content/guide/pipes/change-detection.md +++ b/adev-es/src/content/guide/pipes/change-detection.md @@ -60,7 +60,7 @@ The tabs for the example show the following: | flying-heroes.component.html | Template with the new pipe used. | | flying-heroes.pipe.ts | File with custom pipe that filters flying heroes. | - + diff --git a/adev-es/src/content/guide/pipes/overview.md b/adev-es/src/content/guide/pipes/overview.md index db43038..833e90c 100644 --- a/adev-es/src/content/guide/pipes/overview.md +++ b/adev-es/src/content/guide/pipes/overview.md @@ -24,4 +24,4 @@ The following are commonly used built-in pipes for data formatting: - [`JsonPipe`](api/common/JsonPipe): Display a component object property to the screen as JSON for debugging. Note: For a complete list of built-in pipes, see the [pipes API documentation](/api/common#pipes "Pipes API reference summary"). -To learn more about using pipes for internationalization (i18n) efforts, see [formatting data based on locale](/guide/i18n/format-data-locale). +To learn more about using pipes for internationalization (i18n) efforts, see [formatting data based on locale](guide/i18n/format-data-locale). diff --git a/adev-es/src/content/guide/pipes/transform-data.md b/adev-es/src/content/guide/pipes/transform-data.md index 36cc0fb..7cac3ab 100644 --- a/adev-es/src/content/guide/pipes/transform-data.md +++ b/adev-es/src/content/guide/pipes/transform-data.md @@ -57,7 +57,7 @@ The following code example shows two component definitions: | `exponential-strength.pipe.ts` | Defines a custom pipe named `exponentialStrength` with the `transform` method that performs the transformation. It defines an argument to the `transform` method \(`exponent`\) for a parameter passed to the pipe. | | `power-booster.component.ts` | Demonstrates how to use the pipe, specifying a value \(`2`\) and the exponent parameter \(`10`\). | - - - + + + diff --git a/adev-es/src/content/guide/routing/common-router-tasks.md b/adev-es/src/content/guide/routing/common-router-tasks.md index 0d6b23c..ad23815 100644 --- a/adev-es/src/content/guide/routing/common-router-tasks.md +++ b/adev-es/src/content/guide/routing/common-router-tasks.md @@ -168,12 +168,6 @@ set id(heroId: string) { ``` NOTE: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters. -If you want to use the parent components route info you will need to set the router paramsInheritanceStrategy option: withRouterConfig({paramsInheritanceStrategy: 'always'}) - - - -Note: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters. - If you want to use the parent components route info you will need to set the router `paramsInheritanceStrategy` option: `withRouterConfig({paramsInheritanceStrategy: 'always'})` @@ -233,6 +227,29 @@ In this example, the third route is a redirect so that the router defaults to th Notice that this redirect precedes the wildcard route. Here, `path: ''` means to use the initial relative URL \(`''`\). +Sometimes a redirect is not a simple, static redirect. The `redirectTo` property can also be a function +with more complex logic that returns a string or `UrlTree`. + +```ts +const routes: Routes = [ + { path: "first-component", component: FirstComponent }, + { + path: "old-user-page", + redirectTo: ({ queryParams }) => { + const errorHandler = inject(ErrorHandler); + const userIdParam = queryParams['userId']; + if (userIdParam !== undefined) { + return `/user/${userIdParam}`; + } else { + errorHandler.handleError(new Error('Attempted navigation to user page without user ID.')); + return `/not-found`; + } + }, + }, + { path: "user/:userId", component: OtherComponent }, +]; +``` + ## Nesting routes As your application grows more complex, you might want to create routes that are relative to a component other than your root component. diff --git a/adev-es/src/content/guide/routing/router-reference.md b/adev-es/src/content/guide/routing/router-reference.md index 6435251..e3d71db 100644 --- a/adev-es/src/content/guide/routing/router-reference.md +++ b/adev-es/src/content/guide/routing/router-reference.md @@ -170,7 +170,7 @@ These events are shown in the following table. | [`ChildActivationEnd`](api/router/ChildActivationEnd) | Triggered when the Router finishes activating a route's children. | | [`ActivationEnd`](api/router/ActivationEnd) | Triggered when the Router finishes activating a route. | | [`NavigationEnd`](api/router/NavigationEnd) | Triggered when navigation ends successfully. | -| [`NavigationCancel`](api/router/NavigationCancel) | Triggered when navigation is canceled. This can happen when a Route Guard returns false during navigation, or redirects by returning a `UrlTree`. | +| [`NavigationCancel`](api/router/NavigationCancel) | Triggered when navigation is canceled. This can happen when a Route Guard returns false during navigation, or redirects by returning a `UrlTree` or `RedirectCommand`. | | [`NavigationError`](api/router/NavigationError) | Triggered when navigation fails due to an unexpected error. | | [`Scroll`](api/router/Scroll) | Represents a scrolling event. | diff --git a/adev-es/src/content/guide/security.md b/adev-es/src/content/guide/security.md index 39b611c..69705e6 100644 --- a/adev-es/src/content/guide/security.md +++ b/adev-es/src/content/guide/security.md @@ -63,7 +63,7 @@ Angular defines the following security contexts: | URL | Used for URL properties, such as ``. | | Resource URL | A URL that is loaded and executed as code, for example, in `