Check my position
@@ -102,6 +106,11 @@
margin-top: 1rem;
}
+ .global-count {
+ color: red;
+ font-size: 20px;
+ }
+
.link-username {
margin-top: 2rem;
width: 100%;
diff --git a/docs/src/components/leaderboard/LeaderboardChallenge.svelte b/docs/src/components/leaderboard/LeaderboardChallenge.svelte
index 184d1a20f..3cee5229e 100644
--- a/docs/src/components/leaderboard/LeaderboardChallenge.svelte
+++ b/docs/src/components/leaderboard/LeaderboardChallenge.svelte
@@ -35,7 +35,7 @@
login,
avatar: pr.avatar,
count: pr.count
- })).filter((r) => r.login !== 'allcontributors[bot]').sort((a, b) => b.count - a.count);
+ })).filter((r) => r.login !== 'allcontributors[bot]' && r.login !== 'tomalaforge').sort((a, b) => b.count - a.count);
};
async function fetchGitHubUsers() {
diff --git a/docs/src/content/authors/Ioannis-Tsironis.json b/docs/src/content/authors/Ioannis-Tsironis.json
new file mode 100644
index 000000000..9cb257672
--- /dev/null
+++ b/docs/src/content/authors/Ioannis-Tsironis.json
@@ -0,0 +1,5 @@
+{
+ "name": "Ioannis Tsironis",
+ "github": "https://github.com/tsironis13",
+ "linkedin": "https://www.linkedin.com/in/giannis-tsironis/"
+}
diff --git a/docs/src/content/authors/lance-finney.json b/docs/src/content/authors/lance-finney.json
new file mode 100644
index 000000000..be44e3e89
--- /dev/null
+++ b/docs/src/content/authors/lance-finney.json
@@ -0,0 +1,6 @@
+{
+ "name": "Lance Finney",
+ "twitter": "https://twitter.com/LMFinneyCoder",
+ "linkedin": "https://www.linkedin.com/in/lmfinney/",
+ "github": "https://github.com/LMFinney"
+}
diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts
index 15a009589..91a2d506a 100644
--- a/docs/src/content/config.ts
+++ b/docs/src/content/config.ts
@@ -22,12 +22,14 @@ const docs = defineCollection({
contributors: z.array(z.string()).optional(),
command: z.string().optional(),
blogLink: z.string().optional(),
- videoLink: z
- .object({
- link: z.string(),
- alt: z.string(),
- flag: z.enum(['FR']).optional(),
- })
+ videoLinks: z
+ .array(
+ z.object({
+ link: z.string(),
+ alt: z.string(),
+ flag: z.enum(['FR', 'ES']).optional(),
+ }),
+ )
.optional(),
}),
})(ctx),
diff --git a/docs/src/content/docs/challenges/angular/1-projection.md b/docs/src/content/docs/challenges/angular/1-projection.md
index 0fce427c2..127530f03 100644
--- a/docs/src/content/docs/challenges/angular/1-projection.md
+++ b/docs/src/content/docs/challenges/angular/1-projection.md
@@ -11,10 +11,13 @@ contributors:
challengeNumber: 1
command: angular-projection
blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
-videoLink:
- link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
- alt: Projection video by Arthur Lannelucq
- flag: FR
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
sidebar:
order: 1
---
@@ -25,7 +28,7 @@ In Angular, content projection is a powerful technique for creating highly custo
You can learn all about ng-content [here](https://angular.dev/guide/components/content-projection) from simple projection to more complex ones.
-To learn about ngTemplateOutlet, you can find the API documentation [here](https://angular.io/api/common/NgTemplateOutlet) along with some basic examples.
+To learn about ngTemplateOutlet, you can find the API documentation [here](https://angular.dev/api/common/NgTemplateOutlet) along with some basic examples.
With these two tools in hand, you are now ready to take on the challenge.
@@ -38,12 +41,11 @@ While the application works, the developer experience is far from being optimal.
## Constraints
- You must refactor the `CardComponent` and `ListItemComponent`.
-- The `NgFor` directive must be declared and remain inside the `CardComponent`. You might be tempted to move it to the `ParentCardComponent` like `TeacherCardComponent`.
-- `CardComponent` should not contain any `NgIf` or `NgSwitch`.
+- The `@for` must be declared and remain inside the `CardComponent`. You might be tempted to move it to the `ParentCardComponent` like `TeacherCardComponent`.
+- `CardComponent` should not contain any conditions.
- CSS: try to avoid using `::ng-deep`. Find a better way to handle CSS styling.
## Bonus Challenges
-- Try to work with the new built-in control flow syntax for loops and conditionals (documentation [here](https://angular.dev/guide/templates/control-flow))
- Use the signal API to manage your components state (documentation [here](https://angular.dev/guide/signals))
- To reference the template, use a directive instead of magic strings ([What is wrong with magic strings?](https://softwareengineering.stackexchange.com/a/365344))
diff --git a/docs/src/content/docs/challenges/angular/10-utility-wrapper-pipe.md b/docs/src/content/docs/challenges/angular/10-utility-wrapper-pipe.md
index ea5d1096c..f74bb1612 100644
--- a/docs/src/content/docs/challenges/angular/10-utility-wrapper-pipe.md
+++ b/docs/src/content/docs/challenges/angular/10-utility-wrapper-pipe.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- svenson95
+ - LMFinney
challengeNumber: 10
command: angular-utility-wrapper-pipe
sidebar:
@@ -14,13 +15,13 @@ sidebar:
## Information
-This is the third of three `@Pipe()` challenges, the goal of this series is to master **pipes** in Angular.
+This is the third of three `@Pipe()` challenges. The goal of this series is to master **pipes** in Angular.
-Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So they won't be recalculated every change detection cycle if their inputs haven't changed.
+Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So, they won't be recalculated every change detection cycle if their inputs haven't changed.
-Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improving rendering performance.
+Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improve rendering performance.
-By default a pipe is pure, you should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
+By default, a pipe is pure. You should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
:::note
A **pure** pipe is only called when the value changes.\
@@ -31,7 +32,7 @@ There are some useful predefined pipes like the DatePipe, UpperCasePipe and Curr
## Statement
-In this exercise, you want to access utils functions. Currently you cannot access them directly from your template. The goal is to create a specific pipe for this utils file, where you will need to pass the name of the function you want to call and the needed arguments.
+In this exercise, you want to access utils functions. Currently, you cannot access them directly from your template. The goal is to create a specific pipe for this utils file, where you will need to pass the name of the function you want to call and the needed arguments.
## Constraints
diff --git a/docs/src/content/docs/challenges/angular/13-highly-customizable-css.md b/docs/src/content/docs/challenges/angular/13-highly-customizable-css.md
index 7508c11d8..b08786ea3 100644
--- a/docs/src/content/docs/challenges/angular/13-highly-customizable-css.md
+++ b/docs/src/content/docs/challenges/angular/13-highly-customizable-css.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- kabrunko-dev
+ - LMFinney
challengeNumber: 13
command: angular-highly-customizable-css
sidebar:
@@ -14,7 +15,7 @@ sidebar:
## Information
-Styling is an important aspect of a frontend developer's day job, but it is often underestimated. In Angular applications, I frequently see people using `@Input()` to customize the style of their components. However, `@Input()` should only be used for logic. Other techniques, such as **CSS variables** and **host-context** should be used for styling.
+Styling is an important aspect of a frontend developer's day job, but it is often underestimated. In Angular applications, I frequently see people using `@Input()` to customize the style of their components. However, `@Input()` should only be used for logic. Other techniques, such as **CSS variables** and **host-context**, should be used for styling.
In this challenge, you will need to use both CSS variables and `:host-context` to remove all `@Input()` from your code.
diff --git a/docs/src/content/docs/challenges/angular/22-router-input.md b/docs/src/content/docs/challenges/angular/22-router-input.md
index 16368321c..1a5127e89 100644
--- a/docs/src/content/docs/challenges/angular/22-router-input.md
+++ b/docs/src/content/docs/challenges/angular/22-router-input.md
@@ -1,11 +1,12 @@
---
title: 🟢 @RouterInput()
-description: Challenge 22 is about using the @Input decorator to retreive router params.
+description: Challenge 22 is about using the @Input decorator to retrieve router params.
author: thomas-laforge
contributors:
- tomalaforge
- tomer953
- svenson95
+ - LMFinney
challengeNumber: 22
command: angular-router-input
blogLink: https://medium.com/ngconf/accessing-route-params-in-angular-1f8e12770617
diff --git a/docs/src/content/docs/challenges/angular/3-directive-enhancement.md b/docs/src/content/docs/challenges/angular/3-directive-enhancement.md
index 72e4cd058..2937e5800 100644
--- a/docs/src/content/docs/challenges/angular/3-directive-enhancement.md
+++ b/docs/src/content/docs/challenges/angular/3-directive-enhancement.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- kabrunko-dev
- svenson95
+ - LMFinney
challengeNumber: 3
command: angular-directive-enhancement
blogLink: https://medium.com/@thomas.laforge/ngfor-enhancement-716b44656a6c
@@ -20,15 +21,15 @@ This exercise can feel obsolete with the new control flow and the empty block in
## Information
-Directive is a very powerful tool only offered by the Angular framework. You can apply the DRY principle by having shared logic inside a directive and applying it to any component you want.
+Directives are a very powerful tool only offered by the Angular framework. You can apply the DRY principle by having shared logic inside a directive and applying it to any component you want.
-But the real power is that you can enhance an already existing directive which moreover doesn't **belong** to you.
+But the real power is that you can enhance an already-existing directive, which moreover doesn't **belong** to you.
## Statement
In this exercise, we have a want to display a list of persons. If the list is empty, you must display _" the list is empty !! "_.
-Currently we have:
+Currently, we have:
```typescript
0; else emptyList">
diff --git a/docs/src/content/docs/challenges/angular/32-change-detection-bug.md b/docs/src/content/docs/challenges/angular/32-change-detection-bug.md
index cd88f3b43..633d41721 100644
--- a/docs/src/content/docs/challenges/angular/32-change-detection-bug.md
+++ b/docs/src/content/docs/challenges/angular/32-change-detection-bug.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- jdegand
+ - LMFinney
challengeNumber: 32
command: angular-change-detection-bug
blogLink: https://medium.com/ngconf/function-calls-inside-template-are-dangerous-15f9822a6629
@@ -19,7 +20,7 @@ This challenge is inspired by a real-life example that I simplified to create th
## Information
-In this small application, we have a navigation menu to route our application to either `BarComponent` or `FooComponent`. However our application is not loading and no errors are displayed inside the console.
+In this small application, we have a navigation menu to route our application to either `BarComponent` or `FooComponent`. However, our application is not loading and no errors are displayed inside the console.
## Statement
diff --git a/docs/src/content/docs/challenges/angular/33-decoupling-components.md b/docs/src/content/docs/challenges/angular/33-decoupling-components.md
index 83104628d..2b900c7a6 100644
--- a/docs/src/content/docs/challenges/angular/33-decoupling-components.md
+++ b/docs/src/content/docs/challenges/angular/33-decoupling-components.md
@@ -5,6 +5,7 @@ author: thomas-laforge
contributors:
- tomalaforge
- jdegand
+ - LMFinney
challengeNumber: 33
command: angular-decoupling-components
sidebar:
@@ -18,9 +19,9 @@ sidebar:
The goal of this challenge is to separate the behavior of a component from its style. For the purpose of this challenge, we will be working on a button element. When we click on it, we will toggle a _disabled_ property which will change the style of the element. This is quite useless in real life but the challenge aims to demonstrate a useful concept.
-The behavior of the component (referred to as the _brain_ in the Spartan stack) is located in the brain library. The styling part (referred to as the _helmet_) is located inside the helmet library. Both libraries cannot depend on each other because we want to be able to publish them separately. To help us address the issue, we are using the Nx enforce eslint rule. You can find more details [here](https://nx.dev/core-features/enforce-module-boundaries).
+The behavior of the component (referred to as the _brain_ in the Spartan stack) is located in the brain library. The styling part (referred to as the _helmet_) is located inside the helmet library. Both libraries cannot depend on each other because we want to be able to publish them separately. To help us address the issue, we are using the Nx `enforce-module-boundaries` eslint rule. You can find more details [here](https://nx.dev/core-features/enforce-module-boundaries).
-However the button's helmet needs to access the state of the component to style the button differently based on its state. As mention above, we cannot import the `BtnDisabledDirective` directly into the helmet library as done currently. If you go to [`BtnHelmetDirective`](../../libs/decoupling/helmet/src/lib/btn-style.directive.ts), you will encounter a linting error. **A project tagged with `type:hlm` can only depend on libs tagged with `type:core`**.
+However, the button's helmet needs to access the state of the component to style the button differently based on its state. As mentioned above, we cannot import the `BtnDisabledDirective` directly into the helmet library as done currently. If you go to [`BtnHelmetDirective`](../../libs/decoupling/helmet/src/lib/btn-style.directive.ts), you will encounter a linting error. **A project tagged with `type:hlm` can only depend on libs tagged with `type:core`**.
## Statement
diff --git a/docs/src/content/docs/challenges/angular/39-injection-token.md b/docs/src/content/docs/challenges/angular/39-injection-token.md
index 5d325a670..4e2f3119d 100644
--- a/docs/src/content/docs/challenges/angular/39-injection-token.md
+++ b/docs/src/content/docs/challenges/angular/39-injection-token.md
@@ -1,12 +1,17 @@
---
title: 🟠 InjectionToken
-description: Challenge 39 is about learning the power of dependancy injection
+description: Challenge 39 is about learning the power of dependency injection
author: thomas-laforge
contributors:
- tomalaforge
- jdegand
+ - LMFinney
challengeNumber: 39
command: angular-injection-token
+videoLinks:
+ - link: https://www.youtube.com/watch?v=ntggdQycFyc
+ alt: Injection Token by Arthur Lannelucq
+ flag: FR
sidebar:
order: 118
---
diff --git a/docs/src/content/docs/challenges/angular/4-typed-context-outlet.md b/docs/src/content/docs/challenges/angular/4-typed-context-outlet.md
index 2df8dea36..86d43e5f1 100644
--- a/docs/src/content/docs/challenges/angular/4-typed-context-outlet.md
+++ b/docs/src/content/docs/challenges/angular/4-typed-context-outlet.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 4
command: angular-typed-context-outlet
blogLink: https://medium.com/@thomas.laforge/ngtemplateoutlet-type-checking-5d2dcb07a2c6
@@ -18,7 +19,7 @@ sidebar:
You can improve template type checking for custom directives by adding template guard properties to your directive definition. Angular offers the static function [`ngTemplateContextGuard`](https://angular.dev/guide/directives/structural-directives#improving-template-type-checking-for-custom-directives) to strongly type structural directives.
-However the context of **NgTemplateOutlet** type is **Object**. But with the help of the above guard, we can improve that behavior.
+However, the context of **NgTemplateOutlet** type is **Object**. But with the help of the above guard, we can improve that behavior.
## Statement
@@ -28,17 +29,17 @@ This exercise has two levels of complexity.
### Level 1: Known Interface
-Currently we have the following piece of code.
+Currently, we have the following piece of code.
-
+
As we can see, `name` is of type `any`. We want to infer the correct type using the custom directive `PersonDirective`.
### Level 2: Generic Interface
-Currently we have the following piece of code.
+Currently, we have the following piece of code.
-
+
As we can see, `student` is of type `any`. We want to infer the correct type using the custom directive `ListDirective`.
diff --git a/docs/src/content/docs/challenges/angular/44-view-transition.md b/docs/src/content/docs/challenges/angular/44-view-transition.md
index 33d096e73..74d0a88bb 100644
--- a/docs/src/content/docs/challenges/angular/44-view-transition.md
+++ b/docs/src/content/docs/challenges/angular/44-view-transition.md
@@ -5,6 +5,7 @@ author: thomas-laforge
contributors:
- tomalaforge
- jdegand
+ - LMFinney
challengeNumber: 44
command: angular-view-transition
sidebar:
@@ -13,9 +14,9 @@ sidebar:
## Information
-This is the second of two animation challenges, the goal of this series is to master animations in Angular.
+This is the second of two animation challenges. The goal of this series is to master animations in Angular.
-The View Transition API is a brand new API that provides a set of features that allow developers to control and manipulate the transitions and animations between views within an application.
+The View Transition API is a brand-new API that provides a set of features that allow developers to control and manipulate the transitions and animations between views within an application.
It plays a pivotal role in enhancing the user experience (UX), bringing applications to life with engaging and captivating transitions to guide users through different pages or sections of the app.
The goal of this challenge is to learn about and manipulate all types of transitions proposed by the API.
diff --git a/docs/src/content/docs/challenges/angular/45-react-in-angular.md b/docs/src/content/docs/challenges/angular/45-react-in-angular.md
index 7f6ab2da1..cef0a4841 100644
--- a/docs/src/content/docs/challenges/angular/45-react-in-angular.md
+++ b/docs/src/content/docs/challenges/angular/45-react-in-angular.md
@@ -6,6 +6,7 @@ contributors:
- wandri
- tomalaforge
- jdegand
+ - LMFinney
challengeNumber: 45
command: angular-react-in-angular
sidebar:
@@ -57,7 +58,7 @@ npm i --save-dev @types/react @types/react-dom
Hint 2 - Initialization
- Create a react root with `createRoot(...)`
+ Create a React root with `createRoot(...)`
@@ -76,5 +77,5 @@ npm i --save-dev @types/react @types/react-dom
Hint 4 - Design
- Do not forget to allow the react file in Tailwind.
+ Do not forget to allow the React file in Tailwind.
diff --git a/docs/src/content/docs/challenges/angular/46-simple-animations.md b/docs/src/content/docs/challenges/angular/46-simple-animations.md
index 3806a6864..aa8887977 100644
--- a/docs/src/content/docs/challenges/angular/46-simple-animations.md
+++ b/docs/src/content/docs/challenges/angular/46-simple-animations.md
@@ -4,6 +4,7 @@ description: Challenge 46 is about learning Angular's integrated animation API
author: sven-brodny
contributors:
- svenson95
+ - LMFinney
challengeNumber: 46
command: angular-simple-animations
sidebar:
@@ -12,7 +13,7 @@ sidebar:
## Information
-This is the first of two animation challenges, the goal of this series is to master animations in Angular.
+This is the first of two animation challenges. The goal of this series is to master animations in Angular.
Well-designed animations can make your application more fun and straightforward to use, but they aren't just cosmetic. Animations can improve your application and user experience in a number of ways:
@@ -22,7 +23,7 @@ Well-designed animations can make your application more fun and straightforward
I would recommend you read the [official documentation](https://angular.dev/guide/animations). You will learn everything that is necessary to successfully complete the challenge.
-Otherwise look at this [working example](https://svenson95.github.io/ng-xmp-animations/) and [git repo](https://github.com/svenson95/ng-xmp-animations) to get inspired.
+Otherwise, look at this [working example](https://svenson95.github.io/ng-xmp-animations/) and [git repo](https://github.com/svenson95/ng-xmp-animations) to get inspired.
## Statement
diff --git a/docs/src/content/docs/challenges/angular/5-crud-application.md b/docs/src/content/docs/challenges/angular/5-crud-application.md
index 6b36c30e0..1e439150a 100644
--- a/docs/src/content/docs/challenges/angular/5-crud-application.md
+++ b/docs/src/content/docs/challenges/angular/5-crud-application.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 5
command: angular-crud-application
sidebar:
@@ -21,7 +22,7 @@ Communicating and having a global/local state in sync with your backend is the h
In this exercise, you have a small CRUD application, which get a list of TODOS, update and delete some todos.
-Currently we have a working example but filled with lots of bad practices.
+Currently, we have a working example but filled with lots of bad practices.
### Step 1: refactor with best practices
diff --git a/docs/src/content/docs/challenges/angular/50-bug-effect-signal.md b/docs/src/content/docs/challenges/angular/50-bug-effect-signal.md
deleted file mode 100644
index 0e73301d5..000000000
--- a/docs/src/content/docs/challenges/angular/50-bug-effect-signal.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: 🟢 Bug in Effect ?
-description: Challenge 50 is about understanding why an effect is not triggered.
-author: thomas-laforge
-contributors:
- - tomalaforge
-challengeNumber: 50
-command: angular-bug-effect-signal
-sidebar:
- order: 19
----
-
-## Information
-
-In this basic exercise, we aim to display an alert whenever at least one checkbox is checked.
-
-## Statement
-
-The alert correctly triggers when clicking on each checkbox separately. However, if you first click on one checkbox and then click on a second one, the alert fails to appear. Why does this happen?
-
-The objective of this challenge is to understand and correct the issue preventing the alert from appearing when the second checkbox is clicked.
diff --git a/docs/src/content/docs/challenges/angular/52-lazy-load-component.md b/docs/src/content/docs/challenges/angular/52-lazy-load-component.md
new file mode 100644
index 000000000..f71c57d48
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/52-lazy-load-component.md
@@ -0,0 +1,48 @@
+---
+title: 🟢 Lazy Load a Component
+description: Challenge 52 is about understanding how to lazy load a component in Angular.
+author: lance-finney
+contributors:
+ - LMFinney
+challengeNumber: 52
+command: angular-lazy-load-component
+sidebar:
+ order: 21
+---
+
+## Information
+
+Angular has long had route-based lazy loading for entire modules, but lazy loading individual components was much more complicated. This challenge is about understanding how to lazy load a component easily with a feature that was introduced in Angular 17.
+
+## Statement
+
+This is a simple application that can display a `TopComponent` that we are pretending would slow the application down if it were part of the initial bundle (it actually contains just a bit of text, but we are pretending).
+
+The current implementation shows a `PlaceholderComponent` until the user clicks a button to display the `TopComponent`. However, even though the `TopComponent` isn't visible until the button is clicked, it is still loaded as part of the initial bundle.
+
+Use a new feature of Angular 17 to lazy load the `TopComponent` so that it is visible _and loaded_ when the user clicks the button to display it.
+
+When you are done, you should be able to see the `TopComponent` being loaded into the browser in a separate bundle when you click the button to display it. In Chrome, you should see this by opening the DevTools, going to the Network tab, and then clicking the button to display the `TopComponent`.
+
+## Hints
+
+
+ Hint 1
+
+You should be able to remove the `topLoaded` signal when you are done.
+
+
+
+
+ Hint 2
+
+The new Angular feature will hide the `TopComponent` from view, but it will still be loaded in the initial bundle unless you change how both `AppComponent` and `TopComponent` are defined in their decorators. This challenge start with the old `NgModule`-based architecture, but you will need to change it to use the new feature.
+
+
+
+
+ Hint 3
+
+The new feature is [Deferrable Views](https://angular.dev/guide/defer), which provides several different triggers. One of them is ideal for this challenge.
+
+
diff --git a/docs/src/content/docs/challenges/angular/55-back-button-navigation.md b/docs/src/content/docs/challenges/angular/55-back-button-navigation.md
new file mode 100644
index 000000000..3a2255f49
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/55-back-button-navigation.md
@@ -0,0 +1,56 @@
+---
+title: 🟠 Back-Button-Navigation
+description: Challenge 55 is about overriding browser back button navigation
+author: Ioannis-Tsironis
+contributors:
+ - tsironis13
+challengeNumber: 55
+command: angular-back-button-navigation
+sidebar:
+ order: 123
+---
+
+## Information
+
+The goal of this challenge is to override the default behavior of the browser back button in Angular applications.
+
+We have been prompted by the team's PO to provide a specific implementation when displaying dialog components and
+native browser back button is clicked. Currently, Angular's default behavior when the native back button is clicked is
+to remove the current history entry and go back to the previous route.
+
+The initial state of the application is as follows:
+When any dialog is displayed and the back button is clicked, any opened dialog is closed, and the app redirects to the previous page.
+
+This behavior should be changed according to these requirements:
+
+1. The requirements dictate a few different behaviors depending on which type of dialog is currently visible.
+2. For example, we have a simple
+ action dialog that should be closed on the back button click, but we **MUST** remain on the current visited route (/simple-action).
+3. In addition, we have sensitive dialogs like the one on the '/sensitive-action' page that must open a confirmation dialog on a back button click.
+4. The confirmation dialog in combination with the back button click should behave like the simple dialog action one; the confirmation dialog must be closed, and we must remain on the '/sensitive-action' page with the initial dialog still visible.
+
+## Statement
+
+Provide an abstract, generic approach to handling any type of dialog behavior when the native browser back button is clicked.
+Some Typescript design patterns, in combination with the Angular features, could be utilized to support this kind of infrastructure.
+
+## Constraints
+
+- The implementation must not be static depending on the 2 dialog type behaviors presenting on this challenge but also scalable to support any
+ new behavior requirements may arise in the future.
+
+### Hint
+
+
+ Hint 1
+
+Use the `CanDeactivate` functional guard
+
+
+
+
+ Hint 2
+
+Material Design dialog documentation can be found [here](https://material.angular.io/components/dialog/overview)
+
+
diff --git a/docs/src/content/docs/challenges/angular/57-content-projection-default.md b/docs/src/content/docs/challenges/angular/57-content-projection-default.md
new file mode 100644
index 000000000..68bc9454a
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/57-content-projection-default.md
@@ -0,0 +1,36 @@
+---
+title: 🟢 Content Projection Default
+description: Challenge 57 is about content projection default container
+author: thomas-laforge
+contributors:
+ - tomalaforge
+challengeNumber: 57
+command: angular-content-projection-default
+sidebar:
+ order: 22
+---
+
+## Information
+
+Content projection in Angular allows developers to create flexible and customizable components by passing content from the parent component to the child component dynamically using ``.
+
+Currently, we have a shared component that relies on `input` properties to receive and display data. However, we want to improve its flexibility by replacing all `inputs` with content projection while maintaining the same appearance and behavior.
+
+## Statement
+
+Your task is to refactor the existing shared component to remove all `input` properties and instead use Angular’s `` for content projection. After your modifications, the application should look and function exactly as before, but without any `input`.
+
+### Steps to complete:
+
+- Identify all `input` properties in the shared component.
+- Remove them and replace them with appropriate `` containers.
+- Adjust the parent component to pass the necessary content using content projection instead of binding to `input`s.
+- Ensure that the application still displays the same UI and behavior after the changes.
+
+## Constraints
+
+- You must not use any `input` in the shared component.
+- The application’s UI and functionality must remain unchanged after the refactoring.
+- You must use `` for content projection.
+- Do not introduce additional properties or services to pass data.
+- Ensure that projected content is correctly styled and positioned as before.
diff --git a/docs/src/content/docs/challenges/angular/58-content-projection-condition.md b/docs/src/content/docs/challenges/angular/58-content-projection-condition.md
new file mode 100644
index 000000000..7dead94de
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/58-content-projection-condition.md
@@ -0,0 +1,38 @@
+---
+title: 🟠 Content Projection Condition
+description: Challenge 58 is about conditional content projection in Angular
+author: thomas-laforge
+contributors:
+ - tomalaforge
+challengeNumber: 58
+command: angular-content-projection-condition
+sidebar:
+ order: 124
+---
+
+## Information
+
+Content projection in Angular allows you to create flexible and reusable components by dynamically inserting content from a parent component using ``. However, debugging content projection issues can sometimes be tricky.
+
+In this challenge, we have a `CardComponent` that supports a small mode, which conditionally changes how the projected content is displayed. However, there is a bug: when `small` is `false`, the card does not render properly.
+
+Your task is to identify and fix this issue without adding `inputs` while ensuring that the intended behavior remains unchanged.
+
+## Statement
+
+Your goal is to fix the issue where the `CardComponent` does not render when `small` is `false`.
+
+## Steps to complete:
+
+- Analyze how the `small` property is used inside the template.
+- Identify why the content is not displayed when `small` is `false`.
+- Modify the component to ensure that both cases (`small` = `true` and `small` = `false`) work as expected, while keeping the same structure and behavior.
+- Ensure that no new `input` properties are introduced in the component.
+
+## Constraints
+
+- You must not add any new `input` properties.
+- The expected UI and behavior must remain unchanged.
+- The `@if` directive must be correctly handled to ensure content projection works.
+- Do not introduce additional services or state management solutions.
+- The fix should be minimal and focused on resolving the rendering issue.
diff --git a/docs/src/content/docs/challenges/angular/59-content-projection-defer.md b/docs/src/content/docs/challenges/angular/59-content-projection-defer.md
new file mode 100644
index 000000000..0a8ab685e
--- /dev/null
+++ b/docs/src/content/docs/challenges/angular/59-content-projection-defer.md
@@ -0,0 +1,28 @@
+---
+title: 🔴 content-projection-defer
+description: Challenge 59 is about deferring fetching data
+author: thomas-laforge
+contributors:
+ - tomalaforge
+challengeNumber: 59
+command: angular-content-projection-defer
+sidebar:
+ order: 212
+ badge: New
+---
+
+# Challenge: Deferred Loading for Expandable Card Content
+
+## Information
+
+Within the application, specifically on page2, there is an expandable card component. This component consists of a permanently visible title and a content section that is hidden until the card is expanded. This content section is populated with a list of posts retrieved via a backend API call. The current implementation presents an issue: upon navigating to page2, although the card defaults to a collapsed state, the API call to load the list of posts is triggered immediately during the page load process, before the user has chosen to expand the card and view the content.
+
+## Statement
+
+The goal of this challenge is to optimize the data loading behavior for the expandable card component on `page2`. Modify the implementation so that the backend API call to fetch the list of posts is **deferred**. The data should **only** be fetched when the user explicitly interacts with the card to **expand** it. No data fetching for the post list should occur upon the initial load of `page2` while the card remains collapsed.
+
+## Constraints
+
+- The expandable card must retain its core functionality: display a title, be initially collapsed (on `page2` load), and expand/collapse upon user interaction.
+- When the card is expanded, the list of posts must be fetched from the backend and displayed within the content area.
+- The data fetching mechanism itself (e.g., the API endpoint) should not be changed, only _when_ it is triggered.
diff --git a/docs/src/content/docs/challenges/angular/8-pure-pipe.md b/docs/src/content/docs/challenges/angular/8-pure-pipe.md
index e02288827..c981cda55 100644
--- a/docs/src/content/docs/challenges/angular/8-pure-pipe.md
+++ b/docs/src/content/docs/challenges/angular/8-pure-pipe.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- kabrunko-dev
- svenson95
+ - LMFinney
challengeNumber: 8
command: angular-pure-pipe
blogLink: https://medium.com/ngconf/deep-dive-into-angular-pipes-c040588cd15d
@@ -16,13 +17,13 @@ sidebar:
## Information
-This is the first of three `@Pipe()` challenges, the goal of this series is to master **pipes** in Angular.
+This is the first of three `@Pipe()` challenges. The goal of this series is to master **pipes** in Angular.
-Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So they won't be recalculated every change detection cycle if their inputs haven't changed.
+Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So, they won't be recalculated every change detection cycle if their inputs haven't changed.
-Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improving rendering performance.
+Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improve rendering performance.
-By default a pipe is pure, you should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
+By default, a pipe is pure. You should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
:::note
A **pure** pipe is only called when the value changes.\
diff --git a/docs/src/content/docs/challenges/angular/9-wrap-function-pipe.md b/docs/src/content/docs/challenges/angular/9-wrap-function-pipe.md
index a9c2545cc..5213fb079 100644
--- a/docs/src/content/docs/challenges/angular/9-wrap-function-pipe.md
+++ b/docs/src/content/docs/challenges/angular/9-wrap-function-pipe.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- kabrunko-dev
- svenson95
+ - LMFinney
challengeNumber: 9
command: angular-wrap-function-pipe
blogLink: https://medium.com/ngconf/boost-your-apps-performance-by-wrapping-your-functions-inside-a-pipe-7e889a901d1d
@@ -16,26 +17,26 @@ sidebar:
## Information
-This is the second of three `@Pipe()` challenges, the goal of this series is to master **pipes** in Angular.
+This is the second of three `@Pipe()` challenges. The goal of this series is to master **pipes** in Angular.
-Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So they won't be recalculated every change detection cycle if their inputs haven't changed.
+Pipes are a very powerful way to transform data in your template. The difference between calling a function and a pipe is that pure pipes are memoized. So, they won't be recalculated every change detection cycle if their inputs haven't changed.
-Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improving rendering performance.
+Pipes are designed to be efficient and optimized for performance. They use change detection mechanisms to only recalculate the value if the input changes, to minimize unnecessary calculations and improve rendering performance.
-By default a pipe is pure, you should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
+By default, a pipe is pure. You should be aware that setting `pure` to false is prone to be inefficient, because it increases the amount of rerenders.
:::note
A **pure** pipe is only called when the value changes.\
A **impure** pipe is called every change detection cycle.
:::
-There are some useful predefined pipes like the DatePipe, UpperCasePipe and CurrencyPipe. To learn more about pipes in Angular, check the API documentation [here]https://angular.dev/guide/pipes).
+There are some useful predefined pipes like the DatePipe, UpperCasePipe and CurrencyPipe. To learn more about pipes in Angular, check the API documentation [here](https://angular.dev/guide/pipes).
## Statement
-In this exercise, you are calling multiple functions inside your template. You can create a specific pipe for each of the functions but this will be too cumbersome.
+In this exercise, you are calling multiple functions inside your template. You can create a specific pipe for each of the functions, but this will be too cumbersome.
The goal is to create a `wrapFn` pipe to wrap your callback function through a pipe. Your function MUST remain inside your component. **`WrapFn` must be highly reusable.**
-## Constraints:
+## Constraints
- Must be strongly typed
diff --git a/docs/src/content/docs/challenges/forms/48-avoid-losing-form-data.md b/docs/src/content/docs/challenges/forms/48-avoid-losing-form-data.md
index 37676b642..1af6c52c4 100644
--- a/docs/src/content/docs/challenges/forms/48-avoid-losing-form-data.md
+++ b/docs/src/content/docs/challenges/forms/48-avoid-losing-form-data.md
@@ -5,6 +5,7 @@ author: timothy-alcaide
contributors:
- alcaidio
- svenson95
+ - LMFinney
challengeNumber: 48
command: forms-avoid-losing-form-data
sidebar:
@@ -26,7 +27,6 @@ Here's the feature expressed as a user story with a functional expectation:
## Acceptance Criteria
1. If one of the form fields is not empty and the user tries to navigate to a different route or page, or wants to reload the page, show an alert dialog to _avoid losing form data_.
-
2. The content of `dialog.component.ts` must be used for your alert.
3. The appearance and behavior of the alert dialog box must comply with W3C conventions, see [alert dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/).
4. Maximize the use of the new concepts and syntax in the latest version of Angular.
diff --git a/docs/src/content/docs/challenges/ngrx/2-effect-selector.md b/docs/src/content/docs/challenges/ngrx/2-effect-selector.md
deleted file mode 100644
index d473409cd..000000000
--- a/docs/src/content/docs/challenges/ngrx/2-effect-selector.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: 🟠 Effect vs Selector
-description: Challenge 2 is about learning the difference between effects and selectors in NgRx
-author: thomas-laforge
-contributors:
- - tomalaforge
- - tomer953
- - svenson95
- - jdegand
-challengeNumber: 2
-command: ngrx-effect-vs-selector
-blogLink: https://medium.com/@thomas.laforge/ngrx-effect-vs-reducer-vs-selector-58337ab59043
-sidebar:
- order: 113
----
-
-For this exercise, you will have a dashboard of activities displaying the name, the main teacher and a list of subtitutes.
-
-## Information
-
-In NgRx, **selectors** is a very powerful tool often **misused**. You should use them as soon as you need to transform an already existing data in the store.
-
-- You shouldn't store **derived state**. This is error prone because when your data changes, you will have to change it at multiple places => you should have only one place of truth with that data, and every transformation should be done in a **selector**.
-
-- Inside a component, you shouldn't transform a selector (using map operator), or you shouldn't have to call a selector from a function in your view. The useful data for a component should be done in a **selector**.
-
-## Statement
-
-You will have to Refactor this working example of a dashboard of activities.
-
-## Contraints:
-
-- Only **one action** should be dispatched from a component
-- Status effect is useless. Using **combineLatest** should be a red flag. And Effect are made for side effect, not transforming data. That's a selector role
-- Status state might not be useful, it's only a **derived state** of existing state.
diff --git a/docs/src/content/docs/challenges/ngrx/7-power-effect.md b/docs/src/content/docs/challenges/ngrx/7-power-effect.md
deleted file mode 100644
index 305ba50ac..000000000
--- a/docs/src/content/docs/challenges/ngrx/7-power-effect.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: 🔴 Power of Effect
-description: Challenge 7 is about creating an Ngrx effect with another Rxjs Hot observable
-author: thomas-laforge
-contributors:
- - tomalaforge
- - tomer953
- - jdegand
-challengeNumber: 7
-command: ngrx-power-of-effect
-sidebar:
- order: 206
----
-
-## Information
-
-This application exhibits local and global state confusion. Right now, a notification service is used to update the component lists of students and teachers. You need to add schools to this service, but you _cannot_. The school component uses its _own_ local state inside a `ComponentStore`. Thus, you are unable to dispatch an action in the notification service that the school component can respond to (remember, component stores do not have `actions`). So, how can we get around these issues?
-
-Injection tokens and NgRx effects can greatly help.
-
-`NgRx Effects` is a very powerful library developed by the NgRx team. Effects subscribe to a HOT Observable and listen for all events dispatched inside an application. `NgRx Effects` can subscribe to _any_ observable, which means we can wrap a hot observable inside an effect and add logic to it. You don't have to worry about the local or global state. Although you should be mindful of bad practices, when you refactor this application, you should make a determination of what should be a part of the local state and what should be a part of the global state.
-
-In this exercise, we will need to find a way to create a very powerful, scalable, and maintainable push message listener.
-
-### Step 1
-
-Create an injection token to `inject` the push service inside each component. Injection tokens are very powerful. If you are unfamiliar with them, you may want to complete the [Injection token challenge](https://angular-challenges.vercel.app/challenges/angular/39-injection-token) first. This [article](https://netbasal.com/the-hidden-power-of-injectiontoken-factory-functions-in-angular-d42d5575859b) is also a great resource.
-
-_Eliminate_ the notification service. It is not extensible. Testing (not required for this challenge) the notification service would also be overly complicated. You would need to test each branching scenario. Injection tokens can easily be mocked.
-
-Since the notification service is global, all component lists update whether or not, a user is on that route. We need to decouple that logic. The notification messages should display only on their respective routes.
-
-### Step 2
-
-Create one ngrx effect, or component store effect for each push type, and implement your logic.
-
-### Step 3
-
-Show an [Angular Material snackbar](https://material.angular.io/components/snack-bar/overview) notification when an add event happens. Make each notification distinct.
-
-### Step 4
-
-Load your effect only when necessary.
-
-The application contains a root route, a lazy loaded route, and a component with a local state (implemented with `ComponentStore`).
diff --git a/docs/src/content/docs/challenges/nx/25-generator-lib-ext.md b/docs/src/content/docs/challenges/nx/25-generator-lib-ext.md
index a47765827..891be9b16 100644
--- a/docs/src/content/docs/challenges/nx/25-generator-lib-ext.md
+++ b/docs/src/content/docs/challenges/nx/25-generator-lib-ext.md
@@ -4,6 +4,7 @@ description: Challenge 25 is about creating a Nx generator to extend the built-i
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 25
sidebar:
order: 207
@@ -21,9 +22,9 @@ The goal of this challenge is to create a generator that extends the default lib
You can either use all the default parameters of the Nx library generator or choose to modify some and keep others as defaults. The choice is yours.
-## Constraints:
+## Constraints
-You should only override the jest configuration is the `unitTestRunner` option is set at `JEST`, and you should only update the eslint configuration if the `linter` is set to `eslint`.
+You should only override the jest configuration is the `unitTestRunner` option is set at `jest`, and you should only update the eslint configuration if the `linter` is set to `eslint`.
---
@@ -52,4 +53,4 @@ export default {
`eslintrc.json`
-add this rule `"@typescript-eslint/member-ordering": "off"` inside the rules properties of ts files.
+Add the rule `"@typescript-eslint/member-ordering": "off"` inside the rules properties of ts files.
diff --git a/docs/src/content/docs/challenges/nx/26-generator-comp.md b/docs/src/content/docs/challenges/nx/26-generator-comp.md
index c07f0c775..308296418 100644
--- a/docs/src/content/docs/challenges/nx/26-generator-comp.md
+++ b/docs/src/content/docs/challenges/nx/26-generator-comp.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- Sagardevkota
+ - LMFinney
challengeNumber: 26
sidebar:
order: 116
@@ -21,7 +22,7 @@ Generators are awesome tools that can help you and your team generate code more
The goal of this challenge is to create a generator that will create all the boilerplate of a component for you.
-Just below, you will have the end result of your generator for a `UserComponent` associated with a `@ngrx/component-store`.
+Below are the end result of your generator for a `UserComponent` associated with a `@ngrx/component-store`.
## Options
@@ -55,11 +56,12 @@ export class UserComponent {
---
-`user.store.json`
+`user.store.ts`
```ts
import { Injectable, inject } from '@angular/core';
-import { ComponentStore, OnStateInit, OnStoreInit, tapResponse } from '@ngrx/component-store';
+import { ComponentStore, OnStateInit, OnStoreInit } from '@ngrx/component-store';
+import { tapResponse } from '@ngrx/operators';
import { mergeMap, pipe, tap } from 'rxjs';
import { User } from './user.model';
import { UserService } from './user.service';
diff --git a/docs/src/content/docs/challenges/performance/12-optimize-change-detection.md b/docs/src/content/docs/challenges/performance/12-optimize-change-detection.md
index 71276beb1..5fa698a43 100644
--- a/docs/src/content/docs/challenges/performance/12-optimize-change-detection.md
+++ b/docs/src/content/docs/challenges/performance/12-optimize-change-detection.md
@@ -4,6 +4,7 @@ description: Challenge 12 about optimizing the number of change detection cycle
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 12
command: performance-optimize-change-detection
sidebar:
@@ -37,4 +38,4 @@ Your goal for this challenge is to avoid all unnecessary change detection cycles
## Constraint:
-You cannot opt-out of Zone.js globally. If this code is part of a large project and you opt out of Zone.js, you will break your application without any doubt.
+You cannot opt out of Zone.js globally. If this code is part of a large project, and you opt out of Zone.js, you will break your application without any doubt.
diff --git a/docs/src/content/docs/challenges/performance/35-memoization.md b/docs/src/content/docs/challenges/performance/35-memoization.md
index 5acff6023..52f61389b 100644
--- a/docs/src/content/docs/challenges/performance/35-memoization.md
+++ b/docs/src/content/docs/challenges/performance/35-memoization.md
@@ -4,6 +4,7 @@ description: Challenge 35 is about learning how pure pipe works
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 35
command: performance-memoization
sidebar:
@@ -45,6 +46,6 @@ The goal of this challenge is to understand what is causing this latency and to
Hint 1
-Use `Pipes` to memoize the Fibonnaci computation.
+Use `Pipes` to memoize the Fibonacci computation.
diff --git a/docs/src/content/docs/challenges/performance/36-ngfor-optimization.md b/docs/src/content/docs/challenges/performance/36-ngfor-optimization.md
index 2749a9543..336f525fa 100644
--- a/docs/src/content/docs/challenges/performance/36-ngfor-optimization.md
+++ b/docs/src/content/docs/challenges/performance/36-ngfor-optimization.md
@@ -4,6 +4,7 @@ description: Challenge 36 is about learning how trackby works
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 36
command: performance-ngfor-optimization
sidebar:
@@ -12,7 +13,7 @@ sidebar:
## Information
-In this application, we have a list of individuals that we can add, delete or update. If you open the developer Chrome panel by pressing **F12**, go to he source tab, and expand the element to see the list, you will notice that each time, you add, delete or update a list item, the entire DOM elements are destroyed and initialized again. (See video below).
+In this application, we have a list of individuals that we can add, delete or update. If you open the developer Chrome panel by pressing **F12**, go to the Elements tab, and expand the element to see the list, you will notice that each time you add, delete or update a list item, all the DOM elements are destroyed and initialized again. (See video below).
diff --git a/docs/src/content/docs/challenges/performance/37-optimize-big-list.md b/docs/src/content/docs/challenges/performance/37-optimize-big-list.md
index 5cda87bd0..daeb5aec9 100644
--- a/docs/src/content/docs/challenges/performance/37-optimize-big-list.md
+++ b/docs/src/content/docs/challenges/performance/37-optimize-big-list.md
@@ -5,6 +5,7 @@ author: thomas-laforge
contributors:
- tomalaforge
- jdegand
+ - LMFinney
challengeNumber: 37
command: performance-optimize-big-list
sidebar:
@@ -13,7 +14,7 @@ sidebar:
## Information
-In this application, we will render a list of 100,000 individuals by clicking on the **loadList** button. If you open the Chrome developer panel by pressing **F12**, go to the Source tab, and expand the element to see the list, you will notice that all 100,000 elements are rendered in the DOM, even though we can only see about 20 elements in the viewport. This process takes a lot of time, which is why the application is very slow at displaying the list.
+In this application, we will render a list of 100,000 individuals by clicking on the **loadList** button. If you open the Chrome developer panel by pressing **F12**, go to the Elements tab, and expand the element to see the list, you will notice that all 100,000 elements are rendered in the DOM, even though we can only see about 20 elements in the viewport. This process takes a lot of time, which is why the application is very slow at displaying the list.
We can use the Angular DevTool to profile our application and understand what is happening inside our application. I will show you how to do it inside the following video.
diff --git a/docs/src/content/docs/challenges/performance/index.mdx b/docs/src/content/docs/challenges/performance/index.mdx
index 729273794..5a7bb0abe 100644
--- a/docs/src/content/docs/challenges/performance/index.mdx
+++ b/docs/src/content/docs/challenges/performance/index.mdx
@@ -5,6 +5,7 @@ next: false
contributors:
- tomalaforge
- tomer953
+ - LMFinney
description: Learn how to use the Angular Devtool chrome extension.
noCommentSection: true
sidebar:
@@ -15,7 +16,7 @@ import { LinkCard } from '@astrojs/starlight/components';
In this series of challenges about performance, you will learn how to optimize and enhance the performance of your Angular application.
-Before starting to resolve any challenge, I invite you to download the [Angular DevTools Chrome extention](https://chrome.google.com/webstore/detail/angular-devtools/ienfalfjdbdpebioblfackkekamfmbnh) if you haven't already done so.
+Before starting to resolve any challenge, I invite you to download the [Angular DevTools Chrome extension](https://chrome.google.com/webstore/detail/angular-devtools/ienfalfjdbdpebioblfackkekamfmbnh) if you haven't already done so.
This extension allows you to profile your application and detect performance issues, which is very useful for understanding where performance issues can occur.
@@ -45,8 +46,26 @@ Now that you know how to use the Angular DevTool, you can choose a challe
href="http://github.com/challenges/performance/35-memoization/"
/>
+
+
+
+
+
+
diff --git a/docs/src/content/docs/challenges/rxjs/11-high-order-operator-bug.md b/docs/src/content/docs/challenges/rxjs/11-high-order-operator-bug.md
index 5523896b0..dbc0b53d0 100644
--- a/docs/src/content/docs/challenges/rxjs/11-high-order-operator-bug.md
+++ b/docs/src/content/docs/challenges/rxjs/11-high-order-operator-bug.md
@@ -4,13 +4,14 @@ description: Challenge 11 is about resolving a Rxjs bug because of high order op
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 11
command: rxjs-high-order-operator-bug
sidebar:
order: 114
---
-Let's dive inside the wonderful word of RxJs.
+Let's dive inside the wonderful word of RxJS.
This challenge is inspired by a real-life example.
@@ -18,9 +19,9 @@ This challenge is inspired by a real-life example.
### User Story
-We need a button for each `Topic`. When we click on it, we delete all objects with this `Topic` in our database _(Fake DB in our case)_. Finally we display **All [topic] have been deleted** is everything was deleted successfully or **Error: deletion of some [topic] failed** if some deletions failed
+We need a button for each `Topic`. When we click on it, we delete all objects with this `Topic` in our database _(Fake DB in our case)_. Finally, we display **All [topic] have been deleted** if everything was deleted successfully or **Error: deletion of some [topic] failed** if some deletions failed
-### Constraints:
+### Constraints
We can only pass one object to our DB for deletion at the time. The DB will respond true if the data was successfully deleted and false otherwise.
diff --git a/docs/src/content/docs/challenges/rxjs/14-race-condition.md b/docs/src/content/docs/challenges/rxjs/14-race-condition.md
index c6d37cb51..b4fbb8d95 100644
--- a/docs/src/content/docs/challenges/rxjs/14-race-condition.md
+++ b/docs/src/content/docs/challenges/rxjs/14-race-condition.md
@@ -4,6 +4,7 @@ description: Challenge 14 is about race condition in Rxjs
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 14
command: rxjs-race-condition
sidebar:
@@ -18,12 +19,12 @@ The goal of this application is to display a list of topics in a modal when a bu
Correct your application to pass the test
-## Constraints:
+## Constraints
-- I can see you coming 🤣 => You CANNOT change the test (Test is working fine) 😳
+- I can see you coming 🤣 => You CANNOT change the test (the test is working fine) 😳
- You CANNOT change the `fakeGetHttpTopic` method. A delay has been added to fake a slow network.
## Run the test
-HEADLESS : `npx nx component-test rxjs-race-condition`
-WATCH MODE : `npx nx component-test rxjs-race-condition --watch`
+HEADLESS : `npx nx test rxjs-race-condition`
+WATCH MODE : `npx nx test rxjs-race-condition --watch`
diff --git a/docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md b/docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md
index cab6cb0cb..5680d1544 100644
--- a/docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md
+++ b/docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md
@@ -1,11 +1,12 @@
---
title: 🟢 catchError
-description: Challenge 38 is about learning obervable completion.
+description: Challenge 38 is about learning observable completion.
author: devesh-chaudhari
command: rxjs-catch-error
contributors:
- DeveshChau
- tomalaforge
+ - LMFinney
challengeNumber: 38
sidebar:
order: 14
diff --git a/docs/src/content/docs/challenges/rxjs/49-hold-to-save-button.md b/docs/src/content/docs/challenges/rxjs/49-hold-to-save-button.md
index 3081a4d12..050ccc48a 100644
--- a/docs/src/content/docs/challenges/rxjs/49-hold-to-save-button.md
+++ b/docs/src/content/docs/challenges/rxjs/49-hold-to-save-button.md
@@ -4,6 +4,7 @@ description: You're tasked with implementing Lucie's button design, requiring ho
author: timothy-alcaide
contributors:
- alcaidio
+ - LMFinney
challengeNumber: 49
command: rxjs-hold-to-save-button
sidebar:
@@ -22,7 +23,7 @@ So you're going to take over from him.
> "As a user, I would like to save something by holding down the button for a certain amount of time."
-Here the prototype made by Lucie:
+Here is the prototype made by Lucie:

diff --git a/docs/src/content/docs/challenges/signal/50-bug-effect-signal.md b/docs/src/content/docs/challenges/signal/50-bug-effect-signal.md
index 3715b2c15..46f07c6bd 100644
--- a/docs/src/content/docs/challenges/signal/50-bug-effect-signal.md
+++ b/docs/src/content/docs/challenges/signal/50-bug-effect-signal.md
@@ -5,6 +5,7 @@ author: thomas-laforge
contributors:
- tomalaforge
- svenson95
+ - LMFinney
challengeNumber: 50
command: signal-bug-in-effect
sidebar:
@@ -19,9 +20,9 @@ In this basic exercise, we aim to display an alert whenever at least one checkbo
## Statement
-The actual implementation doesn't work as expected, your task is to fix the issue. Your team exposed a bug, there is a alert to be shown if atleast one of the three checkboxes is checked. But if the first one is checked, the other two checkboxes gets checked without displaying the alert. Why does this happen?
+The actual implementation doesn't work as expected, and your task is to fix a bug that your team discovered. An alert should be shown if at least one of the three checkboxes is checked (independent of any other checkboxes). But if the first one is checked, checking one or both of the other two checkboxes does not cause the alert to display. Why does this happen?
-The objective of this challenge is to understand the issue and fix the problem, preventing the alert from appearing when the second checkbox is clicked.
+The objective of this challenge is to understand the issue and fix the problem that prevents the alert from appearing when the second checkbox is clicked.
## Acceptance Criteria
diff --git a/docs/src/content/docs/challenges/signal/51-function-call-effect.md b/docs/src/content/docs/challenges/signal/51-function-call-effect.md
index 91d02bd23..e2a94694c 100644
--- a/docs/src/content/docs/challenges/signal/51-function-call-effect.md
+++ b/docs/src/content/docs/challenges/signal/51-function-call-effect.md
@@ -8,7 +8,6 @@ challengeNumber: 51
command: signal-function-call-effect
sidebar:
order: 20
- badge: New
---
## Information
@@ -20,3 +19,7 @@ In this second challenge focusing on Signal effects, we've introduced an input s
Ideally, the system should log an action only when one is specifically selected. However, we currently face an issue where changing the user also triggers a log entry, even though we do not explicitly monitor user changes.
The objective of this challenge is to identify and resolve the cause of these extra triggers. We aim to ensure that logging only occurs when an action is selected.
+
+## Constraints
+
+- You cannot modify the `UserService` file.
diff --git a/docs/src/content/docs/challenges/signal/53-big-signal-performance.md b/docs/src/content/docs/challenges/signal/53-big-signal-performance.md
new file mode 100644
index 000000000..d3b4ea4a2
--- /dev/null
+++ b/docs/src/content/docs/challenges/signal/53-big-signal-performance.md
@@ -0,0 +1,24 @@
+---
+title: 🟠 Big Signal Performance
+description: Challenge 53 is about performance while using big signal object
+author: thomas-laforge
+contributors:
+ - tomalaforge
+ - jdegand
+challengeNumber: 53
+command: signal-big-signal-performance
+sidebar:
+ order: 122
+---
+
+## Information
+
+For this challenge, you can imagine a large-scale application where you use a service to save and retrieve your user state at any time within the application.
+
+The problem is that updating a single user property updates the entire application.
+
+I added the `CDFlashingDirective` to visualize when one component is rendering.
+
+## Statement
+
+With signals, you can now be more fine-grained in what the UI is rendering. The goal of this challenge is to understand why everything is re-rendering and to refactor the application to be more performant.
diff --git a/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md b/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md
new file mode 100644
index 000000000..2b88b528f
--- /dev/null
+++ b/docs/src/content/docs/challenges/signal/54-pipe-observable-to-signal.md
@@ -0,0 +1,22 @@
+---
+title: 🔴 Pipe Observable to Signal
+description: Challenge 54 is about refactoring an application using observable to signals
+author: thomas-laforge
+contributors:
+ - tomalaforge
+ - LMFinney
+challengeNumber: 54
+command: signal-pipe-observable-to-signal
+sidebar:
+ order: 210
+---
+
+## Information
+
+We have a legacy application that is using observables to store a state. Signals are a very good fit for that.
+
+## Statement
+
+So, the goal of this challenge is to refactor the following application to be a fully signal-based application. When you are done, neither the pipe nor the service should import RxJS.
+
+Be careful along the way; everything might not work as you wish.
diff --git a/docs/src/content/docs/challenges/signal/56-forms-and-signal.md b/docs/src/content/docs/challenges/signal/56-forms-and-signal.md
new file mode 100644
index 000000000..077fd822f
--- /dev/null
+++ b/docs/src/content/docs/challenges/signal/56-forms-and-signal.md
@@ -0,0 +1,27 @@
+---
+title: 🔴 forms and signal
+description: Challenge 56 is about working with reactive forms and signals
+author: thomas-laforge
+contributors:
+ - tomalaforge
+challengeNumber: 56
+command: signal-forms-and-signal
+sidebar:
+ order: 211
+---
+
+## Information
+
+We are working within a large e-commerce codebase that utilizes a substantial number of forms. The team predominantly uses reactive forms, and since the release of signals, we have been integrating them extensively.
+
+The current feature in development is a multi-step form process. The steps include: selecting a product, choosing the quantity, and finally proceeding to the checkout step to complete the billing details. However, an issue has been identified: when a user navigates back from the checkout step to the quantity step, the previously selected quantity is not retained. This needs to be fixed.
+
+## Challenge Statement
+
+The objective of this challenge is to make sure that the selected quantity is preserved when navigating back from the checkout step to the quantity step.
+
+## Constraints
+
+The solution must use reactive forms and signals.
+
+Additionally, as an optional side challenge, you may refactor the code to use template-driven forms.
diff --git a/docs/src/content/docs/challenges/testing/17-router.md b/docs/src/content/docs/challenges/testing/17-router.md
index 77355ce30..2af0c8d77 100644
--- a/docs/src/content/docs/challenges/testing/17-router.md
+++ b/docs/src/content/docs/challenges/testing/17-router.md
@@ -4,6 +4,7 @@ description: Challenge 17 is about testing the router
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 17
command: testing-router
sidebar:
@@ -14,13 +15,13 @@ sidebar:
We have a functional application that lists available books for borrowing inside a library. If the book you searched for is available, you will be directed to the corresponding book(s), otherwise, you will end up on an error page.
-The file named `app.component.spec.ts` will let you test your application using Testing Library. To run the test suits, you need to run `npx nx test testing-router-outlet`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
+The file named `app.component.spec.ts` will let you test your application using [Angular Testing Library](https://testing-library.com/) . To run the test suites, you need to run `npx nx test testing-router-outlet`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
-For testing cypress, you will execute your test inside the `app.component.cy.ts` and run `npx nx component-test testing-router-outlet` to execute your test suits. You can add the `--watch` flag to execute your test in watch mode.
+For testing with Cypress, you will execute your test inside the `app.component.cy.ts` and run `npx nx component-test testing-router-outlet` to execute your test suites. You can add the `--watch` flag to execute your test in watch mode.
# Statement
-The goal is to test multiple behaviors of the application described in each test file using Testing library and Cypress Component Testing.
+The goal is to test multiple behaviors of the application described in each test file using [Angular Testing Library](https://testing-library.com/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/overview).
:::note
I have created some `it` blocks but feel free to add more tests if you want.
diff --git a/docs/src/content/docs/challenges/testing/18-nested-components.md b/docs/src/content/docs/challenges/testing/18-nested-components.md
index 97f6110c6..d7ba391c2 100644
--- a/docs/src/content/docs/challenges/testing/18-nested-components.md
+++ b/docs/src/content/docs/challenges/testing/18-nested-components.md
@@ -4,6 +4,7 @@ description: Challenge 18 is about testing nested components
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 18
command: testing-nested-components
sidebar:
@@ -12,19 +13,19 @@ sidebar:
## Information
-We have a small application that sends a title, typed into an input to a fake backend.
-If the title is correctly typed, you can send the request otherwise you receive an error and the request is not sent.
-The application is created with nested components. `ChildComponent` is the container that includes four components: `ResultComponent`, `ButtonComponent`, `InputComponent` and `ErrorComponent`. However since we are testing our component as a black box, the architecture of our components doesn't change anything. You can create your test, change how the components are structured, and your tests should still pass. That's the goal of integration tests. Never test internal implementation details!!!.
+We have a small application that sends a title to a fake backend when the user types the value into an input.
+If the title is correctly typed, you can send the request; otherwise you receive an error, and the request is not sent.
+The application is created with nested components. `ChildComponent` is the container that includes four components: `ResultComponent`, `ButtonComponent`, `InputComponent` and `ErrorComponent`. However, since we are testing our component as a black box, the architecture of our components doesn't change anything. You can create your test, change how the components are structured, and your tests should still pass. That's the goal of integration tests. Never test internal implementation details!!!.
You can play with it by running : `npx nx serve testing-nested`.
-The file named `child.component.spec.ts` will let test your application using Testing Library. To run the test suits, you need to run `npx nx test testing-nested`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
+The file named `child.component.spec.ts` will let you test your application using [Angular Testing Library](https://testing-library.com/) . To run the test suites, you need to run `npx nx test testing-nested`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
-For testing cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-nested` to execute your test suits. You can add the `--watch` flag to execute your test in watch mode.
+For testing with Cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-nested` to execute your test suites. You can add the `--watch` flag to execute your test in watch mode.
# Statement
-The goal is to test multiple behaviors of the application describe inside each test files using Testing library and Cypress Component Testing.
+The goal is to test multiple behaviors of the application describe inside each test files using [Angular Testing Library](https://testing-library.com/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/overview).
:::note
I have created some `it` blocks but feel free to add more tests if you want.
diff --git a/docs/src/content/docs/challenges/testing/19-input-output.md b/docs/src/content/docs/challenges/testing/19-input-output.md
index d8e85589e..d77db7eb0 100644
--- a/docs/src/content/docs/challenges/testing/19-input-output.md
+++ b/docs/src/content/docs/challenges/testing/19-input-output.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 19
command: testing-input-output
sidebar:
@@ -19,13 +20,13 @@ We have a small counter application that increments or decrements a number. The
You can play with it by running : `npx nx serve testing-input-output`.
-The file named `counter.component.spec.ts` will let test your application using Testing Library. To run the test suits, you need to run `npx nx test testing-input-output`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
+The file named `counter.component.spec.ts` will let you test your application using [Angular Testing Library](https://testing-library.com/) . To run the test suites, you need to run `npx nx test testing-input-output`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
-For testing cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-input-output` to execute your test suits. You can add the `--watch` flag to execute your test in watch mode.
+For testing with Cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-input-output` to execute your test suites. You can add the `--watch` flag to execute your test in watch mode.
# Statement
-The goal is to test multiple behaviors of the application described inside each test file using Testing library and Cypress Component Testing.
+The goal is to test multiple behaviors of the application described inside each test file using [Angular Testing Library](https://testing-library.com/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/overview).
:::note
I have created some `it` blocks but feel free to add more tests if you want.
diff --git a/docs/src/content/docs/challenges/testing/20-modal.md b/docs/src/content/docs/challenges/testing/20-modal.md
index 1d5df28d5..8a1d34c8b 100644
--- a/docs/src/content/docs/challenges/testing/20-modal.md
+++ b/docs/src/content/docs/challenges/testing/20-modal.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 20
command: testing-modal
sidebar:
@@ -23,13 +24,13 @@ The goal of this challenge is to test the dialogs inside your application. To do
You can play with it by running : `npx nx serve testing-modal`.
-The file named `app.component.spec.ts` will let you test your application using Testing Library. To run the test suites, you need to run `npx nx test testing-modal`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
+The file named `app.component.spec.ts` will let you test your application using [Angular Testing Library](https://testing-library.com/) . To run the test suites, you need to run `npx nx test testing-modal`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
For testing with Cypress, you will execute your test inside `app.component.cy.ts` and run `npx nx component-test testing-modal` to execute your test suites. You can add the `--watch` flag to execute your test in watch mode.
# Statement
-The goal is to test multiple behaviors of the application described inside each test file using Testing library and Cypress Component Testing.
+The goal is to test multiple behaviors of the application described inside each test file using [Angular Testing Library](https://testing-library.com/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/overview).
:::note
I have created some `it` blocks but feel free to add more tests if you want.
diff --git a/docs/src/content/docs/challenges/testing/23-harness.md b/docs/src/content/docs/challenges/testing/23-harness.md
index 524c9e8ba..629ffdf5d 100644
--- a/docs/src/content/docs/challenges/testing/23-harness.md
+++ b/docs/src/content/docs/challenges/testing/23-harness.md
@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 23
command: testing-harness
sidebar:
@@ -26,4 +27,4 @@ Documentation for Angular Material component is [here](https://material.angular.
Test the functionality of `child.component.ts`, which consists of some inputs & checkboxes related to a `mat-slider`. Implement the prepared test suite, but feel free to include additional tests as well.
-**Note:** You are welcome to use Testing Library if you wish.
+**Note:** You are welcome to use [Angular Testing Library](https://testing-library.com/) if you wish.
diff --git a/docs/src/content/docs/challenges/testing/28-checkbox.md b/docs/src/content/docs/challenges/testing/28-checkbox.md
index d25f58da9..15b66eb73 100644
--- a/docs/src/content/docs/challenges/testing/28-checkbox.md
+++ b/docs/src/content/docs/challenges/testing/28-checkbox.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- jdegand
+ - LMFinney
challengeNumber: 28
command: testing-checkbox
sidebar:
@@ -14,9 +15,9 @@ sidebar:
## Information
-This application is very simple. It consists of a checkbox that enables or disables a button. The primary goal of this application is to become familiar with the debug API of Testing Library. Knowing how to debug your tests is a crucial tool you need to have in your toolkit.
+This application is very simple. It consists of a checkbox that enables or disables a button. The primary goal of this application is to become familiar with the debug API of [Angular Testing Library](https://testing-library.com/). Knowing how to debug your tests is a crucial tool you need to have in your toolkit.
-You can find the documentation about debugging in Testing Library [here](https://testing-library.com/docs/dom-testing-library/api-debugging#screenlogtestingplaygroundurl).
+You can find the documentation about debugging in Angular Testing Library [here](https://testing-library.com/docs/dom-testing-library/api-debugging#screenlogtestingplaygroundurl).
The main functions to remember are as follows:
diff --git a/docs/src/content/docs/challenges/testing/29-real-life-application.md b/docs/src/content/docs/challenges/testing/29-real-life-application.md
index 11b284bd3..1546bf9e7 100644
--- a/docs/src/content/docs/challenges/testing/29-real-life-application.md
+++ b/docs/src/content/docs/challenges/testing/29-real-life-application.md
@@ -6,6 +6,7 @@ contributors:
- tomalaforge
- tomer953
- svenson95
+ - LMFinney
challengeNumber: 29
command: testing-real-life-application
sidebar:
@@ -18,19 +19,19 @@ This application presents a greater challenge because it closely resembles a rea
The application is a typical todo list application. You can filter tickets, create new ones, assign each ticket, close others, and navigate to the details of each ticket.
-In this challenge, you will write tests for the `ListComponent`, which represents the global view, and the `RowComponent`, which represents a specific ticket. Additionally, you will need to write unit tests for the `TicketStoreService` using Testing Library. _This library allows you to test services effectively._
+In this challenge, you will write tests for the `ListComponent`, which represents the global view, and the `RowComponent`, which represents a specific ticket. Additionally, you will need to write unit tests for the `TicketStoreService` using [Angular Testing Library](https://testing-library.com/) . _This library allows you to test services effectively._
Handling asynchronous tasks will be particularly challenging. It's important not to introduce any explicit waits in your tests, as this would introduce unnecessary delays. Instead, it's better to look for an element that needs to appear or disappear from the DOM. In this case, the test will naturally wait for the correct period of time, as the waits are already implemented within both libraries. Take advantage of these built-in functionalities to create efficient and reliable tests.
You can play with it by running : `npx nx serve testing-todos-list`.
-To run Testing Library test suits, you need to run `npx nx test testing-todos-list`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
+To run [Angular Testing Library](https://testing-library.com/) test suites, you need to run `npx nx test testing-todos-list`. You can also install [Jest Runner](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner) to execute your test by clicking on the `Run` button above each `describe` or `it` blocks.
-For testing cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-todos-list` to execute your test suits. You can add the `--watch` flag to execute your test in watch mode.
+For testing with Cypress, you will execute your test inside the `child.component.cy.ts` and run `npx nx component-test testing-todos-list` to execute your test suites. You can add the `--watch` flag to execute your test in watch mode.
# Statement
-The goal is to test multiple behaviors of the application describe inside each test files using Testing library and Cypress Component Testing.
+The goal is to test multiple behaviors of the application describe inside each test files using [Angular Testing Library](https://testing-library.com/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/overview).
:::note
I have created some `it` blocks but feel free to add more tests if you want.
diff --git a/docs/src/content/docs/challenges/testing/index.mdx b/docs/src/content/docs/challenges/testing/index.mdx
index 97dc59017..0231ad2ed 100644
--- a/docs/src/content/docs/challenges/testing/index.mdx
+++ b/docs/src/content/docs/challenges/testing/index.mdx
@@ -4,6 +4,7 @@ prev: false
next: false
contributors:
- tomalaforge
+ - LMFinney
description: Introduction to testing challenges.
noCommentSection: true
sidebar:
@@ -16,9 +17,9 @@ Testing is a crucial step in building scalable, maintainable, and trustworthy ap
Testing should never be avoided, even in the face of short deadlines or strong pressure from the product team.
Nowadays, there are numerous awesome tools available that make it easy to test your code and provide a great developer experience.
-In this series of testing exercises, we will learn and master [Testing Library](https://testing-library.com/docs/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/angular/overview) that simplifies DOM manipulation for testing any Angular component.
+In this series of testing exercises, we will learn and master [Angular Testing Library](https://testing-library.com/docs/) and [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/angular/overview) that simplifies DOM manipulation for testing any Angular component.
-The benefits of using Testing Library or Cypress Component Testing are to test your component as a black box. You will only interact with what the user can do on the UI. However, the difference with end-to-end tests is that the backend is mocked, which makes the tests faster and more maintainable.
+The benefits of using Angular Testing Library or Cypress Component Testing are to test your component as a black box. You will only interact with what the user can do on the UI. However, the difference with end-to-end tests is that the backend is mocked, which makes the tests faster and more maintainable.
The goal is to mock as little as possible to test your component at a higher level than unit testing, which will make refactoring easier.
Within a real application, integration tests are the tests you will write the most. Learning how to write them will make your application more robust and more maintainable.
@@ -32,7 +33,7 @@ Here is a series of 8 challenges that you can take in any order.
diff --git a/docs/src/content/docs/challenges/typescript/15-function-overload.md b/docs/src/content/docs/challenges/typescript/15-function-overload.md
index 6ef44a960..44d289a77 100644
--- a/docs/src/content/docs/challenges/typescript/15-function-overload.md
+++ b/docs/src/content/docs/challenges/typescript/15-function-overload.md
@@ -4,6 +4,7 @@ description: Challenge 15 is about creating overload functions
author: thomas-laforge
contributors:
- tomalaforge
+ - LMFinney
challengeNumber: 15
command: typescript-function-overload
blogLink: https://medium.com/ngconf/function-overloading-in-typescript-8236706b2c05
@@ -16,7 +17,7 @@ sidebar:
Angular uses TypeScript, and mastering TypeScript can help you avoid runtime errors by catching them at compile time.
In this challenge, we have a function to create a vehicle. However, each vehicle type requires different mandatory properties.
-Currently, we are getting an error at runtime if one property is missing and we don't get the return Type, which is not ideal.
+Currently, we are getting an error at runtime if one property is missing, and we don't get the return Type, which is not ideal.
One solution would be to create a separate function for each vehicle type, but for this challenge, I want to use the same function and have TypeScript automatically complete the properties depending on the type passed as the first parameter.
To achieve this, we will use overload functions.
diff --git a/docs/src/content/docs/challenges/typescript/47-enums-vs-union-types.md b/docs/src/content/docs/challenges/typescript/47-enums-vs-union-types.md
index 4614caa98..6ae54a72e 100644
--- a/docs/src/content/docs/challenges/typescript/47-enums-vs-union-types.md
+++ b/docs/src/content/docs/challenges/typescript/47-enums-vs-union-types.md
@@ -5,6 +5,7 @@ author: sven-brodny
contributors:
- svenson95
- jdegand
+ - LMFinney
challengeNumber: 47
command: typescript-enums-vs-union-types
sidebar:
@@ -35,7 +36,7 @@ Enums are a concept borrowed from languages like C# and Java. TypeScript enums a
Enums have some more pitfalls as well:
- Non-const enums do not fit the concept of "a typed superset of JavaScript." They violate the concept by emitting global JavaScript objects that live in runtime with a syntax that is not compatible with JavaScript (JavaScript uses dynamic typing rather than static typing; enums are a form of static typing). Since JavaScript has no compilation step, there is little or no value in having static typing.
-- Const enums, in contrast, cannot be transpiled with Babel. But there are workarounds for this issue, e. g., using the `babel-plugin-const-enum` plugin. The TypeScript documentation about [const enums](https://www.typescriptlang.org/docs/handbook/enums.html#const-enums) says "_Do not use const enums at all_".
+- Const enums, in contrast, cannot be transpiled with Babel. But there are workarounds for this issue, e.g., using the `babel-plugin-const-enum` plugin. The TypeScript documentation about [const enums](https://www.typescriptlang.org/docs/handbook/enums.html#const-enums) says "_Do not use const enums at all_".
- To use enums, you have to import them. If you want to use enum values in a template, you'll need to declare a variable in your component too.
- Numeric enums are not type safe ...
diff --git a/docs/src/content/docs/es/challenges/angular/1-projection.md b/docs/src/content/docs/es/challenges/angular/1-projection.md
index e0e1250f0..0b9d5cc17 100644
--- a/docs/src/content/docs/es/challenges/angular/1-projection.md
+++ b/docs/src/content/docs/es/challenges/angular/1-projection.md
@@ -7,10 +7,13 @@ contributors:
challengeNumber: 1
command: angular-projection
blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
-videoLink:
- link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
- alt: Projection video by Arthur Lannelucq
- flag: FR
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
sidebar:
order: 1
---
diff --git a/docs/src/content/docs/es/challenges/angular/39-injection-token.md b/docs/src/content/docs/es/challenges/angular/39-injection-token.md
index f006ffb36..03422d342 100644
--- a/docs/src/content/docs/es/challenges/angular/39-injection-token.md
+++ b/docs/src/content/docs/es/challenges/angular/39-injection-token.md
@@ -6,6 +6,10 @@ contributors:
- nelsongutidev
challengeNumber: 39
command: angular-injection-token
+videoLinks:
+ - link: https://www.youtube.com/watch?v=ntggdQycFyc
+ alt: Injection Token by Arthur Lannelucq
+ flag: FR
sidebar:
order: 118
---
diff --git a/docs/src/content/docs/es/index.mdx b/docs/src/content/docs/es/index.mdx
index cefa56bf1..640ca9071 100644
--- a/docs/src/content/docs/es/index.mdx
+++ b/docs/src/content/docs/es/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Ir al Desafío más reciente
- link: /es/challenges/signal/51-function-call-effect
+ link: /es/challenges/angular/59-content-projection-defer/
icon: rocket
- text: Dar una estrella
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Este repositorio contiene 51 Desafíos relacionados con Angular, Nx, RxJS, Ngrx y Typescript.
+
+ Este repositorio contiene 59 Desafíos relacionados con Angular, Nx, RxJS, Ngrx y Typescript.
Estos desafíos se resuelven en torno a problemas de la vida real o características específicas para mejorar tus habilidades.
diff --git a/docs/src/content/docs/fr/challenges/angular/1-projection.md b/docs/src/content/docs/fr/challenges/angular/1-projection.md
new file mode 100644
index 000000000..509752c38
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/1-projection.md
@@ -0,0 +1,47 @@
+---
+title: 🟢 Projection
+description: Le challenge 1 consiste à apprendre à projeter des éléments DOM à travers des composants
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 1
+command: angular-projection
+blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
+sidebar:
+ order: 1
+---
+
+## Information
+
+Dans Angular, la projection de contenu est une technique puissante pour créer des composants hautement personnalisables. Utiliser et comprendre les concepts liés aux ng-content et ngTemplateOutlet peut grandement améliorer votre capacité à créer des composants réutilisables.
+
+Vous pouvez tout apprendre sur ng-content [ici](https://angular.dev/guide/components/content-projection), de la projection de contenu la plus simple jusqu'à des utilisations plus complexes.
+
+Pour en savoir plus sur ngTemplateOutlet, vous pouvez trouver la documentation de l'API [ici](https://angular.io/api/common/NgTemplateOutlet) avec quelques exemples de base.
+
+Avec ces deux outils en main, vous êtes maintenant prêt à relever le défi.
+
+## Énoncé
+
+Vous commencerez avec une application entièrement fonctionnelle qui comprend un tableau de bord contenant une carte pour les enseignants et une carte pour les élèves. L'objectif est de mettre en place la carte de la ville.
+
+Bien que l'application fonctionne, l'expérience développeur est loin d'être optimale. Chaque fois que vous devez implémenter une nouvelle carte, vous devez modifier le `card.component.ts`. Dans des projets réels, ce composant pourrait être partagé entre de nombreuses applications. Le but du défi est de créer un `CardComponent` qui peut être personnalisé sans aucune modification. Une fois que vous aurez créé ce composant, vous pourrez commencer à implémenter le `CityCardComponent` et vous assurer de ne pas toucher au `CardComponent`.
+
+## Contraintes
+
+- Vous devez refactoriser le `CardComponent` et le `ListItemComponent`.
+- La boucle `@for` doit être déclarée et rester à l'intérieur du `CardComponent`. Vous pourriez être tenté de la déplacer dans le `ParentCardComponent` comme `TeacherCardComponent`.
+- Le composant `CardComponent` ne doit contenir aucune condition.
+- CSS: essayez d'éviter d'utiliser `::ng-deep`. Trouvez un meilleur moyen de gérer le style CSS.
+
+## Challenges Bonus
+
+- Utilisez l'API des signals pour gérer l'état de vos composants (documentation [ici](https://angular.dev/guide/signals))
+- Pour référencer le template, utilisez une directive au lieu d'une magic string ([Qu'est-ce qui pose problème avec les magic string ?](https://softwareengineering.stackexchange.com/a/365344))
diff --git a/docs/src/content/docs/fr/challenges/angular/21-anchor-navigation.md b/docs/src/content/docs/fr/challenges/angular/21-anchor-navigation.md
new file mode 100644
index 000000000..e8e7ea947
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/21-anchor-navigation.md
@@ -0,0 +1,20 @@
+---
+title: 🟢 Naviguer sur une page
+description: Le challenge 21 consiste à apprendre à utiliser la navigation intégrée d'Angular
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 21
+command: angular-anchor-navigation
+sidebar:
+ order: 4
+---
+
+## Information
+
+Vous commencez avec une application qui possède une navigation de base et une navigation par ancre dans le `HomeComponent`. Cependant, l'utilisation de `href` recrée le chemin à chaque fois et rafraîchit la page.
+
+## Énoncé
+
+- Votre tâche consiste à refactoriser cette application pour utiliser la navigation intégrée afin de mieux s'intégrer dans le Framework Angular. Vous pouvez explorer le router, mais il est préférable de rester dans le template et d'utiliser la directive `RouterLink`.
+- Pour améliorer l'expérience utilisateur, ajoutez un scroll fluide.
diff --git a/docs/src/content/docs/fr/challenges/angular/22-router-input.md b/docs/src/content/docs/fr/challenges/angular/22-router-input.md
new file mode 100644
index 000000000..4bb9c8359
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/22-router-input.md
@@ -0,0 +1,28 @@
+---
+title: 🟢 @RouterInput()
+description: Challenge 22 is about using the @Input decorator to retreive router params.
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 22
+command: angular-router-input
+blogLink: https://medium.com/ngconf/accessing-route-params-in-angular-1f8e12770617
+sidebar:
+ order: 5
+---
+
+## Information
+
+Dans cette application, nous récupérons trois informations depuis le routeur dans notre `TestComponent` :
+
+- `testId` qui est situé dans les paramètres de l'URL.
+- `user` qui est situé dans les paramètres de la requête de l'URL.
+- `permission` qui est défini dans l'objet `data` de la route.
+
+Jusqu'à la version 15 d'Angular, nous devions utiliser le `ActivatedRoute` pour obtenir toutes ces informations et les récupérer via des observables pour écouter sur les changements d'URL.
+
+Depuis la version 16, Angular a introduit un nouvel `Input` qui peut écouter les changements de données d'une route. Vous pouvez en savoir plus [ici](https://medium.com/ngconf/accessing-route-params-in-angular-1f8e12770617).
+
+## Énoncé
+
+L'objectif de cet exercice est de refactoriser le code pour utiliser la nouvelle stratégie `RouterInput`.
diff --git a/docs/src/content/docs/fr/challenges/angular/31-module-to-standalone.md b/docs/src/content/docs/fr/challenges/angular/31-module-to-standalone.md
new file mode 100644
index 000000000..bd0356610
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/31-module-to-standalone.md
@@ -0,0 +1,29 @@
+---
+title: 🟢 Module vers Standalone
+description: Le challenge 31 consiste à migrer une application basée sur des modules vers une application standalone.
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 31
+command: angular-module-to-standalone
+sidebar:
+ order: 6
+---
+
+## Information
+
+Dans la version 14 d'Angular, les composants standalone ont été introduits et sont devenus stables dans la version 15. Si vous ne les avez pas encore essayés, il n'est jamais trop tard. Vous pouvez les essayer dans ce challenge.
+
+L'objectif est de voir comment **Nx** et les **composants standalone** fonctionnent ensemble, et d'expérimenter le processus de découplage de votre application avec la bibliothèque Nx et les composants standalone.
+
+Les composants standalone sont très simples à comprendre mais les utilisations de ces composants dans **le routing et via du lazy-loading** peuvent être un peu plus difficiles à appréhender. Ce challenge vous permettra de manipuler des composants à différents niveaux d'imbrication et de travailler avec des routes qui utilisent du lazy loading.
+
+Après avoir complété ce défi, les composants standalone n'auront plus aucun secret pour vous.
+
+## Énoncé
+
+L'objectif de ce challenge est de migrer votre application depuis des composants basés sur des modules vers des composants standalone.
+
+## Note
+
+Vous pouvez également tester le [schematic Angular](https://angular.dev/reference/migrations/standalone) pour migrer les NgModule vers des composants standalone. _(Comme nous utilisons Nx, commencez votre commande par nx au lieu de ng)_
diff --git a/docs/src/content/docs/fr/challenges/angular/46-simple-animations.md b/docs/src/content/docs/fr/challenges/angular/46-simple-animations.md
new file mode 100644
index 000000000..d20446040
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/46-simple-animations.md
@@ -0,0 +1,48 @@
+---
+title: 🟢 Animations Simples
+description: Le challenge 46 consiste à apprendre comment utiliser l'API d'animations intégrée dans Angular
+author: sven-brodny
+contributors:
+ - alannelucq
+challengeNumber: 46
+command: angular-simple-animations
+sidebar:
+ order: 17
+---
+
+## Information
+
+Il s'agit du premier des deux challenges sur les animations. Le but de cette série est de maîtriser les animations en Angular.
+
+Des animations bien conçues peuvent rendre votre application plus agréable et plus intuitive à utiliser, mais elles ne sont pas seulement cosmétiques. Les animations peuvent améliorer votre application et l'expérience utilisateur de plusieurs façons :
+
+- Sans animations, les transitions de pages web peuvent sembler abruptes et désagréables.
+- Le mouvement améliore grandement l'expérience utilisateur, les animations permettent donc aux utilisateurs de percevoir la réponse de l'application à leurs actions.
+- De bonnes animations attirent intuitivement l'attention de l'utilisateur là où elle est nécessaire.
+
+Je vous recommande de lire la [documentation officielle](https://angular.dev/guide/animations). Vous y apprendrez tout ce qui est nécessaire pour réussir ce challenge.
+
+Vous pouvez également regarder cet [exemple fonctionnel](https://svenson95.github.io/ng-xmp-animations/) et ce [repertoire git](https://github.com/svenson95/ng-xmp-animations) pour vous inspirer.
+
+## Énoncé
+
+L'objectif de ce challenge est d'ajouter des animations qui doivent être déclenchées lorsque l'utilisateur arrive sur la page ou la recharge.
+
+## Contraintes
+
+- N'utilisez aucun CSS et utilisez l'API intégrée d'Angular `@angular/animations`.
+- Ne déclenchez pas les animations avec un bouton comme dans les exemples, mais lorsque l'utilisateur entre ou recharge la page.
+
+### Niveau 1
+
+Ajoutez une animation de fondu ou de déplacement pour les paragraphes sur le côté gauche.
+
+
+
+### Niveau 2
+
+Ajoutez une animation en cascade pour la liste sur le côté droit.
+
+
diff --git a/docs/src/content/docs/fr/challenges/angular/5-crud-application.md b/docs/src/content/docs/fr/challenges/angular/5-crud-application.md
new file mode 100644
index 000000000..0ef30ec4d
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/5-crud-application.md
@@ -0,0 +1,52 @@
+---
+title: 🟢 Application CRUD
+description: Le challenge 5 consiste à refactoriser une application CRUD
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 5
+command: angular-crud-application
+sidebar:
+ order: 2
+---
+
+## Information
+
+Communiquer et synchroniser un état global ou local avec votre backend est au cœur de toute application. Vous devrez maîtriser les meilleures pratiques suivantes pour construire des applications Angular solides et fiables.
+
+## Énoncé
+
+Dans cet exercice, vous avez une petite application CRUD dans laquelle vous pouvez récupérer, mettre à jour et supprimer des tâches.
+
+Pour le moment, nous avons un exemple fonctionnel mais qui est rempli de nombreuses mauvaises pratiques.
+
+### Étape 1 : refactoriser avec les meilleures pratiques
+
+Ce que vous devrez faire:
+
+- Évitez d'utiliser **any** comme type. Utiliser des interfaces pour tirer parti du système de typage de Typescript permet d'éviter les erreurs.
+- Utilisez un **service séparé** pour tous vos appels HTTP et utilisez un **Signal** pour votre liste de tâches.
+- Ne **mutez** pas les données
+
+```typescript
+// À éviter
+this.todos[todoUpdated.id - 1] = todoUpdated;
+
+// Privilégier une approche comme celle-ci, mais qui doit être améliorée car nous voulons toujours conserver le même ordre
+this.todos = [...this.todos.filter((t) => t.id !== todoUpdated.id), todoUpdated];
+```
+
+### Étape 2 : Améliorer
+
+- Ajoutez un bouton **Supprimer** : _Documentation de l'API fictive_
+- Gérez correctement les **erreurs**. _(De façon globale)_
+- Ajoutez un **indicateur de chargement** global. _Vous pouvez utilisez le MatProgressSpinnerModule_
+
+### Étape 3 : Maintenabilité !! (ajoutez des tests)
+
+- Ajoutez 2/3 tests
+
+### Étape 4 : Effet waouw !!! (maîtrisez votre état).
+
+- Utilisez le **component store de ngrx**, **ngrx/store**, **rxAngular**, **tanstack-query** ou **ngrx/signal-store** pour gérer l'état local de votre composant.
+- Ayez un indicateur de chargement/erreur **localisé** , par exemple uniquement sur la tâche en cours de traitement et **désactivez** tous les boutons sur cette tâche. _(Astuce: vous devrez créer un ItemComponent)_
diff --git a/docs/src/content/docs/fr/challenges/angular/8-pure-pipe.md b/docs/src/content/docs/fr/challenges/angular/8-pure-pipe.md
new file mode 100644
index 000000000..0932e7a67
--- /dev/null
+++ b/docs/src/content/docs/fr/challenges/angular/8-pure-pipe.md
@@ -0,0 +1,37 @@
+---
+title: 🟢 Pipe pur
+description: Le challenge 8 consiste à créer un pipe pur
+author: thomas-laforge
+contributors:
+ - alannelucq
+challengeNumber: 8
+command: angular-pure-pipe
+blogLink: https://medium.com/ngconf/deep-dive-into-angular-pipes-c040588cd15d
+sidebar:
+ order: 3
+---
+
+## Information
+
+Il s'agit du premier des trois challenges `@Pipe()`. L'objectif de cette série est de maîtriser les **pipes** en Angular.
+
+Les pipes sont un moyen très puissant de transformer les données dans votre template. La différence entre appeler une fonction et un pipe réside dans le fait que les pipes purs sont mémorisés. Ils ne seront donc pas recalculés à chaque cycle de détection des changements si les données en entrée n'ont pas changées.
+
+Les pipes sont conçus pour être efficaces et optimisés pour la performance. Ils utilisent des mécanismes de détection des changements pour ne recalculer la valeur que si la donnée en entrée change, ce qui minimise les calculs inutiles et améliore les performances de rendu.
+
+Par défaut, un pipe est pur. Vous devez être conscient que définir `pure` à false est susceptible d'être inefficace, car cela augmente le nombre de rerenders.
+
+:::note
+Un pipe **pur** est appelé uniquement lorsque la valeur change.
+Un pipe **impur** est appelé à chaque cycle de détection des changements.
+:::
+
+Il existe quelques pipes prédéfinis utiles comme DatePipe, UpperCasePipe et CurrencyPipe. Pour en savoir plus sur les pipes dans Angular, consultez la documentation de l'API [ici](https://angular.dev/guide/pipes).
+
+## Énoncé
+
+Dans cet exercice, vous devez refactoriser une fonction de transformation à l'intérieur d'un composant qui est appelée dans votre template. L'objectif est de convertir cette fonction en un pipe.
+
+## Contraintes
+
+- Doit être fortement typé
diff --git a/docs/src/content/docs/fr/guides/checkout-answer.md b/docs/src/content/docs/fr/guides/checkout-answer.md
new file mode 100644
index 000000000..9a16f2a51
--- /dev/null
+++ b/docs/src/content/docs/fr/guides/checkout-answer.md
@@ -0,0 +1,59 @@
+---
+title: Consulter la réponse de quelqu'un d'autre
+description: Guide pour consulter la réponse de quelqu'un d'autre.
+contributors:
+ - alannelucq
+sidebar:
+ order: 3
+---
+
+Toutes les réponses aux Challenges Angular seront présentées sous la forme d'une pull request (PR). Pour les consulter
+et
+les suivre, naviguez dans la page Files Changes sur GitHub. Cependant, comprendre et suivre ce processus peut ne pas
+être simple si vous n'êtes pas familier avec l'interface. Dans de nombreux cas, vous préférerez peut-être vous mettre
+sur la branche et examiner la réponse dans votre IDE préféré.
+
+## Installer la CLI de GitHub
+
+Suivez les instructions pour votre système d'exploitation [ici](https://github.com/cli/cli#installation).
+
+## Consulter la PR de quelqu'un d'autre en local
+
+### Synchronisez votre dépôt
+
+Tout d'abord, vous devez synchroniser votre fork pour vous assurer qu'il soit à jour avec le dépôt forké.
+
+Cela peut être réalisé en cliquant sur le bouton Sync fork sur la page principale de votre fork.
+
+
+
+L'image ci-dessus montre que ma branche a 8 commits de retard par rapport à la branche principale, et je dois la
+synchroniser pour qu'elle soit à jour.
+
+
+
+### Consulter la PR en local
+
+Recherchez la PR que vous souhaitez consulter en local et récupérez son ID. Vous le trouverez dans le titre de la
+PR (comme illustré ci-dessous).
+
+
+
+Ensuite, ouvrez n'importe quel terminal dans le répertoire de votre projet et exécutez la commande suivante :
+
+```bash
+gh pr checkout
+```
+
+Si vous ne vous souvenez pas de la commande, cliquez sur le bouton Code sur le côté droit de l'en-tête, et vous pourrez
+facilement la copier/coller.
+
+
+
+:::note
+Si la commande ne fonctionne pas ou échoue, l'interface CLI de GitHub vous guidera à travers le processus.
+:::
+
+🔥 Vous pouvez maintenant consulter la réponse en local et la lancer pour la tester. 🔥
+
+
diff --git a/docs/src/content/docs/fr/guides/contribute.md b/docs/src/content/docs/fr/guides/contribute.md
new file mode 100644
index 000000000..69e8d4a2b
--- /dev/null
+++ b/docs/src/content/docs/fr/guides/contribute.md
@@ -0,0 +1,24 @@
+---
+title: Comment contribuer ?
+description: Guide pour savoir comment contribuer à ce projet.
+contributors:
+ - alannelucq
+sidebar:
+ order: 4
+---
+
+Vous pouvez contribuer à ce projet de plusieurs manières :
+
+🔥 Créer un nouveau challenge en suivant ces [instructions](/guides/create-challenge).
+
+🔥 Répondre aux challenges et soumettez les résultats (guide [ici](/guides/resolve-challenge)).
+
+🔥 Donner des retours bienveillants et constructifs sur les solutions des autres.
+
+🔥 Corriger les fautes de frappe dans la documentation.
+
+🔥 Aider à la traduction de la documentation.
+
+🔥 Créer une issue pour suggérer de nouvelles idées de challenges ou signaler un bug.
+
+🔥 Sponsoriser le projet [ici](https://github.com/sponsors/tomalaforge).
diff --git a/docs/src/content/docs/fr/guides/create-challenge.md b/docs/src/content/docs/fr/guides/create-challenge.md
new file mode 100644
index 000000000..a197db052
--- /dev/null
+++ b/docs/src/content/docs/fr/guides/create-challenge.md
@@ -0,0 +1,68 @@
+---
+title: Créer un challenge
+description: Guide sur comment créer un challenge
+contributors:
+ - alannelucq
+sidebar:
+ order: 5
+---
+
+Vous avez une idée à partager, un bug intéressant avec lequel vous luttez dans l'un de vos projets privés ou
+secondaires, ou une astuce Angular que vous avez découverte ? Toutes ces situations sont un bon point de départ pour
+créer un challenge et partager votre solution avec les autres.
+
+Comment commencer à créer ces challenges ?
+
+## Configuration de base
+
+Pour simplifier le processus, j'ai créé un générateur Nx qui configurera tout le code de base pour vous. Le moyen le
+plus
+simple de l'exécuter est d'utiliser la console Nx : allez dans Nx Console > generate > @angular-challenges/cli -
+challenge.
+
+Vous pouvez également utiliser [l'extension Nx Console](https://nx.dev/getting-started/editor-setup) de votre IDE pour
+générer les fichiers.
+
+### Paramètres
+
+#### Paramètres obligatoires
+
+- title: Le titre que vous souhaitez donner à votre challenge.
+ :::note
+ Le titre doit comporter un maximum de 25 caractères.
+ :::
+
+- challengeDifficulty: La difficulté estimée de votre challenge. Il y a trois niveaux de difficulté : 🟢 facile /
+ 🟠 moyen / 🔴 difficile
+- name: Le nom de l'application Nx.
+ :::note
+ Il doit être écrit en **kebab-case**.
+ :::
+- docRepository: La catégorie de votre challenge : Nx, Angular, Angular Performance, Rxjs, NgRx, Typescript, ou
+ Forms.
+
+#### Paramètres optionnels
+
+- directory: Si vous souhaitez que votre application soit située dans un dossier spécifique à l'intérieur
+ de `apps`.
+- addTest: Si vous souhaitez ajouter une configuration de test.
+
+### Qu'est-ce qui est créé ?
+
+- Le générateur créera tous les fichiers nécessaires pour avoir une nouvelle application fonctionnelle. Tous ces
+ fichiers seront créés dans apps/${directory}/${name}.
+- Un fichier Markdown avec une configuration minimale sera créé dans docs/src/content/docs/challenges/${docRepository}.
+
+## Création d'un challenge
+
+La seule chose qu'il vous reste à faire est de créer votre challenge. 🚀
+
+:::danger
+N'oubliez pas de mettre à jour la documentation pour présenter votre challenge et fournir vos instructions.
+:::
+
+À vous de jouer !!! 💪
+
+## Soumission d'une solution
+
+Après environ une semaine, fournissez une pull request de la solution de votre challenge.
diff --git a/docs/src/content/docs/fr/guides/faq.md b/docs/src/content/docs/fr/guides/faq.md
new file mode 100644
index 000000000..abbba29af
--- /dev/null
+++ b/docs/src/content/docs/fr/guides/faq.md
@@ -0,0 +1,24 @@
+---
+title: FAQ
+description: Foire Aux Questions
+contributors:
+ - alannelucq
+sidebar:
+ order: 7
+---
+
+
+
+ Pourquoi mon application ne démarre-t-elle pas, ou pourquoi est-ce que je rencontre des erreurs dans mon terminal lorsque je lance `nx serve` ?
+
+
+La plupart du temps, ce problème survient parce que vos node_modules sont obsolètes et que vous devez les mettre à jour
+en exécutant `npm ci`.
+
+Si le processus d'installation échoue, vous pouvez résoudre ce problème en supprimant votre dossier node_modules en
+utilisant la commande `rm -rf node_modules` ou `npx npkill`, puis en relançant `npm ci`.
+
+Si le problème persiste, veuillez signaler le
+problème [ici](https://github.com/tomalaforge/angular-challenges/issues/new).
+
+
diff --git a/docs/src/content/docs/fr/guides/rebase.md b/docs/src/content/docs/fr/guides/rebase.md
new file mode 100644
index 000000000..bf50ebb71
--- /dev/null
+++ b/docs/src/content/docs/fr/guides/rebase.md
@@ -0,0 +1,63 @@
+---
+title: Rebase votre branche
+description: Guide pour faire un rebase de sa branche et récupérer les derniers changements.
+contributors:
+ - alannelucq
+sidebar:
+ order: 6
+---
+
+Parfois, des modifications peuvent être ajoutées au projet. Je vais essayer de faire des changements qui ne cassent
+rien, mais parfois, c'est inévitable.
+
+La plupart du temps, vous n'aurez pas besoin de rebaser votre solution, mais voici un guide pour vous aider à savoir
+comment le faire.
+
+:::note
+Ce guide est applicable à tout projet Open Source.
+:::
+
+## Étapes pour rebaser votre branche
+
+### Synchronisez votre dépôt
+
+Tout d'abord, vous devez synchroniser votre fork pour vous assurer qu'il est à jour avec le dépôt forké.
+
+Vous pouvez le faire en cliquant sur le bouton Sync fork sur la page principale de votre fork.
+
+
+
+L'image ci-dessus montre que ma branche a 8 commits de retard par rapport à la branche principale et que je dois la
+synchroniser pour qu'elle soit à jour.
+
+
+
+### Ouvrez un terminal
+
+Ouvrez le terminal de votre choix, soit celui de votre IDE préféré, soit une instance autonome.
+
+### Git
+
+Exécutez les commandes suivantes pour rebaser votre branche locale :
+
+- git checkout main
+- git pull
+- git checkout [votre branche]
+- git rebase main
+- Résolvez les conflits
+
+À cette étape, le rebase peut s'arrêter parce que votre branche locale a des fichiers en conflit avec la branche
+principale. Corrigez-les.
+
+Une fois que c'est fait :
+
+- git add .
+- git rebase --continue
+
+Si votre branche n'a pas de conflit, un message de succès sera affiché.
+
+### Envoyez votre travail vers la branche distante
+
+Enfin, envoyez votre travail vers GitHub :
+
+- git push -f
diff --git a/docs/src/content/docs/fr/index.mdx b/docs/src/content/docs/fr/index.mdx
index e510057d5..25435d041 100644
--- a/docs/src/content/docs/fr/index.mdx
+++ b/docs/src/content/docs/fr/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Aller au dernier Challenge
- link: /fr/challenges/signal/51-function-call-effect
+ link: /fr/challenges/angular/59-content-projection-defer/
icon: rocket
- text: Donne une étoile
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Ce répertoire rassemble 51 Défis liés à Angular, Nx, RxJS, Ngrx et Typescript. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences.
+
+ Ce répertoire rassemble 59 Défis liés à Angular, Nx, RxJS, Ngrx et Typescript. Ces défis portent sur des problèmes réels ou des fonctionnalités spécifiques pour améliorer vos compétences.
diff --git a/docs/src/content/docs/guides/checkout-answer.md b/docs/src/content/docs/guides/checkout-answer.md
index 31375f7af..2e56ce162 100644
--- a/docs/src/content/docs/guides/checkout-answer.md
+++ b/docs/src/content/docs/guides/checkout-answer.md
@@ -52,4 +52,6 @@ If the command doesn't work or fails, GitHub CLI will guide you through the proc
🔥 You can now navigate through the solution locally and serve it to test it. 🔥
-
+### Checkout with GitHub Codespaces
+
+You can checkout any **open** PR with GitHub Codespaces. After clicking the code button, you can navigate to the codespaces tab and click the green button to create a codespace on the PR's branch. After the codespace initializes, you can serve the app.
diff --git a/docs/src/content/docs/guides/create-challenge.md b/docs/src/content/docs/guides/create-challenge.md
index 6c70786a4..4b01d6bb8 100644
--- a/docs/src/content/docs/guides/create-challenge.md
+++ b/docs/src/content/docs/guides/create-challenge.md
@@ -28,15 +28,21 @@ Alternatively, you may utilize your IDE's [Nx Console extension](https://nx.dev/
The title must be a maximum of 25 characters.
:::
-- challengeDifficulty: The difficulty you think your challenge has. There are three difficulty levels : 🟢 easy / 🟠 medium / 🔴 hard
-- name: name of the Nx application.
+- author: Your name
+ :::note
+ Your name should be in kebab-case. (e.g. john-doe)
+ :::
:::note
- It must be written in **kebab-case**.
+ Don't forget to update your personal information inside the file at your name.
:::
-- docRepository: The category of your Challenge is Nx, Angular, Angular Performance, Rxjs, NgRx, Typescript, or Forms.
+
+- challengeDifficulty: The difficulty you think your challenge has. There are three difficulty levels : 🟢 easy / 🟠 medium / 🔴 hard
+
+- docRepository: The category of your Challenge is Nx, Angular, Angular Performance, Rxjs, NgRx, Typescript, Forms or Signals.
#### optional parameters
+- challengeNumber: You can specify a challenge number if a challenge is being submitted. (If empty, the number will be the next one).
- directory: If you want your application to be located in a specific folder inside `apps`.
- addTest: If you want to add test configuration.
diff --git a/docs/src/content/docs/guides/getting-started.md b/docs/src/content/docs/guides/getting-started.md
index 9e9b27819..e707fa36c 100644
--- a/docs/src/content/docs/guides/getting-started.md
+++ b/docs/src/content/docs/guides/getting-started.md
@@ -5,6 +5,7 @@ contributors:
- tomalaforge
- 1fbr
- ho-ssain
+ - jdegand
sidebar:
order: 1
---
@@ -18,7 +19,7 @@ If you wish to submit an answer, you will need to have your own GitHub account.
## Fork the GitHub project
Navigate to the [Angular Challenges Repository](https://github.com/tomalaforge/angular-challenges) and click on the Fork button in the header. This will create a copy of this repository on your own GitHub page.
+Fork button in the header. This will create a copy of this repository on your own GitHub profile.
## Clone the repository to your local machine
@@ -59,3 +60,23 @@ Each challenge consists of:
- 🟢 easy
- 🟠 medium
- 🔴 difficult
+
+## (Alternately) Use GitHub Codespaces
+
+From your own instance of the Angular Challenges repository, click the code button and navigate to the codespaces tab.
+
+
+
+Click the `Create codespace on main` button, and you will navigate to a GitHub codespace.
+
+If you never used a GitHub codespace before, I would recommend you try this short interactive [GitHub Skills Tutorial](https://github.com/skills/code-with-codespaces).
+
+When you navigate to the codespace, there will be a prompt to install the recommended `VS Code` plugins. If you plan on creating a challenge, you can use the `Nx plugin` to generate the starter code. Either way, the codespace will install the dependencies, and you can create a new branch, tackle any challenge, and create a pull request.
+
+When you push to a branch, you do not have to provide a GitHub token.
+
+Once you are finished, remember to pause or delete your codespace. If you don't, GitHub will automatically pause an idle codespace after 30 minutes. You do have a generous amount of free codespace time per month, but it is still important not to waste your allotment.
+
+In the GitHub codespace, copy and paste will be blocked until you give permission.
+
+The GitHub codespace uses port forwarding to serve the projects. Click the prompt after running `npx nx serve [project-name]` to navigate to `localhost:4200`.
diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx
index 60f3a6d4b..85b774b73 100644
--- a/docs/src/content/docs/index.mdx
+++ b/docs/src/content/docs/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Go to the latest Challenge
- link: /challenges/signal/51-function-call-effect
+ link: /challenges/angular/59-content-projection-defer/
icon: rocket
- text: Give a star
link: https://github.com/tomalaforge/angular-challenges
@@ -27,8 +27,8 @@ import MyIcon from '../../components/MyIcon.astro';
import SubscriptionForm from '../../components/SubscriptionForm.astro';
-
- This repository gathers 51 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript.
+
+ This repository gathers 59 Challenges related to Angular, Nx, RxJS, Ngrx and Typescript.
These challenges resolve around real-life issues or specific features to elevate your skills.
@@ -43,8 +43,8 @@ import SubscriptionForm from '../../components/SubscriptionForm.astro';
- Learning and practicing a new framework is always challenging. This set of
- challenges provide real-world use cases to apply what you've been learning.
+ Learning and practicing a new framework is always challenging. This set of
+ challenges provide real-world use cases to apply what you've been learning.
Anyone can comment or offer assistance.
Learning alone is great, but learning alongside others will get you further.
@@ -57,7 +57,8 @@ import SubscriptionForm from '../../components/SubscriptionForm.astro';
- By completing these challenges, you'll be ready for any technical questions that may come up during a frontend job interview.
+ By completing these challenges, you'll be ready for any technical questions
+ that may come up during a frontend job interview.
diff --git a/docs/src/content/docs/pt/challenges/angular/1-projection.md b/docs/src/content/docs/pt/challenges/angular/1-projection.md
index 2b782b2d6..2dd44690e 100644
--- a/docs/src/content/docs/pt/challenges/angular/1-projection.md
+++ b/docs/src/content/docs/pt/challenges/angular/1-projection.md
@@ -7,10 +7,13 @@ contributors:
challengeNumber: 1
command: angular-projection
blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
-videoLink:
- link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
- alt: Vídeo de projeção por Arthur Lannelucq
- flag: FR
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
sidebar:
order: 1
---
diff --git a/docs/src/content/docs/pt/challenges/angular/39-injection-token.md b/docs/src/content/docs/pt/challenges/angular/39-injection-token.md
index 3af2edfb0..b6f4ae8e1 100644
--- a/docs/src/content/docs/pt/challenges/angular/39-injection-token.md
+++ b/docs/src/content/docs/pt/challenges/angular/39-injection-token.md
@@ -6,6 +6,10 @@ contributors:
- kabrunko-dev
challengeNumber: 39
command: angular-injection-token
+videoLinks:
+ - link: https://www.youtube.com/watch?v=ntggdQycFyc
+ alt: Injection Token by Arthur Lannelucq
+ flag: FR
sidebar:
order: 118
---
diff --git a/docs/src/content/docs/pt/index.mdx b/docs/src/content/docs/pt/index.mdx
index e39936812..d2670bbc4 100644
--- a/docs/src/content/docs/pt/index.mdx
+++ b/docs/src/content/docs/pt/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Ir para o desafio mais recente
- link: /pt/challenges/signal/51-function-call-effect
+ link: /pt/challenges/angular/59-content-projection-defer/
icon: rocket
- text: Dar uma estrela
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Este repositório possui 51 Desafios relacionados a Angular, Nx, RxJS,
+
+ Este repositório possui 59 Desafios relacionados a Angular, Nx, RxJS,
Ngrx e Typescript.
Esses desafios são voltados para problemas reais ou funcionalidades específicas afim de
melhorar suas habilidades.
diff --git a/docs/src/content/docs/ru/challenges/angular/1-projection.md b/docs/src/content/docs/ru/challenges/angular/1-projection.md
index 1f2a3a946..3ff9c2ea9 100644
--- a/docs/src/content/docs/ru/challenges/angular/1-projection.md
+++ b/docs/src/content/docs/ru/challenges/angular/1-projection.md
@@ -7,10 +7,13 @@ contributors:
challengeNumber: 1
command: angular-projection
blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
-videoLink:
- link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
- alt: Projection video by Arthur Lannelucq
- flag: FR
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
sidebar:
order: 1
---
diff --git a/docs/src/content/docs/ru/challenges/angular/52-lazy-load-component.md b/docs/src/content/docs/ru/challenges/angular/52-lazy-load-component.md
new file mode 100644
index 000000000..a0697c784
--- /dev/null
+++ b/docs/src/content/docs/ru/challenges/angular/52-lazy-load-component.md
@@ -0,0 +1,50 @@
+---
+title: 🟢 Ленивая загрузка компонента
+description: Испытание 52 посвящено изучению ленивой загрузки компонентов в Angular.
+author: lance-finney
+contributors:
+ - LMFinney
+ - stillst
+challengeNumber: 52
+command: angular-lazy-load-component
+sidebar:
+ order: 21
+ badge: Новое
+---
+
+## Информация
+
+В Angular уже давно существует механизм для ленивой загрузки модулей на основе маршрутов, но ленивая загрузка отдельных компонентов была намного сложнее. Это испытание посвящено изучению того, как лениво загружать компоненты при помощи новой фичи, которая появилась в Angular 17.
+
+## Пояснение
+
+Это простое приложение отображает `TopComponent`, который, по нашим предположениям, замедлил бы работу приложения, если бы был частью начального пакета (хотя на самом деле он содержит лишь немного текста, но мы притворяемся, что он замедляет приложение).
+
+В текущем решении `PlaceholderComponent` отображается до тех пор, пока пользователь не нажмет кнопку для показа `TopComponent`. Однако, несмотря на то что `TopComponent` не виден до нажатия на кнопку, он все равно загружается вместе с начальным пакетом.
+
+Используйте новую фичу Angular 17 для ленивой загрузки `TopComponent`, чтобы он загружался и отображался только после нажатия пользователем кнопки.
+
+Когда вы закончите, вы увидите, что браузер загружает `TopComponent` в отдельном пакете после нажатия на кнопку для его отображения. В Chrome вы можете увидеть это, открыв DevTools, перейдя на вкладку "Network", и нажав кнопку для отображения `TopComponent`.
+
+## Подсказки
+
+
+ Подсказка 1
+
+Вы должны иметь возможность удалить сигнал `topLoaded`, когда закончите.
+
+
+
+
+ Подсказка 2
+
+Новая фича Angular скроет `TopComponent` из вида, но он все равно будет загружаться в начальном пакете, если вы не измените способ определения `AppComponent`, и `TopComponent` в их декораторах. Эта задача начинается со старой архитектуры на основе `NgModule`, но вам нужно будет изменить ее, чтобы использовать новую фичу.
+
+
+
+
+ Подсказка 3
+
+Новая фича - это [Отложенные представления (Deferrable Views)](https://angular.dev/guide/defer). Фича предлагает несколько триггеров. Один из них идеально подходит для этой задачи.
+
+
diff --git a/docs/src/content/docs/ru/index.mdx b/docs/src/content/docs/ru/index.mdx
index 79f2bd223..a80dab6a1 100644
--- a/docs/src/content/docs/ru/index.mdx
+++ b/docs/src/content/docs/ru/index.mdx
@@ -13,7 +13,7 @@ hero:
icon: right-arrow
variant: primary
- text: Перейти к последней задаче
- link: /ru/challenges/signal/51-function-call-effect
+ link: /ru/challenges/angular/59-content-projection-defer/
icon: rocket
- text: Добавить звезду
link: https://github.com/tomalaforge/angular-challenges
@@ -26,8 +26,8 @@ import MyIcon from '../../../components/MyIcon.astro';
import SubscriptionForm from '../../../components/SubscriptionForm.astro';
-
- Этот репозиторий содержит 51 испытаний, связанных с Angular, Nx, RxJS, Ngrx и Typescript.
+
+ Этот репозиторий содержит 56 испытаний, связанных с Angular, Nx, RxJS, Ngrx и Typescript.
Испытания основаны на реальных задачах или инструментах для того, чтобы прокачать вас.
diff --git a/docs/src/content/docs/zh-cn/challenges/angular/1-projection.md b/docs/src/content/docs/zh-cn/challenges/angular/1-projection.md
new file mode 100644
index 000000000..9a21713fb
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/challenges/angular/1-projection.md
@@ -0,0 +1,52 @@
+---
+title: 🟢 投影
+description: 挑战1是学习如何通过组件投影DOM元素
+author: thomas-laforge
+contributors:
+ - tomalaforge
+ - jdegand
+ - dmmishchenko
+ - kabrunko-dev
+ - svenson95
+challengeNumber: 1
+command: angular-projection
+blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5
+videoLinks:
+ - link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq
+ alt: Projection video by Arthur Lannelucq
+ flag: FR
+ - link: https://www.youtube.com/watch?v=yNrfvu7vTa4
+ alt: Projection video by Amos Lucian Isaila
+ flag: ES
+sidebar:
+ order: 1
+---
+
+## 信息
+
+在Angular中,内容投影是一种创建高度可定制组件的强大技术。利用和理解ng-content和ngTemplateOutlet的概念可以显著增强你创建可共享组件的能力
+
+你可以在[这里](https://angular.dev/guide/components/content-projection)了解ng-content 的所有内容,从简单的投影到更复杂的投影。
+
+要了解ngTemplateOutlet,你可以在[这里](https://angular.io/api/common/NgTemplateOutlet)找到API文档和一些基本示例。
+
+有了这两个工具,您现在就可以接受挑战了。
+
+## 说明
+
+您将从一个功能齐全的应用程序开始,该应用程序包括一个包含教师卡和学生卡的仪表盘。目标是实现城市卡。
+
+虽然应用程序可以工作,但开发人员的体验还远没有达到最佳。每次需要实现新卡时,都必须修改`card.component.ts` 。在实际项目中,该组件可以在许多应用程序之间共享。该挑战的目标是创建一个 `CardComponent` ,它可以在不做任何修改的情况下进行自定义。一旦你创建了这个组件,你就可以开始实现 `CityCardComponent` ,并确保你没有触碰 `CardComponent` 。
+
+## 约束
+
+- 必须重构 `CardComponent` 和 `ListItemComponent`。
+- `NgFor` 指令必须声明并保持在 `CardComponent` 内。你可能想把它移到 `ParentCardComponent` ,比如 `TeacherCardComponent` 。
+- `CardComponent` 不应包含任何 `NgIf` 或 `NgSwitch` 。
+- CSS:尽量避免使用 `::ng-deep` 。寻找更好的方法来处理CSS样式。
+
+## 挑战奖励
+
+- 尝试使用新的内置控制流语法for循环和条件语句(文档在[这里](https://angular.dev/guide/templates/control-flow))
+- 使用signal API来管理组件状态(文档在[这里](https://angular.dev/guide/signals))
+- 要引用模板,请使用指令而不是魔术字符串([魔术字符串有什么问题?](https://softwareengineering.stackexchange.com/a/365344))
diff --git a/docs/src/content/docs/zh-cn/guides/checkout-answer.md b/docs/src/content/docs/zh-cn/guides/checkout-answer.md
new file mode 100644
index 000000000..5ac31b98b
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/checkout-answer.md
@@ -0,0 +1,57 @@
+---
+title: 查看某人的回答
+description: 查看某人的回答指南
+contributors:
+ - tomalaforge
+ - gsgonzalez88
+ - 1fbr
+ - jdegand
+sidebar:
+ order: 3
+---
+
+所有Angular Challenges的答案都将以pull request (PR)的形式呈现。要查看和跟踪它们,请浏览GitHub上的**文件更改**页面。但是,如果您不熟悉界面,理解和遵循此过程可能并不简单。在许多情况下,您可能更喜欢签出分支并在您首选的IDE中检查解决方案。
+
+## 安装 GitHub CLI
+
+在[这里](https://github.com/cli/cli#installation)按照操作系统的说明操作。
+
+## 查看本地其他人的PR
+
+### 同步存储库
+
+首先,您需要同步您的分支,以确保它与分支存储库是最新的。
+
+这可以通过点击你的分支主页上的**Sync fork**按钮来实现。
+
+
+
+上图显示我的分支落后于主分支 8 个提交,我需要将其同步才能保持最新。
+
+
+
+### 本地检出查看
+
+导航到你想在本地查看的PR并获取其ID。你可以在PR的标题中找到它(如下所示)。
+
+
+
+接下来,切换到项目目录中的任意终端,并运行以下命令:
+
+```bash
+gh pr checkout
+```
+
+如果你不记得这个命令,点击标题右侧的Code按钮,你可以轻松地复制/粘贴这个命令。
+
+
+
+:::note[注意]
+如果命令不起作用或失败,GitHub CLI会引导你完成整个过程。
+:::
+
+🔥您现在可以在本地浏览解决方案并提供服务以测试它。🔥
+
+### 使用GitHub Codespaces检出查看
+
+你可以使用GitHub Codespaces查看任何**打开**的PR。点击code按钮后,你可以导航到codespaces标签,然后点击绿色按钮,在PR的分支上创建一个codesace。codespace初始化后,就可以启动应用了。
diff --git a/docs/src/content/docs/zh-cn/guides/contribute.md b/docs/src/content/docs/zh-cn/guides/contribute.md
new file mode 100644
index 000000000..7fea19df6
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/contribute.md
@@ -0,0 +1,25 @@
+---
+title: 贡献
+description: 贡献指南
+contributors:
+ - tomalaforge
+ - jdegand
+sidebar:
+ order: 4
+---
+
+你可以通过以下多种方式为这个存储库做出贡献:
+
+🔥 依照以下[指示](/guides/create-challenge)创建一个新的挑战。
+
+🔥 接受挑战并提交结果(指南 [在此](/guides/resolve-challenge))。
+
+🔥 对他人提出的解决方案给予有建设性的、热情的反馈。
+
+🔥 校正文档中的拼写错误。
+
+🔥 协助翻译文档。
+
+🔥 提交问题建议新的挑战想法或报告错误。
+
+🔥 [在此](https://github.com/sponsors/tomalaforge)赞助该项目。
diff --git a/docs/src/content/docs/zh-cn/guides/create-challenge.md b/docs/src/content/docs/zh-cn/guides/create-challenge.md
new file mode 100644
index 000000000..6b13e69cd
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/create-challenge.md
@@ -0,0 +1,68 @@
+---
+title: 创建你自己的挑战
+description: 创建你自己的挑战指南
+contributors:
+ - tomalaforge
+ - gsgonzalez88
+ - jdegand
+sidebar:
+ order: 5
+---
+
+你有一个想法想要分享,你正在努力解决某个私人项目或业余项目中的一个有趣的bug,或者你发现的一个Angular技巧。所有这些可能性都是创建挑战并与他人分享解决方案的良好起点。
+
+如何开始创造这些挑战?
+
+## 样板设置
+
+为了简化这个过程,我创建了一个Nx生成器,它将为您设置所有样板文件。运行它最简单的方法是使用Nx控制台:转到Nx Console > generate > @angular-challenges/cli - challenge。
+
+或者,你也可以利用IDE的 [Nx Console extension](https://nx.dev/getting-started/editor-setup)来生成文件
+
+### 参数
+
+#### 强制参数
+
+- title: 你想给你的挑战的标题。
+ :::note[注意]
+ 标题长度不能超过25个字符。
+ :::
+
+- author: 你的名字
+
+ :::note[注意]
+ 你的名字应该使用烤肉串格式(如: john-doe)
+ :::
+
+ :::note[注意]
+ 别忘了在以你名字命名的文件中更新你的个人信息
+ :::
+
+- challengeDifficulty:你认为你的挑战有多大的难度。有三个难度级别:🟢简单/🟠中等/🔴困难
+
+- docRepository: 你挑战的类别是Nx、Angular、Angular性能、Rxjs、NgRx、Typescript、表单或信号。
+
+#### 可选参数
+
+- challengeNumber: 当有挑战提交时,可以指定挑战号。(如果为空,该数字将是下一个数字)。
+- directory: 如果您希望您的应用程序位于 `apps` 中的特定文件夹中。
+- addTest: 如果您想添加测试配置。
+
+### 创建了什么?
+
+- 生成器将创建新应用程序运行所需的所有文件。所有这些文件都将创建在 `apps/${directory}/${name}` 中
+- 将在 `docs/src/content/docs/challenges/${docRepository}` 中创建一个带有最小设置的Markdown文件。
+
+## 创造挑战
+
+剩下唯一要做的就是创造挑战。 🚀
+
+:::danger[危险]
+不要忘记更新文档以介绍您的挑战并提供说明。
+:::
+
+轮到你行动了!!💪
+
+## 解决方案提交
+
+大约一周后,提供一个针对您的挑战的解决方案的pull request。
diff --git a/docs/src/content/docs/zh-cn/guides/faq.md b/docs/src/content/docs/zh-cn/guides/faq.md
new file mode 100644
index 000000000..0a79778b6
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/faq.md
@@ -0,0 +1,22 @@
+---
+title: 常见问题解答
+description: 回答问题
+contributors:
+ - tomalaforge
+ - jdegand
+sidebar:
+ order: 7
+---
+
+
+
+ 为什么我的应用程序没有启动,或者为什么我在运行`nx serve`时在终端中遇到错误?
+
+
+ 大多数情况下,出现这个问题是因为你的node_modules已经过时了,你需要通过运行 `npm ci` 来更新它们。
+
+如果安装失败,可以通过 `rm -rf node_modules` 或 `npx npkill` 删除node_modules文件夹,然后重新运行 `npm ci` 来解决。
+
+如果问题仍然存在,请在[这里](https://github.com/tomalaforge/angular-challenges/issues/new)报告问题。
+
+
diff --git a/docs/src/content/docs/zh-cn/guides/getting-started.md b/docs/src/content/docs/zh-cn/guides/getting-started.md
new file mode 100644
index 000000000..53033cae6
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/getting-started.md
@@ -0,0 +1,83 @@
+---
+title: 开始
+description: 关于如何开始Angular挑战的指南。
+contributors:
+ - tomalaforge
+ - 1fbr
+ - ho-ssain
+ - jdegand
+sidebar:
+ order: 1
+---
+
+要开始使用 Angular Challenges,请按照以下步骤操作:
+
+## 创建一个GitHub账户
+
+如果你想提交答案,你需要拥有自己的GitHub账户。此外,拥有GitHub账户总是有益的,而且是免费的。
+
+## Fork GitHub 项目
+
+导航至 [Angular Challenges Repository](https://github.com/tomalaforge/angular-challenges) 在页面顶部点击 Fork 按钮。这将在您的 GitHub 个人资料中创建该存储库的副本。
+
+## 将存储库克隆到您的本地机器上
+
+在您的本地计算机上选择一个目录,然后克隆此存储库。
+
+打开终端,导航到选择的目录,并输入以下命令:
+
+```bash
+git clone https://github.com/[YOUR_GITHUB_NAME]/angular-challenges.git
+```
+
+:::note[注意]
+
+你可以通过点击Angular Challenges存储库中你自己的实例中的<> Code 按钮来找到克隆URL
+
+
+
+:::
+
+## 在您最喜欢的IDE中打开该项目
+
+使用您选择的任意集成开发环境(IDE)打开该项目。
+
+## 安装所有依赖项
+
+```bash
+npm ci
+```
+
+## 选择一个挑战
+
+您的项目现已启动并正在运行。剩下的唯一步骤是选择一个挑战 🚀
+
+每项挑战包括:
+
+- Name: 表示挑战的内容。
+- Number: 创建顺序。 这个数字没有任何特别的含义,但有助于在 GitHub Pull Request 部分进行参考。
+- Badge: 有助于可视化难度程度。这完全是主观的 😅
+ - 🟢 容易
+ - 🟠 中等
+ - 🔴 困难
+
+## (交替) 使用 GitHub Codespaces
+
+在你自己的 Angular Challenges 存储库实例中,单击代码按钮并导航到 codespaces 选项卡。
+
+
+
+单击 `Create codespace on main` 按钮, 您将导航到 GitHub codespace
+
+如果您以前从未使用过 GitHub codespace,我建议您尝试这个简短的交互式 [GitHub Skills Tutorial](https://github.com/skills/code-with-codespaces).
+
+当您导航到codespace时,将出现一个提示,要求安装推荐的 `VS Code` 插件。如果您打算创建一个挑战,您可以使用 `Nx plugin` 来生成开始代码。无论哪种方式,codespace都将安装依赖项,你可以创建一个新分支,解决任何挑战,并创建一个pull request。
+
+当您推送到分支时,您不必提供 GitHub 令牌。
+
+一旦你完成,记得暂停或删除你的codesace。如果不这样做,GitHub将在30分钟后自动暂停空闲的codesace。你每个月确实有大量的免费codespace时间,但重要的是不要浪费你的分配时间
+
+在GitHub codesace中,复制和粘贴将被阻止,直到你获得许可
+
+GitHub codespace使用端口转发为项目提供服务。单击运行 `npx nx serve [project-name]` 后的提示符,导航到 `localhost:4200` 。
diff --git a/docs/src/content/docs/zh-cn/guides/rebase.md b/docs/src/content/docs/zh-cn/guides/rebase.md
new file mode 100644
index 000000000..a88ec24a6
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/rebase.md
@@ -0,0 +1,57 @@
+---
+title: 变基分支
+description: 将分支变基到最新更改的指南
+contributors:
+ - tomalaforge
+sidebar:
+ order: 6
+---
+
+有时,可能会向项目添加更改。我会尝试做出不会破坏任何东西的更改,但有时这是不可避免的。
+
+大多数情况下,您不需要变基您的解决方案,但这里有一个指南可以帮助您知道如何操作。
+
+:::note[注意]
+本指南适用于任何开源项目。
+:::
+
+## 变基分支的步骤
+
+### 同步存储库
+
+首先,你需要同步你的分支,以确保它与分支的存储库是最新的。
+
+你可以通过点击你的fork主页面上的Sync fork按钮来实现这一点。
+
+
+
+上图显示我的分支比主分支落后 8 个提交,我需要将其同步才能保持最新。
+
+
+
+### 打开终端
+
+打开您选择的任何终端,可以是您最喜欢的 IDE 中的终端,也可以是独立实例。
+
+### Git
+
+请按照以下命令重新设置本地分支的基础:
+
+- git checkout main
+- git pull
+- git checkout [你的分支]
+- git rebase main
+- 解决冲突
+
+在此步骤中,变基可能会停止,因为您的本地分支与主分支有冲突的文件。纠正它们。完成此操作后:
+
+- git add .
+- git rebase --continue
+
+如果您的分支没有任何冲突,则会显示成功消息。
+
+### 将你的工作推送到远程分支
+
+最后,将你的工作推送到GitHub:
+
+- git push -f
diff --git a/docs/src/content/docs/zh-cn/guides/resolve-challenge.md b/docs/src/content/docs/zh-cn/guides/resolve-challenge.md
new file mode 100644
index 000000000..a943fb311
--- /dev/null
+++ b/docs/src/content/docs/zh-cn/guides/resolve-challenge.md
@@ -0,0 +1,107 @@
+---
+title: 解决挑战
+description: 解决挑战指南
+contributors:
+ - tomalaforge
+ - 1fbr
+ - gsgonzalez88
+sidebar:
+ order: 2
+---
+
+在本指南中,您将学习如何解决挑战并向主GitHub存储库提交答案。
+
+## 介绍
+
+此存储库由 [Nx](https://nx.dev/getting-started/intro) 提供支持。Nx是一个 monorepository,允许您将多个应用程序存储在同一个工作区中。每个挑战都是一个单独的应用程序。如果您打开`apps`目录,您将找到多个目录,每个目录都与一个特定的挑战相关。每个目录都代表一个完整的独立的`Nx`应用程序。想要运行并从某个开始,请打开您的终端并运行:
+
+```bash
+npx nx serve
+```
+
+:::note[注意]
+如果您不确定 `APPLICATION_NAME` ,请打开README.md文件。 `serve` 命令写在那里,并有一个到挑战文档的链接。
+:::
+
+:::note[注意]
+
+如果您的设备已全局安装 `nx` ,则可以跳过使用 `npx`
+
+要全局安装 `nx` ,使用
+
+```bash
+npm i -g nx
+```
+
+:::
+
+## 创建 Git 分支
+
+在你开始实现解决挑战的解决方案之前,创建一个git分支来提交你的工作。
+
+```bash
+git checkout -b
+```
+
+## 完成挑战
+
+按照说明来完成挑战。
+
+## 提交和推送您的工作
+
+最后一步是按照常规的[指导方针](https://www.conventionalcommits.org/en/v1.0.0/)提交工作
+
+最后,使用以下命令将工作推送到远程仓库
+
+```bash
+ git push --set-upstream origin
+```
+
+:::tip[不用去记]
+你不必精确地记住这个命令。你只需要记住 `git push` ,如果这是你第一次推送这个分支, `git` 将为你提供完整的命令。
+:::
+
+## 将您的工作提交到主仓库
+
+现在,你所有的工作都位于Angular Challenges仓库的本地实例中。
+
+下一步是转到Angular的主要[挑战页面](https://github.com/tomalaforge/angular-challenges),并创建一个新的Pull Request。
+
+GitHub应该显示一个通知头来帮助你创建拉取请求。
+
+如果不是这样,要么是你错误地执行了前面的某个步骤,要么你可以转到Pull Request选项卡并点击New pull request按钮
+
+一旦你选择了要比较的两个分支,就会看到下面的页面:
+
+
+
+在标题部分,以Answer:开始,然后是你的挑战号。之后,您可以随意添加任何您想要的内容
+
+:::danger[危险]
+这非常重要。它让别人知道你试图解决的是什么挑战。
+:::
+
+在描述部分,您可以添加您遇到的问题、麻烦或任何其他您想要分享的内容。如果你没什么可说的,可以把它空着
+
+现在你可以点击 Create pull request.
+
+## 获取审查
+
+为了继续提供有价值的反馈和评论,请在Github上支持这个项目:
+
+