diff --git a/adev-ja/src/app/features/update/recommendations.en.ts b/adev-ja/src/app/features/update/recommendations.en.ts index c4038024c6..e1ab7b9d4a 100644 --- a/adev-ja/src/app/features/update/recommendations.en.ts +++ b/adev-ja/src/app/features/update/recommendations.en.ts @@ -2592,6 +2592,28 @@ export const RECOMMENDATIONS: Step[] = [ action: 'Adjust code that directly calls functions returning `RedirectFn`. These functions can now also return an `Observable` or `Promise`; ensure your logic correctly handles these asynchronous return types.', }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Basic, + step: '20.0.0_rename_resource_request_to_param', + action: 'Rename the `request` property passed in resources to `params`.', + }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Medium, + step: '20.0.0_rename_rxResource_loader_to_stream', + action: 'Rename the `loader` property passed in rxResources to `stream`.', + }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Basic, + step: '20.0.0_replace_ResourceStatus_by_corresponding_strings', + action: + '`ResourceStatus` is no longer an enum. Use the corresponding constant string values instead.', + }, { possibleIn: 2000, necessaryAsOf: 2000, @@ -2712,4 +2734,12 @@ export const RECOMMENDATIONS: Step[] = [ action: 'Review `DatePipe` usages. Using the `Y` (week-numbering year) formatter without also including `w` (week number) is now detected as suspicious. Use `y` (year) if that was the intent, or include `w` alongside `Y`.', }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Medium, + step: '20.0.0_handle_uncaught_listener_errors_in_tests', + action: + 'In templates parentheses are now always respected. This can lead to runtime breakages when nullish coalescing were nested in parathesis. eg `(foo?.bar).baz` will throw if `foo` is nullish as it would in native JavaScript.', + }, ]; diff --git a/adev-ja/src/app/features/update/recommendations.ts b/adev-ja/src/app/features/update/recommendations.ts index 55d61609ab..484e177702 100644 --- a/adev-ja/src/app/features/update/recommendations.ts +++ b/adev-ja/src/app/features/update/recommendations.ts @@ -2592,6 +2592,28 @@ export const RECOMMENDATIONS: Step[] = [ action: '`RedirectFn`を返す関数を直接呼び出すコードを調整してください。これらの関数は`Observable`または`Promise`も返すことができるようになりました。ロジックがこれらの非同期戻り値を正しく処理することを確認してください。', }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Basic, + step: '20.0.0_rename_resource_request_to_param', + action: 'リソースで渡される`request`プロパティを`params`にリネームしてください。', + }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Medium, + step: '20.0.0_rename_rxResource_loader_to_stream', + action: 'rxResourcesで渡される`loader`プロパティを`stream`にリネームしてください。', + }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Basic, + step: '20.0.0_replace_ResourceStatus_by_corresponding_strings', + action: + '`ResourceStatus`はもはやenumではありません。代わりに対応する定数文字列値を使用してください。', + }, { possibleIn: 2000, necessaryAsOf: 2000, @@ -2712,4 +2734,12 @@ export const RECOMMENDATIONS: Step[] = [ action: '`DatePipe`の使用を見直してください。`Y`(週番号付け年)フォーマッターを`w`(週番号)を含めずに使用すると、疑わしいと検出されるようになりました。意図がそうであった場合は`y`(年)を使用するか、`Y`と一緒に`w`を含めてください。', }, + { + possibleIn: 2000, + necessaryAsOf: 2000, + level: ApplicationComplexity.Medium, + step: '20.0.0_handle_uncaught_listener_errors_in_tests', + action: + 'テンプレートでは括弧が常に尊重されるようになりました。これは、null合体演算子が括弧内にネストされている場合にランタイムエラーを引き起こす可能性があります。例:`(foo?.bar).baz`は、`foo`がnullishの場合、ネイティブJavaScriptと同様にエラーを投げます。', + }, ]; diff --git a/adev-ja/src/app/sub-navigation-data.en.ts b/adev-ja/src/app/sub-navigation-data.en.ts index cf26dc3957..fe20e9ea3c 100644 --- a/adev-ja/src/app/sub-navigation-data.en.ts +++ b/adev-ja/src/app/sub-navigation-data.en.ts @@ -351,6 +351,16 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'guide/routing/read-route-state', contentPath: 'guide/routing/read-route-state', }, + { + label: 'Redirecting routes', + path: 'guide/routing/redirecting-routes', + contentPath: 'guide/routing/redirecting-routes', + }, + { + label: 'Control route access with guards', + path: 'guide/routing/route-guards', + contentPath: 'guide/routing/route-guards', + }, { label: 'Other routing tasks', path: 'guide/routing/common-router-tasks', @@ -421,6 +431,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'guide/http/making-requests', contentPath: 'guide/http/making-requests', }, + { + label: 'Reactive data fetching with httpResource', + path: 'guide/http/http-resource', + contentPath: 'guide/http/http-resource', + }, { label: 'Intercepting requests and responses', path: 'guide/http/interceptors', @@ -623,6 +638,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'ai', contentPath: 'ai/overview', }, + { + label: 'LLM prompts and AI IDE setup', + path: 'ai/develop-with-ai', + contentPath: 'ai/develop-with-ai', + }, ], }, { @@ -763,6 +783,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'best-practices/a11y', contentPath: 'best-practices/a11y', }, + { + label: 'Unhandled errors in Angular', + path: 'best-practices/error-handling', + contentPath: 'best-practices/error-handling', + }, { label: 'Performance', children: [ @@ -786,6 +811,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'best-practices/skipping-subtrees', contentPath: 'best-practices/runtime-performance/skipping-subtrees', }, + { + label: 'Profiling with the Chrome DevTools', + path: 'best-practices/profiling-with-chrome-devtools', + contentPath: 'best-practices/runtime-performance/profiling-with-chrome-devtools', + }, {label: 'Zoneless', path: 'guide/zoneless', contentPath: 'guide/zoneless'}, ], }, diff --git a/adev-ja/src/app/sub-navigation-data.ts b/adev-ja/src/app/sub-navigation-data.ts index 69ebacad21..9e0dc0e429 100644 --- a/adev-ja/src/app/sub-navigation-data.ts +++ b/adev-ja/src/app/sub-navigation-data.ts @@ -351,6 +351,16 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'guide/routing/read-route-state', contentPath: 'guide/routing/read-route-state', }, + { + label: 'ルートのリダイレクト', + path: 'guide/routing/redirecting-routes', + contentPath: 'guide/routing/redirecting-routes', + }, + { + label: 'ガードによるルートアクセスの制御', + path: 'guide/routing/route-guards', + contentPath: 'guide/routing/route-guards', + }, { label: 'その他のルーティングタスク', path: 'guide/routing/common-router-tasks', @@ -421,6 +431,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'guide/http/making-requests', contentPath: 'guide/http/making-requests', }, + { + label: 'httpResourceを使ったリアクティブなデータ取得', + path: 'guide/http/http-resource', + contentPath: 'guide/http/http-resource', + }, { label: 'リクエストとレスポンスへの介入', path: 'guide/http/interceptors', @@ -623,6 +638,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'ai', contentPath: 'ai/overview', }, + { + label: 'LLMプロンプトとAI IDEセットアップ', + path: 'ai/develop-with-ai', + contentPath: 'ai/develop-with-ai', + }, ], }, { @@ -763,6 +783,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'best-practices/a11y', contentPath: 'best-practices/a11y', }, + { + label: 'Angularでの未処理のエラー', + path: 'best-practices/error-handling', + contentPath: 'best-practices/error-handling', + }, { label: 'パフォーマンス', children: [ @@ -786,6 +811,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [ path: 'best-practices/skipping-subtrees', contentPath: 'best-practices/runtime-performance/skipping-subtrees', }, + { + label: 'Chrome DevToolsでのプロファイリング', + path: 'best-practices/profiling-with-chrome-devtools', + contentPath: 'best-practices/runtime-performance/profiling-with-chrome-devtools', + }, {label: 'Zoneless', path: 'guide/zoneless', contentPath: 'guide/zoneless'}, ], }, diff --git a/adev-ja/src/content/ai/develop-with-ai.md b/adev-ja/src/content/ai/develop-with-ai.md new file mode 100644 index 0000000000..8c75f8e4f5 --- /dev/null +++ b/adev-ja/src/content/ai/develop-with-ai.md @@ -0,0 +1,36 @@ +# LLM prompts and AI IDE setup +Generating code with large language models (LLMs) is a rapidly growing area of interest for developers. While LLMs are often capable of generating working code it can be a challenge to generate code for consistently evolving frameworks like Angular. + +Advanced instructions and prompting are an emerging standard for supporting modern code generation with domain specific details. This section contains curated content and resources to support more accurate code generation for Angular and LLMs. + +## Custom Prompts and System Instructions +Improve your experience generating code with LLMs by using one of the following custom, domain specific files. + +NOTE: These files will be updated on a regular basis staying up to date with Angular's conventions. + +Here is a set of instructions to help LLMs generate correct code that follows Angular best practices. This file can be included as system instructions to your AI tooling or included along with your prompt as context. + + + +Click here to download the best-practices.md file. + +## Rules Files +Several editors, such as Firebase Studio have rules files useful for providing critical context to LLMs. + +| Environment/IDE | Rules File | Installation Instructions | +|:----------------|:----------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------| +| Firebase Studio | airules.md | Configure `airules.md` | +| Copilot powered IDEs | copilot-instructions.md | Configure `.github/copilot-instructions.md` | +| Cursor | cursor.md | Configure `cursorrules.md` | +| JetBrains IDEs | guidelines.md | Configure `guidelines.md` | +| VS Code | .instructions.md | Configure `.instructions.md` | +| Windsurf | guidelines.md | Configure `guidelines.md` | + +## Providing Context with `llms.txt` +`llms.txt` is a proposed standard for websites designed to help LLMs better understand and process their content. The Angular team has developed two versions of this file to help LLMs and tools that use LLMs for code generation to create better modern Angular code. + + +* llms.txt - an index file providing links to key files and resources. +* llms-full.txt - a more robust compiled set of resources describing how Angular works and how to build Angular applications. + +Be sure [to check out the overview page](/ai) for more information on how to integrate AI into your Angular applications. diff --git a/adev-ja/src/content/ai/overview.en.md b/adev-ja/src/content/ai/overview.en.md index feeda50560..d816855eac 100644 --- a/adev-ja/src/content/ai/overview.en.md +++ b/adev-ja/src/content/ai/overview.en.md @@ -3,6 +3,8 @@ Build AI-powered apps. Develop faster with AI. +HELPFUL: Looking to get started with building in your favorite AI powered IDE?
Check out our [prompt rules and best practices](/ai/develop-with-ai). + Generative AI (GenAI) with large language models (LLMs) enables the creation of sophisticated and engaging application experiences, including personalized content, intelligent recommendations, media generation and comprehension, information summarization, and dynamic functionality. Developing features like these would have previously required deep domain expertise and significant engineering effort. However, new products and SDKs are lowering the barrier to entry. Angular is well-suited for integrating AI into your web application as a result of: @@ -11,7 +13,7 @@ Developing features like these would have previously required deep domain expert * Strong, signal-based architecture designed to dynamically manage data and state * Angular integrates seamlessly with AI SDKs and APIs -This guide demonstrates how you can use [Genkit](/ai#build-ai-powered-applications-with-genkit-and-angular), [Firebase AI Logic](https://firebase.google.com/products/firebase-ai-logic), and the [Gemini API](https://ai.google.dev/) to infuse your Angular apps with AI today. This guide will jumpstart your AI-powered web app development journey by explaining how to begin integrating AI into Angular apps. This guide also shares resources, such as starter kits, example code, and recipes for common workflows, you can use to get up to speed quickly. +This guide demonstrates how you can use [Genkit](/ai#build-ai-powered-applications-with-genkit-and-angular), [Firebase AI Logic](/ai#build-ai-powered-applications-with-firebase-ai-logic-and-angular), and the [Gemini API](/ai#build-ai-powered-applications-with-gemini-api-and-angular) to infuse your Angular apps with AI today. This guide will jumpstart your AI-powered web app development journey by explaining how to begin integrating AI into Angular apps. This guide also shares resources, such as starter kits, example code, and recipes for common workflows, you can use to get up to speed quickly. To get started, you should have a basic understanding of Angular. New to Angular? Try our [essentials guide](/essentials) or our [getting started tutorials](/tutorials). @@ -20,20 +22,20 @@ NOTE: While this page features integrations and examples with Google AI products ## Getting Started Building AI-powered applications is a new and rapidly developing field. It can be challenging to decide where to start and which technologies to choose. The following section provides three options to choose from: -1. *Genkit* gives you the choice of [supported model and interface with a unified API](https://firebase.google.com/docs/genkit) for building full-stack applications. Ideal for applications requiring sophisticated back-end AI logic, such as personalized recommendations. +1. *Genkit* gives you the choice of [supported model and interface with a unified API](https://genkit.dev) for building full-stack applications. Ideal for applications requiring sophisticated back-end AI logic, such as personalized recommendations. 1. *Firebase AI Logic* provides a secure client-side API for Google's models to build client-side only applications or mobile apps. Best for interactive AI features directly in the browser, such as real-time text analysis or basic chatbots. 1. *Gemini API* enables you to build an application that uses the methods and functionality exposed through the API surface directly, best for full-stack applications. Suitable for applications needing direct control over AI models, like custom image generation or deep data processing. ### Build AI-powered applications with Genkit and Angular -[Genkit](https://firebase.google.com/docs/genkit) is an open-source toolkit designed to help you build AI-powered features in web and mobile apps. It offers a unified interface for integrating AI models from Google, OpenAI, Anthropic, Ollama, and more, so you can explore and choose the best models for your needs. As a server-side solution, your web apps need a supported server environment, such as a node-based server in order to integrate with Genkit. Building a full-stack app using Angular SSR gives you the starting server-side code, for example. +[Genkit](https://genkit.dev) is an open-source toolkit designed to help you build AI-powered features in web and mobile apps. It offers a unified interface for integrating AI models from Google, OpenAI, Anthropic, Ollama, and more, so you can explore and choose the best models for your needs. As a server-side solution, your web apps need a supported server environment, such as a node-based server in order to integrate with Genkit. Building a full-stack app using Angular SSR gives you the starting server-side code, for example. Here are examples of how to build with Genkit and Angular: * [Agentic Apps with Genkit and Angular starter-kit](https://github.com/angular/examples/tree/main/genkit-angular-starter-kit)— New to building with AI? Start here with a basic app that features an agentic workflow. Perfect place to start for your first AI building experience. -* [Use Genkit in an Angular app](https://firebase.google.com/docs/genkit/angular)— Build a basic application that uses Genkit Flows, Angular and Gemini 2.0 Flash. This step-by-step walkthrough guides you through creating a full-stack Angular application with AI features. +* [Use Genkit in an Angular app](https://genkit.dev/docs/angular/)— Build a basic application that uses Genkit Flows, Angular and Gemini 2.0 Flash. This step-by-step walkthrough guides you through creating a full-stack Angular application with AI features. * [Dynamic Story Generator app](https://github.com/angular/examples/tree/main/genkit-angular-story-generator)— Learn to build an agentic Angular app powered by Genkit, Gemini and Imagen 3 to dynamically generate a story based on user interaction featuring beautiful image panels to accompany the events that take place. Start here if you'd like to experiment with a more advanced use-case. diff --git a/adev-ja/src/content/ai/overview.md b/adev-ja/src/content/ai/overview.md index d689d9381f..903833b8a7 100644 --- a/adev-ja/src/content/ai/overview.md +++ b/adev-ja/src/content/ai/overview.md @@ -3,6 +3,8 @@ AI搭載アプリケーションを構築。AIで開発を加速。 +HELPFUL: お気に入りのAIパワードIDEで構築を始めたい方は、[プロンプトルールとベストプラクティス](/ai/develop-with-ai)をご確認ください。 + 生成AI (GenAI)と大規模言語モデル (LLM)は、パーソナライズされたコンテンツ、インテリジェントなレコメンデーション、メディアの生成と理解、情報の要約、動的な機能など、高度で魅力的なアプリケーション体験の作成を可能にします。 このような機能の開発は、これまで深いドメイン知識と多大なエンジニアリング作業を必要としました。しかし、新しい製品とSDKが参入障壁を下げています。Angularは、以下の理由により、AIをウェブアプリケーションに統合するのに非常に適しています。 @@ -11,7 +13,7 @@ AI搭載アプリケーションを構築。AIで開発を加速。 * データと状態を動的に管理するために設計された、強力なシグナルベースのアーキテクチャ * AngularはAI SDKとAPIにシームレスに統合 -このガイドでは、[Genkit](/ai#build-ai-powered-applications-with-genkit-and-angular)、[Firebase AI Logic](https://firebase.google.com/products/firebase-ai-logic)、および[Gemini API](https://ai.google.dev/)を使用して、AngularアプリケーションにAIを組み込む方法を示します。このガイドは、AngularアプリケーションにAIを統合する方法を説明することで、AI搭載ウェブアプリケーション開発の旅を加速させるでしょう。また、このガイドでは、迅速に習得できるスターターキット、サンプルコード、一般的なワークフローのレシピなどのリソースも共有しています。 +このガイドでは、[Genkit](/ai#build-ai-powered-applications-with-genkit-and-angular)、[Firebase AI Logic](/ai#build-ai-powered-applications-with-firebase-ai-logic-and-angular)、および[Gemini API](/ai#build-ai-powered-applications-with-gemini-api-and-angular)を使用して、AngularアプリケーションにAIを組み込む方法を示します。このガイドは、AngularアプリケーションにAIを統合する方法を説明することで、AI搭載ウェブアプリケーション開発の旅を加速させるでしょう。また、このガイドでは、迅速に習得できるスターターキット、サンプルコード、一般的なワークフローのレシピなどのリソースも共有しています。 始めるには、Angularの基本的な理解が必要です。Angularは初めてですか?[必須ガイド](/essentials)または[入門チュートリアル](/tutorials)をお試しください。 @@ -20,20 +22,20 @@ NOTE: このページではGoogle AI製品との統合と例を紹介してい ## はじめに AI搭載アプリケーションの構築は、新しく急速に発展している分野です。どこから始め、どの技術を選択するかを決定するのは難しい場合があります。以下のセクションでは、選択できる3つのオプションを提供します。 -1. *Genkit*は、フルスタックアプリケーション構築のために、[サポートされているモデルと統合APIを備えたインターフェース](https://firebase.google.com/docs/genkit)の選択肢を提供します。パーソナライズされたレコメンデーションなど、高度なバックエンドAIロジックを必要とするアプリケーションに最適です。 +1. *Genkit*は、フルスタックアプリケーション構築のために、[サポートされているモデルと統合APIを備えたインターフェース](https://genkit.dev)の選択肢を提供します。パーソナライズされたレコメンデーションなど、高度なバックエンドAIロジックを必要とするアプリケーションに最適です。 1. *Firebase AI Logic*は、Googleのモデル向けに安全なクライアントサイドAPIを提供し、クライアントサイド専用アプリケーションやモバイルアプリケーションを構築できます。リアルタイムテキスト分析や基本的なチャットボットなど、ブラウザで直接インタラクティブなAI機能を利用するのに最適です。 1. *Gemini API*を使用すると、APIサーフェスを通じて直接公開されるメソッドと機能を使用するアプリケーションを構築でき、フルスタックアプリケーションに最適です。カスタム画像生成やディープデータ処理など、AIモデルを直接制御する必要があるアプリケーションに適しています。 ### GenkitとAngularでAI搭載アプリケーションを構築する {#build-ai-powered-applications-with-genkit-and-angular} -[Genkit](https://firebase.google.com/docs/genkit)は、ウェブアプリケーションやモバイルアプリケーションにAI搭載機能を構築するのに役立つように設計されたオープンソースツールキットです。Google、OpenAI、Anthropic、OllamaなどからのAIモデルを統合するための統合インターフェースを提供するため、ニーズに最適なモデルを探索して選択できます。サーバーサイドソリューションであるため、Genkitと統合するには、ウェブアプリケーションにはNode.jsベースのサーバーなどのサポートされているサーバー環境が必要です。たとえば、Angular SSRを使用してフルスタックアプリケーションを構築すると、サーバーサイドの開始コードが得られます。 +[Genkit](https://genkit.dev)は、ウェブアプリケーションやモバイルアプリケーションにAI搭載機能を構築するのに役立つように設計されたオープンソースツールキットです。Google、OpenAI、Anthropic、OllamaなどからのAIモデルを統合するための統合インターフェースを提供するため、ニーズに最適なモデルを探索して選択できます。サーバーサイドソリューションであるため、Genkitと統合するには、ウェブアプリケーションにはNode.jsベースのサーバーなどのサポートされているサーバー環境が必要です。たとえば、Angular SSRを使用してフルスタックアプリケーションを構築すると、サーバーサイドの開始コードが得られます。 GenkitとAngularで構築する方法の例を次に示します。 * [GenkitとAngularのスターターキットを使用したエージェントアプリ](https://github.com/angular/examples/tree/main/genkit-angular-starter-kit)— AIでの構築は初めてですか?エージェントワークフローを備えた基本的なアプリケーションから始めましょう。初めてのAI構築体験に最適な場所です。 -* [AngularアプリでGenkitを使用する](https://firebase.google.com/docs/genkit/angular)— Genkit Flows、Angular、Gemini 2.0 Flashを使用する基本的なアプリケーションを構築します。このステップバイステップのウォークスルーは、AI機能を備えたフルスタックAngularアプリケーションの作成をガイドします。 +* [AngularアプリでGenkitを使用する](https://genkit.dev/docs/angular/)— Genkit Flows、Angular、Gemini 2.0 Flashを使用する基本的なアプリケーションを構築します。このステップバイステップのウォークスルーは、AI機能を備えたフルスタックAngularアプリケーションの作成をガイドします。 * [動的ストーリー生成アプリ](https://github.com/angular/examples/tree/main/genkit-angular-story-generator)— Genkit、Gemini、Imagen 3を搭載したエージェントAngularアプリケーションを構築し、ユーザーインタラクションに基づいてストーリーを動的に生成し、発生するイベントに付随する美しい画像パネルを特徴とする方法を学びます。より高度なユースケースを試したい場合は、ここから始めましょう。 diff --git a/adev-ja/src/content/best-practices/runtime-performance/profiling-with-chrome-devtools.md b/adev-ja/src/content/best-practices/runtime-performance/profiling-with-chrome-devtools.md new file mode 100644 index 0000000000..c78d6c28ef --- /dev/null +++ b/adev-ja/src/content/best-practices/runtime-performance/profiling-with-chrome-devtools.md @@ -0,0 +1,100 @@ +# Profiling with the Chrome DevTools + +Angular integrates with the [Chrome DevTools extensibility API](https://developer.chrome.com/docs/devtools/performance/extension) to present framework-specific data and insights directly in the [Chrome DevTools performance panel](https://developer.chrome.com/docs/devtools/performance/overview). + +With the integration enabled, you can [record a performance profile](https://developer.chrome.com/docs/devtools/performance#record) containing two sets of data: + +- Standard performance entries based on Chrome's understanding of your code executing in a browser, and +- Angular-specific entries contributed by the framework's runtime. + +Both sets of data are presented together on the same tab, but on separate tracks: + +Angular custom track in Chrome DevTools profiler + +Angular-specific data are expressed in terms of framework concepts (components, change detection, lifecycle hooks, etc.) alongside lower-level function and method calls captured by a browser. These two data sets are correlated, and you can switch between the different views and level of details. + +You can use the Angular track to better understand how your code runs in the browser, including: + +- Determining whether a given code block is part of the Angular application, or whether it belongs to another script running on the same page. +- Identifying performance bottlenecks and attribute those to specific components or services. +- Gaining deeper insight into Angular's inner working with a visual breakdown of each change detection cycle. + +## Recording a profile + +### Enable integration + +You can enable Angular profiling in one of two ways: + +1. Run `ng.enableProfiling()` in Chrome's console panel, or +1. Include a call to `enableProfiling()` in your application startup code (imported from `@angular/core`). + +NOTE: +Angular profiling works exclusively in development mode. + +Here is an example of how you can enable the integration in the application bootstrap to capture all possible events: + +```ts +import { enableProfiling } from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { MyApp } from './my-app'; + +// Turn on profiling *before* bootstrapping your application +// in order to capture all of the code run on start-up. +enableProfiling(); +bootstrapApplication(MyApp); +``` + +### Record a profile + +Use the **Record** button in the Chrome DevTools performance panel: + +Recording a profile + +See the [Chrome DevTools documentation](https://developer.chrome.com/docs/devtools/performance#record) for more details on recording profiles. + +## Interpreting a recorded profile + +You can use the "Angular" custom track to quickly identify and diagnose performance issues. The following sections describe some common profiling scenarios. + +### Differentiating between your Angular application and other tasks on the same page + +As Angular and Chrome data are presented on the separate but correlated tracks, you can see when Angular's application code is executed as opposed to some other browser processing (typically layout and paint) or other scripts running on the same page (in this case the custom Angular track does not have any data): + +Profile data: Angular vs. 3rd party scripts execution + +This allows you to determine whether further investigations should focus on the Angular application code or on other parts of your codebase or dependencies. + +### Color-coding + +Angular uses colors in the flame chart graph to distinguish tasks types: + +- 🟦 Blue represents TypeScript code written by the application developer (for example: services, component constructors and lifecycle hooks, etc.). +- 🟪 Purple represents templates code written by the application developer and transformed by the Angular compiler. +- 🟩 Green represents entry points to the application code and identifies _reasons_ for executing code. + +The following examples illustrate the described color-coding in various, real-life recordings. + +#### Example: Application bootstrapping + +The application bootstrap process usually consists of: + +- Triggers marked in blue, such as the call to the `bootstrapApplication`, instantiation of the root component, and initial change detection +- Various DI services instantiated during bootstrap, marked in green. + +Profile data: bootstrap application + +#### Example: Component execution + +One component processing is typically represented as an entry point (blue) followed by its template execution (purple). A template might, in turn, trigger instantiation of directives and execution of lifecycle hooks (green): + +Profile data: component processing + +#### Example: Change detection + +A change detection cycle usually consists of one or more data synchronization passes (blue), where each pass traverses a subset of components. + +Profile data: change detection + +With this data visualization, it is possible to immediately identify components that were involved in the change detection and which were skipped (typically the `OnPush` components that were not marked dirty). + +Additionally, you can inspect the number of synchronization passes for one change detection. Having more than one synchronization pass suggest that state is updated during change detection. You should avoid this, as it slows down page updates and can even result in infinite loops in the worst cases. diff --git a/adev-ja/src/content/best-practices/style-guide.en.md b/adev-ja/src/content/best-practices/style-guide.en.md index 1add59bdd6..fe9c8345f3 100644 --- a/adev-ja/src/content/best-practices/style-guide.en.md +++ b/adev-ja/src/content/best-practices/style-guide.en.md @@ -222,6 +222,9 @@ Prefer `class` and `style` bindings over using the `NgClass` and `NgStyle` direc ```html
+ +
+
diff --git a/adev-ja/src/content/best-practices/style-guide.md b/adev-ja/src/content/best-practices/style-guide.md index b07a62b102..cdab623b19 100644 --- a/adev-ja/src/content/best-practices/style-guide.md +++ b/adev-ja/src/content/best-practices/style-guide.md @@ -222,6 +222,9 @@ Prefer `class` and `style` bindings over using the `NgClass` and `NgStyle` direc ```html
+ +
+
diff --git a/adev-ja/src/content/guide/components/programmatic-rendering.en.md b/adev-ja/src/content/guide/components/programmatic-rendering.en.md index 99004d77ec..678d49dc21 100644 --- a/adev-ja/src/content/guide/components/programmatic-rendering.en.md +++ b/adev-ja/src/content/guide/components/programmatic-rendering.en.md @@ -2,9 +2,17 @@ TIP: This guide assumes you've already read the [Essentials Guide](essentials). Read that first if you're new to Angular. -In addition to using a component directly in a template, you can also dynamically render components. -There are two main ways to dynamically render a component: in a template with `NgComponentOutlet`, -or in your TypeScript code with `ViewContainerRef`. +In addition to using a component directly in a template, you can also dynamically render components +programmatically. This is helpful for situations when a component is unknown initially (thus can not +be referenced in a template directly) and it depends on some conditions. + +There are two main ways to render a component programmatically: in a template using `NgComponentOutlet`, +or in your TypeScript code using `ViewContainerRef`. + +HELPFUL: for lazy-loading use-cases (for example if you want to delay loading of a heavy component), consider +using the built-in [`@defer` feature](/guide/templates/defer) instead. The `@defer` feature allows the code +of any components, directives, and pipes inside the `@defer` block to be extracted into separate JavaScript +chunks automatically and loaded only when necessary, based on the configured triggers. ## Using NgComponentOutlet @@ -28,7 +36,7 @@ export class CustomDialog { user = input.required(); getBioComponent() { - return this.user.isAdmin ? AdminBio : StandardBio; + return this.user().isAdmin ? AdminBio : StandardBio; } } ``` @@ -95,9 +103,11 @@ In the example above, clicking the "Load content" button results in the followin ## Lazy-loading components -You can use both of the approaches described above, `NgComponentOutlet` and `ViewContainerRef`, to -render components that are lazy-loaded with a standard -JavaScript [dynamic import](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import). +HELPFUL: if you want to lazy-load some components, you may consider using the built-in [`@defer` feature](/guide/templates/defer) +instead. + +If your use-case is not covered by the `@defer` feature, you can use either `NgComponentOutlet` or +`ViewContainerRef` with a standard JavaScript [dynamic import](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import). ```angular-ts @Component({ diff --git a/adev-ja/src/content/guide/components/programmatic-rendering.md b/adev-ja/src/content/guide/components/programmatic-rendering.md index 9ca1d7caba..b42de64bbe 100644 --- a/adev-ja/src/content/guide/components/programmatic-rendering.md +++ b/adev-ja/src/content/guide/components/programmatic-rendering.md @@ -2,10 +2,17 @@ TIP: このガイドでは、[基本概念のガイド](essentials)をすでに読んでいることを前提としています。Angularを初めて使用する場合は、まずこのガイドを読んでください。 -コンポーネントはテンプレートで直接使用できるだけでなく、動的にもレンダリングできます。 -コンポーネントを動的にレンダリングする主な方法は2つあります。 +コンポーネントはテンプレートで直接使用できるだけでなく、プログラムで動的にもレンダリングできます。 +これは、コンポーネントが最初は不明で(そのためテンプレートで直接参照できない)、何らかの条件に依存する場合に便利です。 + +コンポーネントをプログラムでレンダリングする主な方法は2つあります。 テンプレートで`NgComponentOutlet`を使用するか、TypeScriptコードで`ViewContainerRef`を使用します。 +HELPFUL: 遅延読み込みのユースケース(たとえば、重いコンポーネントの読み込みを遅らせたい場合)については、 +組み込みの[`@defer`機能](/guide/templates/defer)の使用を検討してください。`@defer`機能により、 +`@defer`ブロック内のコンポーネント、ディレクティブ、パイプのコードを自動的に別のJavaScriptチャンクに +抽出し、設定されたトリガーに基づいて必要な時にのみ読み込むことができます。 + ## NgComponentOutletを使用する `NgComponentOutlet`は、 @@ -28,7 +35,7 @@ export class CustomDialog { user = input.required(); getBioComponent() { - return this.user.isAdmin ? AdminBio : StandardBio; + return this.user().isAdmin ? AdminBio : StandardBio; } } ``` @@ -95,9 +102,12 @@ export class InnerItem { ## コンポーネントの遅延読み込み -上記で説明した`NgComponentOutlet`と`ViewContainerRef`の両方の方法を使用して、 -標準のJavaScript [動的インポート](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import)で -遅延読み込みされるコンポーネントをレンダリングできます。 +HELPFUL: いくつかのコンポーネントを遅延読み込みしたい場合は、 +組み込みの[`@defer`機能](/guide/templates/defer)の使用を検討してください。 + +あなたのユースケースが`@defer`機能でカバーされない場合は、 +`NgComponentOutlet`または`ViewContainerRef`を標準のJavaScript +[動的インポート](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import)と一緒に使用できます。 ```angular-ts @Component({ diff --git a/adev-ja/src/content/guide/directives/overview.en.md b/adev-ja/src/content/guide/directives/overview.en.md index 76a3a4d0d7..9b87981e90 100644 --- a/adev-ja/src/content/guide/directives/overview.en.md +++ b/adev-ja/src/content/guide/directives/overview.en.md @@ -23,7 +23,7 @@ The most common attribute directives are as follows: | :------------------------------------------------------------ | :------------------------------------------------- | | [`NgClass`](#adding-and-removing-classes-with-ngclass) | Adds and removes a set of CSS classes. | | [`NgStyle`](#setting-inline-styles-with-ngstyle) | Adds and removes a set of HTML styles. | -| [`NgModel`](#displaying-and-updating-properties-with-ngmodel) | Adds two-way data binding to an HTML form element. | +| [`NgModel`](guide/forms/template-driven-forms) | Adds two-way data binding to an HTML form element. | HELPFUL: Built-in directives use only public APIs. They do not have special access to any private APIs that other directives can't access. @@ -92,41 +92,6 @@ For this use case, Angular applies the styles upon initialization and in case of To do this, the full example calls `setCurrentStyles()` initially with `ngOnInit()` and when the dependent properties change through a button click. However, these steps are not necessary to implement `ngStyle` on its own. -## Displaying and updating properties with `ngModel` - -Use the `NgModel` directive to display a data property and update that property when the user makes changes. - -1. Import `FormsModule` and add it to the AppComponent's `imports` list. - - - -1. Add an `[(ngModel)]` binding on an HTML `
` element and set it equal to the property, here `name`. - - - - This `[(ngModel)]` syntax can only set a data-bound property. - -To customize your configuration, write the expanded form, which separates the property and event binding. -Use [property binding](guide/templates/property-binding) to set the property and [event binding](guide/templates/event-listeners) to respond to changes. -The following example changes the `` value to uppercase: - - - -Here are all variations in action, including the uppercase version: - -NgModel variations - -### `NgModel` and value accessors - -The `NgModel` directive works for an element supported by a [ControlValueAccessor](api/forms/ControlValueAccessor). -Angular provides _value accessors_ for all of the basic HTML form elements. -For more information, see [Forms](guide/forms). - -To apply `[(ngModel)]` to a non-form built-in element or a third-party custom component, you have to write a value accessor. -For more information, see the API documentation on [DefaultValueAccessor](api/forms/DefaultValueAccessor). - -HELPFUL: When you write an Angular component, you don't need a value accessor or `NgModel` if you name the value and event properties according to Angular's [two-way binding syntax](guide/templates/two-way-binding#how-two-way-binding-works). - ## Hosting a directive without a DOM element The Angular `` is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM. diff --git a/adev-ja/src/content/guide/directives/overview.md b/adev-ja/src/content/guide/directives/overview.md index bda9bc3dd6..1787a0987f 100644 --- a/adev-ja/src/content/guide/directives/overview.md +++ b/adev-ja/src/content/guide/directives/overview.md @@ -23,7 +23,7 @@ Angularディレクティブの種類は以下のとおりです。 | :------------------------------------------------------------ | :------------------------------------------------- | | [`NgClass`](#adding-and-removing-classes-with-ngclass) | CSS クラスのセットを追加および削除します。 | | [`NgStyle`](#setting-inline-styles-with-ngstyle) | HTML スタイルのセットを追加および削除します。 | -| [`NgModel`](#displaying-and-updating-properties-with-ngmodel) | HTML フォーム要素に双方向データバインディングを追加します。 | +| [`NgModel`](guide/forms/template-driven-forms) | HTML フォーム要素に双方向データバインディングを追加します。 | HELPFUL: 組み込みディレクティブは、公開APIのみを使用します。他のディレクティブがアクセスできないプライベートAPIには、特別なアクセス権がありません。 @@ -92,40 +92,6 @@ HELPFUL: To add or remove a _single_ style, use [style bindings](guide/templates これを行うために、完全な例では、`ngOnInit()` を使用して最初に `setCurrentStyles()` を呼び出し、依存プロパティがボタンクリックを通じて変更されたときに呼び出します。 ただし、これらの手順は、`ngStyle` 自体を実装するために必要ではありません。 -## `ngModel` を使用してプロパティを表示および更新する {#displaying-and-updating-properties-with-ngmodel} - -`NgModel` ディレクティブを使用して、データプロパティを表示し、ユーザーが変更を加えたときにそのプロパティを更新します。 - -1. `FormsModule` をインポートし、AppComponentの `imports` リストに追加します。 - - - -1. HTML `` 要素に `[(ngModel)]` バインディングを追加して、プロパティ(ここでは `name`)に等しく設定します。 - - - - この `[(ngModel)]` 構文は、データバインドプロパティのみを設定できます。 - -構成をカスタマイズするには、拡張フォームを記述します。これにより、プロパティとイベントバインディングが分離されます。 -[プロパティバインディング](guide/templates/property-binding) を使用してプロパティを設定し、[イベントバインディング](guide/templates/event-listeners) を使用して変更に応答します。 -次の例では、`` 値を大文字に変更します。 - - - -以下は、大文字バージョンを含む、すべてのバリエーションが動作している様子です。 - -NgModel のバリエーション - -### `NgModel` と値アクセサー - -`NgModel` ディレクティブは、[ControlValueAccessor](api/forms/ControlValueAccessor) によってサポートされている要素で機能します。 -Angularは、すべての基本的なHTMLフォーム要素に対して _値アクセサー_ を提供します。 -詳細については、[フォーム](guide/forms) を参照してください。 - -`[(ngModel)]` を非フォームの組み込み要素またはサードパーティのカスタムコンポーネントに適用するには、値アクセサーを作成する必要があります。 -詳細については、[DefaultValueAccessor](api/forms/DefaultValueAccessor) に関するAPIドキュメントを参照してください。 - -HELPFUL: Angularコンポーネントを作成する際、Angularの [双方向バインディング構文](guide/templates/two-way-binding#how-two-way-binding-works) に従って値とイベントプロパティに名前を付ければ、値アクセサーや `NgModel` は必要ありません。 ## DOM 要素のないディレクティブをホストする diff --git a/adev-ja/src/content/guide/directives/structural-directives.en.md b/adev-ja/src/content/guide/directives/structural-directives.en.md index 2a6e6e09c4..7a4b531066 100644 --- a/adev-ja/src/content/guide/directives/structural-directives.en.md +++ b/adev-ja/src/content/guide/directives/structural-directives.en.md @@ -90,13 +90,13 @@ export class SelectDirective { -Add a `selectFrom` `@Input()` property. +Add a `selectFrom` `input()` property. ```ts export class SelectDirective { // ... - @Input({required: true}) selectFrom!: DataSource; + selectFrom = input.required(); } ``` @@ -201,9 +201,9 @@ To narrow the input expression by defining a type assertion function: // expression is narrowed to `User`. @Directive(...) class ActorIsUser { - @Input() actor: User|Robot; + actor = input(); - static ngTemplateGuard_actor(dir: ActorIsUser, expr: User|Robot): expr is User { + static ngTemplateGuard_actor(dir: ActorIsUser, expr: User | Robot): expr is User { // The return statement is unnecessary in practice, but included to // prevent TypeScript errors. return true; @@ -218,7 +218,7 @@ Some directives only render their templates when an input is truthy. It's not po ```ts @Directive(...) class CustomIf { - @Input() condition!: any; + condition = input.required(); static ngTemplateGuard_condition: 'binding'; } @@ -242,7 +242,7 @@ export interface SelectTemplateContext { export class SelectDirective { // The directive's generic type `T` will be inferred from the `DataSource` type // passed to the input. - @Input({required: true}) selectFrom!: DataSource; + selectFrom = input.required>(); // Narrow the type of the context using the generic type of the directive. static ngTemplateContextGuard(dir: SelectDirective, ctx: any): ctx is SelectTemplateContext { diff --git a/adev-ja/src/content/guide/directives/structural-directives.md b/adev-ja/src/content/guide/directives/structural-directives.md index 0297ac15ea..7cbc1239f3 100644 --- a/adev-ja/src/content/guide/directives/structural-directives.md +++ b/adev-ja/src/content/guide/directives/structural-directives.md @@ -90,13 +90,13 @@ export class SelectDirective { -`selectFrom` `@Input()`プロパティを追加します。 +`selectFrom` `input()`プロパティを追加します。 ```ts export class SelectDirective { // ... - @Input({required: true}) selectFrom!: DataSource; + selectFrom = input.required(); } ``` @@ -201,9 +201,9 @@ Angularは、構造ディレクティブの省略記法を次の通常のバイ // アサートしたいと考えています。 @Directive(...) class ActorIsUser { - @Input() actor: User|Robot; + actor = input(); - static ngTemplateGuard_actor(dir: ActorIsUser, expr: User|Robot): expr is User { + static ngTemplateGuard_actor(dir: ActorIsUser, expr: User | Robot): expr is User { // 実際にはreturn文は不要ですが、 // TypeScriptエラーを防ぐために含めています。 return true; @@ -218,7 +218,7 @@ class ActorIsUser { ```ts @Directive(...) class CustomIf { - @Input() condition!: any; + condition = input.required(); static ngTemplateGuard_condition: 'binding'; } @@ -242,7 +242,7 @@ export interface SelectTemplateContext { export class SelectDirective { // ディレクティブのジェネリック型`T`は、 // 入力に渡される`DataSource`型から推測されます。 - @Input({required: true}) selectFrom!: DataSource; + selectFrom = input.required>(); // ジェネリック型のディレクティブを使用して、コンテキストの型を絞り込みます。 static ngTemplateContextGuard(dir: SelectDirective, ctx: any): ctx is SelectTemplateContext { diff --git a/adev-ja/src/content/guide/drag-drop.md b/adev-ja/src/content/guide/drag-drop.md index 87a17e2c95..0e97557678 100644 --- a/adev-ja/src/content/guide/drag-drop.md +++ b/adev-ja/src/content/guide/drag-drop.md @@ -76,7 +76,7 @@ The `cdkDropListConnectedTo` directive works both with a direct reference to ano
-
+
diff --git a/adev-ja/src/content/guide/elements.en.md b/adev-ja/src/content/guide/elements.en.md index d2fb692983..9d2a298ff8 100644 --- a/adev-ja/src/content/guide/elements.en.md +++ b/adev-ja/src/content/guide/elements.en.md @@ -64,8 +64,8 @@ Component properties and logic maps directly into HTML attributes and the browse For example, for a component with `inputProp = input({alias: 'myInputProp'})`, the corresponding custom element defines an attribute `my-input-prop`. * Component outputs are dispatched as HTML [Custom Events](https://developer.mozilla.org/docs/Web/API/CustomEvent), with the name of the custom event matching the output name. - For example, for a component with valueChanged = output()`, the corresponding custom element dispatches events with the name "valueChanged", and the emitted data is stored on the event's `detail` property. - If you provide an alias, that value is used; for example, clicks = output({alias: 'myClick'});` results in dispatch events with the name "myClick". + For example, for a component `with valueChanged = output()`, the corresponding custom element dispatches events with the name "valueChanged", and the emitted data is stored on the event's `detail` property. + If you provide an alias, that value is used; for example, `clicks = output({alias: 'myClick'});` results in dispatch events with the name "myClick". For more information, see Web Component documentation for [Creating custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_custom_events). diff --git a/adev-ja/src/content/guide/http/http-resource.md b/adev-ja/src/content/guide/http/http-resource.md new file mode 100644 index 0000000000..40d4950b45 --- /dev/null +++ b/adev-ja/src/content/guide/http/http-resource.md @@ -0,0 +1,124 @@ +# Reactive data fetching with `httpResource` + +IMPORTANT: `httpResource` is [experimental](reference/releases#experimental). It's ready for you to try, but it might change before it is stable. + +`httpResource` is a reactive wrapper around `HttpClient` that gives you the request status and response as signals. You can thus use these signals with `computed`, `effect`, `linkedSignal`, or any other reactive API. Because it's built on top of `HttpClient`, `httpResource` supports all the same features, such as interceptors. + +For more about Angular's `resource` pattern, see [Async reactivity with `resource`](/guide/signals/resource). + +## `Using httpResource` + +TIP: Make sure to include `provideHttpClient` in your application providers. See [Setting up HttpClient](/guide/http/setup) for details. + + +You can define an HTTP resource by returning a url: + +```ts +userId = input.required(); + +user = httpResource(() => `/api/user/${userId()}`); // A reactive function as argument +``` + +`httResource` is reactive, meaning that whenever one of the signal it depends on changes (like `userId`), the resource will emit a new http request. +If a request is already pending, the resource cancels the outstanding request before issuing a new one. + +HELPFUL: `httpResource` differs from the `HttpClient` as it initiates the request _eagerly_. In contrast, the `HttpClient` only initiates requests upon subscription to the returned `Observable`. + +For more advanced requests, you can define a request object similar to the request taken by `HttpClient`. +Each property of the request object that should be reactive should be composed by a signal. + +```ts +user = httpResource(() => ({ + url: `/api/user/${userId()}`, + method: 'GET', + headers: { + 'X-Special': 'true', + }, + params: { + 'fast': 'yes', + }, + reportProgress: true, + withCredentials: true, + transferCache: true, + keepalive: true, +})); +``` + +TIP: Avoid using `httpResource` for _mutations_ like `POST` or `PUT`. Instead, prefer directly using the underlying `HttpClient` APIs. + +The signals of the `httpResource` can be used in the template to control which elements should be displayed. + +```angular-html +@if(user.hasValue()) { + +} @else if (user.error()) { +
Could not load user information
+} @else if (user.isLoading()) { +
Loading user info...
+} +``` + +HELPFUL: Reading the `value` signal on a `resource` that is in error state throws at runtime. It is recommended to guard `value` reads with `hasValue()`. + +### Response types + +By default, `httpResource` returns and parses the response as JSON. However, you can specify alternate return with additional functions on `httpResource`: + +```ts +httpResource.text(() => ({ … })); // returns a string in value() + +httpResource.blob(() => ({ … })); // returns a Blob object in value() + +httpResource.arrayBuffer(() => ({ … })); // returns an ArrayBuffer in value() +``` + +## Response parsing and validation + +When fetching data, you may want to validate responses against a predefined schema, often using popular open-source libraries like [Zod](https://zod.dev) or [Valibot](https://valibot.dev). You can integrate validation libraries like this with `httpResource` by specifying a `parse` option. The return type of the `parse` function determines the type of the resource's `value`. + +The following example uses Zod to parse and validate the response from the [StarWars API](https://swapi.info/). The resource is then typed the same as the output type of Zod’s parsing. + +```ts +const starWarsPersonSchema = z.object({ + name: z.string(), + height: z.number({ coerce: true }), + edited: z.string().datetime(), + films: z.array(z.string()), +}); + +export class CharacterViewer { + id = signal(1); + + swPersonResource = httpResource( + () => `https://swapi.info/api/people/${this.id()}`, + { parse: starWarsPersonSchema.parse } + ); +} +``` + +## Testing an httpResource + +Because `httpResource` is a wrapper around `HttpClient`, you can test `httpResource` with the exact same APIs as `HttpClient`. See [HttpClient Testing](/guide/http/testing) for details. + +The following example shows a unit test for code using `httpResource`. + +```ts +TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + ], +}); + +const id = signal(0); +const mockBackend = TestBed.inject(HttpTestingController); +const response = httpResource(() => `/data/${id()}`, {injector: TestBed.inject(Injector)}); +TestBed.tick(); // Triggers the effect +const firstRequest = mockBackend.expectOne('/data/0'); +firstRequest.flush(0); + +// Ensures the values are propagated to the httpResource +await TestBed.inject(ApplicationRef).whenStable(); + +expect(response.value()).toEqual(0); +``` diff --git a/adev-ja/src/content/guide/http/making-requests.en.md b/adev-ja/src/content/guide/http/making-requests.en.md index 1df8c66443..5b528691a6 100644 --- a/adev-ja/src/content/guide/http/making-requests.en.md +++ b/adev-ja/src/content/guide/http/making-requests.en.md @@ -262,7 +262,9 @@ export class UserProfileComponent { private userService = inject(UserService); constructor(): void { - this.user$ = this.userService.getUser(this.userId()); + effect(() => { + this.user$ = this.userService.getUser(this.userId()); + }); } }
diff --git a/adev-ja/src/content/guide/http/making-requests.md b/adev-ja/src/content/guide/http/making-requests.md index 647b90b7b1..4ab2bb2c4d 100644 --- a/adev-ja/src/content/guide/http/making-requests.md +++ b/adev-ja/src/content/guide/http/making-requests.md @@ -262,7 +262,9 @@ export class UserProfileComponent { private userService = inject(UserService); constructor(): void { - this.user$ = this.userService.getUser(this.userId()); + effect(() => { + this.user$ = this.userService.getUser(this.userId()); + }); } }
diff --git a/adev-ja/src/content/guide/http/testing.en.md b/adev-ja/src/content/guide/http/testing.en.md index 9df0a7b951..20fc8cfac0 100644 --- a/adev-ja/src/content/guide/http/testing.en.md +++ b/adev-ja/src/content/guide/http/testing.en.md @@ -10,7 +10,7 @@ At the end, tests can verify that the app made no unexpected requests. To begin testing usage of `HttpClient`, configure `TestBed` and include `provideHttpClient()` and `provideHttpClientTesting()` in your test's setup. This configures `HttpClient` to use a test backend instead of the real network. It also provides `HttpTestingController`, which you'll use to interact with the test backend, set expectations about which requests have been made, and flush responses to those requests. `HttpTestingController` can be injected from `TestBed` once configured. -Keep in mind to provide `provideHttpClient()` **before** `provideHttpClientTesting()`, as `provideHttpClientTesting()` will overwrite parts of `provideHttpCient()`. Doing it the other way around can potentially break your tests. +Keep in mind to provide `provideHttpClient()` **before** `provideHttpClientTesting()`, as `provideHttpClientTesting()` will overwrite parts of `provideHttpClient()`. Doing it the other way around can potentially break your tests. TestBed.configureTestingModule({ diff --git a/adev-ja/src/content/guide/http/testing.md b/adev-ja/src/content/guide/http/testing.md index 1d1a63f300..4dff197fa9 100644 --- a/adev-ja/src/content/guide/http/testing.md +++ b/adev-ja/src/content/guide/http/testing.md @@ -10,7 +10,7 @@ `HttpClient` の使用のテストを開始するには、`TestBed` を構成してテストの設定に `provideHttpClient()` と `provideHttpClientTesting()` を含めます。これにより、`HttpClient` が実際のネットワークではなくテストバックエンドを使用するように構成されます。また、`HttpTestingController` も提供され、これを使用してテストバックエンドとやり取ります。そして、どのリクエストが行われたかについての期待を設定し、それらのリクエストに対するレスポンスを流します。`HttpTestingController` は、構成されたら `TestBed` から注入できます。 -`provideHttpClientTesting()` は `provideHttpCient()` の一部を上書きするため、`provideHttpClient()` を `provideHttpClientTesting()` の**前**に提供することに留意してください。これを逆に行うと、テストが壊れてしまう可能性があります。 +`provideHttpClientTesting()` は `provideHttpClient()` の一部を上書きするため、`provideHttpClient()` を `provideHttpClientTesting()` の**前**に提供することに留意してください。これを逆に行うと、テストが壊れてしまう可能性があります。 TestBed.configureTestingModule({ diff --git a/adev-ja/src/content/guide/hydration.en.md b/adev-ja/src/content/guide/hydration.en.md index af9ce586f3..f1c1e7c9af 100644 --- a/adev-ja/src/content/guide/hydration.en.md +++ b/adev-ja/src/content/guide/hydration.en.md @@ -177,7 +177,7 @@ Application stability is an important part of the hydration process. Hydration a ## I18N -HELPFUL: Support for internationalization with hydration is currently in [developer preview](/reference/releases#developer-preview). By default, Angular will skip hydration for components that use i18n blocks, effectively re-rendering those components from scratch. +HELPFUL: By default, Angular will skip hydration for components that use i18n blocks, effectively re-rendering those components from scratch. To enable hydration for i18n blocks, you can add [`withI18nSupport`](/api/platform-browser/withI18nSupport) to your `provideClientHydration` call. @@ -203,7 +203,7 @@ There are a number of third party libraries that depend on DOM manipulation to b ## Third Party Scripts with DOM Manipulation -Many third party scripts, such as ad trackers and analytics, modify the DOM before hydration can occur. These scripts may cause hydration errors because the page no longer matches the structure expected by Angular. Prefer deferring this type of script until after hydration whenever possible. Consider using [`AfterNextRender`](api/core/afterNextRender) to delay the script until post-hydration processes have occured. +Many third party scripts, such as ad trackers and analytics, modify the DOM before hydration can occur. These scripts may cause hydration errors because the page no longer matches the structure expected by Angular. Prefer deferring this type of script until after hydration whenever possible. Consider using [`AfterNextRender`](api/core/afterNextRender) to delay the script until post-hydration processes have occurred. ## Incremental Hydration diff --git a/adev-ja/src/content/guide/hydration.md b/adev-ja/src/content/guide/hydration.md index cbf9dca963..7818f9f73f 100644 --- a/adev-ja/src/content/guide/hydration.md +++ b/adev-ja/src/content/guide/hydration.md @@ -177,7 +177,7 @@ HELPFUL: これによりレンダリングの問題は修正されますが、 ## I18N {#i18n} -HELPFUL: ハイドレーションによる国際化のサポートは、現在 [開発者プレビュー](/reference/releases#developer-preview) 段階です。デフォルトでは、Angularはi18nブロックを使用するコンポーネントのハイドレーションをスキップし、それらのコンポーネントを最初から再レンダリングします。 +HELPFUL: デフォルトでは、Angularはi18nブロックを使用するコンポーネントのハイドレーションをスキップし、それらのコンポーネントを最初から再レンダリングします。 i18nブロックのハイドレーションを有効にするには、`provideClientHydration` の呼び出しに [`withI18nSupport`](/api/platform-browser/withI18nSupport) を追加します。 @@ -203,7 +203,7 @@ bootstrapApplication(AppComponent, { ## DOM操作を伴うサードパーティスクリプト {#third-party-scripts-with-dom-manipulation} -広告トラッカーやアナリティクスなど、多くのサードパーティスクリプトは、ハイドレーションが行われる前にDOMを変更します。これらのスクリプトは、ページがAngularが期待する構造と一致しなくなるため、ハイドレーションエラーを引き起こす可能性があります。可能な限り、この種のスクリプトをハイドレーション後まで遅らせることを推奨します。`AfterNextRender` を使用して、ハイドレーション後のプロセスが発生するまでスクリプトを遅延させることを検討してください。 +広告トラッカーやアナリティクスなど、多くのサードパーティスクリプトは、ハイドレーションが行われる前にDOMを変更します。これらのスクリプトは、ページがAngularが期待する構造と一致しなくなるため、ハイドレーションエラーを引き起こす可能性があります。可能な限り、この種のスクリプトをハイドレーション後まで遅らせることを推奨します。[`AfterNextRender`](api/core/afterNextRender) を使用して、ハイドレーション後のプロセスが完了するまでスクリプトを遅延させることを検討してください。 ## インクリメンタルハイドレーション {#incremental-hydration} diff --git a/adev-ja/src/content/guide/ngmodules/overview.md b/adev-ja/src/content/guide/ngmodules/overview.md index eec8477959..778e1b3279 100644 --- a/adev-ja/src/content/guide/ngmodules/overview.md +++ b/adev-ja/src/content/guide/ngmodules/overview.md @@ -145,7 +145,7 @@ Some NgModules define a static `forRoot` method that accepts some configuration Any providers included in this way are eagerly loaded, increasing the JavaScript bundle size of your initial page load. ```typescript -boorstrapApplication(MyApplicationRoot, { +bootstrapApplication(MyApplicationRoot, { providers: [ CustomMenuModule.forRoot(/* some config */), ], diff --git a/adev-ja/src/content/guide/routing/common-router-tasks.en.md b/adev-ja/src/content/guide/routing/common-router-tasks.en.md index dc4c60cc63..1ae7d949da 100644 --- a/adev-ja/src/content/guide/routing/common-router-tasks.en.md +++ b/adev-ja/src/content/guide/routing/common-router-tasks.en.md @@ -11,7 +11,7 @@ To edit an item, users click an Edit button, which opens an `EditGroceryItem` co You want that component to retrieve the `id` for the grocery item so it can display the right information to the user. Use a route to pass this type of information to your application components. -To do so, you use the [withComponentInputBinding](api/router/withComponentInputBinding) feature with `provideRouter` or the `bindToComponentInputs` option of `RouterModule.forRoot`. +To do so, you use the [`withComponentInputBinding`](api/router/withComponentInputBinding) feature with `provideRouter` or the `bindToComponentInputs` option of `RouterModule.forRoot`. To get information from a route: @@ -29,23 +29,39 @@ providers: [ - + Update the component to have an `input()` property matching the name of the parameter. ```ts id = input.required() -hero = computed(() => this.service.getHero(heroId)); +hero = computed(() => this.service.getHero(id)); ``` -NOTE: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters. -If you want to use the parent components route info you will need to set the router `paramsInheritanceStrategy` option: -`withRouterConfig({paramsInheritanceStrategy: 'always'})` - + +The router assigns values to all inputs based on the current route when `withComponentInputBinding` is enabled. +The router assigns `undefined` if no route data matches the input key, such as when an optional query parameter is missing. +You should include `undefined` in the `input`'s type when there's a possibility that an input might not be matched by the route. + +Provide a default value by either using the `transform` option on the input or managing a local state with a `linkedSignal`. + +```ts +id = input.required({ + transform: (maybeUndefined: string | undefined) => maybeUndefined ?? '0', +}); +// or +id = input(); +internalId = linkedSignal(() => this.id() ?? getDefaultId()); +``` + +NOTE: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters. +If you want to use the parent components route info you will need to set the router `paramsInheritanceStrategy` option: +`withRouterConfig({paramsInheritanceStrategy: 'always'})` + ## Displaying a 404 page To display a 404 page, set up a [wildcard route](guide/routing/common-router-tasks#setting-up-wildcard-routes) with the `component` property set to the component you'd like to use for your 404 page as follows: @@ -61,51 +77,6 @@ const routes: Routes = [ The last route with the `path` of `**` is a wildcard route. The router selects this route if the requested URL doesn't match any of the paths earlier in the list and sends the user to the `PageNotFoundComponent`. -## Preventing unauthorized access - -Use route guards to prevent users from navigating to parts of an application without authorization. -The following route guards are available in Angular: - - - - - - - - - - -To use route guards, consider using [component-less routes](api/router/Route#componentless-routes) as this facilitates guarding child routes. - -Create a file for your guard: - -```bash -ng generate guard your-guard -``` - -In your guard file, add the guard functions you want to use. -The following example uses `canActivateFn` to guard the route. - -```ts -export const yourGuardFunction: CanActivateFn = ( - next: ActivatedRouteSnapshot, - state: RouterStateSnapshot -) => { - // your logic goes here -} -``` - -In your routing module, use the appropriate property in your `routes` configuration. -Here, `canActivate` tells the router to mediate navigation to this particular route. - -```ts -{ - path: '/your-path', - component: YourComponent, - canActivate: [yourGuardFunction], -} -``` - ## Link parameters array A link parameters array holds the following ingredients for router navigation: diff --git a/adev-ja/src/content/guide/routing/common-router-tasks.md b/adev-ja/src/content/guide/routing/common-router-tasks.md index 49798746c5..7b1de3f4fa 100644 --- a/adev-ja/src/content/guide/routing/common-router-tasks.md +++ b/adev-ja/src/content/guide/routing/common-router-tasks.md @@ -11,7 +11,7 @@ そのコンポーネントは、食料品アイテムの `id` を取得して、ユーザーに正しい情報を表示できるようにする必要があります。 ルートを使用して、このタイプの情報をアプリケーションコンポーネントに渡します。 -これを行うには、`provideRouter` を使用した [withComponentInputBinding](api/router/withComponentInputBinding) 機能、または `RouterModule.forRoot` の `bindToComponentInputs` オプションを使用します。 +これを行うには、`provideRouter` を使用した [`withComponentInputBinding`](api/router/withComponentInputBinding) 機能、または `RouterModule.forRoot` の `bindToComponentInputs` オプションを使用します。 ルートから情報を取得するには: @@ -29,23 +29,39 @@ providers: [ - + パラメータ名と一致する `input()` プロパティを持つようにコンポーネントを更新します。 ```ts id = input.required() -hero = computed(() => this.service.getHero(heroId)); +hero = computed(() => this.service.getHero(id)); ``` -NOTE: 静的なルートデータ、解決されたルートデータ、パスパラメータ、マトリックスパラメータ、クエリパラメータなど、すべてのルートデータをキーと値のペアでコンポーネントの入力にバインドできます。 -親コンポーネントのルート情報を使用する場合は、ルーターの `paramsInheritanceStrategy` オプションを設定する必要があります。 -`withRouterConfig({paramsInheritanceStrategy: 'always'})` - + +`withComponentInputBinding` が有効な場合、ルーターは現在のルートに基づいてすべての入力に値を割り当てます。 +オプションのクエリパラメータが欠落している場合など、ルートデータが入力キーと一致しない場合、ルーターは `undefined` を割り当てます。 +入力がルートによって一致しない可能性がある場合は、`input` の型に `undefined` を含める必要があります。 + +`input` の `transform` オプションを使用するか、`linkedSignal` でローカル状態を管理することで、デフォルト値を提供します。 + +```ts +id = input.required({ + transform: (maybeUndefined: string | undefined) => maybeUndefined ?? '0', +}); +// or +id = input(); +internalId = linkedSignal(() => this.id() ?? getDefaultId()); +``` + +NOTE: 静的なルートデータ、解決されたルートデータ、パスパラメータ、マトリックスパラメータ、クエリパラメータなど、すべてのルートデータをキーと値のペアでコンポーネントの入力にバインドできます。 +親コンポーネントのルート情報を使用する場合は、ルーターの `paramsInheritanceStrategy` オプションを設定する必要があります。 +`withRouterConfig({paramsInheritanceStrategy: 'always'})` + ## 404 ページの表示 {#displaying-a-404-page} 404ページを表示するには、[ワイルドカードルート](guide/routing/common-router-tasks#setting-up-wildcard-routes) を設定します。このルートの `component` プロパティは、404ページに使用したいコンポーネントに設定します。 @@ -61,51 +77,6 @@ const routes: Routes = [ `path` が `**` の最後のルートは、ワイルドカードルートです。 ルーターは、要求されたURLがリストの先頭にあるパスと一致しない場合、このルートを選択し、ユーザーを `PageNotFoundComponent` にルーティングします。 -## 権限のないアクセスの防止 {#preventing-unauthorized-access} - -ルートガードを使用して、ユーザーが権限なしでアプリケーションの特定の部分にナビゲートできないようにします。 -Angularでは、次のルートガードを使用できます。 - - - - - - - - - - -ルートガードを使用するには、[コンポーネントレスルート](api/router/Route#componentless-routes) を使用することを検討してください。これにより、子ルートのガードが容易になります。 - -ガードのファイルを作成します。 - -```bash -ng generate guard your-guard -``` - -ガードファイルに、使用するガード関数を追加します。 -次の例では、`canActivateFn` を使用してルートをガードしています。 - -```ts -export const yourGuardFunction: CanActivateFn = ( - next: ActivatedRouteSnapshot, - state: RouterStateSnapshot -) => { - // your logic goes here -} -``` - -ルーティングモジュールで、`routes` 構成の適切なプロパティを使用します。 -ここでは、`canActivate` は、ルーターに、この特定のルートへのナビゲーションを制御するよう指示します。 - -```ts -{ - path: '/your-path', - component: YourComponent, - canActivate: [yourGuardFunction], -} -``` - ## リンクパラメータ配列 {#link-parameters-array} リンクパラメータ配列には、ルーターナビゲーションの次の要素が含まれています。 diff --git a/adev-ja/src/content/guide/routing/define-routes.en.md b/adev-ja/src/content/guide/routing/define-routes.en.md index cf36c3c401..a596c98e2a 100644 --- a/adev-ja/src/content/guide/routing/define-routes.en.md +++ b/adev-ja/src/content/guide/routing/define-routes.en.md @@ -311,7 +311,7 @@ export const ROUTES: Route[] = [ ]; ``` -In this code sample, the `admin` path contains a protected data property of `ADMIN_API_KEY` that is only available to children within its section. As a result, no other paths will be able to access the data provided via `ADMIN_AP +In this code sample, the `admin` path contains a protected data property of `ADMIN_API_KEY` that is only available to children within its section. As a result, no other paths will be able to access the data provided via `ADMIN_API_KEY`. See the [Dependency injection guide](/guide/di) for more information about providers and injection in Angular. @@ -363,18 +363,20 @@ You can add child routes to any route definition with the `children` property: ```angular-ts const routes: Routes = [ - path: 'product/:id', - component: 'ProductComponent', - children: [ - { - path: 'info', - component: ProductInfoComponent - }, - { - path: 'reviews', - component: ProductReviewsComponent - } - ] + { + path: 'product/:id', + component: 'ProductComponent', + children: [ + { + path: 'info', + component: ProductInfoComponent + }, + { + path: 'reviews', + component: ProductReviewsComponent + } + ] + } ] ``` diff --git a/adev-ja/src/content/guide/routing/define-routes.md b/adev-ja/src/content/guide/routing/define-routes.md index fb0233c2c0..5f01e9ba3d 100644 --- a/adev-ja/src/content/guide/routing/define-routes.md +++ b/adev-ja/src/content/guide/routing/define-routes.md @@ -363,18 +363,20 @@ const routes: Routes = [ ```angular-ts const routes: Routes = [ - path: 'product/:id', - component: 'ProductComponent', - children: [ - { - path: 'info', - component: ProductInfoComponent - }, - { - path: 'reviews', - component: ProductReviewsComponent - } - ] + { + path: 'product/:id', + component: 'ProductComponent', + children: [ + { + path: 'info', + component: ProductInfoComponent + }, + { + path: 'reviews', + component: ProductReviewsComponent + } + ] + } ] ``` diff --git a/adev-ja/src/content/guide/routing/navigate-to-routes.en.md b/adev-ja/src/content/guide/routing/navigate-to-routes.en.md index 8e7d4a95e7..78daed10b0 100644 --- a/adev-ja/src/content/guide/routing/navigate-to-routes.en.md +++ b/adev-ja/src/content/guide/routing/navigate-to-routes.en.md @@ -5,12 +5,19 @@ The RouterLink directive is Angular's declarative approach to navigation. It all ## How to use RouterLink Instead of using regular anchor elements `` with an `href` attribute, you add a RouterLink directive with the appropriate path in order to leverage Angular routing. - -```angular-html - +```angular-ts +import {RouterLink} from '@angular/router'; +@Component({ + template: ` + + ` + imports: [RouterLink], + ... +}) +export class App {} ``` ### Using absolute or relative links diff --git a/adev-ja/src/content/guide/routing/navigate-to-routes.md b/adev-ja/src/content/guide/routing/navigate-to-routes.md index a3c6cd47f2..bb299f444f 100644 --- a/adev-ja/src/content/guide/routing/navigate-to-routes.md +++ b/adev-ja/src/content/guide/routing/navigate-to-routes.md @@ -5,12 +5,19 @@ ## RouterLinkの使い方 {#how-to-use-routerlink} 通常のアンカー要素``に`href`属性を使用する代わりに、Angularルーティングを活用するために、適切なパスを持つ`RouterLink`ディレクティブを追加します。 - -```angular-html - +```angular-ts +import {RouterLink} from '@angular/router'; +@Component({ + template: ` + + ` + imports: [RouterLink], + ... +}) +export class App {} ``` ### 絶対リンクと相対リンクの使用 {#using-absolute-or-relative-links} diff --git a/adev-ja/src/content/guide/routing/read-route-state.en.md b/adev-ja/src/content/guide/routing/read-route-state.en.md index 7b03ed648a..2279405ee8 100644 --- a/adev-ja/src/content/guide/routing/read-route-state.en.md +++ b/adev-ja/src/content/guide/routing/read-route-state.en.md @@ -47,7 +47,7 @@ import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router'; @Component({ ... }) export class UserProfileComponent { readonly userId: string; - private activatedRoute = inject(ActivatedRoute); + private route = inject(ActivatedRoute); constructor() { // Example URL: https://www.angular.dev/users/123?role=admin&status=active#contact diff --git a/adev-ja/src/content/guide/routing/read-route-state.md b/adev-ja/src/content/guide/routing/read-route-state.md index 9c34180d58..92900401c2 100644 --- a/adev-ja/src/content/guide/routing/read-route-state.md +++ b/adev-ja/src/content/guide/routing/read-route-state.md @@ -47,7 +47,7 @@ import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router'; @Component({ ... }) export class UserProfileComponent { readonly userId: string; - private activatedRoute = inject(ActivatedRoute); + private route = inject(ActivatedRoute); constructor() { // URLの例: https://www.angular.dev/users/123?role=admin&status=active#contact diff --git a/adev-ja/src/content/guide/routing/redirecting-routes.md b/adev-ja/src/content/guide/routing/redirecting-routes.md new file mode 100644 index 0000000000..d8b6148a35 --- /dev/null +++ b/adev-ja/src/content/guide/routing/redirecting-routes.md @@ -0,0 +1,144 @@ +# Redirecting Routes + +Route redirects allow you to automatically navigate users from one route to another. Think of it like mail forwarding, where mail intended for one address is sent to a different address. This is useful for handling legacy URLs, implementing default routes, or managing access control. + +## How to configure redirects + +You can define redirects in your route configuration with the `redirectTo` property. This property accepts a string. + +```ts +import { Routes } from '@angular/router'; + +const routes: Routes = [ + // Simple redirect + { path: 'marketing', redirectTo: 'newsletter' }, + + // Redirect with path parameters + { path: 'legacy-user/:id', redirectTo: 'users/:id' }, + + // Redirect any other URLs that don’t match + // (also known as a "wildcard" redirect) + { path: '**', redirectTo: '/login' } +]; +``` + +In this example, there are three redirects: + +1. When a user visits the `/marketing` path, they are redirected to `/newsletter`. +2. When a user visits any `/legacy-user/:id` path, they are routed to the corresponding `/users/:id` path. +3. When a user visit any path that’s not defined in the router, they are redirected to the login page because of the `**` wildcard path definition. + +## Understanding `pathMatch` + +The `pathMatch` property on routes enables developers to control how Angular matches a URL to routes. + +There are two values that `pathMatch` accepts: + +| Value | Description | +| ---------- | -------------------------------------------- | +| `'full'` | The entire URL path must match exactly | +| `'prefix'` | Only the beginning of the URL needs to match | + +By default, all redirects use the `prefix` strategy. + +### `pathMatch: 'prefix'` + +`pathMatch: 'prefix'` is the default strategy and ideal when you want Angular Router to match all subsequent routes when triggering a redirect. + +```ts +export const routes: Routes = [ + // This redirect route is equivalent to… + { path: 'news', redirectTo: 'blog }, + + // This explicitly defined route redirect pathMatch + { path: 'news', redirectTo: 'blog', pathMatch: 'prefix' }, +]; +``` + +In this example, all routes that are prefixed with `news` are redirected to their `/blog` equivalents. Here are some examples where users are redirected when visiting the old `news` prefix: + +- `/news` redirects to `/blog` +- `/news/article` redirects to `/blog/article` +- `/news/article/:id` redirects to `/blog/article/:id` + +### `pathMatch: 'full'` + +On the other hand, `pathMatch: 'full'` is useful when you want Angular Router to only redirect a specific path. + +```ts +export const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, +]; +``` + +In this example, any time the user visits the root URL (i.e., `''`), the router redirects that user to the `'/dashboard'` page. + +Any subsequent pages (e.g., `/login`, `/about`, `/product/id`, etc.), are ignored and do not trigger a redirect. + +TIP: Be careful when configuring a redirect on the root page (i.e., `"/"` or `""`). If you do not set `pathMatch: 'full'`, the router will redirect all URLs. + +To further illustrate this, if the `news` example from the previous section used `pathMatch: 'full'` instead: + +```ts +export const routes: Routes = [ + { path: 'news', redirectTo: '/blog', pathMatch: 'full' }, +]; +``` + +This means that: + +1. Only the `/news` path will be redirected to `/blog`. +2. Any subsequent segments such as `/news/articles` or `/news/articles/1` would not redirect with the new `/blog` prefix. + +## Conditional redirects + +The `redirectTo` property can also accept a function in order to add logic to how users are redirected. + +The [function](api/router/RedirectFunction) only has access part of the [`ActivatedRouteSnapshot`](api/router/ActivatedRouteSnapshot) data since some data is not accurately known at the route matching phase. Examples include: resolved titles, lazy loaded components, etc. + +It typically returns a string or [`URLTree`](api/router/UrlTree), but it can also return an observable or promise. + +Here is an example where the user is redirected to different menu based on the time of the day: + +```ts +import { Routes } from '@angular/router'; +import { MenuComponent } from './menu/menu.component'; + +export const routes: Routes = [ + { + path: 'restaurant/:location/menu', + redirectTo: (activatedRouteSnapshot) => { + const location = activatedRouteSnapshot.params['location']; + const currentHour = new Date().getHours(); + + // Check if user requested a specific meal via query parameter + if (activatedRouteSnapshot.queryParams['meal']) { + return `/restaurant/${location}/menu/${queryParams['meal']}`; + } + + // Auto-redirect based on time of day + if (currentHour >= 5 && currentHour < 11) { + return `/restaurant/${location}/menu/breakfast`; + } else if (currentHour >= 11 && currentHour < 17) { + return `/restaurant/${location}/menu/lunch`; + } else { + return `/restaurant/${location}/menu/dinner`; + } + } + }, + + // Destination routes + { path: 'restaurant/:location/menu/breakfast', component: MenuComponent }, + { path: 'restaurant/:location/menu/lunch', component: MenuComponent }, + { path: 'restaurant/:location/menu/dinner', component: MenuComponent }, + + // Default redirect + { path: '', redirectTo: '/restaurant/downtown/menu', pathMatch: 'full' } +]; +``` + +To learn more, check out [the API docs for the RedirectFunction](api/router/RedirectFunction). + +## Next steps + +For more information about the `redirectTo` property, check out the [API docs](api/router/Route#redirectTo). diff --git a/adev-ja/src/content/guide/routing/route-guards.md b/adev-ja/src/content/guide/routing/route-guards.md new file mode 100644 index 0000000000..b25e9eb480 --- /dev/null +++ b/adev-ja/src/content/guide/routing/route-guards.md @@ -0,0 +1,208 @@ +# Control route access with guards + +CRITICAL: Never rely on client-side guards as the sole source of access control. All JavaScript that runs in a web browser can be modified by the user running the browser. Always enforce user authorization server-side, in addition to any client-side guards. + +Route guards are functions that control whether a user can navigate to or leave a particular route. They are like checkpoints that manage whether a user can access specific routes. Common examples of using route guards include authentication and access control. + +## Creating a route guard + +You can generate a route guard using the Angular CLI: + +```bash +ng generate guard CUSTOM_NAME +``` + +This will prompt you to select which [type of route guard](#types-of-route-guards) to use and then create the corresponding `CUSTOM_NAME-guard.ts` file. + +TIP: You can also create a route guard manually by creating a separate TypeScript file in your Angular project. Developers typically add a suffix of `-guard.ts` in the filename to distinguish it from other files. + +## Route guard return types + +All route guards share the same possible return types. This gives you flexibility in how you control navigation: + +| Return types | Description | +| ------------------------------- | --------------------------------------------------------------------------------- | +| `boolean` | `true` allows navigation, `false` blocks it (see note for `CanMatch` route guard) | +| `UrlTree` or `RedirectCommand` | Redirects to another route instead of blocking | +| `Promise` or `Observable` | Router uses the first emitted value and then unsubscribes | + +Note: `CanMatch` behaves differently— when it returns `false`, Angular tries other matching routes instead of completely blocking navigation. + +## Types of route guards + +Angular provides four types of route guards, each serving different purposes: + + + + + + + + +### CanActivate + +The `CanActivate` guard determines whether a user can access a route. It is most commonly used for authentication and authorization. + +It has access to the following default arguments: + +- `route: ActivatedRouteSnapshot` - Contains information about the route being activated +- `state: RouterStateSnapshot` - Contains the router's current state + +It can return the [standard return guard types](#route-guard-return-types). + +```ts +export const authGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const authService = inject(AuthService); + return authService.isAuthenticated(); +}; +``` + +Tip: If you need to redirect the user, return a [`URLTree`](api/router/UrlTree) or [`RedirectCommand`](api/router/RedirectCommand). Do **not** return `false` and then programmatically `navigate` the user. + +For more information, check out the [API docs for CanActivateFn](api/router/CanActivateFn). + +### CanActivateChild + +The `CanActivateChild` guard determines whether a user can access child routes of a particular parent route. This is useful when you want to protect an entire section of nested routes. In other words, `canActivateChild` runs for _all_ children. If there is a child component with another child component underneath of it, `canActivateChild` will run once for both components. + +It has access to the following default arguments: + +- `childRoute: ActivatedRouteSnapshot` - Contains information about the "future" snapshot (i.e., state the router is attempting to navigate to) of the child route being activated +- `state: RouterStateSnapshot` - Contains the router's current state + +It can return the [standard return guard types](#route-guard-return-types). + +```ts +export const adminChildGuard: CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const authService = inject(AuthService); + return authService.hasRole('admin'); +}; +``` + +For more information, check out the [API docs for CanActivateChildFn](api/router/CanActivateChildFn). + +### CanDeactivate + +The `CanDeactivate` guard determines whether a user can leave a route. A common scenario is preventing navigation away from unsaved forms. + +It has access to the following default arguments: + +- `component: T` - The component instance being deactivated +- `currentRoute: ActivatedRouteSnapshot` - Contains information about the current route +- `currentState: RouterStateSnapshot` - Contains the current router state +- `nextState: RouterStateSnapshot` - Contains the next router state being navigated to + +It can return the [standard return guard types](#route-guard-return-types). + +```ts +export const unsavedChangesGuard: CanDeactivateFn = (component: FormComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => { + return component.hasUnsavedChanges() + ? confirm('You have unsaved changes. Are you sure you want to leave?') + : true; +}; +``` + +For more information, check out the [API docs for CanDeactivateFn](api/router/CanDeactivateFn). + +### CanMatch + +The `CanMatch` guard determines whether a route can be matched during path matching. Unlike other guards, rejection falls through to try other matching routes instead of blocking navigation entirely. This can be useful for feature flags, A/B testing, or conditional route loading. + +It has access to the following default arguments: + +- `route: Route` - The route configuration being evaluated +- `segments: UrlSegment[]` - The URL segments that have not been consumed by previous parent route evaluations + +It can return the [standard return guard types](#route-guard-return-types), but when it returns `false`, Angular tries other matching routes instead of completely blocking navigation. + +```ts +export const featureToggleGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) => { + const featureService = inject(FeatureService); + return featureService.isFeatureEnabled('newDashboard'); +}; +``` + +It can also allow you to use different components for the same path. + +```ts +// 📄 routes.ts +const routes: Routes = [ + { + path: 'dashboard', + component: AdminDashboard, + canMatch: [adminGuard] + }, + { + path: 'dashboard', + component: UserDashboard, + canMatch: [userGuard] + } +] +``` + +In this example, when the user visits `/dashboard`, the first one that matches the correct guard will be used. + +For more information, check out the [API docs for CanMatchFn](api/router/CanMatchFn). + +## Applying guards to routes + +Once you've created your route guards, you need to configure them in your route definitions. + +Guards are specified as arrays in the route configuration in order to allow you to apply multiple guards to a single route. They are executed in the order they appear in the array. + +```ts +import { Routes } from '@angular/router'; +import { authGuard } from './guards/auth.guard'; +import { adminGuard } from './guards/admin.guard'; +import { canDeactivateGuard } from './guards/can-deactivate.guard'; +import { featureToggleGuard } from './guards/feature-toggle.guard'; + +const routes: Routes = [ + // Basic CanActivate - requires authentication + { + path: 'dashboard', + component: DashboardComponent, + canActivate: [authGuard] + }, + + // Multiple CanActivate guards - requires authentication AND admin role + { + path: 'admin', + component: AdminComponent, + canActivate: [authGuard, adminGuard] + }, + + // CanActivate + CanDeactivate - protected route with unsaved changes check + { + path: 'profile', + component: ProfileComponent, + canActivate: [authGuard], + canDeactivate: [canDeactivateGuard] + }, + + // CanActivateChild - protects all child routes + { + path: 'users', // /user - NOT protected + canActivateChild: [authGuard], + children: [ + // /users/list - PROTECTED + { path: 'list', component: UserListComponent }, + // /useres/detail/:id - PROTECTED + { path: 'detail/:id', component: UserDetailComponent } + ] + }, + + // CanMatch - conditionally matches route based on feature flag + { + path: 'beta-feature', + component: BetaFeatureComponent, + canMatch: [featureToggleGuard] + }, + + // Fallback route if beta feature is disabled + { + path: 'beta-feature', + component: ComingSoonComponent + } +]; +``` diff --git a/adev-ja/src/content/guide/routing/show-routes-with-outlets.en.md b/adev-ja/src/content/guide/routing/show-routes-with-outlets.en.md index e2114431f4..761787805d 100644 --- a/adev-ja/src/content/guide/routing/show-routes-with-outlets.en.md +++ b/adev-ja/src/content/guide/routing/show-routes-with-outlets.en.md @@ -45,17 +45,17 @@ const routes: Routes = [ When a user visits `/products`, Angular renders the following: ```angular-html - - - + + + ``` If the user goes back to the home page, then Angular renders: ```angular-html - - - + + + ``` When displaying a route, the `` element remains present in the DOM as a reference point for future navigations. Angular inserts routed content just after the outlet element as a sibling. diff --git a/adev-ja/src/content/guide/routing/show-routes-with-outlets.md b/adev-ja/src/content/guide/routing/show-routes-with-outlets.md index 22ad045391..52067a71a5 100644 --- a/adev-ja/src/content/guide/routing/show-routes-with-outlets.md +++ b/adev-ja/src/content/guide/routing/show-routes-with-outlets.md @@ -45,17 +45,17 @@ const routes: Routes = [ ユーザーが`/products`にアクセスすると、Angularは次のようにレンダリングします。 ```angular-html - - - + + + ``` ユーザーがホームページに戻ると、Angularは次のようにレンダリングします。 ```angular-html - - - + + + ``` ルートを表示するとき、``要素は将来のナビゲーションのための参照点としてDOMに存在し続けます。Angularはルーティングされたコンテンツをアウトレット要素の直後に兄弟要素として挿入します。 diff --git a/adev-ja/src/content/guide/signals/resource.en.md b/adev-ja/src/content/guide/signals/resource.en.md index a5ccdf5800..1b4aeacd2e 100644 --- a/adev-ja/src/content/guide/signals/resource.en.md +++ b/adev-ja/src/content/guide/signals/resource.en.md @@ -60,10 +60,10 @@ const userId: Signal = getUserId(); const userResource = resource({ params: () => ({id: userId()}), - loader: ({request, abortSignal}): Promise => { + loader: ({params, abortSignal}): Promise => { // fetch cancels any outstanding HTTP requests when the given `AbortSignal` // indicates that the request has been aborted. - return fetch(`users/${request.id}`, {signal: abortSignal}); + return fetch(`users/${params.id}`, {signal: abortSignal}); }, }); ``` @@ -111,3 +111,7 @@ The `status` signal provides a specific `ResourceStatus` that describes the stat | `'local'` | Locally set value | The resource's value has been set locally via `.set()` or `.update()` | You can use this status information to conditionally display user interface elements, such loading indicators and error messages. + +## Reactive data fetching with `httpResource` + +[`httpResource`](/guide/http/http-resource) is a wrapper around `HttpClient` that gives you the request status and response as signals. It makes HTTP requests through the Angular HTTP stack, including interceptors. \ No newline at end of file diff --git a/adev-ja/src/content/guide/signals/resource.md b/adev-ja/src/content/guide/signals/resource.md index 2a5352cf7c..e7f68a23ce 100644 --- a/adev-ja/src/content/guide/signals/resource.md +++ b/adev-ja/src/content/guide/signals/resource.md @@ -59,7 +59,7 @@ const firstName = computed(() => userResource.value().firstName); const userId: Signal = getUserId(); const userResource = resource({ - request: () => ({id: userId()}), + params: () => ({id: userId()}), loader: ({params, abortSignal}): Promise => { // 与えられた`AbortSignal`がリクエストの中断を示している場合、 // fetchは未処理のHTTPリクエストをキャンセルします。 @@ -78,7 +78,7 @@ const userResource = resource({ const userId: Signal = getUserId(); const userResource = resource({ - request: () => ({id: userId()}), + params: () => ({id: userId()}), loader: ({params}) => fetchUser(params), }); @@ -99,15 +99,19 @@ userResource.reload(); | `isLoading` | リソースローダーが現在実行中かどうか。 | | `status` | 後述のリソースの特定の`ResourceStatus`。 | -The `status` signal provides a specific `ResourceStatus` that describes the state of the resource using a string constant. +`status` シグナルは、文字列定数を使用してリソースの状態を説明する特定の `ResourceStatus` を提供します。 -| Status | `value()` | Description | +| ステータス | `value()` | 説明 | | ------------- | :---------------- | ---------------------------------------------------------------------------- | -| `'idle'` | `undefined` | The resource has no valid request and the loader has not run. | -| `'error'` | `undefined` | The loader has encountered an error. | -| `'loading'` | `undefined` | The loader is running as a result of the `request` value changing. | -| `'reloading'` | Previous value | The loader is running as a result calling of the resource's `reload` method. | -| `'resolved'` | Resolved value | The loader has completed. | -| `'local'` | Locally set value | The resource's value has been set locally via `.set()` or `.update()` | +| `'idle'` | `undefined` | リソースに有効なリクエストがなく、ローダーが実行されていません。 | +| `'error'` | `undefined` | ローダーの読み込みがエラーになりました。 | +| `'loading'` | `undefined` | `params` 値の変更の結果としてローダーが実行中です。 | +| `'reloading'` | 前の値 | リソースの `reload` メソッドの呼び出しの結果としてローダーが実行中です。 | +| `'resolved'` | 解決された値 | ローダーが完了しました。 | +| `'local'` | ローカルに設定された値 | リソースの値が `.set()` または `.update()` を介してローカルに設定されています。 | この状態情報を使用して、ローディングインジケーターやエラーメッセージなどのユーザーインターフェース要素を条件付きで表示できます。 + +## `httpResource` を使用したリアクティブデータ取得 + +[`httpResource`](/guide/http/http-resource) は `HttpClient` のラッパーで、リクエストの状態とレスポンスをシグナルとして提供します。これはインターセプターを含むAngular HTTPスタックを通してHTTPリクエストを行います。 diff --git a/adev-ja/src/content/guide/ssr.en.md b/adev-ja/src/content/guide/ssr.en.md index 6d72ec6e65..1d03b5b85e 100644 --- a/adev-ja/src/content/guide/ssr.en.md +++ b/adev-ja/src/content/guide/ssr.en.md @@ -67,7 +67,7 @@ const serverConfig: ApplicationConfig = { }; ``` -When using the [App shell pattern](ecosystem/service-workers/app-shell), you must specify the component to be used as the app shell for client-side rendered routes. To do this, use the [`withAppShell`](api/ssr/withAppShell 'API reference') fetaure: +When using the [App shell pattern](ecosystem/service-workers/app-shell), you must specify the component to be used as the app shell for client-side rendered routes. To do this, use the [`withAppShell`](api/ssr/withAppShell 'API reference') feature: ```typescript import { provideServerRendering, withRoutes, withAppShell } from '@angular/ssr'; diff --git a/adev-ja/src/content/guide/templates/defer.en.md b/adev-ja/src/content/guide/templates/defer.en.md index 7e30d8ef07..994ea32da1 100644 --- a/adev-ja/src/content/guide/templates/defer.en.md +++ b/adev-ja/src/content/guide/templates/defer.en.md @@ -33,9 +33,9 @@ Angular's compiler produces a [dynamic import](https://developer.mozilla.org/en- ### `@defer` -This is the primary block that defines the section of content that is lazily loaded. It is not rendered initially– deferred content loads and renders once the specified [trigger](/guide/defer#triggers) occurs or the `when` condition is met. +This is the primary block that defines the section of content that is lazily loaded. It is not rendered initially– deferred content loads and renders once the specified [trigger](/guide/templates/defer#triggers) occurs or the `when` condition is met. -By default, a @defer block is triggered when the browser state becomes [idle](/guide/defer#idle). +By default, a @defer block is triggered when the browser state becomes [idle](/guide/templates/defer#idle). ```angular-html @defer { @@ -57,7 +57,7 @@ The `@placeholder` is an optional block that declares what content to show befor } ``` -While optional, certain triggers may require the presence of either a `@placeholder` or a [template reference variable](/guide/templates/variables#template-reference-variables) to function. See the [Triggers](/guide/defer#triggers) section for more details. +While optional, certain triggers may require the presence of either a `@placeholder` or a [template reference variable](/guide/templates/variables#template-reference-variables) to function. See the [Triggers](/guide/templates/defer#triggers) section for more details. Angular replaces placeholder content with the main content once loading is complete. You can use any content in the placeholder section including plain HTML, components, directives, and pipes. Keep in mind the _dependencies of the placeholder block are eagerly loaded_. diff --git a/adev-ja/src/content/guide/templates/defer.md b/adev-ja/src/content/guide/templates/defer.md index a7121d9649..3320bfd4ef 100644 --- a/adev-ja/src/content/guide/templates/defer.md +++ b/adev-ja/src/content/guide/templates/defer.md @@ -33,9 +33,9 @@ Angularのコンパイラは、`@defer`ブロックで使用される各コン ### `@defer` -これは、遅延読み込みされるコンテンツのセクションを定義するプライマリブロックです。これは最初はレンダリングされません。遅延コンテンツは、指定された[トリガー](/guide/defer#triggers)が発生するか、`when`条件が満たされたときに読み込まれてレンダリングされます。 +これは、遅延読み込みされるコンテンツのセクションを定義するプライマリブロックです。これは最初はレンダリングされません。遅延コンテンツは、指定された[トリガー](/guide/templates/defer#triggers)が発生するか、`when`条件が満たされたときに読み込まれてレンダリングされます。 -デフォルトでは、`@defer`ブロックはブラウザの状態が[アイドル](/guide/defer#idle)になるとトリガーされます。 +デフォルトでは、`@defer`ブロックはブラウザの状態が[アイドル](/guide/templates/defer#idle)になるとトリガーされます。 ```angular-html @defer { @@ -57,7 +57,7 @@ Angularのコンパイラは、`@defer`ブロックで使用される各コン } ``` -オプションですが、特定のトリガーでは、`@placeholder`または[テンプレート参照変数](/guide/templates/variables#template-reference-variables)のいずれかの存在が必要になる場合があります。詳細については、[トリガー](/guide/defer#triggers)セクションを参照してください。 +オプションですが、特定のトリガーでは、`@placeholder`または[テンプレート参照変数](/guide/templates/variables#template-reference-variables)のいずれかの存在が必要になる場合があります。詳細については、[トリガー](/guide/templates/defer#triggers)セクションを参照してください。 Angularは、読み込みが完了すると、プレースホルダーコンテンツをメインコンテンツに置き換えます。プレースホルダーセクションには、プレーンHTML、コンポーネント、ディレクティブ、パイプなど、あらゆるコンテンツを使用できます。_プレースホルダーブロックの依存関係は先に読み込まれます_。 diff --git a/adev-ja/src/content/guide/templates/expression-syntax.en.md b/adev-ja/src/content/guide/templates/expression-syntax.en.md index ce01924d9f..d3b497afb6 100644 --- a/adev-ja/src/content/guide/templates/expression-syntax.en.md +++ b/adev-ja/src/content/guide/templates/expression-syntax.en.md @@ -24,7 +24,6 @@ Angular supports a subset of [literal values](https://developer.mozilla.org/en-U | Literal type | Example value | | ---------------------- | ------------------------ | | RegExp | `/\d+/` | -| Tagged template string | `` tag`Hello ${name}` `` | ## Globals diff --git a/adev-ja/src/content/guide/templates/expression-syntax.md b/adev-ja/src/content/guide/templates/expression-syntax.md index 5254b02be4..4c132dbaec 100644 --- a/adev-ja/src/content/guide/templates/expression-syntax.md +++ b/adev-ja/src/content/guide/templates/expression-syntax.md @@ -17,7 +17,6 @@ Angularは、[リテラル値](https://developer.mozilla.org/en-US/docs/Glossary | Array | `['Onion', 'Cheese', 'Garlic']` | | null | `null` | | Template string | `` `Hello ${name}` `` | -| Tagged template string | `` tag`Hello ${name}` `` | ### サポートされていないリテラル diff --git a/adev-ja/src/content/introduction/essentials/components.en.md b/adev-ja/src/content/introduction/essentials/components.en.md index 818605125c..47ec800416 100644 --- a/adev-ja/src/content/introduction/essentials/components.en.md +++ b/adev-ja/src/content/introduction/essentials/components.en.md @@ -60,7 +60,7 @@ export class UserProfile { ```angular-html -

Use profile

+

User profile

This is the user profile page

``` diff --git a/adev-ja/src/content/introduction/essentials/components.md b/adev-ja/src/content/introduction/essentials/components.md index 3ddfea2b9c..6db6308f4b 100644 --- a/adev-ja/src/content/introduction/essentials/components.md +++ b/adev-ja/src/content/introduction/essentials/components.md @@ -60,7 +60,7 @@ export class UserProfile { ```angular-html -

Use profile

+

User profile

This is the user profile page

``` diff --git a/adev-ja/src/content/introduction/installation.en.md b/adev-ja/src/content/introduction/installation.en.md index a495ea87ac..6d4c59557c 100644 --- a/adev-ja/src/content/introduction/installation.en.md +++ b/adev-ja/src/content/introduction/installation.en.md @@ -110,6 +110,10 @@ NOTE: Raw file sizes do not reflect development server per-request transformatio And now you can visit the path in `Local` (e.g., `http://localhost:4200`) to see your application. Happy coding! 🎉 +### Using AI for Development + +To get started with building in your preferred AI powered IDE, [check out Angular prompt rules and best practices](/ai/develop-with-ai). + ## Next steps Now that you've created your Angular project, you can learn more about Angular in our [Essentials guide](/essentials) or choose a topic in our in-depth guides! diff --git a/adev-ja/src/content/introduction/installation.md b/adev-ja/src/content/introduction/installation.md index 33c054cd82..cf43150916 100644 --- a/adev-ja/src/content/introduction/installation.md +++ b/adev-ja/src/content/introduction/installation.md @@ -110,6 +110,10 @@ NOTE: Raw file sizes do not reflect development server per-request transformatio これで、`Local`のパス(例:`http://localhost:4200`)にアクセスしてアプリケーションを確認できます。コーディングを楽しんでください!🎉 +### 開発でのAIの使用 + +AI搭載IDEでの開発を開始するには、[Angularプロンプトルールとベストプラクティスをチェックしてください](/ai/develop-with-ai)。 + ## 次のステップ Angularプロジェクトを作成したので、[基本概念ガイド](/essentials)でAngularの詳細について学ぶか、詳しいガイドからトピックを選択してください! diff --git a/adev-ja/src/content/reference/extended-diagnostics/NG8115.md b/adev-ja/src/content/reference/extended-diagnostics/NG8115.md new file mode 100644 index 0000000000..f36732e2cf --- /dev/null +++ b/adev-ja/src/content/reference/extended-diagnostics/NG8115.md @@ -0,0 +1,61 @@ +# Uninvoked Track Function + +This diagnostic detects when a track function is not invoked in `@for` blocks. + + + +import {Component} from '@angular/core'; + +@Component({ + template: `@for (item of items; track trackByName) {}`, +}) +class Items { + protected trackByName(item) { return item.name; } +} + + + +## What's wrong with that? + +`@for` blocks need to uniquely identify items in the iterable to correctly perform DOM updates when items in the iterable are reordered, new items are added, or existing items are removed. +When you don't invoke the function, the reconcialiation algorithm will use the function reference instead of returned value to compare items. + +## What should I do instead? + +Ensure to invoke the track function when you use it in a `@for` block to execute the function so the loop can uniquely identify items. + + + +import {Component} from '@angular/core'; + +@Component({ + template: `@for (item of items; track trackByName(item)) {}`, +}) +class Items { + protected trackByName(item) { return item.name; } +} + + + +## Configuration requirements + +[`strictTemplates`](tools/cli/template-typecheck#strict-mode) must be enabled for any extended diagnostic to emit. +`uninvokedTrackFunction` has no additional requirements beyond `strictTemplates`. + +## What if I can't avoid this? + +This diagnostic can be disabled by editing the project's `tsconfig.json` file: + + +{ + "angularCompilerOptions": { + "extendedDiagnostics": { + "checks": { + "uninvokedTrackFunction": "suppress" + } + } + } +} + + +See [extended diagnostic configuration](extended-diagnostics#configuration) for more info. diff --git a/adev-ja/src/content/reference/extended-diagnostics/overview.md b/adev-ja/src/content/reference/extended-diagnostics/overview.md index 92829d8094..46391f5eef 100644 --- a/adev-ja/src/content/reference/extended-diagnostics/overview.md +++ b/adev-ja/src/content/reference/extended-diagnostics/overview.md @@ -22,6 +22,7 @@ Currently, Angular supports the following extended diagnostics: | `NG8111` | [`uninvokedFunctionInEventBinding`](extended-diagnostics/NG8111) | | `NG8113` | [`unusedStandaloneImports`](extended-diagnostics/NG8113) | | `NG8114` | [`unparenthesizedNullishCoalescing`](extended-diagnostics/NG8114) | +| `NG8115` | [`uninvokedTrackFunction`](extended-diagnostics/NG8115) | | `NG8116` | [`missingStructuralDirective`](extended-diagnostics/NG8116) | ## Configuration @@ -50,8 +51,7 @@ Check severity can be configured as an [Angular compiler option](reference/confi // The category to use for any diagnostics not listed in `checks` above. "defaultCategory": "error" } - -} + } }
diff --git a/adev-ja/src/content/reference/migrations/control-flow.md b/adev-ja/src/content/reference/migrations/control-flow.md index d764a9bdb6..d1622fbefb 100644 --- a/adev-ja/src/content/reference/migrations/control-flow.md +++ b/adev-ja/src/content/reference/migrations/control-flow.md @@ -8,6 +8,6 @@ Run the schematic using the following command: -ng update @angular/core --name=control-flow-migration +ng generate @angular/core:control-flow diff --git a/adev-ja/src/content/reference/releases.en.md b/adev-ja/src/content/reference/releases.en.md index 4c19f2328a..1b704f7726 100644 --- a/adev-ja/src/content/reference/releases.en.md +++ b/adev-ja/src/content/reference/releases.en.md @@ -74,9 +74,9 @@ HELPFUL: Approximate dates are offered as general guidance and are subject to ch | Version | Date | |:--------|:-------------------| -| v20.1 | TBD | -| v20.2 | TBD | -| v21.0 | TBD | +| v20.1 | Week of 2025-07-07 | +| v20.2 | Week of 2025-08-18 | +| v21.0 | Week of 2025-11-17 | ### Support window diff --git a/adev-ja/src/content/reference/releases.md b/adev-ja/src/content/reference/releases.md index 628a165747..82fdf37f44 100644 --- a/adev-ja/src/content/reference/releases.md +++ b/adev-ja/src/content/reference/releases.md @@ -74,9 +74,9 @@ HELPFUL: 概算の日付は一般的なガイダンスとして提供されて | バージョン | 日付 | |:--------|:-------------------| -| v20.1 | TBD | -| v20.2 | TBD | -| v21.0 | TBD | +| v20.1 | Week of 2025-07-07 | +| v20.2 | Week of 2025-08-18 | +| v21.0 | Week of 2025-11-17 | ### サポート期間 diff --git a/adev-ja/src/content/tools/language-service.md b/adev-ja/src/content/tools/language-service.md index 6c022c21e6..9cc309ca47 100644 --- a/adev-ja/src/content/tools/language-service.md +++ b/adev-ja/src/content/tools/language-service.md @@ -172,6 +172,10 @@ Angular Language Service can be used with Neovim by using the [nvim-lspconfig](h 2. [Configure angularls for nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#angularls) +### Zed + +In [Zed](https://zed.dev), install the extension from [Extensions: Marketplace](https://zed.dev/extensions?query=angular). + ## How the Language Service works When you use an editor with a language service, the editor starts a separate language-service process and communicates with it through an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call), using the [Language Server Protocol](https://microsoft.github.io/language-server-protocol). diff --git a/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.en.md b/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.en.md index 70af0fda02..0dd4d85f4d 100644 --- a/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.en.md +++ b/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.en.md @@ -8,7 +8,7 @@ Deferrable views let you define content to be shown in different loading states. @placeholder By default, defer blocks do not render any content before they are triggered. The @placeholder is an optional block that declares content to show before the deferred content loads. Angular replaces the placeholder with the deferred content after loading completes. While this block is optional, the Angular team recommends always including a placeholder. - + Learn more in the full deferrable views documentation diff --git a/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.md b/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.md index 3291f4c1f0..8f121a09df 100644 --- a/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.md +++ b/adev-ja/src/content/tutorials/deferrable-views/steps/2-loading-error-placeholder/README.md @@ -8,7 +8,7 @@ @placeholder デフォルトでは、遅延ブロックはトリガーされる前にコンテンツをレンダリングしません。@placeholderは、遅延コンテンツの読み込み前に表示するコンテンツを宣言するオプションのブロックです。Angularは読み込みが完了した後、プレースホルダーを遅延コンテンツに置き換えます。このブロックはオプションですが、Angularチームは常にプレースホルダーを含めることを推奨しています。 - + 遅延可能ビューの完全なドキュメントで詳細を確認してください diff --git a/adev-ja/src/content/tutorials/first-app/intro/README.md b/adev-ja/src/content/tutorials/first-app/intro/README.md index 0a9e0e13ab..8413c26699 100644 --- a/adev-ja/src/content/tutorials/first-app/intro/README.md +++ b/adev-ja/src/content/tutorials/first-app/intro/README.md @@ -69,6 +69,12 @@ You are free to use any tool you prefer to build apps with Angular. We recommend 3. [WebStorm](https://www.jetbrains.com/webstorm/) + + +In case you're following this tutorial in your preferred AI powered IDE, [check out Angular prompt rules and best practices](/ai/develop-with-ai). + + + For more information about the topics covered in this lesson, visit: diff --git a/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/README.md b/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/README.md index bdeae67f3b..69e6f2a67e 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/README.md @@ -94,11 +94,11 @@ In your IDE: 1. Next, open `first-app/src/app/app.ts`. 1. In `app.ts`, in the `@Component` definition, replace the `template` line with this code to change the text in the app component. - + 1. In `app.ts`, in the `App` class definition, replace the `title` line with this code to change the component title. - + Then, save the changes you made to `app.ts`. diff --git a/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/config.json b/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/config.json index b67a5512c9..7801959be2 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/01-hello-world/config.json @@ -2,5 +2,6 @@ "title": "Hello world!", "type": "editor", "answerSrc": "../02-Home/src", + "answerRootDir": "../02-Home/", "openFiles": ["src/app/app.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/02-Home/README.md b/adev-ja/src/content/tutorials/first-app/steps/02-Home/README.md index 4007439832..c0556a3160 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/02-Home/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/02-Home/README.md @@ -70,11 +70,11 @@ In the **Edit** pane of your IDE: 1. In `app.ts`, in `@Component`, update the `imports` array property and add `Home`. - + 1. In `app.ts`, in `@Component`, update the `template` property to include the following HTML code. - + 1. Save your changes to `app.ts`. 1. If `ng serve` is running, the app should update. @@ -100,7 +100,7 @@ In the **Edit** pane of your IDE: 1. In the `first-app` directory, open `home.ts` in the editor. 1. In `home.ts`, in `@Component`, update the `template` property with this code. - + 1. Next, open `home.css` in the editor and update the content with these styles. diff --git a/adev-ja/src/content/tutorials/first-app/steps/02-Home/config.json b/adev-ja/src/content/tutorials/first-app/steps/02-Home/config.json index 4074bc42c8..08f5d75c33 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/02-Home/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/02-Home/config.json @@ -2,5 +2,6 @@ "title": "Create home component", "type": "editor", "answerSrc": "../03-HousingLocation/src", + "answerRootDir": "../03-HousingLocation", "openFiles": ["src/app/app.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/README.md b/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/README.md index 91332a02c8..4d45d8b2d9 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/README.md @@ -51,11 +51,11 @@ In the **Edit** pane of your IDE: 1. Next update the `imports` property of the `@Component` metadata by adding `HousingLocation` to the array. - + 1. Now the component is ready for use in the template for the `Home`. Update the `template` property of the `@Component` metadata to include a reference to the `` tag. - + diff --git a/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/config.json b/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/config.json index 494c487c77..c78152f96c 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/03-HousingLocation/config.json @@ -2,5 +2,6 @@ "title": "Create housing location component", "type": "editor", "answerSrc": "../04-interfaces/src", + "answerRootDir": "../04-interfaces/", "openFiles": ["src/app/home/home.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/README.md b/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/README.md index 548970bb50..d82c564d69 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/README.md @@ -70,9 +70,9 @@ There are a few more lessons to complete before that happens. 1. In `src/app/home/home.ts`, replace the empty `export class Home {}` definition with this code to create a single instance of the new interface in the component. - + -1. Confirm that your `home.ts` file matches like this example. +1. Confirm that your `home.ts` file matches this example. diff --git a/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/config.json b/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/config.json index 5c7c028069..4ed73f4eaf 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/04-interfaces/config.json @@ -2,5 +2,6 @@ "title": "Create an interface", "type": "editor", "answerSrc": "../05-inputs/src", + "answerRootDir": "../05-inputs/", "openFiles": ["src/app/home/home.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/05-inputs/README.md b/adev-ja/src/content/tutorials/first-app/steps/05-inputs/README.md index dac34b0dea..3aaacc94f8 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/05-inputs/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/05-inputs/README.md @@ -1,41 +1,40 @@ # Add an input parameter to the component -This tutorial lesson demonstrates how to create a component `@Input()` and use it to pass data to a component for customization. +This tutorial lesson demonstrates how to create a component `input` and use it to pass data to a component for customization. ## What you'll learn - Your app's `HousingLocation` template has a `HousingLocation` property to receive input. ## Conceptual preview of Inputs -[Inputs](api/core/Input) allow components to share data. The direction of the data sharing is from parent component to child component. +[Inputs](api/core/input) allow components to share data. The direction of the data sharing is from parent component to child component. -In this lesson, you'll define `@Input()` properties in the `HousingLocation` component which will enable you to customize the data displayed in the component. +In this lesson, you'll define an `input` property in the `HousingLocation` component which will enable you to customize the data displayed in the component. Learn more in the [Accepting data with input properties](guide/components/inputs) and [Custom events with outputs](guide/components/outputs) guides. - -This step imports the `Input` decorator into the class. + +This step imports the `input()` function into the class. In the code editor: 1. Navigate to `src/app/housing-location/housing-location.ts` -1. Update the file imports to include `Input` and `HousingLocation`: +1. Update the file imports to include `input` and `HousingLocation`: -1. In the same file, add a property called `housingLocation` of type `HousingLocation` to the `HousingLocation` class. Add an `!` after the property name and prefix it with the `@Input()` decorator: +1. In the same file, add a property called `housingLocation` and initialize it using `input.required()` with the type `HousingLocationInfo`. To set the type, use a generic parameter, by writing <HousingLocationInfo> immediately after .required: - You have to add the `!` because the input is expecting the value to be passed. In this case, there is no default value. In our example application case we know that the value will be passed in - this is by design. The exclamation point is called the non-null assertion operator and it tells the TypeScript compiler that the value of this property won't be null or undefined. + You have to add `.required` after `input` to indicate that the parent component must provide a value. In our example application, we know this value will always be passed in — this is by design. The `.required()` call ensures that the TypeScript compiler enforces this and treats the property as non-nullable when this component is used in a template. 1. Save your changes and confirm the app does not have any errors. @@ -44,7 +43,7 @@ In the code editor: -SUMMARY: In this lesson, you created a new property decorated with the `@Input()` decorator. You also used the non-null assertion operator to notify the compiler that the value of the new property won't be `null` or `undefined`. +SUMMARY: In this lesson, you created a new `input` property. You also used the `.required` method to ensure the signal value is always defined. diff --git a/adev-ja/src/content/tutorials/first-app/steps/05-inputs/config.json b/adev-ja/src/content/tutorials/first-app/steps/05-inputs/config.json index b129c0dd7a..46294c0b7a 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/05-inputs/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/05-inputs/config.json @@ -2,5 +2,6 @@ "title": "Add inputs to components", "type": "editor", "answerSrc": "../06-property-binding/src", + "answerRootDir": "../06-property-binding/", "openFiles": ["src/app/housing-location/housing-location.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/06-property-binding/config.json b/adev-ja/src/content/tutorials/first-app/steps/06-property-binding/config.json index 6be9c87656..53cbcd2c30 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/06-property-binding/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/06-property-binding/config.json @@ -2,5 +2,6 @@ "title": "Add property binding to components", "type": "editor", "answerSrc": "../07-dynamic-template-values/src", + "answerRootDir": "../07-dynamic-template-values", "openFiles": ["src/app/home/home.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/07-dynamic-template-values/config.json b/adev-ja/src/content/tutorials/first-app/steps/07-dynamic-template-values/config.json index 0b74f2e24e..76bb08e4d5 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/07-dynamic-template-values/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/07-dynamic-template-values/config.json @@ -2,5 +2,6 @@ "title": "Add dynamic values to templates", "type": "editor", "answerSrc": "../08-ngFor/src", + "answerRootDir": "../08-ngFor/", "openFiles": ["src/app/housing-location/housing-location.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/08-ngFor/config.json b/adev-ja/src/content/tutorials/first-app/steps/08-ngFor/config.json index c2edee61c2..3819203bbb 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/08-ngFor/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/08-ngFor/config.json @@ -2,5 +2,6 @@ "title": "Use *ngFor in templates", "type": "editor", "answerSrc": "../09-services/src", + "answerRootDir": "../09-services/", "openFiles": ["src/app/home/home.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/09-services/config.json b/adev-ja/src/content/tutorials/first-app/steps/09-services/config.json index df458e182f..a352e649af 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/09-services/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/09-services/config.json @@ -2,5 +2,6 @@ "title": "Angular services", "type": "editor", "answerSrc": "../10-routing/src", + "answerRootDir": "../10-routing/", "openFiles": ["src/app/home/home.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/10-routing/config.json b/adev-ja/src/content/tutorials/first-app/steps/10-routing/config.json index fdc7fd1a47..6f72913d98 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/10-routing/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/10-routing/config.json @@ -2,5 +2,6 @@ "title": "Add routing", "type": "local", "answerSrc": "../11-details-page/src", + "answerRootDir": "../11-details-page/", "openFiles": ["src/main.ts", "src/app/app.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/11-details-page/README.md b/adev-ja/src/content/tutorials/first-app/steps/11-details-page/README.md index 2b65717d6a..ba7d28f90d 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/11-details-page/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/11-details-page/README.md @@ -72,7 +72,7 @@ In this step, you will get the route parameter in the `Details`. Currently, the 1. In the browser, click on one of the housing location's "Learn More" links and confirm that the numeric value displayed on the page matches the `id` property for that location in the data. - + Now that routing is working properly in the application this is a great time to update the template of the `Details` to display the specific data represented by the housing location for the route parameter. To access the data you will add a call to the `HousingService`. diff --git a/adev-ja/src/content/tutorials/first-app/steps/11-details-page/config.json b/adev-ja/src/content/tutorials/first-app/steps/11-details-page/config.json index 5dc490333b..378ef9b40f 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/11-details-page/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/11-details-page/config.json @@ -2,6 +2,7 @@ "title": "Customize the details page", "type": "local", "answerSrc": "../12-forms/src", + "answerRootDir": "../12-forms/", "openFiles": [ "src/app/housing-location/housing-location.ts", "src/app/details/details.ts", diff --git a/adev-ja/src/content/tutorials/first-app/steps/12-forms/README.md b/adev-ja/src/content/tutorials/first-app/steps/12-forms/README.md index 09ce9e001e..6ef7acf53c 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/12-forms/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/12-forms/README.md @@ -25,7 +25,7 @@ In the **Edit** pane of your IDE: 1. In `src/app/housing.service.ts`, inside the `HousingService` class, paste this method at the bottom of the class definition. - + 1. Confirm that the app builds without error. Correct any errors before you continue to the next step. @@ -38,21 +38,21 @@ In the **Edit** pane of your IDE, in `src/app/details/details.ts`: 1. After the `import` statements at the top of the file, add the following code to import the Angular form classes. - + 1. In the `Details` decorator metadata, update the `imports` property with the following code: - + 1. In the `Details` class, before the `constructor()` method, add the following code to create the form object. - + In Angular, `FormGroup` and `FormControl` are types that enable you to build forms. The `FormControl` type can provide a default value and shape the form data. In this example `firstName` is a `string` and the default value is empty string. 1. In the `Details` class, after the `constructor()` method, add the following code to handle the **Apply now** click. - + This button does not exist yet - you will add it in the next step. In the above code, the `FormControl`s may return `null`. This code uses the nullish coalescing operator to default to empty string if the value is `null`. diff --git a/adev-ja/src/content/tutorials/first-app/steps/12-forms/config.json b/adev-ja/src/content/tutorials/first-app/steps/12-forms/config.json index 46a7602839..8b36b8973b 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/12-forms/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/12-forms/config.json @@ -2,5 +2,6 @@ "title": "Integrate Angular forms", "type": "local", "answerSrc": "../13-search/src", + "answerRootDir": "../13-search/", "openFiles": ["src/app/housing.service.ts", "src/app/details/details.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/13-search/README.md b/adev-ja/src/content/tutorials/first-app/steps/13-search/README.md index 86f8e5795e..3bd4aeeaa8 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/13-search/README.md +++ b/adev-ja/src/content/tutorials/first-app/steps/13-search/README.md @@ -20,13 +20,13 @@ In this step, you'll update the `Home` class to store data in a new array proper 1. In `src/app/home/home.ts`, add new property to the class called `filteredLocationList`. - + The `filteredLocationList` hold the values that match the search criteria entered by the user. 1. The `filteredLocationList` should contain the total set of housing locations values by default when the page loads. Update the `constructor` for the `Home` to set the value. - + @@ -62,7 +62,7 @@ The template has been updated to bind the `filterResults` function to the `click 1. Update the `Home` class to include the implementation of the `filterResults` function. - + This function uses the `String` `filter` function to compare the value of the `text` parameter against the `housingLocation.city` property. You can update this function to match against any property or multiple properties for a fun exercise. diff --git a/adev-ja/src/content/tutorials/first-app/steps/13-search/config.json b/adev-ja/src/content/tutorials/first-app/steps/13-search/config.json index 64e500f41e..c18d1feb28 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/13-search/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/13-search/config.json @@ -2,5 +2,6 @@ "title": "Add search functionality", "type": "local", "answerSrc": "../14-http/src", + "answerRootDir": "../14-http/", "openFiles": ["src/app/home/home.ts", "src/app/details/details.ts"] } diff --git a/adev-ja/src/content/tutorials/first-app/steps/14-http/config.json b/adev-ja/src/content/tutorials/first-app/steps/14-http/config.json index d3d2c0cf9c..b5ecd7bdf8 100644 --- a/adev-ja/src/content/tutorials/first-app/steps/14-http/config.json +++ b/adev-ja/src/content/tutorials/first-app/steps/14-http/config.json @@ -2,5 +2,6 @@ "title": "Add HTTP communication", "type": "local", "answerSrc": "./src-final", + "answerRootDir": "./src-final", "openFiles": ["src/app/app.ts"] } diff --git a/adev-ja/src/content/tutorials/learn-angular/intro/README.en.md b/adev-ja/src/content/tutorials/learn-angular/intro/README.en.md index 799277135f..316e3b04b5 100644 --- a/adev-ja/src/content/tutorials/learn-angular/intro/README.en.md +++ b/adev-ja/src/content/tutorials/learn-angular/intro/README.en.md @@ -11,3 +11,7 @@ Each step represents a concept in Angular. You can do one, or all of them. If you get stuck, click "Reveal answer" at the top. Alright, let's [get started](/tutorials/learn-angular/1-components-in-angular). + +## Using AI for Development + +In case you're following this tutorial in your preferred AI powered IDE, [check out Angular prompt rules and best practices](/ai/develop-with-ai). \ No newline at end of file diff --git a/adev-ja/src/content/tutorials/learn-angular/intro/README.md b/adev-ja/src/content/tutorials/learn-angular/intro/README.md index 2e1b58f19d..0bbdcc5816 100644 --- a/adev-ja/src/content/tutorials/learn-angular/intro/README.md +++ b/adev-ja/src/content/tutorials/learn-angular/intro/README.md @@ -11,3 +11,7 @@ Angularを理解するには、HTML、CSS、およびJavaScriptの基本的な 行き詰まったら、上部の「解答を表示」をクリックしてください。 さあ、[始めましょう](/tutorials/learn-angular/1-components-in-angular)。 + +## 開発でのAIの使用 + +AI搭載IDEでこのチュートリアルに従っている場合は、[Angularプロンプトルールとベストプラクティスをチェックしてください](/ai/develop-with-ai)。 diff --git a/origin b/origin index a70f03a9b4..5766ba6a5e 160000 --- a/origin +++ b/origin @@ -1 +1 @@ -Subproject commit a70f03a9b40a4f1f0e554541f236270025b41501 +Subproject commit 5766ba6a5ec583a8bf92abf4dd99f5b214f9b48a diff --git a/tools/adev-patches/localize-home.patch b/tools/adev-patches/localize-home.patch index 1d462143f1..04b36ee763 100644 --- a/tools/adev-patches/localize-home.patch +++ b/tools/adev-patches/localize-home.patch @@ -1,22 +1,33 @@ diff --git a/adev/src/app/features/home/components/home-animation/home-animation.component.html b/adev/src/app/features/home/components/home-animation/home-animation.component.html -index 255de76efe..4d3d3bdede 100644 +index be86249f55..d7be55fdd8 100644 --- a/adev/src/app/features/home/components/home-animation/home-animation.component.html +++ b/adev/src/app/features/home/components/home-animation/home-animation.component.html -@@ -6,13 +6,13 @@ - class="adev-banner" - target="_blank" - > --

Angular v20 is here!

--

Watch the developer event on May 29th.

-+

Angular v20 がリリースされました!

-+

5月29日の開発者イベントをお見逃しなく

- +@@ -7,22 +7,22 @@ + class="adev-banner" + target="_blank" + > +-

Angular v20 is here!

+-

Read about our newest release

++

Angular v20 がリリースされました!

++

最新リリースについて読む

+ + +-

Available now:

+-

Prompts and best practices for AI and Angular

++

公開中:

++

AIとAngularのためのプロンプトとベストプラクティス

+
+