fix: many grammar tweaks (#957)

* fix: many grammar tweaks

Fix some typos.
Follow some non-obvious English punctuation rules.
remove duplicate md files for 50.
Add some links for Angular Testing Library
Remove inconsistent colons after "Constraints" headers
Fix a broken link on 9.
Chrome's tab is "Elements", not "source"
Add missing challenges to the performance page
Similar changes

* fix: add LMFinney as contributor on tweaked files
This commit is contained in:
Lance Finney
2024-05-23 09:04:13 -05:00
committed by GitHub
parent 0a9ee99841
commit 7cc1d2d61c
40 changed files with 150 additions and 115 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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
<ng-container *ngIf="persons.length > 0; else emptyList">

View File

@@ -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

View File

@@ -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

View File

@@ -1,10 +1,11 @@
---
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
sidebar:

View File

@@ -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.
![Unkown Person](../../../../assets/4/unknown-person.png 'Unkown Person')
![Unknown Person](../../../../assets/4/unknown-person.png 'Unknown Person')
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.
![Unkown Student](../../../../assets/4/unknown-student.png 'Unkown Student')
![Unknown Student](../../../../assets/4/unknown-student.png 'Unknown Student')
As we can see, `student` is of type `any`. We want to infer the correct type using the custom directive `ListDirective`.

View File

@@ -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.

View File

@@ -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
<details>
<summary>Hint 2 - Initialization</summary>
Create a react root with `createRoot(...)`
Create a React root with `createRoot(...)`
</details>
<details>
@@ -76,5 +77,5 @@ npm i --save-dev @types/react @types/react-dom
<details>
<summary>Hint 4 - Design</summary>
Do not forget to allow the react file in Tailwind.
Do not forget to allow the React file in Tailwind.
</details>

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.\

View File

@@ -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

View File

@@ -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.

View File

@@ -7,6 +7,7 @@ contributors:
- tomer953
- svenson95
- jdegand
- LMFinney
challengeNumber: 2
command: ngrx-effect-vs-selector
blogLink: https://medium.com/@thomas.laforge/ngrx-effect-vs-reducer-vs-selector-58337ab59043
@@ -14,22 +15,22 @@ sidebar:
order: 113
---
For this exercise, you will have a dashboard of activities displaying the name, the main teacher and a list of subtitutes.
For this exercise, you will have a dashboard of activities displaying the name, the main teacher and a list of possible substitutes.
## 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.
In NgRx, **selectors** is a very powerful tool that is 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**.
- 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**.
- Inside a component, you shouldn't transform a selector (using the map operator), and you shouldn't have to call a selector from a function in your view. The useful logic for preparing data for a component should be done in a **selector**.
## Statement
You will have to Refactor this working example of a dashboard of activities.
You will have to refactor this working example of a dashboard of activities.
## Contraints:
## Constraints
- 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.
- Only **one action** should be dispatched from a component (or none, if you can solve the problem with Effect lifecycle hooks).
- Status effect is useless. Using **combineLatest** should be a red flag. Effects are made for side effects, not for transforming data. That's a selector's role.
- Status state might not be useful; it's only a **derived state** of existing state.

View File

@@ -1,11 +1,12 @@
---
title: 🔴 Power of Effect
description: Challenge 7 is about creating an Ngrx effect with another Rxjs Hot observable
description: Challenge 7 is about creating an NgRx effect with another Rxjs Hot observable
author: thomas-laforge
contributors:
- tomalaforge
- tomer953
- jdegand
- LMFinney
challengeNumber: 7
command: ngrx-power-of-effect
sidebar:
@@ -28,11 +29,11 @@ Create an injection token to `inject` the push service inside each component. In
_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.
Since the notification service is global, all component lists update, even if a user is not 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.
Create one NgRx effect or component store effect for each push type, and implement your logic.
### Step 3

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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
<details>
<summary>Hint 1</summary>
Use `Pipes` to memoize the Fibonnaci computation.
Use `Pipes` to memoize the Fibonacci computation.
</details>

View File

@@ -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 <b>source</b> 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 <b>Elements</b> 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).
<video controls src="https://github.com/tomalaforge/angular-challenges/assets/30832608/71b90307-3ee3-42c0-a532-b67ce4f20bf6">
</video>

View File

@@ -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 <b>Source</b> 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 <b>Elements</b> 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 <b>Angular DevTool</b> to profile our application and understand what is happening inside our application. I will show you how to do it inside the following video.

View File

@@ -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 <b>Angular DevTool</b>, you can choose a challe
href="/challenges/performance/35-memoization/"
/>
<LinkCard
title="🟢 NgFor Optimization"
description="Learn how to improve looping performance."
href="/challenges/performance/36-ngfor-optimization/"
/>
<LinkCard
title="🟠 Optimize Change Detection"
description="Learn how to remove zone pollution."
href="/challenges/performance/12-optimize-change-detection/"
/>
<LinkCard
title="🟠 Optimize Big List"
description="Learn how to handle large lists."
href="/challenges/performance/37-optimize-big-list/"
/>
<LinkCard
title="🟠 Web workers"
description="Learn how to offload slow calculations."
href="/challenges/performance/40-web-worker/"
/>

View File

@@ -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.

View File

@@ -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,9 +19,9 @@ 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

View File

@@ -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

View File

@@ -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:
![prototype gif](../../../../assets/rxjs/49/prototype.gif)

View File

@@ -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

View File

@@ -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.

View File

@@ -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 <b>nested components</b>. `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. <b>Never test internal implementation details!!!</b>.
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 <b>nested components</b>. `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. <b>Never test internal implementation details!!!</b>.
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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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:

View File

@@ -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 <b>waits</b> 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.

View File

@@ -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 <b>Testing Library</b> or <b>Cypress Component Testing</b> 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 <b>Angular Testing Library</b> or <b>Cypress Component Testing</b> 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.
<LinkCard
title="🟢 Checkbox"
description="Learn how to debug your tests using Testing Library on a simple checkbox application"
description="Learn how to debug your tests using [Angular Testing Library](https://testing-library.com/) on a simple checkbox application"
href="/challenges/testing/28-checkbox/"
/>

View File

@@ -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.

View File

@@ -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 ...