# Migrating to the new build system

In v17 and higher, the new build system provides an improved way to build Angular applications. This new build system includes:

- A modern output format using ESM, with dynamic import expressions to support lazy module loading.
- Faster build-time performance for both initial builds and incremental rebuilds.
- Newer JavaScript ecosystem tools such as [esbuild](https://esbuild.github.io/) and [Vite](https://vitejs.dev/).
- Integrated SSR and prerendering capabilities.

This new build system is stable and fully supported for use with Angular applications.
You can migrate to the new build system with applications that use the `browser` builder.
If using a custom builder, please refer to the documentation for that builder on possible migration options.

IMPORTANT: The existing Webpack-based build system is still considered stable and fully supported.
Applications can continue to use the `browser` builder and will not be automatically migrated when updating.

## For new applications

New applications will use this new build system by default via the `application` builder.

## For existing applications

Both automated and manual procedures are available dependening on the requirements of the project.
Starting with v18, the update process will ask if you would like to migrate existing applications to use the new build system via the automated migration.

HELPFUL: Remember to remove any CommonJS assumptions in the application server code if using SSR such as `require`, `__filename`, `__dirname`, or other constructs from the [CommonJS module scope](https://nodejs.org/api/modules.html#the-module-scope). All application code should be ESM compatible. This does not apply to third-party dependencies.

### Automated migration (Recommended)

The automated migration will adjust both the application configuration within `angular.json` as well as code and stylesheets to remove previous Webpack-specific feature usage.
While many changes can be automated and most applications will not require any further changes, each application is unique and there may be some manual changes required.
After the migration, please attempt a build of the application as there could be new errors that will require adjustments within the code.
The errors will attempt to provide solutions to the problem when possible and the later sections of this guide describe some of the more common situations that you may encounter.
When updating to Angular v18 via `ng update`, you will be asked to execute the migration.
This migration is entirely optional for v18 and can also be run manually at anytime after an update via the following command:

<docs-code language="shell">

ng update @angular/cli --name use-application-builder

</docs-code>

The migration does the following:

* Converts existing `browser` or `browser-esbuild` target to `application`
* Removes any previous SSR builders (because `application` does that now).
* Updates configuration accordingly.
* Merges `tsconfig.server.json` with `tsconfig.app.json` and adds the TypeScript option `"esModuleInterop": true` to ensure `express` imports are [ESM compliant](#esm-default-imports-vs-namespace-imports).
* Updates application server code to use new bootstrapping and output directory structure.
* Removes any Webpack-specific builder stylesheet usage such as the tilde or caret in `@import`/`url()` and updates the configuration to provide equivalent behavior
* Converts to use the new lower dependency `@angular/build` Node.js package if no other `@angular-devkit/build-angular` usage is found.

### Manual migration

Additionally for existing projects, you can manually opt-in to use the new builder on a per-application basis with two different options.
Both options are considered stable and fully supported by the Angular team.
The choice of which option to use is a factor of how many changes you will need to make to migrate and what new features you would like to use in the project.

- The `browser-esbuild` builder builds only the client-side bundle of an application designed to be compatible with the existing `browser` builder that provides the preexisting build system. It serves as a drop-in replacement for existing `browser` applications.
- The `application` builder covers an entire application, such as the client-side bundle, as well as optionally building a server for server-side rendering and performing build-time prerendering of static pages.

The `application` builder is generally preferred as it improves server-side rendered (SSR) builds, and makes it easier for client-side rendered projects to adopt SSR in the future.
However it requires a little more migration effort, particularly for existing SSR applications if performed manually.
If the `application` builder is difficult for your project to adopt, `browser-esbuild` can be an easier solution which gives most of the build performance benefits with fewer breaking changes.

#### Manual migration to the compatibility builder

A builder named `browser-esbuild` is available within the `@angular-devkit/build-angular` package that is present in an Angular CLI generated application.
You can try out the new build system for applications that use the `browser` builder.
If using a custom builder, please refer to the documentation for that builder on possible migration options.

The compatibility option was implemented to minimize the amount of changes necessary to initially migrate your applications.
This is provided via an alternate builder (`browser-esbuild`).
You can update the `build` target for any application target to migrate to the new build system.

The following is what you would typically find in `angular.json` for an application:

<docs-code language="json">
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
...
</docs-code>

Changing the `builder` field is the only change you will need to make.

<docs-code language="json">
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser-esbuild",
...
</docs-code>

#### Manual migration to the new `application` builder

A builder named `application` is also available within the `@angular-devkit/build-angular` package that is present in an Angular CLI generated application.
This builder is the default for all new applications created via `ng new`.

The following is what you would typically find in `angular.json` for an application:

<docs-code language="json">
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
...
</docs-code>

Changing the `builder` field is the first change you will need to make.

<docs-code language="json">
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:application",
...
</docs-code>

Once the builder name has been changed, options within the `build` target will need to be updated.
The following list discusses all the `browser` builder options that will need to be adjusted.

- `main` should be renamed to `browser`.
- `polyfills` should be an array, rather than a single file.
- `buildOptimizer` should be removed, as this is covered by the `optimization` option.
- `resourcesOutputPath` should be removed, this is now always `media`.
- `vendorChunk` should be removed, as this was a performance optimization which is no longer needed.
- `commonChunk` should be removed, as this was a performance optimization which is no longer needed.
- `deployUrl` should be removed and is not supported. Prefer [`<base href>`](guide/routing/common-router-tasks) instead. See [deployment documentation](tools/cli/deployment#--deploy-url) for more information.
- `ngswConfigPath` should be renamed to `serviceWorker`.

If the application is not using SSR currently, this should be the final step to allow `ng build` to function.
After executing `ng build` for the first time, there may be new warnings or errors based on behavioral differences or application usage of Webpack-specific features.
Many of the warnings will provide suggestions on how to remedy that problem.
If it appears that a warning is incorrect or the solution is not apparent, please open an issue on [GitHub](https://github.com/angular/angular-cli/issues).
Also, the later sections of this guide provide additional information on several specific cases as well as current known issues.

For applications new to SSR, the [Angular SSR Guide](guide/ssr) provides additional information regarding the setup process for adding SSR to an application.

For applications that are already using SSR, additional adjustments will be needed to update the application server to support the new integrated SSR capabilities.
The `application` builder now provides the integrated functionality for all of the following preexisting builders:

- `app-shell`
- `prerender`
- `server`
- `ssr-dev-server`

The `ng update` process will automatically remove usages of the `@nguniversal` scope packages where some of these builders were previously located.
The new `@angular/ssr` package will also be automatically added and used with configuration and code being adjusted during the update.
The `@angular/ssr` package supports the `browser` builder as well as the `application` builder.


## Executing a build

Once you have updated the application configuration, builds can be performed using `ng build` as was previously done.
Depending on the choice of builder migration, some of the command line options may be different.
If the build command is contained in any `npm` or other scripts, ensure they are reviewed and updated.
For applications that have migrated to the `application` builder and that use SSR and/or prererending, you also may be able to remove extra `ng run` commands from scripts now that `ng build` has integrated SSR support.

<docs-code language="shell">

ng build

</docs-code>

## Starting the development server

The development server will automatically detect the new build system and use it to build the application.
To start the development server no changes are necessary to the `dev-server` builder configuration or command line.

<docs-code language="shell">

ng serve

</docs-code>

You can continue to use the [command line options](/cli/serve) you have used in the past with the development server.

## Hot module replacement

JavaScript-based hot module replacement (HMR) is currently not supported.
However, global stylesheet (`styles` build option) HMR is available and enabled by default.
Angular focused HMR capabilities are currently planned and will be introduced in a future version.

## Unimplemented options and behavior

Several build options are not yet implemented but will be added in the future as the build system moves towards a stable status. If your application uses these options, you can still try out the build system without removing them. Warnings will be issued for any unimplemented options but they will otherwise be ignored. However, if your application relies on any of these options to function, you may want to wait to try.

- [WASM imports](https://github.com/angular/angular-cli/issues/25102) -- WASM can still be loaded manually via [standard web APIs](https://developer.mozilla.org/docs/WebAssembly/Loading_and_running).

## ESM default imports vs. namespace imports

TypeScript by default allows default exports to be imported as namespace imports and then used in call expressions.
This is unfortunately a divergence from the ECMAScript specification.
The underlying bundler (`esbuild`) within the new build system expects ESM code that conforms to the specification.
The build system will now generate a warning if your application uses an incorrect type of import of a package.
However, to allow TypeScript to accept the correct usage, a TypeScript option must be enabled within the application's `tsconfig` file.
When enabled, the [`esModuleInterop`](https://www.typescriptlang.org/tsconfig#esModuleInterop) option provides better alignment with the ECMAScript specification and is also recommended by the TypeScript team.
Once enabled, you can update package imports where applicable to an ECMAScript conformant form.

Using the [`moment`](https://npmjs.com/package/moment) package as an example, the following application code will cause runtime errors:

```ts
import * as moment from 'moment';

console.log(moment().format());
```

The build will generate a warning to notify you that there is a potential problem. The warning will be similar to:

<docs-code language="text">
▲ [WARNING] Calling "moment" will crash at run-time because it's an import namespace object, not a function [call-import-namespace]

    src/main.ts:2:12:
      2 │ console.log(moment().format());
        ╵             ~~~~~~

Consider changing "moment" to a default import instead:

    src/main.ts:1:7:
      1 │ import * as moment from 'moment';
        │        ~~~~~~~~~~~
        ╵        moment

</docs-code>

However, you can avoid the runtime errors and the warning by enabling the `esModuleInterop` TypeScript option for the application and changing the import to the following:

```ts
import moment from 'moment';

console.log(moment().format());
```

## Vite as a development server

The usage of Vite in the Angular CLI is currently within a _development server capacity only_. Even without using the underlying Vite build system, Vite provides a full-featured development server with client side support that has been bundled into a low dependency npm package. This makes it an ideal candidate to provide comprehensive development server functionality. The current development server process uses the new build system to generate a development build of the application in memory and passes the results to Vite to serve the application. The usage of Vite, much like the Webpack-based development server, is encapsulated within the Angular CLI `dev-server` builder and currently cannot be directly configured.

## Known Issues

There are currently several known issues that you may encounter when trying the new build system. This list will be updated to stay current. If any of these issues are currently blocking you from trying out the new build system, please check back in the future as it may have been solved.

### Type-checking of Web Worker code and processing of nested Web Workers

Web Workers can be used within application code using the same syntax (`new Worker(new URL('<workerfile>', import.meta.url))`) that is supported with the `browser` builder.
However, the code within the Worker will not currently be type-checked by the TypeScript compiler. TypeScript code is supported just not type-checked.
Additionally, any nested workers will not be processed by the build system. A nested worker is a Worker instantiation within another Worker file.

### Order-dependent side-effectful imports in lazy modules

Import statements that are dependent on a specific ordering and are also used in multiple lazy modules can cause top-level statements to be executed out of order.
This is not common as it depends on the usage of side-effectful modules and does not apply to the `polyfills` option.
This is caused by a [defect](https://github.com/evanw/esbuild/issues/399) in the underlying bundler but will be addressed in a future update.

IMPORTANT: Avoiding the use of modules with non-local side effects (outside of polyfills) is recommended whenever possible regardless of the build system being used and avoids this particular issue. Modules with non-local side effects can have a negative effect on both application size and runtime performance as well.

## Bug reports

Report issues and feature requests on [GitHub](https://github.com/angular/angular-cli/issues).

Please provide a minimal reproduction where possible to aid the team in addressing issues.


# Building Angular apps

You can build your Angular CLI application or library with the `ng build` command.
This will compile your TypeScript code to JavaScript, as well as optimize, bundle, and minify the output as appropriate.

`ng build` only executes the builder for the `build` target in the default project as specified in `angular.json`.
Angular CLI includes four builders typically used as `build` targets:

| Builder                                         | Purpose                                                                                |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@angular-devkit/build-angular:browser`         | Bundles a client-side application for use in a browser with [Webpack](https://webpack.js.org/).                                                                                |
| `@angular-devkit/build-angular:browser-esbuild` | Bundles a client-side application for use in a browser with [esbuild](https://esbuild.github.io/). See [`browser-esbuild` documentation](tools/cli/build-system-migration#manual-migration-to-the-compatibility-builder) for more information. |
| `@angular-devkit/build-angular:application`     | Builds an application with a client-side bundle, a Node server, and build-time prerendered routes with [esbuild](https://esbuild.github.io/).                                     |
| `@angular-devkit/build-angular:ng-packagr`      | Builds an Angular library adhering to [Angular Package Format](tools/libraries/angular-package-format).                                                                           |

Applications generated by `ng new` use `@angular-devkit/build-angular:application` by default.
Libraries generated by `ng generate library` use `@angular-devkit/build-angular:ng-packagr` by default.

You can determine which builder is being used for a particular project by looking up the `build` target for that project.

<docs-code language="json">

{
  "projects": {
    "my-app": {
      "architect": {
        // `ng build` invokes the Architect target named `build`.
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          …
        },
        "serve": { … }
        "test": { … }
        …
      }
    }
  }
}

</docs-code>

This page discusses usage and options of `@angular-devkit/build-angular:application`.

## Output directory

The result of this build process is output to a directory (`dist/${PROJECT_NAME}` by default).

## Configuring size budgets

As applications grow in functionality, they also grow in size.
The CLI lets you set size thresholds in your configuration to ensure that parts of your application stay within size boundaries that you define.

Define your size boundaries in the CLI configuration file, `angular.json`, in a `budgets` section for each [configured environment](tools/cli/environments).

<docs-code language="json">

{
  …
  "configurations": {
    "production": {
      …
      "budgets": [
        {
          "type": "initial",
          "maximumWarning": "250kb",
          "maximumError": "500kb"
        },
      ]
    }
  }
}

</docs-code>

You can specify size budgets for the entire app, and for particular parts.
Each budget entry configures a budget of a given type.
Specify size values in the following formats:

| Size value      | Details                                                                     |
| :-------------- | :-------------------------------------------------------------------------- |
| `123` or `123b` | Size in bytes.                                                              |
| `123kb`         | Size in kilobytes.                                                          |
| `123mb`         | Size in megabytes.                                                          |
| `12%`           | Percentage of size relative to baseline. \(Not valid for baseline values.\) |

When you configure a budget, the builder warns or reports an error when a given part of the application reaches or exceeds a boundary size that you set.

Each budget entry is a JSON object with the following properties:

| Property       | Value                                                                                |
| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type           | The type of budget. One of:

  Value 	  Details

  bundle 	  The size of a specific bundle.

  initial 	  The size of JavaScript needed for bootstrapping the application. Defaults to warning at 500kb and erroring at 1mb.

  allScript 	  The size of all scripts.

  all 	  The size of the entire application.

  anyComponentStyle 	  This size of any one component stylesheet. Defaults to warning at 2kb and erroring at 4kb.

  anyScript 	  The size of any one script.

  any 	  The size of any file.

 |
| name           | The name of the bundle (for `type=bundle`).                                                                                |
| baseline       | The baseline size for comparison.                                                                                |
| maximumWarning | The maximum threshold for warning relative to the baseline.                                                                                |
| maximumError   | The maximum threshold for error relative to the baseline.                                                                                |
| minimumWarning | The minimum threshold for warning relative to the baseline.                                                                                |
| minimumError   | The minimum threshold for error relative to the baseline.                                                                                |
| warning        | The threshold for warning relative to the baseline (min & max).                                                                                |
| error          | The threshold for error relative to the baseline (min & max).                                                                                |

## Configuring CommonJS dependencies

Always prefer native [ECMAScript modules](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import) (ESM) throughout your application and its dependencies.
ESM is a fully specified web standard and JavaScript language feature with strong static analysis support. This makes bundle optimizations more powerful than other module formats.

Angular CLI also supports importing [CommonJS](https://nodejs.org/api/modules.html) dependencies into your project and will bundle these dependencies automatically.
However, CommonJS modules can prevent bundlers and minifiers from optimizing those modules effectively, which results in larger bundle sizes.
For more information, see [How CommonJS is making your bundles larger](https://web.dev/commonjs-larger-bundles).

Angular CLI outputs warnings if it detects that your browser application depends on CommonJS modules.
When you encounter a CommonJS dependency, consider asking the maintainer to support ECMAScript modules, contributing that support yourself, or using an alternative dependency which meets your needs.
If the best option is to use a CommonJS dependency, you can disable these warnings by adding the CommonJS module name to `allowedCommonJsDependencies` option in the `build` options located in `angular.json`.

<docs-code language="json">

"build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
     "allowedCommonJsDependencies": [
        "lodash"
     ]
     …
   }
   …
},

</docs-code>

## Configuring browser compatibility

The Angular CLI uses [Browserslist](https://github.com/browserslist/browserslist) to ensure compatibility with different browser versions.
Depending on supported browsers, Angular will automatically transform certain JavaScript and CSS features to ensure the built application does not use a feature which has not been implemented by a supported browser. However, the Angular CLI will not automatically add polyfills to supplement missing Web APIs. Use the `polyfills` option in `angular.json` to add polyfills.

Internally, the Angular CLI uses the below default `browserslist` configuration which matches the [browsers that are supported](reference/versions#browser-support) by Angular.

<docs-code language="text">

last 2 Chrome versions
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
last 2 Android major versions
Firefox ESR

</docs-code>

To override the internal configuration, run [`ng generate config browserslist`](cli/generate/config), which generates a `.browserslistrc` configuration file in the project directory.

See the [browserslist repository](https://github.com/browserslist/browserslist) for more examples of how to target specific browsers and versions.
Avoid expanding this list to more browsers. Even if your application code more broadly compatible, Angular itself might not be.
You should only ever _reduce_ the set of browsers or versions in this list.

HELPFUL: Use [browsersl.ist](https://browsersl.ist) to display compatible browsers for a `browserslist` query.


## Builder input

You can invoke a builder indirectly through a CLI command such as `ng build`, or directly with the Angular CLI `ng run` command.
In either case, you must provide required inputs, but can let other inputs default to values that are pre-configured for a specific *target*, specified by a [configuration](tools/cli/environments), or set on the command line.

### Input validation

You define builder inputs in a JSON schema associated with that builder.
Similar to schematics, the Architect tool collects the resolved input values into an `options` object, and validates their types against the schema before passing them to the builder function.

For our example builder, `options` should be a `JsonObject` with two keys:
a `source` and a `destination`, each of which are a string.

You can provide the following schema for type validation of these values.

<docs-code header="src/schema.json" language="json">

{
  "$schema": "http://json-schema.org/schema",
  "type": "object",
  "properties": {
    "source": {
      "type": "string"
    },
    "destination": {
      "type": "string"
    }
  }
}

</docs-code>

HELPFUL: This is a minimal example, but the use of a schema for validation can be very powerful.
For more information, see the [JSON schemas website](http://json-schema.org).

To link our builder implementation with its schema and name, you need to create a *builder definition* file, which you can point to in `package.json`.

Create a file named `builders.json` that looks like this:

<docs-code header="builders.json" language="json">

{
  "builders": {
    "copy": {
      "implementation": "./dist/my-builder.js",
      "schema": "./src/schema.json",
      "description": "Copies a file."
    }
  }
}

</docs-code>

In the `package.json` file, add a `builders` key that tells the Architect tool where to find our builder definition file.

<docs-code header="package.json" language="json">

{
  "name": "@example/copy-file",
  "version": "1.0.0",
  "description": "Builder for copying files",
  "builders": "builders.json",
  "dependencies": {
    "@angular-devkit/architect": "~0.1200.0",
    "@angular-devkit/core": "^12.0.0"
  }
}

</docs-code>

The official name of our builder is now `@example/copy-file:copy`.
The first part of this is the package name and the second part is the builder name as specified in the `builders.json` file.

These values are accessed on `options.source` and `options.destination`.

<docs-code header="src/my-builder.ts (report status)" path="adev/src/content/examples/cli-builder/src/my-builder.ts" visibleRegion="report-status"/>

### Target configuration

A builder must have a defined target that associates it with a specific input configuration and project.

Targets are defined in the `angular.json` [CLI configuration file](reference/configs/workspace-config).
A target specifies the builder to use, its default options configuration, and named alternative configurations.
Architect in the Angular CLI uses the target definition to resolve input options for a given run.

The `angular.json` file has a section for each project, and the "architect" section of each project configures targets for builders used by CLI commands such as 'build', 'test', and 'serve'.
By default, for example, the `ng build` command runs the builder `@angular-devkit/build-angular:browser` to perform the build task, and passes in default option values as specified for the `build` target in `angular.json`.

<docs-code header="angular.json" language="json">

…

"myApp": {
  …
  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "outputPath": "dist/myApp",
        "index": "src/index.html",
        …
      },
      "configurations": {
        "production": {
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ],
          "optimization": true,
          "outputHashing": "all",
          …
        }
      }
    },
    …
  }
}

…

</docs-code>

The command passes the builder the set of default options specified in the "options" section.
If you pass the `--configuration=production` flag, it uses the override values specified in the `production` configuration.
Specify further option overrides individually on the command line.

#### Target strings

The generic `ng run` CLI command takes as its first argument a target string of the following form.

<docs-code language="shell">

project:target[:configuration]

</docs-code>

|               | Details |
|:---           |:---     |
| project       | The name of the Angular CLI project that the target is associated with.                                               |
| target        | A named builder configuration from the `architect` section of the `angular.json` file.                                |
| configuration | (optional) The name of a specific configuration override for the given target, as defined in the `angular.json` file. |

If your builder calls another builder, it might need to read a passed target string.
Parse this string into an object by using the `targetFromTargetString()` utility function from `@angular-devkit/architect`.

## Schedule


and run

Architect runs builders asynchronously.
To invoke a builder, you schedule a task to be run when all configuration resolution is complete.

The builder function is not executed until the scheduler returns a `BuilderRun` control object.
The CLI typically schedules tasks by calling the `context.scheduleTarget()` function, and then resolves input options using the target definition in the `angular.json` file.

Architect resolves input options for a given target by taking the default options object, then overwriting values from the configuration, then further overwriting values from the overrides object passed to `context.scheduleTarget()`.
For the Angular CLI, the overrides object is built from command line arguments.

Architect validates the resulting options values against the schema of the builder.
If inputs are valid, Architect creates the context and executes the builder.

For more information see [Workspace Configuration](reference/configs/workspace-config).

HELPFUL: You can also invoke a builder directly from another builder or test by calling `context.scheduleBuilder()`.
You pass an `options` object directly to the method, and those option values are validated against the schema of the builder without further adjustment.

Only the  `context.scheduleTarget()` method resolves the configuration and overrides through the `angular.json` file.

### Default architect configuration

Let's create a simple `angular.json` file that puts target configurations into context.

You can publish the builder to npm (see [Publishing your Library](tools/libraries/creating-libraries#publishing-your-library)), and install it using the following command:

<docs-code language="shell">

npm install @example/copy-file

</docs-code>

If you create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations.

<docs-code header="angular.json" language="json">

{
  "projects": {
    "builder-test": {
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            // more options...
            "outputPath": "dist/builder-test",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json"
          },
          "configurations": {
            "production": {
              // more options...
              "optimization": true,
              "aot": true,
              "buildOptimizer": true
            }
          }
        }
      }
    }
  }
}

</docs-code>

### Adding a target

Add a new target that will run our builder to copy a file.
This target tells the builder to copy the `package.json` file.

* We will add a new target section to the `architect` object for our project
* The target named `copy-package` uses our builder, which you published to `@example/copy-file`.
* The options object provides default values for the two inputs that you defined.
  * `source` - The existing file you are copying.
  * `destination` - The path you want to copy to.

<docs-code header="angular.json" language="json">

{
  "projects": {
    "builder-test": {
      "architect": {
        "copy-package": {
          "builder": "@example/copy-file:copy",
          "options": {
            "source": "package.json",
            "destination": "package-copy.json"
          }
        },

        // Existing targets...
      }
    }
  }
}

</docs-code>

### Running the builder

To run our builder with the new target's default configuration, use the following CLI command.

<docs-code language="shell">

ng run builder-test:copy-package

</docs-code>

This copies the `package.json` file to `package-copy.json`.

Use command-line arguments to override the configured defaults.
For example, to run with a different `destination` value, use the following CLI command.

<docs-code language="shell">

ng run builder-test:copy-package --destination=package-other.json

</docs-code>

This copies the file to `package-other.json` instead of `package-copy.json`.
Because you did not override the *source* option, it will still copy from the default `package.json` file.

## Testing a builder

Use integration testing for your builder, so that you can use the Architect scheduler to create a context, as in this [example](https://github.com/mgechev/cli-builders-demo).
In the builder source directory, create a new test file `my-builder.spec.ts`. The test creates new instances of `JsonSchemaRegistry` (for schema validation), `TestingArchitectHost` (an in-memory implementation of `ArchitectHost`), and `Architect`.

Here's an example of a test that runs the copy file builder.
The test uses the builder to copy the `package.json` file and validates that the copied file's contents are the same as the source.

<docs-code header="src/my-builder.spec.ts" path="adev/src/content/examples/cli-builder/src/my-builder.spec.ts"/>

HELPFUL: When running this test in your repo, you need the [`ts-node`](https://github.com/TypeStrong/ts-node) package.
You can avoid this by renaming `my-builder.spec.ts` to `my-builder.spec.js`.

### Watch mode

Most builders to run once and return. However, this behavior is not entirely compatible with a builder that watches for changes (like a devserver, for example).
Architect can support watch mode, but there are some things to look out for.

* To be used with watch mode, a builder handler function should return an `Observable`.
    Architect subscribes to the `Observable` until it completes and might reuse it if the builder is scheduled again with the same arguments.

* The builder should always emit a `BuilderOutput` object after each execution.
    Once it's been executed, it can enter a watch mode, to be triggered by an external event.
    If an event triggers it to restart, the builder should execute the `context.reportRunning()` function to tell Architect that it is running again.
    This prevents Architect from stopping the builder if another run is scheduled.

When your builder calls `BuilderRun.stop()` to exit watch mode, Architect unsubscribes from the builder's `Observable` and calls the builder's teardown logic to clean up.
This behavior also allows for long-running builds to be stopped and cleaned up.

In general, if your builder is watching an external event, you should separate your run into three phases.

| Phases     | Details |
|:---        |:---     |
| Running    | The task being performed, such as invoking a compiler. This ends when the compiler finishes and your builder emits a `BuilderOutput` object.                                                                                |
| Watching   | Between two runs, watch an external event stream. For example, watch the file system for any changes. This ends when the compiler restarts, and `context.reportRunning()` is called.                                                          |
| Completion | Either the task is fully completed, such as a compiler which needs to run a number of times, or the builder run was stopped (using `BuilderRun.stop()`). Architect executes teardown logic and unsubscribes from your builder's `Observable`. |

## Summary

The CLI Builder API provides a means of changing the behavior of the Angular CLI by using builders to execute custom logic.

* Builders can be synchronous or asynchronous, execute once or watch for external events, and can schedule other builders or targets.
* Builders have option defaults specified in the `angular.json` configuration file, which can be overwritten by an alternate configuration for the target, and further overwritten by command line flags
* The Angular team recommends that you use integration tests to test Architect builders. Use unit tests to validate the logic that the builder executes.
* If your builder returns an `Observable`, it should clean up the builder in the teardown logic of that `Observable`.


<docs-decorative-header title="Rendering Dynamic Templates" imgSrc="adev/src/assets/images/templates.svg"> <!-- markdownlint-disable-line -->
Use Angular's template syntax to create dynamic HTML.
</docs-decorative-header>

What you've learned so far enables you to break an application up into components of HTML, but this limits you to static templates (i.e., content that doesn't change). The next step is to learn how to make use of Angular's template syntax to create dynamic HTML.

## Rendering Dynamic Data

When you need to display dynamic content in your template, Angular uses the double curly brace syntax in order to distinguish between static and dynamic content.

Here is a simplified example from a `TodoListItem` component.

```angular-ts
@Component({
  selector: 'todo-list-item',
  template: `
    <p>Title: {{ taskTitle }}</p>
  `,
})
export class TodoListItem {
  taskTitle = 'Read cup of coffee';
}
```

When Angular renders the component you'll see the output:

```angular-html
<p>Title: Read cup of coffee</p>
```

This syntax declares an **interpolation** between the dynamic data property inside of the HTML. As a result, whenever the data changes, Angular will automatically update the DOM reflecting the new value of the property.

## Dynamic Properties

When you need to dynamically set the value of standard DOM properties on an HTML element, the property is wrapped in square brackets to inform Angular that the declared value should be interpreted as a JavaScript-like statement ([with some Angular enhancements](guide/templates/binding#render-dynamic-text-with-text-interpolation)) instead of a plain string.

For example, a common example of dynamically updating properties in your HTML is determining whether the form submit button should be disabled based on whether the form is valid or not.

Wrap the desired property in square brackets to tell Angular that the assigned value is dynamic (i.e., not a static string).

```angular-ts
@Component({
  selector: 'sign-up-form',
  template: `
    <button type="submit" [disabled]="formIsInvalid">Submit</button>
  `,
})
export class SignUpForm {
  formIsInvalid = true;
}
```

In this example, because `formIsInvalid` is true, the rendered HTML would be:

```angular-html
<button type="submit" disabled>Submit</button>
```

## Dynamic Attributes

In the event you want to dynamically bind custom HTML attributes (e.g., `aria-`, `data-`, etc.), you might be inclined to wrap the custom attributes with the same square brackets.

```angular-ts
@Component({
  standalone: true,
  template: `
    <button [data-test-id]="testId">Primary CTA</button>
  `,
})
export class AppBanner {
  testId = 'main-cta';
}
```

Unfortunately, this will not work because custom HTML attributes are not standard DOM properties. In order for this to work as intended, we need to prepend the custom HTML attribute with the `attr.` prefix.

```angular-ts
@Component({
  standalone: true,
  template: `
    <button [attr.data-test-id]="testId">Primary CTA</button>
  `,
})
export class AppBanner {
  testId = 'main-cta';
}
```

## Next Step

Now that you have dynamic data and templates in the application, it's time to learn how to enhance templates by conditionally hiding or showing certain elements, looping over elements, and more.

<docs-pill-row>
  <docs-pill title="Conditionals and Loops" href="essentials/conditionals-and-loops" />
</docs-pill-row>


<docs-decorative-header title="Conditionals and Loops" imgSrc="adev/src/assets/images/directives.svg"> <!-- markdownlint-disable-line -->
Conditionally show and/or repeat content based on dynamic data.
</docs-decorative-header>

One of the advantages of using a framework like Angular is that it provides built-in solutions for common problems that developers encounter. Examples of this include: displaying content based on a certain condition, rendering a list of items based on application data, etc.

To solve this problem, Angular uses built-in control flow blocks, which tell the framework when and how your templates should be rendered.

## Conditional rendering

One of the most common scenarios that developers encounter is the desire to show or hide content in templates based on a condition.

A common example of this is whether or not to display certain controls on the screen based on the user's permission level.

### `@if` block

Similar to JavaScript's `if` statement, Angular uses `@if` control flow blocks to conditionally hide and show part of a template and its contents.

```angular-ts
// user-controls.component.ts
@Component({
  standalone: true,
  selector: 'user-controls',
  template: `
    @if (isAdmin) {
      <button>Erase database</button>
    }
  `,
})
export class UserControls {
  isAdmin = true;
}
```

In this example, Angular only renders the `<button>` element if the `isAdmin` property is true. Otherwise, it does not appear on the page.

### `@else` block

While the `@if` block can be helpful in many situations, it's common to also show fallback UI when the condition is not met.

For example, in the `UserControls` component, rather than show a blank screen, it would be helpful to users to know that they're not able to see anything because they're not authenticated.

When you need a fallback, similar to JavaScript's `else` clause, add an `@else` block to accomplish the same effect.

```angular-ts
// user-controls.component.ts
@Component({
  standalone: true,
  selector: 'user-controls',
  template: `
    @if (isAdmin) {
      <button>Erase database</button>
    } @else {
      <p>You are not authorized.</p>
    }
  `,
})
export class UserControls {
  isAdmin = true;
}
```

## Rendering a list

Another common scenario developers encounter is the need to render a list of items.

### `@for` block

Similar to JavaScript’s `for...of` loops, Angular provides the `@for` block for rendering repeated elements.

```angular-html
<!-- ingredient-list.component.html -->
<ul>
  @for (ingredient of ingredientList; track ingredient.name) {
    <li>{{ ingredient.quantity }} - {{ ingredient.name }}</li>
  }
</ul>
```

```angular-ts
// ingredient-list.component.ts
@Component({
  standalone: true,
  selector: 'ingredient-list',
  templateUrl: './ingredient-list.component.html',
})
export class IngredientList {
  ingredientList = [
    {name: 'noodles', quantity: 1},
    {name: 'miso broth', quantity: 1},
    {name: 'egg', quantity: 2},
  ];
}
```

However, unlike a standard `for...of` loop, you might've noticed that there's an additional `track` keyword.

#### `track` property

When Angular renders a list of elements with `@for`, those items can later change or move. Angular needs to track each element through any reordering, usually by treating a property of the item as a unique identifier or key.

This ensures any updates to the list are reflected correctly in the UI and tracked properly within Angular, especially in the case of stateful elements or animations.

To accomplish this, we can provide a unique key to Angular with the `track` keyword.

## Next Step

With the ability to determine when and how templates are rendered, it's time to learn how we handle an important aspect of most applications: handling user input.

<docs-pill-row>
  <docs-pill title="Handling User Interaction" href="essentials/handling-user-interaction" />
</docs-pill-row>


<docs-decorative-header title="Components" imgSrc="adev/src/assets/images/components.svg"> <!-- markdownlint-disable-line -->
The fundamental building block for creating applications in Angular.
</docs-decorative-header>

Components provide structure for organizing your project into easy-to-understand parts with clear responsibilities so that your code is maintainable and scalable.

Here is an example of how a Todo application could be broken down into a tree of components.

```mermaid
flowchart TD
    A[TodoApp]-->B
    A-->C
    B[TodoList]-->D
    C[TodoMetrics]
    D[TodoListItem]
```

In this guide, we'll take a look at how to create and use components in Angular.

## Defining a Component

Every component has the following core properties:

1. A `@Component`[decorator](https://www.typescriptlang.org/docs/handbook/decorators.html) that contains some configuration
2. An HTML template that controls what renders into the DOM
3. A [CSS selector](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Selectors) that defines how the component is used in HTML
4. A TypeScript class with behaviors such as managing state, handling user input, or fetching data from a server.

Here is a simplified example of a TodoListItem component.

```angular-ts
// todo-list-item.component.ts
@Component({
  selector: 'todo-list-item',
  template: `
    <li>(TODO) Read Angular Essentials Guide</li>
  `,
})
export class TodoListItem {
  /* Component behavior is defined in here */
}
```

Other common metadata that you'll also see in components include:

- `standalone: true` — The recommended approach of streamlining the authoring experience of components
- `styles` — A string or array of strings that contains any CSS styles you want applied to the component

Knowing this, here is an updated version of our `TodoListItem` component.

```angular-ts
// todo-list-item.component.ts
@Component({
  standalone: true,
  selector: 'todo-list-item',
  template: `
    <li>(TODO) Read Angular Essentials Guide</li>
  `,
  styles: `
    li {
      color: red;
      font-weight: 300;
    }
  `,
})
export class TodoListItem {
  /* Component behavior is defined in here */
}
```

### Separating HTML and CSS into separate files

For teams that prefer managing their HTML and/or CSS in separate files, Angular provides two additional properties: `templateUrl` and `styleUrl`.

Using the previous `TodoListItem` component, the alternative approach looks like:

```angular-ts
// todo-list-item.component.ts
@Component({
  standalone: true,
  selector: 'todo-list-item',
  templateUrl: './todo-list-item.component.html',
  styleUrl: './todo-list-item.component.css',
})
export class TodoListItem {
  /* Component behavior is defined in here */
}
```

```angular-html
<!-- todo-list-item.component.html -->
<li>(TODO) Read Angular Essentials Guide</li>
```

```css
/* todo-list-item.component.css */
li {
  color: red;
  font-weight: 300;
}
```

## Using a Component

One advantage of component architecture is that your application is modular. In other words, components can be used in other components.

To use a component, you need to:

1. Import the component into the file
2. Add it to the component's `imports` array
3. Use the component's selector in the `template`

Here's an example of a `TodoList` component importing the `TodoListItem` component from before:

```angular-ts
// todo-list.component.ts
import {TodoListItem} from './todo-list-item.component.ts';

@Component({
  standalone: true,
  imports: [TodoListItem],
  template: `
    <ul>
      <todo-list-item></todo-list-item>
    </ul>
  `,
})
export class TodoList {}
```

## Next Step

Now that you know how components work in Angular, it's time to learn how we add and manage dynamic data in our application.

<docs-pill-row>
  <docs-pill title="Managing Dynamic Data" href="essentials/managing-dynamic-data" />
</docs-pill-row>


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

/* tslint:disable:no-console  */
// #docregion Component
import {Component} from '@angular/core';
import {FormArray, FormControl, FormGroup} from '@angular/forms';

@Component({
  selector: 'example-app',
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <div formArrayName="cities">
        <div *ngFor="let city of cities.controls; index as i">
          <input [formControlName]="i" placeholder="City" />
        </div>
      </div>
      <button>Submit</button>
    </form>

    <button (click)="addCity()">Add City</button>
    <button (click)="setPreset()">Set preset</button>
  `,
  standalone: false,
})
export class NestedFormArray {
  form = new FormGroup({
    cities: new FormArray([new FormControl('SF'), new FormControl('NY')]),
  });

  get cities(): FormArray {
    return this.form.get('cities') as FormArray;
  }

  addCity() {
    this.cities.push(new FormControl());
  }

  onSubmit() {
    console.log(this.cities.value); // ['SF', 'NY']
    console.log(this.form.value); // { cities: ['SF', 'NY'] }
  }

  setPreset() {
    this.cities.patchValue(['LA', 'MTV']);
  }
}
// #enddocregion


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

// #docregion Component
import {Component} from '@angular/core';

@Component({
  selector: 'example-app',
  template: `
    <form #f="ngForm">
      <select name="state" ngModel>
        <option value="" disabled>Choose a state</option>
        <option *ngFor="let state of states" [ngValue]="state">
          {{ state.abbrev }}
        </option>
      </select>
    </form>

Form value: {{ f.value | json }}

  `,
  standalone: false,
})
export class SelectControlComp {
  states = [
    {name: 'Arizona', abbrev: 'AZ'},
    {name: 'California', abbrev: 'CA'},
    {name: 'Colorado', abbrev: 'CO'},
    {name: 'New York', abbrev: 'NY'},
    {name: 'Pennsylvania', abbrev: 'PA'},
  ];
}
// #enddocregion


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

/* tslint:disable:no-console  */
// #docregion Component
import {Component} from '@angular/core';
import {NgForm} from '@angular/forms';

@Component({
  selector: 'example-app',
  template: `
    <form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
      <input name="first" ngModel required #first="ngModel" />
      <input name="last" ngModel />
      <button>Submit</button>
    </form>

First name value: {{ first.value }}

First name valid: {{ first.valid }}

Form value: {{ f.value | json }}

Form valid: {{ f.valid }}

  `,
  standalone: false,
})
export class SimpleFormComp {
  onSubmit(f: NgForm) {
    console.log(f.value); // { first: '', last: '' }
    console.log(f.valid); // false
  }
}
// #enddocregion


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {
  inject,
  InjectFlags,
  InjectionToken,
  InjectOptions,
  Injector,
  ProviderToken,
  ɵsetCurrentInjector as setCurrentInjector,
  ɵsetInjectorProfilerContext,
} from '@angular/core';

class MockRootScopeInjector implements Injector {
  constructor(readonly parent: Injector) {}

  get<T>(
    token: ProviderToken<T>,
    defaultValue?: any,
    flags: InjectFlags | InjectOptions = InjectFlags.Default,
  ): T {
    if ((token as any).ɵprov && (token as any).ɵprov.providedIn === 'root') {
      const old = setCurrentInjector(this);
      const previousInjectorProfilerContext = ɵsetInjectorProfilerContext({
        injector: this,
        token: null,
      });
      try {
        return (token as any).ɵprov.factory();
      } finally {
        setCurrentInjector(old);
        ɵsetInjectorProfilerContext(previousInjectorProfilerContext);
      }
    }
    return this.parent.get(token, defaultValue, flags);
  }
}

{
  describe('injector metadata examples', () => {
    it('works', () => {
      // #docregion Injector
      const injector: Injector = Injector.create({
        providers: [{provide: 'validToken', useValue: 'Value'}],
      });
      expect(injector.get('validToken')).toEqual('Value');
      expect(() => injector.get('invalidToken')).toThrowError();
      expect(injector.get('invalidToken', 'notFound')).toEqual('notFound');
      // #enddocregion
    });

    it('injects injector', () => {
      // #docregion injectInjector
      const injector = Injector.create({providers: []});
      expect(injector.get(Injector)).toBe(injector);
      // #enddocregion
    });

    it('should infer type', () => {
      // #docregion InjectionToken
      const BASE_URL = new InjectionToken<string>('BaseUrl');
      const injector = Injector.create({
        providers: [{provide: BASE_URL, useValue: 'http://localhost'}],
      });
      const url = injector.get(BASE_URL);
      // Note: since `BASE_URL` is `InjectionToken<string>`
      // `url` is correctly inferred to be `string`
      expect(url).toBe('http://localhost');
      // #enddocregion
    });

    it('injects a tree-shakeable InjectionToken', () => {
      class MyDep {}
      const injector = new MockRootScopeInjector(
        Injector.create({providers: [{provide: MyDep, deps: []}]}),
      );

      // #docregion ShakableInjectionToken
      class MyService {
        constructor(readonly myDep: MyDep) {}
      }

      const MY_SERVICE_TOKEN = new InjectionToken<MyService>('Manually constructed MyService', {
        providedIn: 'root',
        factory: () => new MyService(inject(MyDep)),
      });

      const instance = injector.get(MY_SERVICE_TOKEN);
      expect(instance instanceof MyService).toBeTruthy();
      expect(instance.myDep instanceof MyDep).toBeTruthy();
      // #enddocregion
    });
  });
}


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {
  AfterContentChecked,
  AfterContentInit,
  AfterViewChecked,
  AfterViewInit,
  Component,
  DoCheck,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  SimpleChanges,
  Type,
} from '@angular/core';
import {TestBed} from '@angular/core/testing';

(function () {
  describe('lifecycle hooks examples', () => {
    it('should work with ngOnInit', () => {
      // #docregion OnInit
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements OnInit {
        ngOnInit() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]);
    });

    it('should work with ngDoCheck', () => {
      // #docregion DoCheck
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements DoCheck {
        ngDoCheck() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]);
    });

    it('should work with ngAfterContentChecked', () => {
      // #docregion AfterContentChecked
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements AfterContentChecked {
        ngAfterContentChecked() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]);
    });

    it('should work with ngAfterContentInit', () => {
      // #docregion AfterContentInit
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements AfterContentInit {
        ngAfterContentInit() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]);
    });

    it('should work with ngAfterViewChecked', () => {
      // #docregion AfterViewChecked
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements AfterViewChecked {
        ngAfterViewChecked() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]);
    });

    it('should work with ngAfterViewInit', () => {
      // #docregion AfterViewInit
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements AfterViewInit {
        ngAfterViewInit() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]);
    });

    it('should work with ngOnDestroy', () => {
      // #docregion OnDestroy
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements OnDestroy {
        ngOnDestroy() {
          // ...
        }
      }
      // #enddocregion

      expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]);
    });

    it('should work with ngOnChanges', () => {
      // #docregion OnChanges
      @Component({
        selector: 'my-cmp',
        template: `
          ...
        `,
        standalone: false,
      })
      class MyComponent implements OnChanges {
        @Input() prop: number = 0;

        ngOnChanges(changes: SimpleChanges) {
          // changes.prop contains the old and the new value...
        }
      }
      // #enddocregion

      const log = createAndLogComponent(MyComponent, ['prop']);
      expect(log.length).toBe(1);
      expect(log[0][0]).toBe('ngOnChanges');
      const changes: SimpleChanges = log[0][1][0];
      expect(changes['prop'].currentValue).toBe(true);
    });
  });

  function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] {
    const log: any[] = [];
    createLoggingSpiesFromProto(clazz, log);

    const inputBindings = inputs.map((input) => `[${input}] = true`).join(' ');

    @Component({
      template: `
        <my-cmp ${inputBindings}></my-cmp>
      `,
      standalone: false,
    })
    class ParentComponent {}

    const fixture = TestBed.configureTestingModule({
      declarations: [ParentComponent, clazz],
    }).createComponent(ParentComponent);
    fixture.detectChanges();
    fixture.destroy();
    return log;
  }

  function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) {
    const proto = clazz.prototype;
    // For ES2015+ classes, members are not enumerable in the prototype.
    Object.getOwnPropertyNames(proto).forEach((method) => {
      if (method === 'constructor') {
        return;
      }

      proto[method] = (...args: any[]) => {
        log.push([method, args]);
      };
    });
  }
})();


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {
  Component,
  Injectable,
  Injector,
  Input,
  NgModule,
  OnInit,
  TemplateRef,
  ViewChild,
  ViewContainerRef,
} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';

// #docregion SimpleExample
@Component({
  selector: 'hello-world',
  template: 'Hello World!',
  standalone: false,
})
export class HelloWorld {}

@Component({
  selector: 'ng-component-outlet-simple-example',
  template: `
    <ng-container *ngComponentOutlet="HelloWorld"></ng-container>
  `,
  standalone: false,
})
export class NgComponentOutletSimpleExample {
  // This field is necessary to expose HelloWorld to the template.
  HelloWorld = HelloWorld;
}
// #enddocregion

// #docregion CompleteExample
@Injectable()
export class Greeter {
  suffix = '!';
}

@Component({
  selector: 'complete-component',
  template: `
    {{ label }}:
    <ng-content></ng-content>
    <ng-content></ng-content>
    {{ greeter.suffix }}
  `,
  standalone: false,
})
export class CompleteComponent {
  @Input() label!: string;

  constructor(public greeter: Greeter) {}
}

@Component({
  selector: 'ng-component-outlet-complete-example',
  template: `
    <ng-template #ahoj>Ahoj</ng-template>
    <ng-template #svet>Svet</ng-template>
    <ng-container
      *ngComponentOutlet="
        CompleteComponent;
        inputs: myInputs;
        injector: myInjector;
        content: myContent
      "
    ></ng-container>
  `,
  standalone: false,
})
export class NgComponentOutletCompleteExample implements OnInit {
  // This field is necessary to expose CompleteComponent to the template.
  CompleteComponent = CompleteComponent;

  myInputs = {'label': 'Complete'};

  myInjector: Injector;
  @ViewChild('ahoj', {static: true}) ahojTemplateRef!: TemplateRef<any>;
  @ViewChild('svet', {static: true}) svetTemplateRef!: TemplateRef<any>;
  myContent?: any[][];

  constructor(
    injector: Injector,
    private vcr: ViewContainerRef,
  ) {
    this.myInjector = Injector.create({
      providers: [{provide: Greeter, deps: []}],
      parent: injector,
    });
  }

  ngOnInit() {
    // Create the projectable content from the templates
    this.myContent = [
      this.vcr.createEmbeddedView(this.ahojTemplateRef).rootNodes,
      this.vcr.createEmbeddedView(this.svetTemplateRef).rootNodes,
    ];
  }
}
// #enddocregion

@Component({
  selector: 'example-app',
  template: `
    <ng-component-outlet-simple-example></ng-component-outlet-simple-example>
    <hr />
    <ng-component-outlet-complete-example></ng-component-outlet-complete-example>
  `,
  standalone: false,
})
export class AppComponent {}

@NgModule({
  imports: [BrowserModule],
  declarations: [
    AppComponent,
    NgComponentOutletSimpleExample,
    NgComponentOutletCompleteExample,
    HelloWorld,
    CompleteComponent,
  ],
})
export class AppModule {}


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {Component, inject, Injectable} from '@angular/core';
import {bootstrapApplication} from '@angular/platform-browser';
import {
  ActivatedRoute,
  ActivatedRouteSnapshot,
  CanActivateChildFn,
  CanActivateFn,
  CanMatchFn,
  provideRouter,
  ResolveFn,
  Route,
  RouterStateSnapshot,
  UrlSegment,
} from '@angular/router';

@Component({
  template: '',
  standalone: false,
})
export class App {}

@Component({
  template: '',
  standalone: false,
})
export class TeamComponent {}

// #docregion CanActivateFn
@Injectable()
class UserToken {}

@Injectable()
class PermissionsService {
  canActivate(currentUser: UserToken, userId: string): boolean {
    return true;
  }
  canMatch(currentUser: UserToken): boolean {
    return true;
  }
}

const canActivateTeam: CanActivateFn = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
) => {
  return inject(PermissionsService).canActivate(inject(UserToken), route.params['id']);
};
// #enddocregion

// #docregion CanActivateFnInRoute
bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'team/:id',
        component: TeamComponent,
        canActivate: [canActivateTeam],
      },
    ]),
  ],
});
// #enddocregion

// #docregion CanActivateChildFn
const canActivateChildExample: CanActivateChildFn = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
) => {
  return inject(PermissionsService).canActivate(inject(UserToken), route.params['id']);
};

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'team/:id',
        component: TeamComponent,
        canActivateChild: [canActivateChildExample],
        children: [],
      },
    ]),
  ],
});
// #enddocregion

// #docregion CanDeactivateFn
@Component({
  template: '',
  standalone: false,
})
export class UserComponent {
  hasUnsavedChanges = true;
}

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'user/:id',
        component: UserComponent,
        canDeactivate: [(component: UserComponent) => !component.hasUnsavedChanges],
      },
    ]),
  ],
});
// #enddocregion

// #docregion CanMatchFn
const canMatchTeam: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
  return inject(PermissionsService).canMatch(inject(UserToken));
};

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'team/:id',
        component: TeamComponent,
        canMatch: [canMatchTeam],
      },
    ]),
  ],
});
// #enddocregion

// #docregion ResolveDataUse
@Component({
  template: '',
  standalone: false,
})
export class HeroDetailComponent {
  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.activatedRoute.data.subscribe(({hero}) => {
      // do something with your resolved data ...
    });
  }
}
// #enddocregion

// #docregion ResolveFn
interface Hero {
  name: string;
}
@Injectable()
export class HeroService {
  getHero(id: string) {
    return {name: `Superman-${id}`};
  }
}

export const heroResolver: ResolveFn<Hero> = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
) => {
  return inject(HeroService).getHero(route.paramMap.get('id')!);
};

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'detail/:id',
        component: HeroDetailComponent,
        resolve: {hero: heroResolver},
      },
    ]),
  ],
});
// #enddocregion


/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */
// #docregion activated-route
import {Component, NgModule} from '@angular/core';
// #enddocregion activated-route
import {BrowserModule} from '@angular/platform-browser';
// #docregion activated-route
import {ActivatedRoute, RouterModule} from '@angular/router';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';
// #enddocregion activated-route

// #docregion activated-route

@Component({
  // #enddocregion activated-route
  selector: 'example-app',
  template: '...',
  standalone: false,
})
export class ActivatedRouteComponent {
  constructor(route: ActivatedRoute) {
    const id: Observable<string> = route.params.pipe(map((p) => p['id']));
    const url: Observable<string> = route.url.pipe(map((segments) => segments.join('')));
    // route.data includes both `data` and `resolve`
    const user = route.data.pipe(map((d) => d['user']));
  }
}
// #enddocregion activated-route

@NgModule({
  imports: [BrowserModule, RouterModule.forRoot([])],
  declarations: [ActivatedRouteComponent],
  bootstrap: [ActivatedRouteComponent],
})
export class AppModule {}


# CLI Overview and Command Reference

The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications directly from a command shell.

## Installing Angular CLI

Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.

Install the CLI using the `npm` package manager:

npm install -g @angular/cli<aio-angular-dist-tag class="pln"></aio-angular-dist-tag>

For details about changes between versions, and information about updating from previous releases, see the Releases tab on GitHub: https://github.com/angular/angular-cli/releases

## Basic workflow

Invoke the tool on the command line through the `ng` executable.
Online help is available on the command line.
Enter the following to list commands or options for a given command \(such as [new](cli/new)\) with a short description.

ng --help
ng new --help

To create, build, and serve a new, basic Angular project on a development server, go to the parent directory of your new workspace use the following commands:

ng new my-first-project
cd my-first-project
ng serve

In your browser, open http://localhost:4200/ to see the new application run.
When you use the [ng serve](cli/serve) command to build an application and serve it locally, the server automatically rebuilds the application and reloads the page when you change any of the source files.

When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory.
Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.

If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>`.

## Workspaces and project files

The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new application skeleton.
A workspace can contain multiple applications and libraries.
The initial application created by the [ng new](cli/new) command is at the top level of the workspace.
When you generate an additional application or library in a workspace, it goes into a `projects/` subfolder.

A newly generated application contains the source files for a root module, with a root component and template.
Each application has a `src` folder that contains the logic, data, and assets.

You can edit the generated files directly, or add to and modify them using CLI commands.
Use the [ng generate](cli/generate) command to add new files for additional components and services, and code for new pipes, directives, and so on.
Commands such as [add](cli/add) and [generate](cli/generate), which create or operate on applications and libraries, must be executed from within a workspace or project folder.

*   See more about the [Workspace file structure](guide/file-structure).

### Workspace and project configuration

A single workspace configuration file, `angular.json`, is created at the top level of the workspace.
This is where you can set per-project defaults for CLI command options, and specify configurations to use when the CLI builds a project for different targets.

The [ng config](cli/config) command lets you set and retrieve configuration values from the command line, or you can edit the `angular.json` file directly.

**NOTE**:

Option names in the configuration file must use [camelCase](guide/glossary#case-types), while option names supplied to commands must be dash-case.

*   See more about [Workspace Configuration](guide/workspace-config).

## CLI command-language syntax

Command syntax is shown as follows:

`ng` *<command-name>* *<required-arg>* [*optional-arg*] `[options]`

*   Most commands, and some options, have aliases.
    Aliases are shown in the syntax statement for each command.

*   Option names are prefixed with a double dash \(`--`\) characters.
    Option aliases are prefixed with a single dash \(`-`\) character.
    Arguments are not prefixed.
    For example:

    ng build my-app -c production

*   Typically, the name of a generated artifact can be given as an argument to the command or specified with the `--name` option.

*   Arguments and option names must be given in [dash-case](guide/glossary#case-types).
    For example: `--my-option-name`

### Boolean options

Boolean options have two forms: `--this-option` sets the flag to `true`, `--no-this-option` sets it to `false`.
If neither option is supplied, the flag remains in its default state, as listed in the reference documentation.

### Array options

Array options can be provided in two forms: `--option value1 value2` or `--option value1 --option value2`.

### Relative paths

Options that specify files can be given as absolute paths, or as paths relative to the current working directory, which is generally either the workspace or project root.

### Schematics

The [ng generate](cli/generate) and [ng add](cli/add) commands take, as an argument, the artifact or library to be generated or added to the current project.
In addition to any general options, each artifact or library defines its own options in a *schematic*.
Schematic options are supplied to the command in the same format as immediate command options.

@reviewed 2022-02-28


// #docregion
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';

import {AppComponent} from './app.component';
import {ActorFormComponent} from './actor-form/actor-form.component';

@NgModule({
  imports: [BrowserModule, CommonModule, FormsModule],
  declarations: [AppComponent, ActorFormComponent],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}


// #docregion
import {Component} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  standalone: false,
})
export class AppComponent {}


import {Injectable} from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MyLibService {}


<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Angular Quickstart Seed</title>
    <base href="/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfills -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/bundles/zone.umd.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="systemjs.config.js"></script>
    <script>
      System.import('main.js').catch(function(err){ console.error(err); });
    </script>
  </head>

  <body>
    <app-root><!-- content managed by Angular --></app-root>
  </body>

</html>


import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {FavoriteColorComponent} from './favorite-color/favorite-color.component';

@NgModule({
  imports: [CommonModule, FormsModule],
  declarations: [FavoriteColorComponent],
  exports: [FavoriteColorComponent],
})
export class TemplateModule {}


import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideHttpClient} from '@angular/common/http';

import {AppComponent} from './app/app.component';

bootstrapApplication(AppComponent, {
  // HttpClientModule is only used in deprecated HeroListComponent
  providers: [
    provideHttpClient(),
    provideProtractorTestingSupport(), // essential for e2e testing
  ],
});


import {provideHttpClient} from '@angular/common/http';
import {ApplicationConfig, importProvidersFrom} from '@angular/core';
import {provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideRouter} from '@angular/router';
import {HttpClientInMemoryWebApiModule} from 'angular-in-memory-web-api';

import {routes} from './app.routes';
import {InMemoryDataService} from './in-memory-data.service';
import {HeroService} from './model/hero.service';
import {UserService} from './model/user.service';
import {TwainService} from './twain/twain.service';

export const appProviders = [
  provideRouter(routes),
  provideHttpClient(),
  provideProtractorTestingSupport(),
  importProvidersFrom(
    // The HttpClientInMemoryWebApiModule module intercepts HTTP requests
    // and returns simulated server responses.
    // Remove it when a real server is ready to receive requests.
    HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, {dataEncapsulation: false}),
  ),
  HeroService,
  TwainService,
  UserService,
];

export const appConfig: ApplicationConfig = {
  providers: appProviders,
};


/* eslint-disable @angular-eslint/directive-selector, guard-for-in, @angular-eslint/no-input-rename
 */
import {
  Component,
  ContentChildren,
  Directive,
  EventEmitter,
  HostBinding,
  HostListener,
  Injectable,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  Optional,
  Output,
  Pipe,
  PipeTransform,
  SimpleChanges,
} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {of} from 'rxjs';
import {delay} from 'rxjs/operators';

import {sharedImports} from '../shared/shared';

////////// The App: Services and Components for the tests. //////////////

export interface Hero {
  name: string;
}

////////// Services ///////////////
@Injectable()
export class ValueService {
  value = 'real value';

  getValue() {
    return this.value;
  }
  setValue(value: string) {
    this.value = value;
  }

  getObservableValue() {
    return of('observable value');
  }

  getPromiseValue() {
    return Promise.resolve('promise value');
  }

  getObservableDelayValue() {
    return of('observable delay value').pipe(delay(10));
  }
}

// #docregion MasterService
@Injectable()
export class MasterService {
  constructor(private valueService: ValueService) {}
  getValue() {
    return this.valueService.getValue();
  }
}
// #enddocregion MasterService

/////////// Pipe ////////////////
/*
 * Reverse the input string.
 */
@Pipe({name: 'reverse', standalone: true})
export class ReversePipe implements PipeTransform {
  transform(s: string) {
    let r = '';
    for (let i = s.length; i; ) {
      r += s[--i];
    }
    return r;
  }
}

//////////// Components /////////////
@Component({
  standalone: true,
  selector: 'bank-account',
  template: ` Bank Name: {{ bank }} Account Id: {{ id }} `,
})
export class BankAccountComponent {
  @Input() bank = '';
  @Input('account') id = '';

  // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
  // constructor(private renderer: Renderer, private el: ElementRef ) {
  //   renderer.setElementProperty(el.nativeElement, 'customProperty', true);
  // }
}

/** A component with attributes, styles, classes, and property setting */
@Component({
  standalone: true,
  selector: 'bank-account-parent',
  template: `
    <bank-account
      bank="RBC"
      account="4747"
      [style.width.px]="width"
      [style.color]="color"
      [class.closed]="isClosed"
      [class.open]="!isClosed"
    >
    </bank-account>
  `,
  imports: [BankAccountComponent],
})
export class BankAccountParentComponent {
  width = 200;
  color = 'red';
  isClosed = true;
}

// #docregion LightswitchComp
@Component({
  standalone: true,
  selector: 'lightswitch-comp',
  template: ` <button type="button" (click)="clicked()">Click me!</button>
    {{ message }}`,
})
export class LightswitchComponent {
  isOn = false;
  clicked() {
    this.isOn = !this.isOn;
  }
  get message() {
    return `The light is ${this.isOn ? 'On' : 'Off'}`;
  }
}
// #enddocregion LightswitchComp

@Component({
  standalone: true,
  selector: 'child-1',
  template: 'Child-1({{text}})',
})
export class Child1Component {
  @Input() text = 'Original';
}

@Component({
  standalone: true,
  selector: 'child-2',
  template: '
Child-2({{text}})
',
})
export class Child2Component {
  @Input() text = '';
}

@Component({
  standalone: true,
  selector: 'child-3',
  template: '
Child-3({{text}})
',
})
export class Child3Component {
  @Input() text = '';
}

@Component({
  standalone: true,
  selector: 'input-comp',
  template: '<input [(ngModel)]="name">',
  imports: [FormsModule],
})
export class InputComponent {
  name = 'John';
}

/* Prefer this metadata syntax */
// @Directive({
//   selector: 'input[value]',
//   host: {
//     '[value]': 'value',
//     '(input)': 'valueChange.emit($event.target.value)'
//   },
//   inputs:  ['value'],
//   outputs: ['valueChange']
// })
// export class InputValueBinderDirective {
//   value: any;
//   valueChange: EventEmitter<any> = new EventEmitter();
// }

// As the styleguide recommends
@Directive({standalone: true, selector: 'input[value]'})
export class InputValueBinderDirective {
  @HostBinding() @Input() value: any;

  @Output() valueChange: EventEmitter<any> = new EventEmitter();

  @HostListener('input', ['$event.target.value'])
  onInput(value: any) {
    this.valueChange.emit(value);
  }
}

@Component({
  standalone: true,
  selector: 'input-value-comp',
  template: ` Name: <input [value]="name" /> {{ name }} `,
})
export class InputValueBinderComponent {
  name = 'Sally'; // initial value
}

@Component({
  standalone: true,
  selector: 'parent-comp',
  imports: [Child1Component],
  template: 'Parent(<child-1></child-1>)',
})
export class ParentComponent {}

@Component({
  standalone: true,
  selector: 'io-comp',
  template: '<button type="button" class="hero" (click)="click()">Original {{hero.name}}</button>',
})
export class IoComponent {
  @Input() hero!: Hero;
  @Output() selected = new EventEmitter<Hero>();
  click() {
    this.selected.emit(this.hero);
  }
}

@Component({
  standalone: true,
  selector: 'io-parent-comp',
  template: `
    @if (!selectedHero) {

Click to select a hero

    }
    @if (selectedHero) {

The selected hero is {{ selectedHero.name }}

    }
    @for (hero of heroes; track hero) {
      <io-comp [hero]="hero" (selected)="onSelect($event)"> </io-comp>
    }
  `,
  imports: [IoComponent, sharedImports],
})
export class IoParentComponent {
  heroes: Hero[] = [{name: 'Bob'}, {name: 'Carol'}, {name: 'Ted'}, {name: 'Alice'}];
  selectedHero!: Hero;
  onSelect(hero: Hero) {
    this.selectedHero = hero;
  }
}

@Component({
  standalone: true,
  selector: 'my-if-comp',
  template: 'MyIf(@if (showMore) {More})',
  imports: [sharedImports],
})
export class MyIfComponent {
  showMore = false;
}

@Component({
  standalone: true,
  selector: 'my-service-comp',
  template: 'injected value: {{valueService.value}}',
  providers: [ValueService],
})
export class TestProvidersComponent {
  constructor(public valueService: ValueService) {}
}

@Component({
  standalone: true,
  selector: 'my-service-comp',
  template: 'injected value: {{valueService.value}}',
  viewProviders: [ValueService],
})
export class TestViewProvidersComponent {
  constructor(public valueService: ValueService) {}
}

@Component({
  standalone: true,
  selector: 'external-template-comp',
  templateUrl: './demo-external-template.html',
})
export class ExternalTemplateComponent implements OnInit {
  serviceValue = '';

  constructor(@Optional() private service?: ValueService) {}

  ngOnInit() {
    if (this.service) {
      this.serviceValue = this.service.getValue();
    }
  }
}

@Component({
  standalone: true,
  selector: 'comp-w-ext-comp',
  imports: [ExternalTemplateComponent],
  template: `

comp-w-ext-comp

    <external-template-comp></external-template-comp>
  `,
})
export class InnerCompWithExternalTemplateComponent {}

@Component({standalone: true, selector: 'needs-content', template: '<ng-content></ng-content>'})
export class NeedsContentComponent {
  // children with #content local variable
  @ContentChildren('content') children: any;
}

///////// MyIfChildComp ////////


@Component({
  standalone: true,
  selector: 'my-if-child-1',
  template: `
MyIfChildComp

      Child value: <input id="child-value" [(ngModel)]="childValue" />

Change log:

    @for (log of changeLog; track log; let i = $index) {

{{ i + 1 }} - {{ log }}

    }`,
  imports: [FormsModule, sharedImports],
})
export class MyIfChildComponent implements OnInit, OnChanges, OnDestroy {
  @Input() value = '';
  @Output() valueChange = new EventEmitter<string>();

  get childValue() {
    return this.value;
  }
  set childValue(v: string) {
    if (this.value === v) {
      return;
    }
    this.value = v;
    this.valueChange.emit(v);
  }

  changeLog: string[] = [];

  ngOnInitCalled = false;
  ngOnChangesCounter = 0;
  ngOnDestroyCalled = false;

  ngOnInit() {
    this.ngOnInitCalled = true;
    this.changeLog.push('ngOnInit called');
  }

  ngOnDestroy() {
    this.ngOnDestroyCalled = true;
    this.changeLog.push('ngOnDestroy called');
  }

  ngOnChanges(changes: SimpleChanges) {
    for (const propName in changes) {
      this.ngOnChangesCounter += 1;
      const prop = changes[propName];
      const cur = JSON.stringify(prop.currentValue);
      const prev = JSON.stringify(prop.previousValue);
      this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

///////// MyIfParentComp ////////

@Component({
  standalone: true,
  selector: 'my-if-parent-comp',
  template: `

MyIfParentComp

    Parent value:
      <input id="parent" [(ngModel)]="parentValue" />

    <button type="button" (click)="clicked()">{{ toggleLabel }} Child</button>

    @if (showChild) {

        <my-if-child-1 [(value)]="parentValue"></my-if-child-1>

    }
  `,
  imports: [FormsModule, MyIfChildComponent, sharedImports],
})
export class MyIfParentComponent implements OnInit {
  ngOnInitCalled = false;
  parentValue = 'Hello, World';
  showChild = false;
  toggleLabel = 'Unknown';

  ngOnInit() {
    this.ngOnInitCalled = true;
    this.clicked();
  }

  clicked() {
    this.showChild = !this.showChild;
    this.toggleLabel = this.showChild ? 'Close' : 'Show';
  }
}

@Component({
  standalone: true,
  selector: 'reverse-pipe-comp',
  template: `
    <input [(ngModel)]="text" />
    {{ text | reverse }}
  `,
  imports: [ReversePipe, FormsModule],
})
export class ReversePipeComponent {
  text = 'my dog has fleas.';
}

@Component({
  standalone: true,
  imports: [NeedsContentComponent],
  template: '
Replace Me
',
})
export class ShellComponent {}

@Component({
  standalone: true,
  selector: 'demo-comp',
  template: `

Specs Demo

    <my-if-parent-comp></my-if-parent-comp>

Input/Output Component

    <io-parent-comp></io-parent-comp>

External Template Component

    <external-template-comp></external-template-comp>

Component With External Template Component

    <comp-w-ext-comp></comp-w-ext-comp>

Reverse Pipe

    <reverse-pipe-comp></reverse-pipe-comp>

InputValueBinder Directive

    <input-value-comp></input-value-comp>

Button Component

    <lightswitch-comp></lightswitch-comp>

Needs Content

    <needs-content #nc>
      <child-1 #content text="My"></child-1>
      <child-2 #content text="dog"></child-2>
      <child-2 text="has"></child-2>
      <child-3 #content text="fleas"></child-3>

!

    </needs-content>
  `,
  imports: [
    Child1Component,
    Child2Component,
    Child3Component,
    ExternalTemplateComponent,
    InnerCompWithExternalTemplateComponent,
    InputValueBinderComponent,
    IoParentComponent,
    LightswitchComponent,
    NeedsContentComponent,
    ReversePipeComponent,
    MyIfParentComponent,
  ],
})
export class DemoComponent {}
//////// Aggregations ////////////

export const demoProviders = [MasterService, ValueService];


// #docplaster
import {ComponentFixture, inject, TestBed} from '@angular/core/testing';

import {UserService} from '../model/user.service';
import {WelcomeComponent} from './welcome.component';

// #docregion mock-user-service
class MockUserService {
  isLoggedIn = true;
  user = {name: 'Test User'};
}
// #enddocregion mock-user-service

describe('WelcomeComponent', () => {
  let comp: WelcomeComponent;
  let fixture: ComponentFixture<WelcomeComponent>;
  let componentUserService: UserService; // the actually injected service
  let userService: UserService; // the TestBed injected service
  let el: HTMLElement; // the DOM element with the welcome message

  // #docregion setup
  beforeEach(() => {
    fixture = TestBed.createComponent(WelcomeComponent);
    fixture.autoDetectChanges();
    comp = fixture.componentInstance;

    // #docregion injected-service
    // UserService actually injected into the component
    userService = fixture.debugElement.injector.get(UserService);
    // #enddocregion injected-service
    componentUserService = userService;
    // #docregion inject-from-testbed
    // UserService from the root injector
    userService = TestBed.inject(UserService);
    // #enddocregion inject-from-testbed

    //  get the "welcome" element by CSS selector (e.g., by class name)
    el = fixture.nativeElement.querySelector('.welcome');
  });
  // #enddocregion setup

  // #docregion tests
  it('should welcome the user', async () => {
    await fixture.whenStable();
    const content = el.textContent;
    expect(content).withContext('"Welcome ..."').toContain('Welcome');
    expect(content).withContext('expected name').toContain('Test User');
  });

  it('should welcome "Bubba"', async () => {
    userService.user.set({name: 'Bubba'}); // welcome message hasn't been shown yet
    await fixture.whenStable();
    expect(el.textContent).toContain('Bubba');
  });

  it('should request login if not logged in', async () => {
    userService.isLoggedIn.set(false); // welcome message hasn't been shown yet
    await fixture.whenStable();
    const content = el.textContent;
    expect(content).withContext('not welcomed').not.toContain('Welcome');
    expect(content)
      .withContext('"log in"')
      .toMatch(/log in/i);
  });
  // #enddocregion tests

  it("should inject the component's UserService instance", inject(
    [UserService],
    (service: UserService) => {
      expect(service).toBe(componentUserService);
    },
  ));

  it('TestBed and Component UserService should be the same', () => {
    expect(userService).toBe(componentUserService);
  });
});


import {provideHttpClient} from '@angular/common/http';
import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing';
import {NO_ERRORS_SCHEMA} from '@angular/core';
import {TestBed, waitForAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {NavigationEnd, provideRouter, Router} from '@angular/router';
import {RouterTestingHarness} from '@angular/router/testing';
import {firstValueFrom} from 'rxjs';
import {filter} from 'rxjs/operators';

import {addMatchers, click} from '../../testing';
import {HeroService} from '../model/hero.service';
import {getTestHeroes} from '../model/testing/test-heroes';

import {DashboardComponent} from './dashboard.component';
import {appConfig} from '../app.config';
import {HeroDetailComponent} from '../hero/hero-detail.component';

beforeEach(addMatchers);

let comp: DashboardComponent;
let harness: RouterTestingHarness;

////////  Deep  ////////////////

describe('DashboardComponent (deep)', () => {
  compileAndCreate();

  tests(clickForDeep);

  function clickForDeep() {
    // get first

    const heroEl: HTMLElement = harness.routeNativeElement!.querySelector('.hero')!;
    click(heroEl);
    return firstValueFrom(
      TestBed.inject(Router).events.pipe(filter((e) => e instanceof NavigationEnd)),
    );
  }
});

////////  Shallow ////////////////

describe('DashboardComponent (shallow)', () => {
  beforeEach(() => {
    TestBed.configureTestingModule(
      Object.assign({}, appConfig, {
        imports: [DashboardComponent, HeroDetailComponent],
        providers: [provideRouter([{path: 'heroes/:id', component: HeroDetailComponent}])],
        schemas: [NO_ERRORS_SCHEMA],
      }),
    );
  });

  compileAndCreate();

  tests(clickForShallow);

  function clickForShallow() {
    // get first <dashboard-hero> DebugElement
    const heroDe = harness.routeDebugElement!.query(By.css('dashboard-hero'));
    heroDe.triggerEventHandler('selected', comp.heroes[0]);
    return Promise.resolve();
  }
});

/** Add TestBed providers, compile, and create DashboardComponent */
function compileAndCreate() {
  beforeEach(async () => {
    // #docregion router-harness
    TestBed.configureTestingModule(
      Object.assign({}, appConfig, {
        imports: [DashboardComponent],
        providers: [
          provideRouter([{path: '**', component: DashboardComponent}]),
          provideHttpClient(),
          provideHttpClientTesting(),
          HeroService,
        ],
      }),
    );
    harness = await RouterTestingHarness.create();
    comp = await harness.navigateByUrl('/', DashboardComponent);
    TestBed.inject(HttpTestingController).expectOne('api/heroes').flush(getTestHeroes());
    // #enddocregion router-harness
  });
}

/**
 * The (almost) same tests for both.
 * Only change: the way that the first hero is clicked
 */
function tests(heroClick: () => Promise<unknown>) {
  describe('after get dashboard heroes', () => {
    let router: Router;

    // Trigger component so it gets heroes and binds to them
    beforeEach(waitForAsync(() => {
      router = TestBed.inject(Router);
      harness.detectChanges(); // runs ngOnInit -> getHeroes
    }));

    it('should HAVE heroes', () => {
      expect(comp.heroes.length)
        .withContext('should have heroes after service promise resolves')
        .toBeGreaterThan(0);
    });

    it('should DISPLAY heroes', () => {
      // Find and examine the displayed heroes
      // Look for them in the DOM by css class
      const heroes = harness.routeNativeElement!.querySelectorAll('dashboard-hero');
      expect(heroes.length).withContext('should display 4 heroes').toBe(4);
    });

    // #docregion navigate-test
    it('should tell navigate when hero clicked', async () => {
      await heroClick(); // trigger click on first inner

      // expecting to navigate to id of the component's first hero
      const id = comp.heroes[0].id;
      expect(TestBed.inject(Router).url)
        .withContext('should nav to HeroDetail for first hero')
        .toEqual(`/heroes/${id}`);
    });
    // #enddocregion navigate-test
  });
}