Thomas Laforge
{{ date() }}
-
`,
host: {
class: 'flex flex-col justify-center items-center',
diff --git a/apps/angular/44-view-transition/src/app/post/post.component.ts b/apps/angular/44-view-transition/src/app/post/post.component.ts
new file mode 100644
index 000000000..edb87f780
--- /dev/null
+++ b/apps/angular/44-view-transition/src/app/post/post.component.ts
@@ -0,0 +1,46 @@
+import { NgOptimizedImage } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ input,
+} from '@angular/core';
+import { RouterLink } from '@angular/router';
+import { ThumbnailHeaderComponent } from '../blog/thumbnail-header.component';
+import { fakeTextChapters, posts } from '../data';
+import { PostHeaderComponent } from './post-header.component';
+
+@Component({
+ selector: 'post',
+ imports: [
+ ThumbnailHeaderComponent,
+ NgOptimizedImage,
+ PostHeaderComponent,
+ RouterLink,
+ ],
+ template: `
+
+
+
![]()
+
{{ post().title }}
+
+ @for (chapter of fakeTextChapter; track $index) {
+
{{ chapter }}
+ }
+
+ `,
+ host: {
+ class: 'flex h-full justify-center',
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export default class PostComponent {
+ id = input.required
();
+ post = computed(() => posts.filter((p) => p.id === this.id())[0]);
+
+ fakeTextChapter = fakeTextChapters;
+}
diff --git a/apps/angular/pipe-hard/src/assets/.gitkeep b/apps/angular/44-view-transition/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/pipe-hard/src/assets/.gitkeep
rename to apps/angular/44-view-transition/src/assets/.gitkeep
diff --git a/apps/angular/view-transition/src/assets/angular.webp b/apps/angular/44-view-transition/src/assets/angular.webp
similarity index 100%
rename from apps/angular/view-transition/src/assets/angular.webp
rename to apps/angular/44-view-transition/src/assets/angular.webp
diff --git a/apps/angular/view-transition/src/assets/guard.full.webp b/apps/angular/44-view-transition/src/assets/guard.full.webp
similarity index 100%
rename from apps/angular/view-transition/src/assets/guard.full.webp
rename to apps/angular/44-view-transition/src/assets/guard.full.webp
diff --git a/apps/angular/view-transition/src/assets/highly-custom.full.webp b/apps/angular/44-view-transition/src/assets/highly-custom.full.webp
similarity index 100%
rename from apps/angular/view-transition/src/assets/highly-custom.full.webp
rename to apps/angular/44-view-transition/src/assets/highly-custom.full.webp
diff --git a/apps/angular/view-transition/src/assets/profil.webp b/apps/angular/44-view-transition/src/assets/profil.webp
similarity index 100%
rename from apps/angular/view-transition/src/assets/profil.webp
rename to apps/angular/44-view-transition/src/assets/profil.webp
diff --git a/apps/angular/view-transition/src/assets/signal-cd.full.webp b/apps/angular/44-view-transition/src/assets/signal-cd.full.webp
similarity index 100%
rename from apps/angular/view-transition/src/assets/signal-cd.full.webp
rename to apps/angular/44-view-transition/src/assets/signal-cd.full.webp
diff --git a/apps/angular/pipe-hard/src/favicon.ico b/apps/angular/44-view-transition/src/favicon.ico
similarity index 100%
rename from apps/angular/pipe-hard/src/favicon.ico
rename to apps/angular/44-view-transition/src/favicon.ico
diff --git a/apps/angular/view-transition/src/index.html b/apps/angular/44-view-transition/src/index.html
similarity index 100%
rename from apps/angular/view-transition/src/index.html
rename to apps/angular/44-view-transition/src/index.html
diff --git a/apps/angular/router-input/src/main.ts b/apps/angular/44-view-transition/src/main.ts
similarity index 100%
rename from apps/angular/router-input/src/main.ts
rename to apps/angular/44-view-transition/src/main.ts
diff --git a/apps/angular/44-view-transition/src/styles.scss b/apps/angular/44-view-transition/src/styles.scss
new file mode 100644
index 000000000..b5c61c956
--- /dev/null
+++ b/apps/angular/44-view-transition/src/styles.scss
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/apps/angular/permissions/tailwind.config.js b/apps/angular/44-view-transition/tailwind.config.js
similarity index 100%
rename from apps/angular/permissions/tailwind.config.js
rename to apps/angular/44-view-transition/tailwind.config.js
diff --git a/apps/angular/signal-input/tsconfig.app.json b/apps/angular/44-view-transition/tsconfig.app.json
similarity index 100%
rename from apps/angular/signal-input/tsconfig.app.json
rename to apps/angular/44-view-transition/tsconfig.app.json
diff --git a/apps/angular/styling/tsconfig.editor.json b/apps/angular/44-view-transition/tsconfig.editor.json
similarity index 100%
rename from apps/angular/styling/tsconfig.editor.json
rename to apps/angular/44-view-transition/tsconfig.editor.json
diff --git a/apps/angular/signal-input/tsconfig.json b/apps/angular/44-view-transition/tsconfig.json
similarity index 100%
rename from apps/angular/signal-input/tsconfig.json
rename to apps/angular/44-view-transition/tsconfig.json
diff --git a/apps/angular/permissions/.eslintrc.json b/apps/angular/45-react-in-angular/.eslintrc.json
similarity index 100%
rename from apps/angular/permissions/.eslintrc.json
rename to apps/angular/45-react-in-angular/.eslintrc.json
diff --git a/apps/angular/45-react-in-angular/README.md b/apps/angular/45-react-in-angular/README.md
new file mode 100644
index 000000000..0a8679ac4
--- /dev/null
+++ b/apps/angular/45-react-in-angular/README.md
@@ -0,0 +1,13 @@
+# React in angular
+
+> author: wandrille-guesdon
+
+### Run Application
+
+```bash
+npx nx serve angular-react-in-angular
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/45-react-in-angular/).
diff --git a/apps/angular/45-react-in-angular/jest.config.ts b/apps/angular/45-react-in-angular/jest.config.ts
new file mode 100644
index 000000000..cda19a635
--- /dev/null
+++ b/apps/angular/45-react-in-angular/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'angular-react-in-angular',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/angular/45-react-in-angular',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/angular/45-react-in-angular/project.json b/apps/angular/45-react-in-angular/project.json
new file mode 100644
index 000000000..bce6fe70e
--- /dev/null
+++ b/apps/angular/45-react-in-angular/project.json
@@ -0,0 +1,80 @@
+{
+ "name": "angular-react-in-angular",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/45-react-in-angular/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/45-react-in-angular",
+ "index": "apps/angular/45-react-in-angular/src/index.html",
+ "browser": "apps/angular/45-react-in-angular/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/45-react-in-angular/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/45-react-in-angular/src/favicon.ico",
+ "apps/angular/45-react-in-angular/src/assets"
+ ],
+ "styles": ["apps/angular/45-react-in-angular/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-react-in-angular:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-react-in-angular:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-react-in-angular:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/angular/45-react-in-angular/src/app/app.component.ts b/apps/angular/45-react-in-angular/src/app/app.component.ts
new file mode 100644
index 000000000..87b9675cc
--- /dev/null
+++ b/apps/angular/45-react-in-angular/src/app/app.component.ts
@@ -0,0 +1,61 @@
+import { Component, signal } from '@angular/core';
+import { PostComponent } from './react/post.component';
+
+type Post = { title: string; description: string };
+
+@Component({
+ imports: [PostComponent],
+ selector: 'app-root',
+ template: `
+
+
+ @for (post of posts; track post.title) {
+
+ }
+
+
+ Selected Post:
+
+ {{ selectedPost()?.title ?? '-' }}
+
+
+
+ `,
+ styles: [''],
+})
+export class AppComponent {
+ readonly posts = [
+ {
+ title: 'A Deep Dive into Angular',
+ description:
+ "Explore Angular's core features, its evolution, and best practices in development for creating dynamic, efficient web applications in our comprehensive guide.",
+ pictureLink:
+ 'https://images.unsplash.com/photo-1471958680802-1345a694ba6d',
+ },
+ {
+ title: 'The Perfect Combination',
+ description:
+ 'Unveil the power of combining Angular & React in web development, maximizing efficiency and flexibility for building scalable, sophisticated applications.',
+ pictureLink:
+ 'https://images.unsplash.com/photo-1518717202715-9fa9d099f58a',
+ },
+ {
+ title: 'Taking Angular to the Next Level',
+ description:
+ "Discover how integrating React with Angular elevates web development, blending Angular's structure with React's UI prowess for advanced applications.",
+ pictureLink:
+ 'https://images.unsplash.com/photo-1532103050105-860af53bc6aa',
+ },
+ ];
+
+ readonly selectedPost = signal(null);
+
+ selectPost(post: Post) {
+ this.selectedPost.set(post);
+ }
+}
diff --git a/apps/angular/signal-input/src/app/app.config.ts b/apps/angular/45-react-in-angular/src/app/app.config.ts
similarity index 100%
rename from apps/angular/signal-input/src/app/app.config.ts
rename to apps/angular/45-react-in-angular/src/app/app.config.ts
diff --git a/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx b/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx
new file mode 100644
index 000000000..3f6b9e4cd
--- /dev/null
+++ b/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx
@@ -0,0 +1,29 @@
+// import React from 'react';
+
+export default function ReactPost(props: {
+ title?: string;
+ description?: string;
+ pictureLink?: string;
+ selected?: boolean;
+ handleClick: () => void;
+}) {
+ return (
+
+
+

+
+
{props.title}
+
{props.description}
+
+
+
+
+ );
+}
diff --git a/apps/angular/45-react-in-angular/src/app/react/post.component.ts b/apps/angular/45-react-in-angular/src/app/react/post.component.ts
new file mode 100644
index 000000000..2a35eaca6
--- /dev/null
+++ b/apps/angular/45-react-in-angular/src/app/react/post.component.ts
@@ -0,0 +1,17 @@
+import { Component, EventEmitter, input, Output } from '@angular/core';
+
+type Post = { title: string; description: string; pictureLink: string };
+
+@Component({
+ standalone: true,
+ selector: 'app-post',
+ template: `
+
+ `,
+ styles: [''],
+})
+export class PostComponent {
+ post = input(undefined);
+ isSelected = input(false);
+ @Output() selectPost = new EventEmitter();
+}
diff --git a/apps/angular/pipe-intermediate/src/assets/.gitkeep b/apps/angular/45-react-in-angular/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/pipe-intermediate/src/assets/.gitkeep
rename to apps/angular/45-react-in-angular/src/assets/.gitkeep
diff --git a/apps/angular/pipe-intermediate/src/favicon.ico b/apps/angular/45-react-in-angular/src/favicon.ico
similarity index 100%
rename from apps/angular/pipe-intermediate/src/favicon.ico
rename to apps/angular/45-react-in-angular/src/favicon.ico
diff --git a/apps/angular/45-react-in-angular/src/index.html b/apps/angular/45-react-in-angular/src/index.html
new file mode 100644
index 000000000..9d9dd3923
--- /dev/null
+++ b/apps/angular/45-react-in-angular/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-react-in-angular
+
+
+
+
+
+
+
+
diff --git a/apps/angular/signal-input/src/main.ts b/apps/angular/45-react-in-angular/src/main.ts
similarity index 100%
rename from apps/angular/signal-input/src/main.ts
rename to apps/angular/45-react-in-angular/src/main.ts
diff --git a/apps/angular/module-to-standalone/src/styles.scss b/apps/angular/45-react-in-angular/src/styles.scss
similarity index 100%
rename from apps/angular/module-to-standalone/src/styles.scss
rename to apps/angular/45-react-in-angular/src/styles.scss
diff --git a/apps/angular/injection-token/src/test-setup.ts b/apps/angular/45-react-in-angular/src/test-setup.ts
similarity index 100%
rename from apps/angular/injection-token/src/test-setup.ts
rename to apps/angular/45-react-in-angular/src/test-setup.ts
diff --git a/apps/angular/projection/tailwind.config.js b/apps/angular/45-react-in-angular/tailwind.config.js
similarity index 100%
rename from apps/angular/projection/tailwind.config.js
rename to apps/angular/45-react-in-angular/tailwind.config.js
diff --git a/apps/angular/styling/tsconfig.app.json b/apps/angular/45-react-in-angular/tsconfig.app.json
similarity index 100%
rename from apps/angular/styling/tsconfig.app.json
rename to apps/angular/45-react-in-angular/tsconfig.app.json
diff --git a/apps/angular/interop-rxjs-signal/tsconfig.editor.json b/apps/angular/45-react-in-angular/tsconfig.editor.json
similarity index 100%
rename from apps/angular/interop-rxjs-signal/tsconfig.editor.json
rename to apps/angular/45-react-in-angular/tsconfig.editor.json
diff --git a/apps/forms/control-value-accessor/tsconfig.json b/apps/angular/45-react-in-angular/tsconfig.json
similarity index 100%
rename from apps/forms/control-value-accessor/tsconfig.json
rename to apps/angular/45-react-in-angular/tsconfig.json
diff --git a/apps/forms/control-value-accessor/tsconfig.spec.json b/apps/angular/45-react-in-angular/tsconfig.spec.json
similarity index 100%
rename from apps/forms/control-value-accessor/tsconfig.spec.json
rename to apps/angular/45-react-in-angular/tsconfig.spec.json
diff --git a/apps/angular/pipe-easy/.eslintrc.json b/apps/angular/46-simple-animations/.eslintrc.json
similarity index 100%
rename from apps/angular/pipe-easy/.eslintrc.json
rename to apps/angular/46-simple-animations/.eslintrc.json
diff --git a/apps/angular/46-simple-animations/README.md b/apps/angular/46-simple-animations/README.md
new file mode 100644
index 000000000..87e6c7e7c
--- /dev/null
+++ b/apps/angular/46-simple-animations/README.md
@@ -0,0 +1,13 @@
+# Simple Animations
+
+> author: sven-brodny
+
+### Run Application
+
+```bash
+npx nx serve angular-simple-animations
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/46-simple-animations/).
diff --git a/apps/angular/46-simple-animations/jest.config.ts b/apps/angular/46-simple-animations/jest.config.ts
new file mode 100644
index 000000000..2ad20837f
--- /dev/null
+++ b/apps/angular/46-simple-animations/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'angular-simple-animations',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/angular/46-simple-animations',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/angular/46-simple-animations/project.json b/apps/angular/46-simple-animations/project.json
new file mode 100644
index 000000000..1d00fd246
--- /dev/null
+++ b/apps/angular/46-simple-animations/project.json
@@ -0,0 +1,80 @@
+{
+ "name": "angular-simple-animations",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/46-simple-animations/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/46-simple-animations",
+ "index": "apps/angular/46-simple-animations/src/index.html",
+ "browser": "apps/angular/46-simple-animations/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/46-simple-animations/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/46-simple-animations/src/favicon.ico",
+ "apps/angular/46-simple-animations/src/assets"
+ ],
+ "styles": ["apps/angular/46-simple-animations/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-simple-animations:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-simple-animations:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-simple-animations:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/angular/46-simple-animations/src/app/app.component.ts b/apps/angular/46-simple-animations/src/app/app.component.ts
new file mode 100644
index 000000000..ae63db419
--- /dev/null
+++ b/apps/angular/46-simple-animations/src/app/app.component.ts
@@ -0,0 +1,87 @@
+import { Component } from '@angular/core';
+
+@Component({
+ imports: [],
+ selector: 'app-root',
+ styles: `
+ section {
+ @apply flex flex-1 flex-col gap-5;
+ }
+
+ .list-item {
+ @apply flex flex-row border-b px-5 pb-2;
+
+ span {
+ @apply flex-1;
+ }
+ }
+ `,
+ template: `
+
+
+
+
2008
+
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae
+ mollitia sequi accusantium, distinctio similique laudantium eveniet
+ quidem sit placeat possimus tempore dolorum inventore corporis atque
+ quae ad, nobis explicabo delectus.
+
+
+
+
+
2010
+
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae
+ mollitia sequi accusantium, distinctio similique laudantium eveniet
+ quidem sit placeat possimus tempore dolorum inventore corporis atque
+ quae ad, nobis explicabo delectus.
+
+
+
+
+
2012
+
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae
+ mollitia sequi accusantium, distinctio similique laudantium eveniet
+ quidem sit placeat possimus tempore dolorum inventore corporis atque
+ quae ad, nobis explicabo delectus.
+
+
+
+
+
+
+ Name:
+ Samuel
+
+
+
+ Age:
+ 28
+
+
+
+ Birthdate:
+ 02.11.1995
+
+
+
+ City:
+ Berlin
+
+
+
+ Language:
+ English
+
+
+
+ Like Pizza:
+ Hell yeah
+
+
+
+ `,
+})
+export class AppComponent {}
diff --git a/apps/angular/46-simple-animations/src/app/app.config.ts b/apps/angular/46-simple-animations/src/app/app.config.ts
new file mode 100644
index 000000000..81a6edde4
--- /dev/null
+++ b/apps/angular/46-simple-animations/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig } from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [],
+};
diff --git a/apps/angular/projection/src/assets/.gitkeep b/apps/angular/46-simple-animations/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/projection/src/assets/.gitkeep
rename to apps/angular/46-simple-animations/src/assets/.gitkeep
diff --git a/apps/angular/projection/src/favicon.ico b/apps/angular/46-simple-animations/src/favicon.ico
similarity index 100%
rename from apps/angular/projection/src/favicon.ico
rename to apps/angular/46-simple-animations/src/favicon.ico
diff --git a/apps/angular/46-simple-animations/src/index.html b/apps/angular/46-simple-animations/src/index.html
new file mode 100644
index 000000000..8fbebf9fb
--- /dev/null
+++ b/apps/angular/46-simple-animations/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-simple-animations
+
+
+
+
+
+
+
+
diff --git a/apps/angular/view-transition/src/main.ts b/apps/angular/46-simple-animations/src/main.ts
similarity index 100%
rename from apps/angular/view-transition/src/main.ts
rename to apps/angular/46-simple-animations/src/main.ts
diff --git a/apps/angular/permissions/src/styles.scss b/apps/angular/46-simple-animations/src/styles.scss
similarity index 100%
rename from apps/angular/permissions/src/styles.scss
rename to apps/angular/46-simple-animations/src/styles.scss
diff --git a/apps/angular/interop-rxjs-signal/src/test-setup.ts b/apps/angular/46-simple-animations/src/test-setup.ts
similarity index 100%
rename from apps/angular/interop-rxjs-signal/src/test-setup.ts
rename to apps/angular/46-simple-animations/src/test-setup.ts
diff --git a/apps/angular/signal-input/tailwind.config.js b/apps/angular/46-simple-animations/tailwind.config.js
similarity index 100%
rename from apps/angular/signal-input/tailwind.config.js
rename to apps/angular/46-simple-animations/tailwind.config.js
diff --git a/apps/angular/view-transition/tsconfig.app.json b/apps/angular/46-simple-animations/tsconfig.app.json
similarity index 100%
rename from apps/angular/view-transition/tsconfig.app.json
rename to apps/angular/46-simple-animations/tsconfig.app.json
diff --git a/apps/forms/control-value-accessor/tsconfig.editor.json b/apps/angular/46-simple-animations/tsconfig.editor.json
similarity index 100%
rename from apps/forms/control-value-accessor/tsconfig.editor.json
rename to apps/angular/46-simple-animations/tsconfig.editor.json
diff --git a/apps/angular/46-simple-animations/tsconfig.json b/apps/angular/46-simple-animations/tsconfig.json
new file mode 100644
index 000000000..25ca437b4
--- /dev/null
+++ b/apps/angular/46-simple-animations/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ },
+ {
+ "path": "./tsconfig.editor.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/performance/ngfor-optimize/tsconfig.spec.json b/apps/angular/46-simple-animations/tsconfig.spec.json
similarity index 100%
rename from apps/performance/ngfor-optimize/tsconfig.spec.json
rename to apps/angular/46-simple-animations/tsconfig.spec.json
diff --git a/apps/angular/pipe-hard/.eslintrc.json b/apps/angular/5-crud-application/.eslintrc.json
similarity index 100%
rename from apps/angular/pipe-hard/.eslintrc.json
rename to apps/angular/5-crud-application/.eslintrc.json
diff --git a/apps/angular/5-crud-application/README.md b/apps/angular/5-crud-application/README.md
new file mode 100644
index 000000000..8992014e3
--- /dev/null
+++ b/apps/angular/5-crud-application/README.md
@@ -0,0 +1,13 @@
+# Crud application
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-crud-application
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/5-crud/).
diff --git a/apps/angular/5-crud-application/jest.config.ts b/apps/angular/5-crud-application/jest.config.ts
new file mode 100644
index 000000000..f290dd70a
--- /dev/null
+++ b/apps/angular/5-crud-application/jest.config.ts
@@ -0,0 +1,23 @@
+/* eslint-disable */
+export default {
+ displayName: 'angular-crud-application',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ globals: {},
+ coverageDirectory: '../../../coverage/apps/angular/5-crud-application',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/angular/5-crud-application/project.json b/apps/angular/5-crud-application/project.json
new file mode 100644
index 000000000..cdad9374a
--- /dev/null
+++ b/apps/angular/5-crud-application/project.json
@@ -0,0 +1,87 @@
+{
+ "name": "angular-crud-application",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/angular/5-crud-application/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/5-crud-application",
+ "index": "apps/angular/5-crud-application/src/index.html",
+ "main": "apps/angular/5-crud-application/src/main.ts",
+ "polyfills": "apps/angular/5-crud-application/src/polyfills.ts",
+ "tsConfig": "apps/angular/5-crud-application/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/5-crud-application/src/favicon.ico",
+ "apps/angular/5-crud-application/src/assets"
+ ],
+ "styles": [
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
+ "apps/angular/5-crud-application/src/styles.scss"
+ ],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-crud-application:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-crud-application:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-crud-application:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/angular/5-crud-application/src/app/app.component.ts b/apps/angular/5-crud-application/src/app/app.component.ts
new file mode 100644
index 000000000..9152ff5e4
--- /dev/null
+++ b/apps/angular/5-crud-application/src/app/app.component.ts
@@ -0,0 +1,50 @@
+import { CommonModule } from '@angular/common';
+import { HttpClient } from '@angular/common/http';
+import { Component, OnInit } from '@angular/core';
+import { randText } from '@ngneat/falso';
+
+@Component({
+ imports: [CommonModule],
+ selector: 'app-root',
+ template: `
+
+ {{ todo.title }}
+
+
+ `,
+ styles: [],
+})
+export class AppComponent implements OnInit {
+ todos!: any[];
+
+ constructor(private http: HttpClient) {}
+
+ ngOnInit(): void {
+ this.http
+ .get('https://jsonplaceholder.typicode.com/todos')
+ .subscribe((todos) => {
+ this.todos = todos;
+ });
+ }
+
+ update(todo: any) {
+ this.http
+ .put(
+ `https://jsonplaceholder.typicode.com/todos/${todo.id}`,
+ JSON.stringify({
+ todo: todo.id,
+ title: randText(),
+ body: todo.body,
+ userId: todo.userId,
+ }),
+ {
+ headers: {
+ 'Content-type': 'application/json; charset=UTF-8',
+ },
+ },
+ )
+ .subscribe((todoUpdated: any) => {
+ this.todos[todoUpdated.id - 1] = todoUpdated;
+ });
+ }
+}
diff --git a/apps/angular/5-crud-application/src/app/app.config.ts b/apps/angular/5-crud-application/src/app/app.config.ts
new file mode 100644
index 000000000..1c0c9422f
--- /dev/null
+++ b/apps/angular/5-crud-application/src/app/app.config.ts
@@ -0,0 +1,6 @@
+import { provideHttpClient } from '@angular/common/http';
+import { ApplicationConfig } from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideHttpClient()],
+};
diff --git a/apps/angular/router-input/src/assets/.gitkeep b/apps/angular/5-crud-application/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/router-input/src/assets/.gitkeep
rename to apps/angular/5-crud-application/src/assets/.gitkeep
diff --git a/apps/angular/router-input/src/favicon.ico b/apps/angular/5-crud-application/src/favicon.ico
similarity index 100%
rename from apps/angular/router-input/src/favicon.ico
rename to apps/angular/5-crud-application/src/favicon.ico
diff --git a/apps/angular/5-crud-application/src/index.html b/apps/angular/5-crud-application/src/index.html
new file mode 100644
index 000000000..b9ec0b609
--- /dev/null
+++ b/apps/angular/5-crud-application/src/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+ angular-crud-application
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/angular/crud/src/main.ts b/apps/angular/5-crud-application/src/main.ts
similarity index 100%
rename from apps/angular/crud/src/main.ts
rename to apps/angular/5-crud-application/src/main.ts
diff --git a/apps/angular/pipe-easy/src/polyfills.ts b/apps/angular/5-crud-application/src/polyfills.ts
similarity index 100%
rename from apps/angular/pipe-easy/src/polyfills.ts
rename to apps/angular/5-crud-application/src/polyfills.ts
diff --git a/apps/angular/crud/src/styles.scss b/apps/angular/5-crud-application/src/styles.scss
similarity index 100%
rename from apps/angular/crud/src/styles.scss
rename to apps/angular/5-crud-application/src/styles.scss
diff --git a/apps/forms/control-value-accessor/src/test-setup.ts b/apps/angular/5-crud-application/src/test-setup.ts
similarity index 100%
rename from apps/forms/control-value-accessor/src/test-setup.ts
rename to apps/angular/5-crud-application/src/test-setup.ts
diff --git a/apps/angular/pipe-easy/tsconfig.app.json b/apps/angular/5-crud-application/tsconfig.app.json
similarity index 100%
rename from apps/angular/pipe-easy/tsconfig.app.json
rename to apps/angular/5-crud-application/tsconfig.app.json
diff --git a/apps/angular/permissions/tsconfig.editor.json b/apps/angular/5-crud-application/tsconfig.editor.json
similarity index 100%
rename from apps/angular/permissions/tsconfig.editor.json
rename to apps/angular/5-crud-application/tsconfig.editor.json
diff --git a/apps/angular/projection/tsconfig.json b/apps/angular/5-crud-application/tsconfig.json
similarity index 100%
rename from apps/angular/projection/tsconfig.json
rename to apps/angular/5-crud-application/tsconfig.json
diff --git a/apps/angular/crud/tsconfig.spec.json b/apps/angular/5-crud-application/tsconfig.spec.json
similarity index 100%
rename from apps/angular/crud/tsconfig.spec.json
rename to apps/angular/5-crud-application/tsconfig.spec.json
diff --git a/apps/angular/pipe-intermediate/.eslintrc.json b/apps/angular/52-lazy-load-component/.eslintrc.json
similarity index 100%
rename from apps/angular/pipe-intermediate/.eslintrc.json
rename to apps/angular/52-lazy-load-component/.eslintrc.json
diff --git a/apps/angular/52-lazy-load-component/README.md b/apps/angular/52-lazy-load-component/README.md
new file mode 100644
index 000000000..7da25f89b
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/README.md
@@ -0,0 +1,13 @@
+# lazy-load-component
+
+> author: lance-finney
+
+### Run Application
+
+```bash
+npx nx serve angular-lazy-load-component
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/52-lazy-load-component/).
diff --git a/apps/angular/52-lazy-load-component/jest.config.ts b/apps/angular/52-lazy-load-component/jest.config.ts
new file mode 100644
index 000000000..a0fd1100f
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'angular-lazy-load-component',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/angular/52-lazy-load-component',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/angular/52-lazy-load-component/project.json b/apps/angular/52-lazy-load-component/project.json
new file mode 100644
index 000000000..d3b28088a
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/project.json
@@ -0,0 +1,80 @@
+{
+ "name": "angular-lazy-load-component",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/52-lazy-load-component/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/52-lazy-load-component",
+ "index": "apps/angular/52-lazy-load-component/src/index.html",
+ "browser": "apps/angular/52-lazy-load-component/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/52-lazy-load-component/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/52-lazy-load-component/src/favicon.ico",
+ "apps/angular/52-lazy-load-component/src/assets"
+ ],
+ "styles": ["apps/angular/52-lazy-load-component/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-lazy-load-component:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-lazy-load-component:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-lazy-load-component:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/angular/52-lazy-load-component/src/app/app.component.ts b/apps/angular/52-lazy-load-component/src/app/app.component.ts
new file mode 100644
index 000000000..6d8c03d29
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/app/app.component.ts
@@ -0,0 +1,23 @@
+import { Component, signal } from '@angular/core';
+
+@Component({
+ selector: 'app-root',
+ template: `
+
+ @if (topLoaded()) {
+
+ } @else {
+
+
+ }
+
+ `,
+ standalone: false,
+})
+export class AppComponent {
+ topLoaded = signal(false);
+}
diff --git a/apps/angular/52-lazy-load-component/src/app/app.module.ts b/apps/angular/52-lazy-load-component/src/app/app.module.ts
new file mode 100644
index 000000000..b5d430e67
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/app/app.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+import { PlaceholderComponent } from './placeholder.component';
+import { TopComponent } from './top.component';
+
+@NgModule({
+ declarations: [AppComponent, PlaceholderComponent, TopComponent],
+ imports: [BrowserModule],
+ bootstrap: [AppComponent],
+})
+export class AppModule {}
diff --git a/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts b/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts
new file mode 100644
index 000000000..cbb2b5fa6
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts
@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-placeholder',
+ template: `
+ I'm a placeholder component.
+ `,
+ styles: `
+ :host {
+ display: grid;
+ padding: 20px;
+ background-color: #f0f0f0;
+ height: 50%;
+ }
+ `,
+ standalone: false,
+})
+export class PlaceholderComponent {}
diff --git a/apps/angular/52-lazy-load-component/src/app/top.component.ts b/apps/angular/52-lazy-load-component/src/app/top.component.ts
new file mode 100644
index 000000000..e1ca9012c
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/app/top.component.ts
@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-top',
+ template: `
+ I am a very heavy, expensive component that should be lazy loaded.
+ `,
+ styles: `
+ :host {
+ display: grid;
+ padding: 20px;
+ background-color: #f0f0f0;
+ height: 50%;
+ }
+ `,
+ standalone: false,
+})
+export class TopComponent {}
diff --git a/apps/angular/signal-input/src/assets/.gitkeep b/apps/angular/52-lazy-load-component/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/signal-input/src/assets/.gitkeep
rename to apps/angular/52-lazy-load-component/src/assets/.gitkeep
diff --git a/apps/angular/signal-input/src/favicon.ico b/apps/angular/52-lazy-load-component/src/favicon.ico
similarity index 100%
rename from apps/angular/signal-input/src/favicon.ico
rename to apps/angular/52-lazy-load-component/src/favicon.ico
diff --git a/apps/angular/52-lazy-load-component/src/index.html b/apps/angular/52-lazy-load-component/src/index.html
new file mode 100644
index 000000000..242ec3e3f
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-lazy-load-component
+
+
+
+
+
+
+
+
diff --git a/apps/angular/52-lazy-load-component/src/main.ts b/apps/angular/52-lazy-load-component/src/main.ts
new file mode 100644
index 000000000..16de2365d
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/src/main.ts
@@ -0,0 +1,6 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app/app.module';
+
+platformBrowserDynamic()
+ .bootstrapModule(AppModule)
+ .catch((err) => console.error(err));
diff --git a/apps/angular/signal-input/src/styles.scss b/apps/angular/52-lazy-load-component/src/styles.scss
similarity index 100%
rename from apps/angular/signal-input/src/styles.scss
rename to apps/angular/52-lazy-load-component/src/styles.scss
diff --git a/apps/performance/ngfor-optimize/src/test-setup.ts b/apps/angular/52-lazy-load-component/src/test-setup.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/test-setup.ts
rename to apps/angular/52-lazy-load-component/src/test-setup.ts
diff --git a/apps/angular/view-transition/tailwind.config.js b/apps/angular/52-lazy-load-component/tailwind.config.js
similarity index 100%
rename from apps/angular/view-transition/tailwind.config.js
rename to apps/angular/52-lazy-load-component/tailwind.config.js
diff --git a/apps/forms/control-value-accessor/tsconfig.app.json b/apps/angular/52-lazy-load-component/tsconfig.app.json
similarity index 100%
rename from apps/forms/control-value-accessor/tsconfig.app.json
rename to apps/angular/52-lazy-load-component/tsconfig.app.json
diff --git a/apps/angular/52-lazy-load-component/tsconfig.editor.json b/apps/angular/52-lazy-load-component/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/52-lazy-load-component/tsconfig.json b/apps/angular/52-lazy-load-component/tsconfig.json
new file mode 100644
index 000000000..4383e7eb8
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/angular/52-lazy-load-component/tsconfig.spec.json b/apps/angular/52-lazy-load-component/tsconfig.spec.json
new file mode 100644
index 000000000..1a4817a7d
--- /dev/null
+++ b/apps/angular/52-lazy-load-component/tsconfig.spec.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["jest", "node", "@testing-library/jest-dom"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": [
+ "jest.config.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/apps/angular/signal-input/.eslintrc.json b/apps/angular/55-back-button-navigation/.eslintrc.json
similarity index 100%
rename from apps/angular/signal-input/.eslintrc.json
rename to apps/angular/55-back-button-navigation/.eslintrc.json
diff --git a/apps/angular/55-back-button-navigation/README.md b/apps/angular/55-back-button-navigation/README.md
new file mode 100644
index 000000000..2534d270c
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/README.md
@@ -0,0 +1,13 @@
+# Back-Button-Navigation
+
+> author: ioannis-tsironis
+
+### Run Application
+
+```bash
+npx nx serve angular-back-button-navigation
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/55-back-button-navigation/).
diff --git a/apps/angular/55-back-button-navigation/jest.config.ts b/apps/angular/55-back-button-navigation/jest.config.ts
new file mode 100644
index 000000000..845a03a01
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'angular-back-button-navigation',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/angular/55-back-button-navigation',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/angular/55-back-button-navigation/project.json b/apps/angular/55-back-button-navigation/project.json
new file mode 100644
index 000000000..f53d65e27
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/project.json
@@ -0,0 +1,85 @@
+{
+ "name": "angular-back-button-navigation",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/55-back-button-navigation/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/55-back-button-navigation",
+ "index": "apps/angular/55-back-button-navigation/src/index.html",
+ "browser": "apps/angular/55-back-button-navigation/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/55-back-button-navigation/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "apps/angular/55-back-button-navigation/public"
+ }
+ ],
+ "styles": [
+ "apps/angular/55-back-button-navigation/src/styles.scss",
+ "node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-back-button-navigation:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-back-button-navigation:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-back-button-navigation:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/angular/55-back-button-navigation/src/app/app.component.html b/apps/angular/55-back-button-navigation/src/app/app.component.html
new file mode 100644
index 000000000..0680b43f9
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/app.component.html
@@ -0,0 +1 @@
+
diff --git a/apps/angular/55-back-button-navigation/src/app/app.component.ts b/apps/angular/55-back-button-navigation/src/app/app.component.ts
new file mode 100644
index 000000000..baffdae25
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/app.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+import { RouterLink, RouterOutlet } from '@angular/router';
+
+@Component({
+ imports: [RouterOutlet, RouterLink],
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+})
+export class AppComponent {}
diff --git a/apps/angular/55-back-button-navigation/src/app/app.config.ts b/apps/angular/55-back-button-navigation/src/app/app.config.ts
new file mode 100644
index 000000000..440cdf2c3
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/app.config.ts
@@ -0,0 +1,10 @@
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+import { provideRouter } from '@angular/router';
+import { APP_ROUTES } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideZoneChangeDetection({ eventCoalescing: true }),
+ provideRouter(APP_ROUTES),
+ ],
+};
diff --git a/apps/angular/55-back-button-navigation/src/app/app.routes.ts b/apps/angular/55-back-button-navigation/src/app/app.routes.ts
new file mode 100644
index 000000000..7deecd57a
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/app.routes.ts
@@ -0,0 +1,24 @@
+import { Routes } from '@angular/router';
+import { HomeComponent } from './home/home.component';
+import { SensitiveActionComponent } from './sensitive-action/sensitive-action.component';
+import { SimpleActionComponent } from './simple-action/simple-action.component';
+
+export const APP_ROUTES: Routes = [
+ {
+ path: '',
+ pathMatch: 'full',
+ redirectTo: 'home',
+ },
+ {
+ path: 'home',
+ component: HomeComponent,
+ },
+ {
+ path: 'simple-action',
+ component: SimpleActionComponent,
+ },
+ {
+ path: 'sensitive-action',
+ component: SensitiveActionComponent,
+ },
+];
diff --git a/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html
new file mode 100644
index 000000000..ff00ea965
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html
@@ -0,0 +1,6 @@
+Delete file
+Would you like to delete cat.jpeg?
+
+
+
+
diff --git a/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts
new file mode 100644
index 000000000..9a9dd0fef
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts
@@ -0,0 +1,25 @@
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import {
+ MatDialogActions,
+ MatDialogClose,
+ MatDialogContent,
+ MatDialogRef,
+ MatDialogTitle,
+} from '@angular/material/dialog';
+
+@Component({
+ selector: 'app-dialog-dialog',
+ templateUrl: './dialog.component.html',
+ imports: [
+ MatButtonModule,
+ MatDialogActions,
+ MatDialogClose,
+ MatDialogTitle,
+ MatDialogContent,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DialogComponent {
+ readonly dialogRef = inject(MatDialogRef);
+}
diff --git a/apps/angular/55-back-button-navigation/src/app/home/home.component.html b/apps/angular/55-back-button-navigation/src/app/home/home.component.html
new file mode 100644
index 000000000..cce9e6d4f
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/home/home.component.html
@@ -0,0 +1,7 @@
+
+ Go to simple dialog action page
+
+
+
+ Go to sensitive dialog action page
+
diff --git a/apps/angular/55-back-button-navigation/src/app/home/home.component.ts b/apps/angular/55-back-button-navigation/src/app/home/home.component.ts
new file mode 100644
index 000000000..18c4147b1
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/home/home.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { RouterLink } from '@angular/router';
+
+@Component({
+ imports: [MatButtonModule, RouterLink],
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+})
+export class HomeComponent {}
diff --git a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html
new file mode 100644
index 000000000..bcb7382e9
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html
@@ -0,0 +1,3 @@
+
diff --git a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts
new file mode 100644
index 000000000..a97282c33
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts
@@ -0,0 +1,19 @@
+import { Component, inject } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialog } from '@angular/material/dialog';
+import { DialogComponent } from '../dialog/dialog.component';
+
+@Component({
+ imports: [MatButtonModule],
+ selector: 'app-sensitive-action',
+ templateUrl: './sensitive-action.component.html',
+})
+export class SensitiveActionComponent {
+ readonly #dialog = inject(MatDialog);
+
+ openDialog(): void {
+ this.#dialog.open(DialogComponent, {
+ width: '250px',
+ });
+ }
+}
diff --git a/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html
new file mode 100644
index 000000000..95f63e65e
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html
@@ -0,0 +1 @@
+
diff --git a/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts
new file mode 100644
index 000000000..fe97e7368
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts
@@ -0,0 +1,19 @@
+import { Component, inject } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialog } from '@angular/material/dialog';
+import { DialogComponent } from '../dialog/dialog.component';
+
+@Component({
+ imports: [MatButtonModule],
+ selector: 'app-simple-action',
+ templateUrl: './simple-action.component.html',
+})
+export class SimpleActionComponent {
+ readonly #dialog = inject(MatDialog);
+
+ openDialog(): void {
+ this.#dialog.open(DialogComponent, {
+ width: '250px',
+ });
+ }
+}
diff --git a/apps/angular/55-back-button-navigation/src/index.html b/apps/angular/55-back-button-navigation/src/index.html
new file mode 100644
index 000000000..4e657d614
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-back-button-navigation
+
+
+
+
+
+
+
+
diff --git a/apps/nx/static-dynamic-import/src/main.ts b/apps/angular/55-back-button-navigation/src/main.ts
similarity index 100%
rename from apps/nx/static-dynamic-import/src/main.ts
rename to apps/angular/55-back-button-navigation/src/main.ts
diff --git a/apps/angular/55-back-button-navigation/src/styles.scss b/apps/angular/55-back-button-navigation/src/styles.scss
new file mode 100644
index 000000000..acd290007
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/src/styles.scss
@@ -0,0 +1,29 @@
+@use '@angular/material' as mat;
+
+/* You can add global styles to this file, and also import other style files */
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@include mat.elevation-classes();
+@include mat.app-background();
+
+$theme-primary: mat.m2-define-palette(mat.$m2-indigo-palette);
+$theme-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400);
+
+$theme-warn: mat.m2-define-palette(mat.$m2-red-palette);
+
+$theme: mat.m2-define-light-theme(
+ (
+ color: (
+ primary: $theme-primary,
+ accent: $theme-accent,
+ warn: $theme-warn,
+ ),
+ typography: mat.m2-define-typography-config(),
+ )
+);
+
+@include mat.dialog-theme($theme);
+@include mat.button-theme($theme);
diff --git a/apps/rxjs/catch-error/src/test-setup.ts b/apps/angular/55-back-button-navigation/src/test-setup.ts
similarity index 100%
rename from apps/rxjs/catch-error/src/test-setup.ts
rename to apps/angular/55-back-button-navigation/src/test-setup.ts
diff --git a/apps/forms/control-value-accessor/tailwind.config.js b/apps/angular/55-back-button-navigation/tailwind.config.js
similarity index 100%
rename from apps/forms/control-value-accessor/tailwind.config.js
rename to apps/angular/55-back-button-navigation/tailwind.config.js
diff --git a/apps/nx/static-dynamic-import/tsconfig.app.json b/apps/angular/55-back-button-navigation/tsconfig.app.json
similarity index 100%
rename from apps/nx/static-dynamic-import/tsconfig.app.json
rename to apps/angular/55-back-button-navigation/tsconfig.app.json
diff --git a/apps/angular/55-back-button-navigation/tsconfig.editor.json b/apps/angular/55-back-button-navigation/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/55-back-button-navigation/tsconfig.json b/apps/angular/55-back-button-navigation/tsconfig.json
new file mode 100644
index 000000000..4383e7eb8
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/angular/55-back-button-navigation/tsconfig.spec.json b/apps/angular/55-back-button-navigation/tsconfig.spec.json
new file mode 100644
index 000000000..1a4817a7d
--- /dev/null
+++ b/apps/angular/55-back-button-navigation/tsconfig.spec.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["jest", "node", "@testing-library/jest-dom"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": [
+ "jest.config.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/apps/forms/control-value-accessor/.eslintrc.json b/apps/angular/57-content-projection-default/.eslintrc.json
similarity index 100%
rename from apps/forms/control-value-accessor/.eslintrc.json
rename to apps/angular/57-content-projection-default/.eslintrc.json
diff --git a/apps/angular/57-content-projection-default/README.md b/apps/angular/57-content-projection-default/README.md
new file mode 100644
index 000000000..fc4579558
--- /dev/null
+++ b/apps/angular/57-content-projection-default/README.md
@@ -0,0 +1,13 @@
+# Content Projection Default
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-content-projection-default
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/57-content-projection-default/).
diff --git a/apps/angular/57-content-projection-default/project.json b/apps/angular/57-content-projection-default/project.json
new file mode 100644
index 000000000..a57738bff
--- /dev/null
+++ b/apps/angular/57-content-projection-default/project.json
@@ -0,0 +1,81 @@
+{
+ "name": "angular-content-projection-default",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/57-content-projection-default/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/57-content-projection-default",
+ "index": "apps/angular/57-content-projection-default/src/index.html",
+ "browser": "apps/angular/57-content-projection-default/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/57-content-projection-default/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "apps/angular/57-content-projection-default/public"
+ }
+ ],
+ "styles": [
+ "apps/angular/57-content-projection-default/src/styles.scss"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "4kb",
+ "maximumError": "8kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-content-projection-default:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-content-projection-default:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-content-projection-default:build"
+ }
+ },
+ "serve-static": {
+ "executor": "@nx/web:file-server",
+ "options": {
+ "buildTarget": "angular-content-projection-default:build",
+ "staticFilePath": "dist/apps/angular/57-content-projection-default/browser",
+ "spa": true
+ }
+ }
+ }
+}
diff --git a/apps/angular/styling/src/favicon.ico b/apps/angular/57-content-projection-default/public/favicon.ico
similarity index 100%
rename from apps/angular/styling/src/favicon.ico
rename to apps/angular/57-content-projection-default/public/favicon.ico
diff --git a/apps/angular/57-content-projection-default/src/app/app.component.ts b/apps/angular/57-content-projection-default/src/app/app.component.ts
new file mode 100644
index 000000000..b3e370a34
--- /dev/null
+++ b/apps/angular/57-content-projection-default/src/app/app.component.ts
@@ -0,0 +1,16 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { CardComponent } from './card.component';
+
+@Component({
+ imports: [CardComponent],
+ selector: 'app-root',
+ template: `
+
+
+ `,
+ host: {
+ class: 'p-4 block flex flex-col gap-1',
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {}
diff --git a/apps/angular/57-content-projection-default/src/app/app.config.ts b/apps/angular/57-content-projection-default/src/app/app.config.ts
new file mode 100644
index 000000000..034603cfd
--- /dev/null
+++ b/apps/angular/57-content-projection-default/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideZoneChangeDetection({ eventCoalescing: true })],
+};
diff --git a/apps/angular/57-content-projection-default/src/app/card.component.ts b/apps/angular/57-content-projection-default/src/app/card.component.ts
new file mode 100644
index 000000000..851a6619d
--- /dev/null
+++ b/apps/angular/57-content-projection-default/src/app/card.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+
+@Component({
+ selector: 'app-card',
+ imports: [],
+ template: `
+ {{ title() }}
+ @if (message()) {
+ {{ message() }}
+ } @else {
+ Aucun message
+ }
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ host: {
+ class: 'p-4 border border-grey rounded-sm flex flex-col w-[200px]',
+ },
+})
+export class CardComponent {
+ title = input.required();
+ message = input(undefined);
+}
diff --git a/apps/angular/57-content-projection-default/src/index.html b/apps/angular/57-content-projection-default/src/index.html
new file mode 100644
index 000000000..8b3015d4b
--- /dev/null
+++ b/apps/angular/57-content-projection-default/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-content-projection-default
+
+
+
+
+
+
+
+
diff --git a/apps/performance/default-onpush/src/main.ts b/apps/angular/57-content-projection-default/src/main.ts
similarity index 100%
rename from apps/performance/default-onpush/src/main.ts
rename to apps/angular/57-content-projection-default/src/main.ts
diff --git a/apps/forms/control-value-accessor/src/styles.scss b/apps/angular/57-content-projection-default/src/styles.scss
similarity index 100%
rename from apps/forms/control-value-accessor/src/styles.scss
rename to apps/angular/57-content-projection-default/src/styles.scss
diff --git a/apps/nx/static-dynamic-import/tailwind.config.js b/apps/angular/57-content-projection-default/tailwind.config.js
similarity index 100%
rename from apps/nx/static-dynamic-import/tailwind.config.js
rename to apps/angular/57-content-projection-default/tailwind.config.js
diff --git a/apps/performance/christmas-web-worker/tsconfig.app.json b/apps/angular/57-content-projection-default/tsconfig.app.json
similarity index 100%
rename from apps/performance/christmas-web-worker/tsconfig.app.json
rename to apps/angular/57-content-projection-default/tsconfig.app.json
diff --git a/apps/angular/57-content-projection-default/tsconfig.editor.json b/apps/angular/57-content-projection-default/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/angular/57-content-projection-default/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/57-content-projection-default/tsconfig.json b/apps/angular/57-content-projection-default/tsconfig.json
new file mode 100644
index 000000000..1b86db04e
--- /dev/null
+++ b/apps/angular/57-content-projection-default/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/ngrx/effect-selector/.eslintrc.json b/apps/angular/58-content-projection-condition/.eslintrc.json
similarity index 100%
rename from apps/ngrx/effect-selector/.eslintrc.json
rename to apps/angular/58-content-projection-condition/.eslintrc.json
diff --git a/apps/angular/58-content-projection-condition/README.md b/apps/angular/58-content-projection-condition/README.md
new file mode 100644
index 000000000..755bd8854
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/README.md
@@ -0,0 +1,13 @@
+# Content Projection Condition
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-content-projection-condition
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/58-content-projection-condition/).
diff --git a/apps/angular/58-content-projection-condition/project.json b/apps/angular/58-content-projection-condition/project.json
new file mode 100644
index 000000000..42869e68b
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/project.json
@@ -0,0 +1,84 @@
+{
+ "name": "angular-content-projection-condition",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/58-content-projection-condition/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/58-content-projection-condition",
+ "index": "apps/angular/58-content-projection-condition/src/index.html",
+ "browser": "apps/angular/58-content-projection-condition/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/58-content-projection-condition/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "apps/angular/58-content-projection-condition/public"
+ }
+ ],
+ "styles": [
+ "apps/angular/58-content-projection-condition/src/styles.scss"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "4kb",
+ "maximumError": "8kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-content-projection-condition:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-content-projection-condition:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-content-projection-condition:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ },
+ "serve-static": {
+ "executor": "@nx/web:file-server",
+ "options": {
+ "buildTarget": "angular-content-projection-condition:build",
+ "staticFilePath": "dist/apps/angular/58-content-projection-condition/browser",
+ "spa": true
+ }
+ }
+ }
+}
diff --git a/apps/angular/view-transition/src/favicon.ico b/apps/angular/58-content-projection-condition/public/favicon.ico
similarity index 100%
rename from apps/angular/view-transition/src/favicon.ico
rename to apps/angular/58-content-projection-condition/public/favicon.ico
diff --git a/apps/angular/58-content-projection-condition/src/app/app.component.ts b/apps/angular/58-content-projection-condition/src/app/app.component.ts
new file mode 100644
index 000000000..afad56f22
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/src/app/app.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { CardComponent } from './card.component';
+
+@Component({
+ imports: [CardComponent],
+ selector: 'app-root',
+ template: `
+
+ Card 1
+ Message 1
+
+
+ Card 2
+ Message 2
+
+ `,
+ host: {
+ class: 'p-4 block flex flex-col gap-1',
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AppComponent {}
diff --git a/apps/angular/58-content-projection-condition/src/app/app.config.ts b/apps/angular/58-content-projection-condition/src/app/app.config.ts
new file mode 100644
index 000000000..034603cfd
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/src/app/app.config.ts
@@ -0,0 +1,5 @@
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideZoneChangeDetection({ eventCoalescing: true })],
+};
diff --git a/apps/angular/58-content-projection-condition/src/app/card.component.ts b/apps/angular/58-content-projection-condition/src/app/card.component.ts
new file mode 100644
index 000000000..46925977c
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/src/app/card.component.ts
@@ -0,0 +1,25 @@
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+
+@Component({
+ selector: 'app-card',
+ template: `
+ @if (small()) {
+
+
+ } @else {
+
+ }
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ host: {
+ class: 'p-4 border border-grey rounded-sm flex flex-col w-[200px]',
+ },
+})
+export class CardComponent {
+ small = input(false);
+}
diff --git a/apps/angular/58-content-projection-condition/src/index.html b/apps/angular/58-content-projection-condition/src/index.html
new file mode 100644
index 000000000..f1768ec71
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-content-projection-condition
+
+
+
+
+
+
+
+
diff --git a/apps/performance/memoized/src/main.ts b/apps/angular/58-content-projection-condition/src/main.ts
similarity index 100%
rename from apps/performance/memoized/src/main.ts
rename to apps/angular/58-content-projection-condition/src/main.ts
diff --git a/apps/nx/static-dynamic-import/src/styles.scss b/apps/angular/58-content-projection-condition/src/styles.scss
similarity index 100%
rename from apps/nx/static-dynamic-import/src/styles.scss
rename to apps/angular/58-content-projection-condition/src/styles.scss
diff --git a/apps/performance/christmas-web-worker/tailwind.config.js b/apps/angular/58-content-projection-condition/tailwind.config.js
similarity index 100%
rename from apps/performance/christmas-web-worker/tailwind.config.js
rename to apps/angular/58-content-projection-condition/tailwind.config.js
diff --git a/apps/performance/default-onpush/tsconfig.app.json b/apps/angular/58-content-projection-condition/tsconfig.app.json
similarity index 100%
rename from apps/performance/default-onpush/tsconfig.app.json
rename to apps/angular/58-content-projection-condition/tsconfig.app.json
diff --git a/apps/angular/58-content-projection-condition/tsconfig.editor.json b/apps/angular/58-content-projection-condition/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/58-content-projection-condition/tsconfig.json b/apps/angular/58-content-projection-condition/tsconfig.json
new file mode 100644
index 000000000..1b86db04e
--- /dev/null
+++ b/apps/angular/58-content-projection-condition/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/angular/59-content-projection-defer/.eslintrc.json b/apps/angular/59-content-projection-defer/.eslintrc.json
new file mode 100644
index 000000000..995177b5b
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/.eslintrc.json
@@ -0,0 +1,37 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/component-class-suffix": "off",
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/angular/59-content-projection-defer/README.md b/apps/angular/59-content-projection-defer/README.md
new file mode 100644
index 000000000..f726842d1
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/README.md
@@ -0,0 +1,13 @@
+# content-projection-defer
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-content-projection-defer
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/59-content-projection-defer/).
diff --git a/apps/angular/59-content-projection-defer/project.json b/apps/angular/59-content-projection-defer/project.json
new file mode 100644
index 000000000..5572ab573
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/project.json
@@ -0,0 +1,82 @@
+{
+ "name": "angular-content-projection-defer",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/angular/59-content-projection-defer/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/59-content-projection-defer",
+ "index": "apps/angular/59-content-projection-defer/src/index.html",
+ "browser": "apps/angular/59-content-projection-defer/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/angular/59-content-projection-defer/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "apps/angular/59-content-projection-defer/public"
+ }
+ ],
+ "styles": ["apps/angular/59-content-projection-defer/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "4kb",
+ "maximumError": "8kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-content-projection-defer:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-content-projection-defer:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-content-projection-defer:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ },
+ "serve-static": {
+ "executor": "@nx/web:file-server",
+ "options": {
+ "buildTarget": "angular-content-projection-defer:build",
+ "staticFilePath": "dist/apps/angular/59-content-projection-defer/browser",
+ "spa": true
+ }
+ }
+ }
+}
diff --git a/apps/forms/control-value-accessor/src/favicon.ico b/apps/angular/59-content-projection-defer/public/favicon.ico
similarity index 100%
rename from apps/forms/control-value-accessor/src/favicon.ico
rename to apps/angular/59-content-projection-defer/public/favicon.ico
diff --git a/apps/angular/59-content-projection-defer/src/app/app.component.ts b/apps/angular/59-content-projection-defer/src/app/app.component.ts
new file mode 100644
index 000000000..ae40bc880
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/app.component.ts
@@ -0,0 +1,23 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { RouterLink, RouterOutlet } from '@angular/router';
+
+@Component({
+ imports: [RouterOutlet, RouterLink],
+ selector: 'app-root',
+ template: `
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ host: {
+ class: 'flex flex-col gap-2 ',
+ },
+})
+export class AppComponent {}
diff --git a/apps/angular/59-content-projection-defer/src/app/app.config.ts b/apps/angular/59-content-projection-defer/src/app/app.config.ts
new file mode 100644
index 000000000..faf4d099a
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/app.config.ts
@@ -0,0 +1,12 @@
+import { provideHttpClient } from '@angular/common/http';
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+import { provideRouter } from '@angular/router';
+import { appRoutes } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideZoneChangeDetection({ eventCoalescing: true }),
+ provideRouter(appRoutes),
+ provideHttpClient(),
+ ],
+};
diff --git a/apps/angular/59-content-projection-defer/src/app/app.routes.ts b/apps/angular/59-content-projection-defer/src/app/app.routes.ts
new file mode 100644
index 000000000..3ca1b67cc
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/app.routes.ts
@@ -0,0 +1,13 @@
+import { Route } from '@angular/router';
+
+export const appRoutes: Route[] = [
+ {
+ path: 'page-1',
+ loadComponent: () => import('./page-1').then((m) => m.Page1),
+ },
+ {
+ path: 'page-2',
+ loadComponent: () => import('./page-2').then((m) => m.Page2),
+ },
+ { path: '**', redirectTo: 'page-1' },
+];
diff --git a/apps/angular/59-content-projection-defer/src/app/expandable-card.ts b/apps/angular/59-content-projection-defer/src/app/expandable-card.ts
new file mode 100644
index 000000000..8f446ed80
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/expandable-card.ts
@@ -0,0 +1,54 @@
+import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
+
+@Component({
+ selector: 'app-expandable-card',
+ template: `
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ host: {
+ class: 'flex flex-col gap-2 ',
+ },
+})
+export class ExpandableCard {
+ public isExpanded = signal(false);
+}
diff --git a/apps/angular/59-content-projection-defer/src/app/page-1.ts b/apps/angular/59-content-projection-defer/src/app/page-1.ts
new file mode 100644
index 000000000..868d76959
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/page-1.ts
@@ -0,0 +1,10 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+@Component({
+ selector: 'app-page-1',
+ template: `
+ page1
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class Page1 {}
diff --git a/apps/angular/59-content-projection-defer/src/app/page-2.ts b/apps/angular/59-content-projection-defer/src/app/page-2.ts
new file mode 100644
index 000000000..5665466d8
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/app/page-2.ts
@@ -0,0 +1,43 @@
+import { httpResource } from '@angular/common/http';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ ResourceStatus,
+} from '@angular/core';
+import { ExpandableCard } from './expandable-card';
+
+interface Post {
+ id: number;
+ title: string;
+ body: string;
+ userId: number;
+}
+
+@Component({
+ selector: 'app-page-2',
+ template: `
+ page2
+
+ Load Post
+
+ @if (postResource.isLoading()) {
+ Loading...
+ } @else if (postResource.status() === ResourceStatus.Error) {
+ Error...
+ } @else {
+ @for (post of postResource.value(); track post.id) {
+
{{ post.title }}
+ }
+ }
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ imports: [ExpandableCard],
+})
+export class Page2 {
+ public postResource = httpResource(
+ 'https://jsonplaceholder.typicode.com/posts',
+ );
+ protected readonly ResourceStatus = ResourceStatus;
+}
diff --git a/apps/angular/59-content-projection-defer/src/index.html b/apps/angular/59-content-projection-defer/src/index.html
new file mode 100644
index 000000000..79f435fa6
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-content-projection-defer
+
+
+
+
+
+
+
+
diff --git a/apps/performance/ngfor-biglist/src/main.ts b/apps/angular/59-content-projection-defer/src/main.ts
similarity index 100%
rename from apps/performance/ngfor-biglist/src/main.ts
rename to apps/angular/59-content-projection-defer/src/main.ts
diff --git a/apps/performance/christmas-web-worker/src/styles.scss b/apps/angular/59-content-projection-defer/src/styles.scss
similarity index 100%
rename from apps/performance/christmas-web-worker/src/styles.scss
rename to apps/angular/59-content-projection-defer/src/styles.scss
diff --git a/apps/performance/default-onpush/tailwind.config.js b/apps/angular/59-content-projection-defer/tailwind.config.js
similarity index 100%
rename from apps/performance/default-onpush/tailwind.config.js
rename to apps/angular/59-content-projection-defer/tailwind.config.js
diff --git a/apps/performance/memoized/tsconfig.app.json b/apps/angular/59-content-projection-defer/tsconfig.app.json
similarity index 100%
rename from apps/performance/memoized/tsconfig.app.json
rename to apps/angular/59-content-projection-defer/tsconfig.app.json
diff --git a/apps/angular/59-content-projection-defer/tsconfig.editor.json b/apps/angular/59-content-projection-defer/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/angular/59-content-projection-defer/tsconfig.json b/apps/angular/59-content-projection-defer/tsconfig.json
new file mode 100644
index 000000000..1b86db04e
--- /dev/null
+++ b/apps/angular/59-content-projection-defer/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/ngrx/notification/.eslintrc.json b/apps/angular/6-structural-directive/.eslintrc.json
similarity index 100%
rename from apps/ngrx/notification/.eslintrc.json
rename to apps/angular/6-structural-directive/.eslintrc.json
diff --git a/apps/angular/6-structural-directive/README.md b/apps/angular/6-structural-directive/README.md
new file mode 100644
index 000000000..775b40981
--- /dev/null
+++ b/apps/angular/6-structural-directive/README.md
@@ -0,0 +1,13 @@
+# Structural Directive
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-structural-directive
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/6-permissions/).
diff --git a/apps/angular/6-structural-directive/project.json b/apps/angular/6-structural-directive/project.json
new file mode 100644
index 000000000..f803b0cb5
--- /dev/null
+++ b/apps/angular/6-structural-directive/project.json
@@ -0,0 +1,72 @@
+{
+ "name": "angular-structural-directive",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/angular/6-structural-directive/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/6-structural-directive",
+ "index": "apps/angular/6-structural-directive/src/index.html",
+ "main": "apps/angular/6-structural-directive/src/main.ts",
+ "polyfills": "apps/angular/6-structural-directive/src/polyfills.ts",
+ "tsConfig": "apps/angular/6-structural-directive/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/6-structural-directive/src/favicon.ico",
+ "apps/angular/6-structural-directive/src/assets"
+ ],
+ "styles": ["apps/angular/6-structural-directive/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-structural-directive:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-structural-directive:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-structural-directive:build"
+ }
+ }
+ }
+}
diff --git a/apps/angular/6-structural-directive/src/app/app.component.ts b/apps/angular/6-structural-directive/src/app/app.component.ts
new file mode 100644
index 000000000..a3d63b374
--- /dev/null
+++ b/apps/angular/6-structural-directive/src/app/app.component.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+
+@Component({
+ imports: [RouterOutlet],
+ selector: 'app-root',
+ template: `
+
+ `,
+ styles: [],
+})
+export class AppComponent {}
diff --git a/apps/angular/permissions/src/app/app.config.ts b/apps/angular/6-structural-directive/src/app/app.config.ts
similarity index 100%
rename from apps/angular/permissions/src/app/app.config.ts
rename to apps/angular/6-structural-directive/src/app/app.config.ts
diff --git a/apps/angular/permissions/src/app/button.component.ts b/apps/angular/6-structural-directive/src/app/button.component.ts
similarity index 100%
rename from apps/angular/permissions/src/app/button.component.ts
rename to apps/angular/6-structural-directive/src/app/button.component.ts
diff --git a/apps/angular/permissions/src/app/dashboard/admin.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts
similarity index 95%
rename from apps/angular/permissions/src/app/dashboard/admin.component.ts
rename to apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts
index 72e4b3bef..26bb23284 100644
--- a/apps/angular/permissions/src/app/dashboard/admin.component.ts
+++ b/apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts
@@ -4,7 +4,6 @@ import { ButtonComponent } from '../button.component';
@Component({
selector: 'app-dashboard',
- standalone: true,
imports: [RouterLink, ButtonComponent],
template: `
dashboard for Admin works!
diff --git a/apps/angular/permissions/src/app/dashboard/manager.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/manager.component.ts
similarity index 100%
rename from apps/angular/permissions/src/app/dashboard/manager.component.ts
rename to apps/angular/6-structural-directive/src/app/dashboard/manager.component.ts
diff --git a/apps/angular/permissions/src/app/information.component.ts b/apps/angular/6-structural-directive/src/app/information.component.ts
similarity index 97%
rename from apps/angular/permissions/src/app/information.component.ts
rename to apps/angular/6-structural-directive/src/app/information.component.ts
index e4adeb1b9..81b339520 100644
--- a/apps/angular/permissions/src/app/information.component.ts
+++ b/apps/angular/6-structural-directive/src/app/information.component.ts
@@ -4,7 +4,6 @@ import { UserStore } from './user.store';
@Component({
selector: 'app-information',
- standalone: true,
imports: [CommonModule],
template: `
Information Panel
diff --git a/apps/angular/permissions/src/app/login.component.ts b/apps/angular/6-structural-directive/src/app/login.component.ts
similarity index 98%
rename from apps/angular/permissions/src/app/login.component.ts
rename to apps/angular/6-structural-directive/src/app/login.component.ts
index cd36d9603..b8644ed38 100644
--- a/apps/angular/permissions/src/app/login.component.ts
+++ b/apps/angular/6-structural-directive/src/app/login.component.ts
@@ -14,7 +14,6 @@ import {
import { UserStore } from './user.store';
@Component({
- standalone: true,
imports: [InformationComponent, RouterLink, ButtonComponent],
selector: 'app-login',
template: `
diff --git a/apps/angular/permissions/src/app/routes.ts b/apps/angular/6-structural-directive/src/app/routes.ts
similarity index 100%
rename from apps/angular/permissions/src/app/routes.ts
rename to apps/angular/6-structural-directive/src/app/routes.ts
diff --git a/apps/angular/permissions/src/app/user.model.ts b/apps/angular/6-structural-directive/src/app/user.model.ts
similarity index 100%
rename from apps/angular/permissions/src/app/user.model.ts
rename to apps/angular/6-structural-directive/src/app/user.model.ts
diff --git a/apps/angular/permissions/src/app/user.store.ts b/apps/angular/6-structural-directive/src/app/user.store.ts
similarity index 100%
rename from apps/angular/permissions/src/app/user.store.ts
rename to apps/angular/6-structural-directive/src/app/user.store.ts
diff --git a/apps/angular/styling/src/assets/.gitkeep b/apps/angular/6-structural-directive/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/styling/src/assets/.gitkeep
rename to apps/angular/6-structural-directive/src/assets/.gitkeep
diff --git a/apps/ngrx/effect-selector/src/favicon.ico b/apps/angular/6-structural-directive/src/favicon.ico
similarity index 100%
rename from apps/ngrx/effect-selector/src/favicon.ico
rename to apps/angular/6-structural-directive/src/favicon.ico
diff --git a/apps/angular/6-structural-directive/src/index.html b/apps/angular/6-structural-directive/src/index.html
new file mode 100644
index 000000000..8a35fb109
--- /dev/null
+++ b/apps/angular/6-structural-directive/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-structural-directive
+
+
+
+
+
+
+
+
diff --git a/apps/angular/permissions/src/main.ts b/apps/angular/6-structural-directive/src/main.ts
similarity index 100%
rename from apps/angular/permissions/src/main.ts
rename to apps/angular/6-structural-directive/src/main.ts
diff --git a/apps/angular/pipe-hard/src/polyfills.ts b/apps/angular/6-structural-directive/src/polyfills.ts
similarity index 100%
rename from apps/angular/pipe-hard/src/polyfills.ts
rename to apps/angular/6-structural-directive/src/polyfills.ts
diff --git a/apps/performance/default-onpush/src/styles.scss b/apps/angular/6-structural-directive/src/styles.scss
similarity index 100%
rename from apps/performance/default-onpush/src/styles.scss
rename to apps/angular/6-structural-directive/src/styles.scss
diff --git a/apps/performance/memoized/tailwind.config.js b/apps/angular/6-structural-directive/tailwind.config.js
similarity index 100%
rename from apps/performance/memoized/tailwind.config.js
rename to apps/angular/6-structural-directive/tailwind.config.js
diff --git a/apps/angular/pipe-hard/tsconfig.app.json b/apps/angular/6-structural-directive/tsconfig.app.json
similarity index 100%
rename from apps/angular/pipe-hard/tsconfig.app.json
rename to apps/angular/6-structural-directive/tsconfig.app.json
diff --git a/apps/angular/pipe-easy/tsconfig.editor.json b/apps/angular/6-structural-directive/tsconfig.editor.json
similarity index 100%
rename from apps/angular/pipe-easy/tsconfig.editor.json
rename to apps/angular/6-structural-directive/tsconfig.editor.json
diff --git a/apps/angular/pipe-easy/tsconfig.json b/apps/angular/6-structural-directive/tsconfig.json
similarity index 100%
rename from apps/angular/pipe-easy/tsconfig.json
rename to apps/angular/6-structural-directive/tsconfig.json
diff --git a/apps/nx/static-dynamic-import/.eslintrc.json b/apps/angular/8-pure-pipe/.eslintrc.json
similarity index 100%
rename from apps/nx/static-dynamic-import/.eslintrc.json
rename to apps/angular/8-pure-pipe/.eslintrc.json
diff --git a/apps/angular/8-pure-pipe/README.md b/apps/angular/8-pure-pipe/README.md
new file mode 100644
index 000000000..a65a33f85
--- /dev/null
+++ b/apps/angular/8-pure-pipe/README.md
@@ -0,0 +1,13 @@
+# Pure Pipe
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-pure-pipe
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/8-pipe-pure/).
diff --git a/apps/angular/8-pure-pipe/project.json b/apps/angular/8-pure-pipe/project.json
new file mode 100644
index 000000000..a684d542f
--- /dev/null
+++ b/apps/angular/8-pure-pipe/project.json
@@ -0,0 +1,72 @@
+{
+ "name": "angular-pure-pipe",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/angular/8-pure-pipe/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/8-pure-pipe",
+ "index": "apps/angular/8-pure-pipe/src/index.html",
+ "main": "apps/angular/8-pure-pipe/src/main.ts",
+ "polyfills": "apps/angular/8-pure-pipe/src/polyfills.ts",
+ "tsConfig": "apps/angular/8-pure-pipe/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/8-pure-pipe/src/favicon.ico",
+ "apps/angular/8-pure-pipe/src/assets"
+ ],
+ "styles": ["apps/angular/8-pure-pipe/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-pure-pipe:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-pure-pipe:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-pure-pipe:build"
+ }
+ }
+ }
+}
diff --git a/apps/angular/8-pure-pipe/src/app/app.component.ts b/apps/angular/8-pure-pipe/src/app/app.component.ts
new file mode 100644
index 000000000..41dd38e25
--- /dev/null
+++ b/apps/angular/8-pure-pipe/src/app/app.component.ts
@@ -0,0 +1,20 @@
+import { NgFor } from '@angular/common';
+import { Component } from '@angular/core';
+
+@Component({
+ imports: [NgFor],
+ selector: 'app-root',
+ template: `
+
+ {{ heavyComputation(person, index) }}
+
+ `,
+})
+export class AppComponent {
+ persons = ['toto', 'jack'];
+
+ heavyComputation(name: string, index: number) {
+ // very heavy computation
+ return `${name} - ${index}`;
+ }
+}
diff --git a/apps/angular/view-transition/src/assets/.gitkeep b/apps/angular/8-pure-pipe/src/assets/.gitkeep
similarity index 100%
rename from apps/angular/view-transition/src/assets/.gitkeep
rename to apps/angular/8-pure-pipe/src/assets/.gitkeep
diff --git a/apps/ngrx/notification/src/favicon.ico b/apps/angular/8-pure-pipe/src/favicon.ico
similarity index 100%
rename from apps/ngrx/notification/src/favicon.ico
rename to apps/angular/8-pure-pipe/src/favicon.ico
diff --git a/apps/angular/8-pure-pipe/src/index.html b/apps/angular/8-pure-pipe/src/index.html
new file mode 100644
index 000000000..c8ee70b97
--- /dev/null
+++ b/apps/angular/8-pure-pipe/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-pure-pipe
+
+
+
+
+
+
+
+
diff --git a/apps/angular/pipe-intermediate/src/main.ts b/apps/angular/8-pure-pipe/src/main.ts
similarity index 100%
rename from apps/angular/pipe-intermediate/src/main.ts
rename to apps/angular/8-pure-pipe/src/main.ts
diff --git a/apps/angular/pipe-intermediate/src/polyfills.ts b/apps/angular/8-pure-pipe/src/polyfills.ts
similarity index 100%
rename from apps/angular/pipe-intermediate/src/polyfills.ts
rename to apps/angular/8-pure-pipe/src/polyfills.ts
diff --git a/apps/angular/router-input/src/styles.scss b/apps/angular/8-pure-pipe/src/styles.scss
similarity index 100%
rename from apps/angular/router-input/src/styles.scss
rename to apps/angular/8-pure-pipe/src/styles.scss
diff --git a/apps/angular/pipe-intermediate/tsconfig.app.json b/apps/angular/8-pure-pipe/tsconfig.app.json
similarity index 100%
rename from apps/angular/pipe-intermediate/tsconfig.app.json
rename to apps/angular/8-pure-pipe/tsconfig.app.json
diff --git a/apps/angular/pipe-hard/tsconfig.editor.json b/apps/angular/8-pure-pipe/tsconfig.editor.json
similarity index 100%
rename from apps/angular/pipe-hard/tsconfig.editor.json
rename to apps/angular/8-pure-pipe/tsconfig.editor.json
diff --git a/apps/angular/pipe-hard/tsconfig.json b/apps/angular/8-pure-pipe/tsconfig.json
similarity index 100%
rename from apps/angular/pipe-hard/tsconfig.json
rename to apps/angular/8-pure-pipe/tsconfig.json
diff --git a/apps/rxjs/pipe-bug/.eslintrc.json b/apps/angular/9-wrap-function-pipe/.eslintrc.json
similarity index 100%
rename from apps/rxjs/pipe-bug/.eslintrc.json
rename to apps/angular/9-wrap-function-pipe/.eslintrc.json
diff --git a/apps/angular/9-wrap-function-pipe/README.md b/apps/angular/9-wrap-function-pipe/README.md
new file mode 100644
index 000000000..1491e7dda
--- /dev/null
+++ b/apps/angular/9-wrap-function-pipe/README.md
@@ -0,0 +1,13 @@
+# Wrap Function Pipe
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve angular-wrap-function-pipe
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/9-pipe-wrapFn/).
diff --git a/apps/angular/9-wrap-function-pipe/project.json b/apps/angular/9-wrap-function-pipe/project.json
new file mode 100644
index 000000000..dc5c4ab6e
--- /dev/null
+++ b/apps/angular/9-wrap-function-pipe/project.json
@@ -0,0 +1,72 @@
+{
+ "name": "angular-wrap-function-pipe",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/angular/9-wrap-function-pipe/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/angular/9-wrap-function-pipe",
+ "index": "apps/angular/9-wrap-function-pipe/src/index.html",
+ "main": "apps/angular/9-wrap-function-pipe/src/main.ts",
+ "polyfills": "apps/angular/9-wrap-function-pipe/src/polyfills.ts",
+ "tsConfig": "apps/angular/9-wrap-function-pipe/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/angular/9-wrap-function-pipe/src/favicon.ico",
+ "apps/angular/9-wrap-function-pipe/src/assets"
+ ],
+ "styles": ["apps/angular/9-wrap-function-pipe/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-wrap-function-pipe:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-wrap-function-pipe:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "angular-wrap-function-pipe:build"
+ }
+ }
+ }
+}
diff --git a/apps/angular/9-wrap-function-pipe/src/app/app.component.ts b/apps/angular/9-wrap-function-pipe/src/app/app.component.ts
new file mode 100644
index 000000000..dd576ae49
--- /dev/null
+++ b/apps/angular/9-wrap-function-pipe/src/app/app.component.ts
@@ -0,0 +1,33 @@
+import { NgFor } from '@angular/common';
+import { Component } from '@angular/core';
+
+@Component({
+ imports: [NgFor],
+ selector: 'app-root',
+ template: `
+
+ {{ showName(person.name, index) }}
+ {{ isAllowed(person.age, isFirst) }}
+
+ `,
+})
+export class AppComponent {
+ persons = [
+ { name: 'Toto', age: 10 },
+ { name: 'Jack', age: 15 },
+ { name: 'John', age: 30 },
+ ];
+
+ showName(name: string, index: number) {
+ // very heavy computation
+ return `${name} - ${index}`;
+ }
+
+ isAllowed(age: number, isFirst: boolean) {
+ if (isFirst) {
+ return 'always allowed';
+ } else {
+ return age > 25 ? 'allowed' : 'declined';
+ }
+ }
+}
diff --git a/apps/forms/control-value-accessor/src/assets/.gitkeep b/apps/angular/9-wrap-function-pipe/src/assets/.gitkeep
similarity index 100%
rename from apps/forms/control-value-accessor/src/assets/.gitkeep
rename to apps/angular/9-wrap-function-pipe/src/assets/.gitkeep
diff --git a/apps/nx/static-dynamic-import/src/favicon.ico b/apps/angular/9-wrap-function-pipe/src/favicon.ico
similarity index 100%
rename from apps/nx/static-dynamic-import/src/favicon.ico
rename to apps/angular/9-wrap-function-pipe/src/favicon.ico
diff --git a/apps/angular/9-wrap-function-pipe/src/index.html b/apps/angular/9-wrap-function-pipe/src/index.html
new file mode 100644
index 000000000..bc8a0ddbd
--- /dev/null
+++ b/apps/angular/9-wrap-function-pipe/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ angular-wrap-function-pipe
+
+
+
+
+
+
+
+
diff --git a/apps/forms/control-value-accessor/src/main.ts b/apps/angular/9-wrap-function-pipe/src/main.ts
similarity index 100%
rename from apps/forms/control-value-accessor/src/main.ts
rename to apps/angular/9-wrap-function-pipe/src/main.ts
diff --git a/apps/angular/projection/src/polyfills.ts b/apps/angular/9-wrap-function-pipe/src/polyfills.ts
similarity index 100%
rename from apps/angular/projection/src/polyfills.ts
rename to apps/angular/9-wrap-function-pipe/src/polyfills.ts
diff --git a/apps/angular/styling/src/styles.scss b/apps/angular/9-wrap-function-pipe/src/styles.scss
similarity index 100%
rename from apps/angular/styling/src/styles.scss
rename to apps/angular/9-wrap-function-pipe/src/styles.scss
diff --git a/apps/angular/projection/tsconfig.app.json b/apps/angular/9-wrap-function-pipe/tsconfig.app.json
similarity index 100%
rename from apps/angular/projection/tsconfig.app.json
rename to apps/angular/9-wrap-function-pipe/tsconfig.app.json
diff --git a/apps/angular/pipe-intermediate/tsconfig.editor.json b/apps/angular/9-wrap-function-pipe/tsconfig.editor.json
similarity index 100%
rename from apps/angular/pipe-intermediate/tsconfig.editor.json
rename to apps/angular/9-wrap-function-pipe/tsconfig.editor.json
diff --git a/apps/angular/pipe-intermediate/tsconfig.json b/apps/angular/9-wrap-function-pipe/tsconfig.json
similarity index 100%
rename from apps/angular/pipe-intermediate/tsconfig.json
rename to apps/angular/9-wrap-function-pipe/tsconfig.json
diff --git a/apps/angular/anchor-scrolling/README.md b/apps/angular/anchor-scrolling/README.md
deleted file mode 100644
index a159fd8b7..000000000
--- a/apps/angular/anchor-scrolling/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Anchor Navigation
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-anchor-scrolling
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/21-achor-scrolling/).
diff --git a/apps/angular/anchor-scrolling/jest.config.ts b/apps/angular/anchor-scrolling/jest.config.ts
deleted file mode 100644
index 166572856..000000000
--- a/apps/angular/anchor-scrolling/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-anchor-scrolling',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/angular/anchor-scrolling',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/anchor-scrolling/project.json b/apps/angular/anchor-scrolling/project.json
deleted file mode 100644
index 3fa125347..000000000
--- a/apps/angular/anchor-scrolling/project.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "name": "angular-anchor-scrolling",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/anchor-scrolling/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/anchor-scrolling",
- "index": "apps/angular/anchor-scrolling/src/index.html",
- "main": "apps/angular/anchor-scrolling/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/anchor-scrolling/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/anchor-scrolling/src/favicon.ico",
- "apps/angular/anchor-scrolling/src/assets"
- ],
- "styles": ["apps/angular/anchor-scrolling/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-anchor-scrolling:build:production"
- },
- "development": {
- "buildTarget": "angular-anchor-scrolling:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-anchor-scrolling:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/anchor-scrolling/**/*.ts",
- "apps/angular/anchor-scrolling/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/anchor-scrolling/jest.config.ts"
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/anchor-scrolling/src/app/app.component.ts b/apps/angular/anchor-scrolling/src/app/app.component.ts
deleted file mode 100644
index 3fb7c5df0..000000000
--- a/apps/angular/anchor-scrolling/src/app/app.component.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet],
- selector: 'app-root',
- template: `
-
- `,
-})
-export class AppComponent {}
diff --git a/apps/angular/anchor-scrolling/src/app/home.component.ts b/apps/angular/anchor-scrolling/src/app/home.component.ts
deleted file mode 100644
index 0f24ff6e7..000000000
--- a/apps/angular/anchor-scrolling/src/app/home.component.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Component } from '@angular/core';
-import { NavButtonComponent } from './nav-button.component';
-
-@Component({
- standalone: true,
- imports: [NavButtonComponent],
- selector: 'app-home',
- template: `
- Foo Page
-
- Empty
- Scroll Bottom
-
-
- I want to scroll each
- Scroll Top
-
- `,
-})
-export class HomeComponent {}
diff --git a/apps/angular/anchor-scrolling/src/index.html b/apps/angular/anchor-scrolling/src/index.html
deleted file mode 100644
index 7a2a4b377..000000000
--- a/apps/angular/anchor-scrolling/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- AnchorScrolling
-
-
-
-
-
-
-
-
diff --git a/apps/angular/bug-cd/README.md b/apps/angular/bug-cd/README.md
deleted file mode 100644
index cb42e778c..000000000
--- a/apps/angular/bug-cd/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Change Detection Bug
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-bug-cd
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/32-bug-cd/).
diff --git a/apps/angular/bug-cd/jest.config.ts b/apps/angular/bug-cd/jest.config.ts
deleted file mode 100644
index ded316d4c..000000000
--- a/apps/angular/bug-cd/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-bug-cd',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/angular/bug-cd',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/bug-cd/project.json b/apps/angular/bug-cd/project.json
deleted file mode 100644
index f5aaa262e..000000000
--- a/apps/angular/bug-cd/project.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "name": "angular-bug-cd",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/bug-cd/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/bug-cd",
- "index": "apps/angular/bug-cd/src/index.html",
- "main": "apps/angular/bug-cd/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/bug-cd/tsconfig.app.json",
- "assets": [
- "apps/angular/bug-cd/src/favicon.ico",
- "apps/angular/bug-cd/src/assets"
- ],
- "styles": ["apps/angular/bug-cd/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-bug-cd:build:production"
- },
- "development": {
- "buildTarget": "angular-bug-cd:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-bug-cd:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/bug-cd/**/*.ts",
- "apps/angular/bug-cd/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/bug-cd/jest.config.ts"
- }
- }
- }
-}
diff --git a/apps/angular/bug-cd/src/app/app.component.ts b/apps/angular/bug-cd/src/app/app.component.ts
deleted file mode 100644
index 046492f9b..000000000
--- a/apps/angular/bug-cd/src/app/app.component.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet],
- selector: 'app-root',
- template: `
- My Application
-
- `,
- host: {
- class: 'flex flex-col gap-2',
- },
-})
-export class AppComponent {}
diff --git a/apps/angular/bug-cd/src/index.html b/apps/angular/bug-cd/src/index.html
deleted file mode 100644
index ab925a75c..000000000
--- a/apps/angular/bug-cd/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- test
-
-
-
-
-
-
-
-
diff --git a/apps/angular/context-outlet-type/README.md b/apps/angular/context-outlet-type/README.md
deleted file mode 100644
index d195baa04..000000000
--- a/apps/angular/context-outlet-type/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Typed ContextOutlet
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-context-outlet-type
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/4-context-outlet-typed/).
diff --git a/apps/angular/context-outlet-type/project.json b/apps/angular/context-outlet-type/project.json
deleted file mode 100644
index b882d73de..000000000
--- a/apps/angular/context-outlet-type/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-context-outlet-type",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/context-outlet-type/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/context-outlet-type",
- "index": "apps/angular/context-outlet-type/src/index.html",
- "main": "apps/angular/context-outlet-type/src/main.ts",
- "polyfills": "apps/angular/context-outlet-type/src/polyfills.ts",
- "tsConfig": "apps/angular/context-outlet-type/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/context-outlet-type/src/favicon.ico",
- "apps/angular/context-outlet-type/src/assets"
- ],
- "styles": ["apps/angular/context-outlet-type/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-context-outlet-type:build:production"
- },
- "development": {
- "buildTarget": "angular-context-outlet-type:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-context-outlet-type:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/context-outlet-type/**/*.ts",
- "apps/angular/context-outlet-type/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/context-outlet-type/src/app/app.component.ts b/apps/angular/context-outlet-type/src/app/app.component.ts
deleted file mode 100644
index 2683ba9d4..000000000
--- a/apps/angular/context-outlet-type/src/app/app.component.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { NgTemplateOutlet } from '@angular/common';
-import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { ListComponent } from './list.component';
-import { PersonComponent } from './person.component';
-
-@Component({
- standalone: true,
- imports: [NgTemplateOutlet, PersonComponent, ListComponent],
- selector: 'app-root',
- template: `
-
-
- {{ name }}: {{ age }}
-
-
-
-
-
- {{ student.name }}: {{ student.age }} - {{ i }}
-
-
-
-
-
- {{ city.name }}: {{ city.country }} - {{ i }}
-
-
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class AppComponent {
- person = {
- name: 'toto',
- age: 3,
- };
-
- students = [
- { name: 'toto', age: 3 },
- { name: 'titi', age: 4 },
- ];
-
- cities = [
- { name: 'Paris', country: 'France' },
- { name: 'Berlin', country: 'Germany' },
- ];
-}
diff --git a/apps/angular/context-outlet-type/src/app/list.component.ts b/apps/angular/context-outlet-type/src/app/list.component.ts
deleted file mode 100644
index 5212a425e..000000000
--- a/apps/angular/context-outlet-type/src/app/list.component.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { CommonModule } from '@angular/common';
-import {
- ChangeDetectionStrategy,
- Component,
- ContentChild,
- Input,
- TemplateRef,
-} from '@angular/core';
-
-@Component({
- selector: 'list',
- standalone: true,
- imports: [CommonModule],
- template: `
-
-
-
-
- No Template
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class ListComponent {
- @Input() list!: TItem[];
-
- @ContentChild('listRef', { read: TemplateRef })
- listTemplateRef!: TemplateRef;
-}
diff --git a/apps/angular/context-outlet-type/src/index.html b/apps/angular/context-outlet-type/src/index.html
deleted file mode 100644
index b3ee6c60d..000000000
--- a/apps/angular/context-outlet-type/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- ContextOutletType
-
-
-
-
-
-
-
-
diff --git a/apps/angular/crud/README.md b/apps/angular/crud/README.md
deleted file mode 100644
index 0a6518b44..000000000
--- a/apps/angular/crud/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Crud application
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-crud
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/5-crud/).
diff --git a/apps/angular/crud/jest.config.ts b/apps/angular/crud/jest.config.ts
deleted file mode 100644
index 485099109..000000000
--- a/apps/angular/crud/jest.config.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-crud',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- globals: {},
- coverageDirectory: '../../../coverage/apps/angular/crud',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/crud/project.json b/apps/angular/crud/project.json
deleted file mode 100644
index 0d656a983..000000000
--- a/apps/angular/crud/project.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "name": "angular-crud",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/crud/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/crud",
- "index": "apps/angular/crud/src/index.html",
- "main": "apps/angular/crud/src/main.ts",
- "polyfills": "apps/angular/crud/src/polyfills.ts",
- "tsConfig": "apps/angular/crud/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/crud/src/favicon.ico",
- "apps/angular/crud/src/assets"
- ],
- "styles": [
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
- "apps/angular/crud/src/styles.scss"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-crud:build:production"
- },
- "development": {
- "buildTarget": "angular-crud:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-crud:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/crud/**/*.ts",
- "apps/angular/crud/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/crud/jest.config.ts"
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/crud/src/app/app.component.ts b/apps/angular/crud/src/app/app.component.ts
deleted file mode 100644
index 8c3d1b8ae..000000000
--- a/apps/angular/crud/src/app/app.component.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { CommonModule } from '@angular/common';
-import { HttpClient } from '@angular/common/http';
-import { Component, OnInit } from '@angular/core';
-import { randText } from '@ngneat/falso';
-
-@Component({
- standalone: true,
- imports: [CommonModule],
- selector: 'app-root',
- template: `
-
- {{ todo.title }}
-
-
- `,
- styles: [],
-})
-export class AppComponent implements OnInit {
- todos!: any[];
-
- constructor(private http: HttpClient) {}
-
- ngOnInit(): void {
- this.http
- .get('https://jsonplaceholder.typicode.com/todos')
- .subscribe((todos) => {
- this.todos = todos;
- });
- }
-
- update(todo: any) {
- this.http
- .put(
- `https://jsonplaceholder.typicode.com/todos/${todo.id}`,
- JSON.stringify({
- todo: todo.id,
- title: randText(),
- body: todo.body,
- userId: todo.userId,
- }),
- {
- headers: {
- 'Content-type': 'application/json; charset=UTF-8',
- },
- },
- )
- .subscribe((todoUpdated: any) => {
- this.todos[todoUpdated.id - 1] = todoUpdated;
- });
- }
-}
diff --git a/apps/angular/crud/src/app/app.config.ts b/apps/angular/crud/src/app/app.config.ts
deleted file mode 100644
index de0a3ccec..000000000
--- a/apps/angular/crud/src/app/app.config.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { HttpClientModule } from '@angular/common/http';
-import { ApplicationConfig, importProvidersFrom } from '@angular/core';
-export const appConfig: ApplicationConfig = {
- providers: [importProvidersFrom(HttpClientModule)],
-};
diff --git a/apps/angular/crud/src/index.html b/apps/angular/crud/src/index.html
deleted file mode 100644
index c556437f0..000000000
--- a/apps/angular/crud/src/index.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- Http
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/angular/decoupling/README.md b/apps/angular/decoupling/README.md
deleted file mode 100644
index 0ba00e70c..000000000
--- a/apps/angular/decoupling/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Decoupling Components
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-decoupling
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/33-decoupling/).
diff --git a/apps/angular/decoupling/project.json b/apps/angular/decoupling/project.json
deleted file mode 100644
index c32f85c13..000000000
--- a/apps/angular/decoupling/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-decoupling",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/decoupling/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/decoupling",
- "index": "apps/angular/decoupling/src/index.html",
- "main": "apps/angular/decoupling/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/decoupling/tsconfig.app.json",
- "assets": [
- "apps/angular/decoupling/src/favicon.ico",
- "apps/angular/decoupling/src/assets"
- ],
- "styles": ["apps/angular/decoupling/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-decoupling:build:production"
- },
- "development": {
- "buildTarget": "angular-decoupling:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-decoupling:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/decoupling/**/*.ts",
- "apps/angular/decoupling/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/angular/decoupling/src/app/app.component.ts b/apps/angular/decoupling/src/app/app.component.ts
deleted file mode 100644
index 34082c331..000000000
--- a/apps/angular/decoupling/src/app/app.component.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { BtnDisabledDirective } from '@angular-challenges/decoupling/brain';
-import { BtnHelmetDirective } from '@angular-challenges/decoupling/helmet';
-import { Component } from '@angular/core';
-
-@Component({
- standalone: true,
- imports: [BtnDisabledDirective, BtnHelmetDirective],
- selector: 'app-root',
- template: `
-
- `,
-})
-export class AppComponent {}
diff --git a/apps/angular/decoupling/src/index.html b/apps/angular/decoupling/src/index.html
deleted file mode 100644
index 25b5ea13c..000000000
--- a/apps/angular/decoupling/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- decoupling
-
-
-
-
-
-
-
-
diff --git a/apps/angular/di/README.md b/apps/angular/di/README.md
deleted file mode 100644
index 032601c1f..000000000
--- a/apps/angular/di/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Master Dependancy Injection
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-di
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/16-di/).
diff --git a/apps/angular/di/project.json b/apps/angular/di/project.json
deleted file mode 100644
index aa7880866..000000000
--- a/apps/angular/di/project.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "name": "angular-di",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/di/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/di",
- "index": "apps/angular/di/src/index.html",
- "main": "apps/angular/di/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/di/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/di/src/favicon.ico",
- "apps/angular/di/src/assets"
- ],
- "styles": ["apps/angular/di/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-di:build:production"
- },
- "development": {
- "buildTarget": "angular-di:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-di:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/di/**/*.ts",
- "apps/angular/di/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/di/src/app/app.component.ts b/apps/angular/di/src/app/app.component.ts
deleted file mode 100644
index e57a5a5bf..000000000
--- a/apps/angular/di/src/app/app.component.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { TableComponent } from '@angular-challenges/angular/di';
-import { AsyncPipe, NgFor } from '@angular/common';
-import { Component, Directive } from '@angular/core';
-import { CurrencyPipe } from './currency.pipe';
-import { CurrencyService } from './currency.service';
-import { Product, products } from './product.model';
-
-interface ProductContext {
- $implicit: Product;
-}
-
-@Directive({
- selector: 'ng-template[product]',
- standalone: true,
-})
-export class ProductDirective {
- static ngTemplateContextGuard(
- dir: ProductDirective,
- ctx: unknown,
- ): ctx is ProductContext {
- return true;
- }
-}
-
-@Component({
- standalone: true,
- imports: [TableComponent, CurrencyPipe, AsyncPipe, NgFor, ProductDirective],
- providers: [CurrencyService],
- selector: 'app-root',
- template: `
-
-
-
-
- {{ col }}
- |
-
-
-
-
- {{ product.name }} |
- {{ product.priceA | currency | async }} |
- {{ product.priceB | currency | async }} |
- {{ product.priceC | currency | async }} |
-
-
-
- `,
-})
-export class AppComponent {
- products = products;
- displayedColumns = ['name', 'priceA', 'priceB', 'priceC'];
-}
diff --git a/apps/angular/di/src/index.html b/apps/angular/di/src/index.html
deleted file mode 100644
index c120f5b9c..000000000
--- a/apps/angular/di/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Di
-
-
-
-
-
-
-
-
diff --git a/apps/angular/injection-token/jest.config.ts b/apps/angular/injection-token/jest.config.ts
deleted file mode 100644
index c48bb4949..000000000
--- a/apps/angular/injection-token/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-injection-token',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/angular/injection-token',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/injection-token/project.json b/apps/angular/injection-token/project.json
deleted file mode 100644
index 2a656807f..000000000
--- a/apps/angular/injection-token/project.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "name": "angular-injection-token",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/injection-token/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/injection-token",
- "index": "apps/angular/injection-token/src/index.html",
- "main": "apps/angular/injection-token/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/injection-token/tsconfig.app.json",
- "assets": [
- "apps/angular/injection-token/src/favicon.ico",
- "apps/angular/injection-token/src/assets"
- ],
- "styles": ["apps/angular/injection-token/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-injection-token:build:production"
- },
- "development": {
- "buildTarget": "angular-injection-token:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-injection-token:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/injection-token/**/*.ts",
- "apps/angular/injection-token/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/injection-token/jest.config.ts"
- }
- }
- }
-}
diff --git a/apps/angular/injection-token/src/app/app.component.ts b/apps/angular/injection-token/src/app/app.component.ts
deleted file mode 100644
index 5ac8087cb..000000000
--- a/apps/angular/injection-token/src/app/app.component.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterLink, RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet, RouterLink],
- selector: 'app-root',
- template: `
-
-
-
-
-
- `,
- host: {
- class: 'p-10 flex flex-col',
- },
-})
-export class AppComponent {}
diff --git a/apps/angular/interop-rxjs-signal/README.md b/apps/angular/interop-rxjs-signal/README.md
deleted file mode 100644
index 9cf32efa5..000000000
--- a/apps/angular/interop-rxjs-signal/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Interoperability Rxjs/Signal
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-interop-rxjs-signal
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/30-interop-rxjs-signal/).
diff --git a/apps/angular/interop-rxjs-signal/jest.config.ts b/apps/angular/interop-rxjs-signal/jest.config.ts
deleted file mode 100644
index 53f7481c3..000000000
--- a/apps/angular/interop-rxjs-signal/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-interop-rxjs-signal',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/angular/interop-rxjs-signal',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/interop-rxjs-signal/project.json b/apps/angular/interop-rxjs-signal/project.json
deleted file mode 100644
index 6a94737ca..000000000
--- a/apps/angular/interop-rxjs-signal/project.json
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "name": "angular-interop-rxjs-signal",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/interop-rxjs-signal/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/interop-rxjs-signal",
- "index": "apps/angular/interop-rxjs-signal/src/index.html",
- "main": "apps/angular/interop-rxjs-signal/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/interop-rxjs-signal/tsconfig.app.json",
- "assets": [
- "apps/angular/interop-rxjs-signal/src/favicon.ico",
- "apps/angular/interop-rxjs-signal/src/assets"
- ],
- "styles": [
- "apps/angular/interop-rxjs-signal/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-interop-rxjs-signal:build:production"
- },
- "development": {
- "buildTarget": "angular-interop-rxjs-signal:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-interop-rxjs-signal:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/interop-rxjs-signal/**/*.ts",
- "apps/angular/interop-rxjs-signal/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/interop-rxjs-signal/jest.config.ts"
- }
- }
- }
-}
diff --git a/apps/angular/interop-rxjs-signal/src/app/app.component.ts b/apps/angular/interop-rxjs-signal/src/app/app.component.ts
deleted file mode 100644
index 7b83d1470..000000000
--- a/apps/angular/interop-rxjs-signal/src/app/app.component.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet],
- selector: 'app-root',
- template: `
-
- `,
- styles: [''],
-})
-export class AppComponent {}
diff --git a/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts b/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts
deleted file mode 100644
index 3576db452..000000000
--- a/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { DatePipe } from '@angular/common';
-import { Component, Input as RouterInput } from '@angular/core';
-import { RouterLink } from '@angular/router';
-import { Photo } from '../photo.model';
-
-@Component({
- selector: 'app-photos',
- standalone: true,
- imports: [DatePipe, RouterLink],
- template: `
-
-
- Title:
- {{ photo.title }}
-
-
- Owner:
- {{ photo.ownername }}
-
-
- Date:
- {{ photo.datetaken | date }}
-
-
- Tags:
- {{ photo.tags }}
-
-
-
- `,
- host: {
- class: 'p-5 block',
- },
-})
-export default class DetailComponent {
- @RouterInput({
- required: true,
- transform: (value: string) => JSON.parse(decodeURIComponent(value)),
- })
- photo!: Photo;
-}
diff --git a/apps/angular/interop-rxjs-signal/src/index.html b/apps/angular/interop-rxjs-signal/src/index.html
deleted file mode 100644
index 1c69fbc7a..000000000
--- a/apps/angular/interop-rxjs-signal/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- rxjs-to-signal
-
-
-
-
-
-
-
-
diff --git a/apps/angular/module-to-standalone/project.json b/apps/angular/module-to-standalone/project.json
deleted file mode 100644
index 4ee3a4e5f..000000000
--- a/apps/angular/module-to-standalone/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-module-to-standalone",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/module-to-standalone/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/module-to-standalone",
- "index": "apps/angular/module-to-standalone/src/index.html",
- "main": "apps/angular/module-to-standalone/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/module-to-standalone/tsconfig.app.json",
- "assets": [
- "apps/angular/module-to-standalone/src/favicon.ico",
- "apps/angular/module-to-standalone/src/assets"
- ],
- "styles": ["apps/angular/module-to-standalone/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-module-to-standalone:build:production"
- },
- "development": {
- "buildTarget": "angular-module-to-standalone:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-module-to-standalone:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/module-to-standalone/**/*.ts",
- "apps/angular/module-to-standalone/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/angular/module-to-standalone/src/app/app.component.ts b/apps/angular/module-to-standalone/src/app/app.component.ts
deleted file mode 100644
index 95eeab5b9..000000000
--- a/apps/angular/module-to-standalone/src/app/app.component.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-root',
- template: `
-
-
-
-
-
-
- `,
- host: {
- class: 'flex flex-col p-4 gap-3',
- },
-})
-export class AppComponent {}
diff --git a/apps/angular/module-to-standalone/src/index.html b/apps/angular/module-to-standalone/src/index.html
deleted file mode 100644
index 4902faa44..000000000
--- a/apps/angular/module-to-standalone/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- module-to-standalone
-
-
-
-
-
-
-
-
diff --git a/apps/angular/ngfor-enhancement/README.md b/apps/angular/ngfor-enhancement/README.md
deleted file mode 100644
index 937dfb54e..000000000
--- a/apps/angular/ngfor-enhancement/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Directive Enhancement
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-ngfor-enhancement
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/3-directive-enhancement/).
diff --git a/apps/angular/ngfor-enhancement/project.json b/apps/angular/ngfor-enhancement/project.json
deleted file mode 100644
index 8f2b72890..000000000
--- a/apps/angular/ngfor-enhancement/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-ngfor-enhancement",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/ngfor-enhancement/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/ngfor-enhancement",
- "index": "apps/angular/ngfor-enhancement/src/index.html",
- "main": "apps/angular/ngfor-enhancement/src/main.ts",
- "polyfills": "apps/angular/ngfor-enhancement/src/polyfills.ts",
- "tsConfig": "apps/angular/ngfor-enhancement/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/ngfor-enhancement/src/favicon.ico",
- "apps/angular/ngfor-enhancement/src/assets"
- ],
- "styles": ["apps/angular/ngfor-enhancement/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-ngfor-enhancement:build:production"
- },
- "development": {
- "buildTarget": "angular-ngfor-enhancement:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-ngfor-enhancement:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/ngfor-enhancement/**/*.ts",
- "apps/angular/ngfor-enhancement/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/ngfor-enhancement/src/app/app.component.ts b/apps/angular/ngfor-enhancement/src/app/app.component.ts
deleted file mode 100644
index cd1d5f23c..000000000
--- a/apps/angular/ngfor-enhancement/src/app/app.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { NgFor, NgIf } from '@angular/common';
-import { ChangeDetectionStrategy, Component } from '@angular/core';
-
-interface Person {
- name: string;
-}
-
-@Component({
- standalone: true,
- imports: [NgFor, NgIf],
- selector: 'app-root',
- template: `
- 0; else emptyList">
-
- {{ person.name }}
-
-
- The list is empty !!
- `,
- styles: [],
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class AppComponent {
- persons: Person[] = [];
-}
diff --git a/apps/angular/ngfor-enhancement/src/index.html b/apps/angular/ngfor-enhancement/src/index.html
deleted file mode 100644
index c38d89dee..000000000
--- a/apps/angular/ngfor-enhancement/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- NgForEnhance
-
-
-
-
-
-
-
-
diff --git a/apps/angular/permissions/README.md b/apps/angular/permissions/README.md
deleted file mode 100644
index 99b2e5582..000000000
--- a/apps/angular/permissions/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Structural Directive
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-permissions
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/6-permissions/).
diff --git a/apps/angular/permissions/project.json b/apps/angular/permissions/project.json
deleted file mode 100644
index 67b83cb78..000000000
--- a/apps/angular/permissions/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-permissions",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/permissions/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/permissions",
- "index": "apps/angular/permissions/src/index.html",
- "main": "apps/angular/permissions/src/main.ts",
- "polyfills": "apps/angular/permissions/src/polyfills.ts",
- "tsConfig": "apps/angular/permissions/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/permissions/src/favicon.ico",
- "apps/angular/permissions/src/assets"
- ],
- "styles": ["apps/angular/permissions/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-permissions:build:production"
- },
- "development": {
- "buildTarget": "angular-permissions:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-permissions:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/permissions/**/*.ts",
- "apps/angular/permissions/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/permissions/src/app/app.component.ts b/apps/angular/permissions/src/app/app.component.ts
deleted file mode 100644
index d89a2f579..000000000
--- a/apps/angular/permissions/src/app/app.component.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet],
- selector: 'app-root',
- template: `
-
- `,
- styles: [],
-})
-export class AppComponent {}
diff --git a/apps/angular/permissions/src/index.html b/apps/angular/permissions/src/index.html
deleted file mode 100644
index 14ab31c3b..000000000
--- a/apps/angular/permissions/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Permissions
-
-
-
-
-
-
-
-
diff --git a/apps/angular/pipe-easy/README.md b/apps/angular/pipe-easy/README.md
deleted file mode 100644
index 8501be8c7..000000000
--- a/apps/angular/pipe-easy/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Pure Pipe
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-pipe-easy
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/8-pipe-pure/).
diff --git a/apps/angular/pipe-easy/project.json b/apps/angular/pipe-easy/project.json
deleted file mode 100644
index a8f051516..000000000
--- a/apps/angular/pipe-easy/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-pipe-easy",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/pipe-easy/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/pipe-easy",
- "index": "apps/angular/pipe-easy/src/index.html",
- "main": "apps/angular/pipe-easy/src/main.ts",
- "polyfills": "apps/angular/pipe-easy/src/polyfills.ts",
- "tsConfig": "apps/angular/pipe-easy/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/pipe-easy/src/favicon.ico",
- "apps/angular/pipe-easy/src/assets"
- ],
- "styles": ["apps/angular/pipe-easy/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-pipe-easy:build:production"
- },
- "development": {
- "buildTarget": "angular-pipe-easy:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-pipe-easy:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/pipe-easy/**/*.ts",
- "apps/angular/pipe-easy/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/pipe-easy/src/app/app.component.ts b/apps/angular/pipe-easy/src/app/app.component.ts
deleted file mode 100644
index 3c19fa169..000000000
--- a/apps/angular/pipe-easy/src/app/app.component.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { NgFor } from '@angular/common';
-import { Component } from '@angular/core';
-
-@Component({
- standalone: true,
- imports: [NgFor],
- selector: 'app-root',
- template: `
-
- {{ heavyComputation(person, index) }}
-
- `,
-})
-export class AppComponent {
- persons = ['toto', 'jack'];
-
- heavyComputation(name: string, index: number) {
- // very heavy computation
- return `${name} - ${index}`;
- }
-}
diff --git a/apps/angular/pipe-easy/src/index.html b/apps/angular/pipe-easy/src/index.html
deleted file mode 100644
index eacdd37b7..000000000
--- a/apps/angular/pipe-easy/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- PipeEasy
-
-
-
-
-
-
-
-
diff --git a/apps/angular/pipe-hard/README.md b/apps/angular/pipe-hard/README.md
deleted file mode 100644
index ba801bd0c..000000000
--- a/apps/angular/pipe-hard/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Utility Wrapper Pipe
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-pipe-hard
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/10-pipe-utility/).
diff --git a/apps/angular/pipe-hard/project.json b/apps/angular/pipe-hard/project.json
deleted file mode 100644
index 544b201f2..000000000
--- a/apps/angular/pipe-hard/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-pipe-hard",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/pipe-hard/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/pipe-hard",
- "index": "apps/angular/pipe-hard/src/index.html",
- "main": "apps/angular/pipe-hard/src/main.ts",
- "polyfills": "apps/angular/pipe-hard/src/polyfills.ts",
- "tsConfig": "apps/angular/pipe-hard/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/pipe-hard/src/favicon.ico",
- "apps/angular/pipe-hard/src/assets"
- ],
- "styles": ["apps/angular/pipe-hard/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-pipe-hard:build:production"
- },
- "development": {
- "buildTarget": "angular-pipe-hard:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-pipe-hard:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/pipe-hard/**/*.ts",
- "apps/angular/pipe-hard/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/pipe-hard/src/app/app.component.ts b/apps/angular/pipe-hard/src/app/app.component.ts
deleted file mode 100644
index d91fc7436..000000000
--- a/apps/angular/pipe-hard/src/app/app.component.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { NgFor } from '@angular/common';
-import { Component } from '@angular/core';
-import { PersonUtils } from './person.utils';
-
-@Component({
- standalone: true,
- imports: [NgFor],
- selector: 'app-root',
- template: `
-
- {{ activity.name }} :
-
- {{ showName(person.name, index) }}
- {{ isAllowed(person.age, isFirst, activity.minimumAge) }}
-
-
- `,
-})
-export class AppComponent {
- persons = [
- { name: 'Toto', age: 10 },
- { name: 'Jack', age: 15 },
- { name: 'John', age: 30 },
- ];
-
- activities = [
- { name: 'biking', minimumAge: 12 },
- { name: 'hiking', minimumAge: 25 },
- { name: 'dancing', minimumAge: 1 },
- ];
-
- showName = PersonUtils.showName;
-
- isAllowed = PersonUtils.isAllowed;
-}
diff --git a/apps/angular/pipe-hard/src/index.html b/apps/angular/pipe-hard/src/index.html
deleted file mode 100644
index 0b81de34b..000000000
--- a/apps/angular/pipe-hard/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- PipeHard
-
-
-
-
-
-
-
-
diff --git a/apps/angular/pipe-intermediate/README.md b/apps/angular/pipe-intermediate/README.md
deleted file mode 100644
index 72809fd19..000000000
--- a/apps/angular/pipe-intermediate/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Wrap Function Pipe
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-pipe-intermediate
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/9-pipe-wrapFn/).
diff --git a/apps/angular/pipe-intermediate/project.json b/apps/angular/pipe-intermediate/project.json
deleted file mode 100644
index e12928037..000000000
--- a/apps/angular/pipe-intermediate/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-pipe-intermediate",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/pipe-intermediate/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/pipe-intermediate",
- "index": "apps/angular/pipe-intermediate/src/index.html",
- "main": "apps/angular/pipe-intermediate/src/main.ts",
- "polyfills": "apps/angular/pipe-intermediate/src/polyfills.ts",
- "tsConfig": "apps/angular/pipe-intermediate/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/pipe-intermediate/src/favicon.ico",
- "apps/angular/pipe-intermediate/src/assets"
- ],
- "styles": ["apps/angular/pipe-intermediate/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-pipe-intermediate:build:production"
- },
- "development": {
- "buildTarget": "angular-pipe-intermediate:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-pipe-intermediate:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/pipe-intermediate/**/*.ts",
- "apps/angular/pipe-intermediate/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/pipe-intermediate/src/app/app.component.ts b/apps/angular/pipe-intermediate/src/app/app.component.ts
deleted file mode 100644
index d9c163c93..000000000
--- a/apps/angular/pipe-intermediate/src/app/app.component.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { NgFor } from '@angular/common';
-import { Component } from '@angular/core';
-
-@Component({
- standalone: true,
- imports: [NgFor],
- selector: 'app-root',
- template: `
-
- {{ showName(person.name, index) }}
- {{ isAllowed(person.age, isFirst) }}
-
- `,
-})
-export class AppComponent {
- persons = [
- { name: 'Toto', age: 10 },
- { name: 'Jack', age: 15 },
- { name: 'John', age: 30 },
- ];
-
- showName(name: string, index: number) {
- // very heavy computation
- return `${name} - ${index}`;
- }
-
- isAllowed(age: number, isFirst: boolean) {
- if (isFirst) {
- return 'always allowed';
- } else {
- return age > 25 ? 'allowed' : 'declined';
- }
- }
-}
diff --git a/apps/angular/pipe-intermediate/src/index.html b/apps/angular/pipe-intermediate/src/index.html
deleted file mode 100644
index 1a8b2ee22..000000000
--- a/apps/angular/pipe-intermediate/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- PipeIntermediate
-
-
-
-
-
-
-
-
diff --git a/apps/angular/projection/jest.config.ts b/apps/angular/projection/jest.config.ts
deleted file mode 100644
index 2af97a39a..000000000
--- a/apps/angular/projection/jest.config.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'angular-projection',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- globals: {},
- coverageDirectory: '../../../coverage/apps/angular/projection',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/angular/projection/project.json b/apps/angular/projection/project.json
deleted file mode 100644
index f1d4943d3..000000000
--- a/apps/angular/projection/project.json
+++ /dev/null
@@ -1,87 +0,0 @@
-{
- "name": "angular-projection",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/projection/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/projection",
- "index": "apps/angular/projection/src/index.html",
- "browser": "apps/angular/projection/src/main.ts",
- "polyfills": ["apps/angular/projection/src/polyfills.ts"],
- "tsConfig": "apps/angular/projection/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/projection/src/favicon.ico",
- "apps/angular/projection/src/assets"
- ],
- "styles": ["apps/angular/projection/src/styles.scss"],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-projection:build:production"
- },
- "development": {
- "buildTarget": "angular-projection:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-projection:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/angular/projection/**/*.ts",
- "apps/angular/projection/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/angular/projection/jest.config.ts"
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/projection/src/app/app.component.ts b/apps/angular/projection/src/app/app.component.ts
deleted file mode 100644
index b1d076a9f..000000000
--- a/apps/angular/projection/src/app/app.component.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Component } from '@angular/core';
-import { CityCardComponent } from './component/city-card/city-card.component';
-import { StudentCardComponent } from './component/student-card/student-card.component';
-import { TeacherCardComponent } from './component/teacher-card/teacher-card.component';
-
-@Component({
- selector: 'app-root',
- template: `
-
- `,
- standalone: true,
- imports: [TeacherCardComponent, StudentCardComponent, CityCardComponent],
-})
-export class AppComponent {}
diff --git a/apps/angular/projection/src/app/component/city-card/city-card.component.ts b/apps/angular/projection/src/app/component/city-card/city-card.component.ts
deleted file mode 100644
index 30c8f88ec..000000000
--- a/apps/angular/projection/src/app/component/city-card/city-card.component.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-city-card',
- template: 'TODO City',
- standalone: true,
- imports: [],
-})
-export class CityCardComponent implements OnInit {
- constructor() {}
-
- ngOnInit(): void {}
-}
diff --git a/apps/angular/projection/src/app/component/student-card/student-card.component.ts b/apps/angular/projection/src/app/component/student-card/student-card.component.ts
deleted file mode 100644
index 441cda189..000000000
--- a/apps/angular/projection/src/app/component/student-card/student-card.component.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { FakeHttpService } from '../../data-access/fake-http.service';
-import { StudentStore } from '../../data-access/student.store';
-import { CardType } from '../../model/card.model';
-import { Student } from '../../model/student.model';
-import { CardComponent } from '../../ui/card/card.component';
-
-@Component({
- selector: 'app-student-card',
- template: `
-
- `,
- standalone: true,
- styles: [
- `
- ::ng-deep .bg-light-green {
- background-color: rgba(0, 250, 0, 0.1);
- }
- `,
- ],
- imports: [CardComponent],
-})
-export class StudentCardComponent implements OnInit {
- students: Student[] = [];
- cardType = CardType.STUDENT;
-
- constructor(
- private http: FakeHttpService,
- private store: StudentStore,
- ) {}
-
- ngOnInit(): void {
- this.http.fetchStudents$.subscribe((s) => this.store.addAll(s));
-
- this.store.students$.subscribe((s) => (this.students = s));
- }
-}
diff --git a/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts
deleted file mode 100644
index 995cb7c2f..000000000
--- a/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { FakeHttpService } from '../../data-access/fake-http.service';
-import { TeacherStore } from '../../data-access/teacher.store';
-import { CardType } from '../../model/card.model';
-import { Teacher } from '../../model/teacher.model';
-import { CardComponent } from '../../ui/card/card.component';
-
-@Component({
- selector: 'app-teacher-card',
- template: `
-
- `,
- styles: [
- `
- ::ng-deep .bg-light-red {
- background-color: rgba(250, 0, 0, 0.1);
- }
- `,
- ],
- standalone: true,
- imports: [CardComponent],
-})
-export class TeacherCardComponent implements OnInit {
- teachers: Teacher[] = [];
- cardType = CardType.TEACHER;
-
- constructor(
- private http: FakeHttpService,
- private store: TeacherStore,
- ) {}
-
- ngOnInit(): void {
- this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t));
-
- this.store.teachers$.subscribe((t) => (this.teachers = t));
- }
-}
diff --git a/apps/angular/projection/src/app/data-access/city.store.ts b/apps/angular/projection/src/app/data-access/city.store.ts
deleted file mode 100644
index 711dad1d7..000000000
--- a/apps/angular/projection/src/app/data-access/city.store.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Injectable } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
-import { City } from '../model/city.model';
-
-@Injectable({
- providedIn: 'root',
-})
-export class CityStore {
- private cities = new BehaviorSubject([]);
- cities$ = this.cities.asObservable();
-
- addAll(cities: City[]) {
- this.cities.next(cities);
- }
-
- addOne(student: City) {
- this.cities.next([...this.cities.value, student]);
- }
-
- deleteOne(id: number) {
- this.cities.next(this.cities.value.filter((s) => s.id !== id));
- }
-}
diff --git a/apps/angular/projection/src/app/data-access/student.store.ts b/apps/angular/projection/src/app/data-access/student.store.ts
deleted file mode 100644
index 7918118c3..000000000
--- a/apps/angular/projection/src/app/data-access/student.store.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Injectable } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
-import { Student } from '../model/student.model';
-
-@Injectable({
- providedIn: 'root',
-})
-export class StudentStore {
- private students = new BehaviorSubject([]);
- students$ = this.students.asObservable();
-
- addAll(students: Student[]) {
- this.students.next(students);
- }
-
- addOne(student: Student) {
- this.students.next([...this.students.value, student]);
- }
-
- deleteOne(id: number) {
- this.students.next(this.students.value.filter((s) => s.id !== id));
- }
-}
diff --git a/apps/angular/projection/src/app/data-access/teacher.store.ts b/apps/angular/projection/src/app/data-access/teacher.store.ts
deleted file mode 100644
index 93f68c4b1..000000000
--- a/apps/angular/projection/src/app/data-access/teacher.store.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Injectable } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
-import { Teacher } from '../model/teacher.model';
-
-@Injectable({
- providedIn: 'root',
-})
-export class TeacherStore {
- private teachers = new BehaviorSubject([]);
- teachers$ = this.teachers.asObservable();
-
- addAll(teachers: Teacher[]) {
- this.teachers.next(teachers);
- }
-
- addOne(teacher: Teacher) {
- this.teachers.next([...this.teachers.value, teacher]);
- }
-
- deleteOne(id: number) {
- this.teachers.next(this.teachers.value.filter((t) => t.id !== id));
- }
-}
diff --git a/apps/angular/projection/src/app/ui/card/card.component.ts b/apps/angular/projection/src/app/ui/card/card.component.ts
deleted file mode 100644
index f06c9ae00..000000000
--- a/apps/angular/projection/src/app/ui/card/card.component.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { NgFor, NgIf } from '@angular/common';
-import { Component, Input } from '@angular/core';
-import { randStudent, randTeacher } from '../../data-access/fake-http.service';
-import { StudentStore } from '../../data-access/student.store';
-import { TeacherStore } from '../../data-access/teacher.store';
-import { CardType } from '../../model/card.model';
-import { ListItemComponent } from '../list-item/list-item.component';
-
-@Component({
- selector: 'app-card',
- template: `
-
-

-

-
-
-
-
-
- `,
- standalone: true,
- imports: [NgIf, NgFor, ListItemComponent],
-})
-export class CardComponent {
- @Input() list: any[] | null = null;
- @Input() type!: CardType;
- @Input() customClass = '';
-
- CardType = CardType;
-
- constructor(
- private teacherStore: TeacherStore,
- private studentStore: StudentStore,
- ) {}
-
- addNewItem() {
- if (this.type === CardType.TEACHER) {
- this.teacherStore.addOne(randTeacher());
- } else if (this.type === CardType.STUDENT) {
- this.studentStore.addOne(randStudent());
- }
- }
-}
diff --git a/apps/angular/projection/src/app/ui/list-item/list-item.component.ts b/apps/angular/projection/src/app/ui/list-item/list-item.component.ts
deleted file mode 100644
index c0f9cff7f..000000000
--- a/apps/angular/projection/src/app/ui/list-item/list-item.component.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Component, Input } from '@angular/core';
-import { StudentStore } from '../../data-access/student.store';
-import { TeacherStore } from '../../data-access/teacher.store';
-import { CardType } from '../../model/card.model';
-
-@Component({
- selector: 'app-list-item',
- template: `
-
- {{ name }}
-
-
- `,
- standalone: true,
-})
-export class ListItemComponent {
- @Input() id!: number;
- @Input() name!: string;
- @Input() type!: CardType;
-
- constructor(
- private teacherStore: TeacherStore,
- private studentStore: StudentStore,
- ) {}
-
- delete(id: number) {
- if (this.type === CardType.TEACHER) {
- this.teacherStore.deleteOne(id);
- } else if (this.type === CardType.STUDENT) {
- this.studentStore.deleteOne(id);
- }
- }
-}
diff --git a/apps/angular/projection/src/index.html b/apps/angular/projection/src/index.html
deleted file mode 100644
index 7f19c5dfd..000000000
--- a/apps/angular/projection/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Projection
-
-
-
-
-
-
-
-
diff --git a/apps/angular/projection/src/main.ts b/apps/angular/projection/src/main.ts
deleted file mode 100644
index 9cd15da95..000000000
--- a/apps/angular/projection/src/main.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { bootstrapApplication } from '@angular/platform-browser';
-import { AppComponent } from './app/app.component';
-
-bootstrapApplication(AppComponent);
diff --git a/apps/angular/router-input/project.json b/apps/angular/router-input/project.json
deleted file mode 100644
index f76728ef1..000000000
--- a/apps/angular/router-input/project.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "angular-router-input",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/router-input/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/router-input",
- "index": "apps/angular/router-input/src/index.html",
- "main": "apps/angular/router-input/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/router-input/tsconfig.app.json",
- "assets": [
- "apps/angular/router-input/src/favicon.ico",
- "apps/angular/router-input/src/assets"
- ],
- "styles": ["apps/angular/router-input/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-router-input:build:production"
- },
- "development": {
- "buildTarget": "angular-router-input:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-router-input:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/router-input/**/*.ts",
- "apps/angular/router-input/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/angular/router-input/src/app/app.component.ts b/apps/angular/router-input/src/app/app.component.ts
deleted file mode 100644
index 1ef7e32aa..000000000
--- a/apps/angular/router-input/src/app/app.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Component } from '@angular/core';
-import { FormControl, ReactiveFormsModule } from '@angular/forms';
-import { RouterLink, RouterModule } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterLink, RouterModule, ReactiveFormsModule],
- selector: 'app-root',
- template: `
-
-
-
-
-
-
-
- `,
-})
-export class AppComponent {
- userName = new FormControl();
- testId = new FormControl();
-}
diff --git a/apps/angular/router-input/src/app/home.component.ts b/apps/angular/router-input/src/app/home.component.ts
deleted file mode 100644
index 2ef8c5eb4..000000000
--- a/apps/angular/router-input/src/app/home.component.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Component } from '@angular/core';
-@Component({
- selector: 'app-home',
- standalone: true,
- imports: [],
- template: `
- Home
- `,
-})
-export default class HomeComponent {}
diff --git a/apps/angular/router-input/src/index.html b/apps/angular/router-input/src/index.html
deleted file mode 100644
index daa121537..000000000
--- a/apps/angular/router-input/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- router-input
-
-
-
-
-
-
-
-
diff --git a/apps/angular/signal-input/README.md b/apps/angular/signal-input/README.md
deleted file mode 100644
index 78ef74d74..000000000
--- a/apps/angular/signal-input/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Signal Input
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-signal-input
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/43-signal-input/).
diff --git a/apps/angular/signal-input/project.json b/apps/angular/signal-input/project.json
deleted file mode 100644
index 00f1a6797..000000000
--- a/apps/angular/signal-input/project.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "name": "angular-signal-input",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/signal-input/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/signal-input",
- "index": "apps/angular/signal-input/src/index.html",
- "browser": "apps/angular/signal-input/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/signal-input/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/signal-input/src/favicon.ico",
- "apps/angular/signal-input/src/assets"
- ],
- "styles": ["apps/angular/signal-input/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-signal-input:build:production"
- },
- "development": {
- "buildTarget": "angular-signal-input:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-signal-input:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"]
- }
- }
-}
diff --git a/apps/angular/signal-input/src/app/app.component.ts b/apps/angular/signal-input/src/app/app.component.ts
deleted file mode 100644
index 22e64386e..000000000
--- a/apps/angular/signal-input/src/app/app.component.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { JsonPipe } from '@angular/common';
-import { Component } from '@angular/core';
-import { UserComponent } from './user.component';
-
-@Component({
- standalone: true,
- imports: [UserComponent, JsonPipe],
- selector: 'app-root',
- template: `
-
-
- Name:
-
- @if (showUser && !name.value) {
-
name required
- }
-
-
- LastName:
-
-
-
- Age:
-
-
-
-
- @if (showUser && !!name.value) {
-
- }
- `,
- host: {
- class: 'p-10 block flex flex-col gap-10',
- },
-})
-export class AppComponent {
- showUser = false;
-}
diff --git a/apps/angular/signal-input/src/index.html b/apps/angular/signal-input/src/index.html
deleted file mode 100644
index 4fc2af8ca..000000000
--- a/apps/angular/signal-input/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- angular-signal-input
-
-
-
-
-
-
-
-
diff --git a/apps/angular/styling/README.md b/apps/angular/styling/README.md
deleted file mode 100644
index d47efe3e8..000000000
--- a/apps/angular/styling/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Highly Customizable CSS
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve angular-styling
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/13-styling/).
diff --git a/apps/angular/styling/project.json b/apps/angular/styling/project.json
deleted file mode 100644
index 5fdaa3866..000000000
--- a/apps/angular/styling/project.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "name": "angular-styling",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/angular/styling/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/styling",
- "index": "apps/angular/styling/src/index.html",
- "main": "apps/angular/styling/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/styling/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/styling/src/favicon.ico",
- "apps/angular/styling/src/assets"
- ],
- "styles": ["apps/angular/styling/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-styling:build:production"
- },
- "development": {
- "buildTarget": "angular-styling:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-styling:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/angular/styling/**/*.ts",
- "apps/angular/styling/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/angular/styling/src/app/page.component.ts b/apps/angular/styling/src/app/page.component.ts
deleted file mode 100644
index 067453294..000000000
--- a/apps/angular/styling/src/app/page.component.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/* eslint-disable @angular-eslint/component-selector */
-import { Component } from '@angular/core';
-import { TextStaticComponent } from './static-text.component';
-import { TextComponent } from './text.component';
-
-@Component({
- selector: 'page',
- standalone: true,
- imports: [TextStaticComponent, TextComponent],
- template: `
-
-
-
- This is a blue text
- `,
-})
-export class PageComponent {}
diff --git a/apps/angular/styling/src/index.html b/apps/angular/styling/src/index.html
deleted file mode 100644
index 7ea1636bf..000000000
--- a/apps/angular/styling/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Styling
-
-
-
-
-
-
-
-
diff --git a/apps/angular/view-transition/project.json b/apps/angular/view-transition/project.json
deleted file mode 100644
index d0a27fd5f..000000000
--- a/apps/angular/view-transition/project.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "name": "angular-view-transition",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/angular/view-transition/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/angular/view-transition",
- "index": "apps/angular/view-transition/src/index.html",
- "browser": "apps/angular/view-transition/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/angular/view-transition/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/angular/view-transition/src/favicon.ico",
- "apps/angular/view-transition/src/assets"
- ],
- "styles": ["apps/angular/view-transition/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "angular-view-transition:build:production"
- },
- "development": {
- "buildTarget": "angular-view-transition:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "angular-view-transition:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"]
- }
- }
-}
diff --git a/apps/angular/view-transition/src/app/app.component.ts b/apps/angular/view-transition/src/app/app.component.ts
deleted file mode 100644
index da56c04c0..000000000
--- a/apps/angular/view-transition/src/app/app.component.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet],
- selector: 'app-root',
- template: `
-
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class AppComponent {}
diff --git a/apps/angular/view-transition/src/app/post/post.component.ts b/apps/angular/view-transition/src/app/post/post.component.ts
deleted file mode 100644
index 1e1c6fd89..000000000
--- a/apps/angular/view-transition/src/app/post/post.component.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { NgOptimizedImage } from '@angular/common';
-import {
- ChangeDetectionStrategy,
- Component,
- computed,
- input,
-} from '@angular/core';
-import { RouterLink } from '@angular/router';
-import { ThumbnailHeaderComponent } from '../blog/thumbnail-header.component';
-import { fakeTextChapters, posts } from '../data';
-import { PostHeaderComponent } from './post-header.component';
-
-@Component({
- selector: 'post',
- standalone: true,
- imports: [
- ThumbnailHeaderComponent,
- NgOptimizedImage,
- PostHeaderComponent,
- RouterLink,
- ],
- template: `
-
-
-
![]()
-
{{ post().title }}
-
- @for (chapter of fakeTextChapter; track $index) {
-
{{ chapter }}
- }
-
- `,
- host: {
- class: 'flex h-full justify-center',
- },
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export default class PostComponent {
- id = input.required();
- post = computed(() => posts.filter((p) => p.id === this.id())[0]);
-
- fakeTextChapter = fakeTextChapters;
-}
diff --git a/apps/angular/view-transition/src/styles.scss b/apps/angular/view-transition/src/styles.scss
deleted file mode 100644
index a90f0749c..000000000
--- a/apps/angular/view-transition/src/styles.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
diff --git a/apps/angular/view-transition/tsconfig.json b/apps/angular/view-transition/tsconfig.json
deleted file mode 100644
index db0ec0f25..000000000
--- a/apps/angular/view-transition/tsconfig.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "compilerOptions": {
- "target": "es2022",
- "useDefineForClassFields": false,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "noImplicitOverride": true,
- "noPropertyAccessFromIndexSignature": true,
- "noImplicitReturns": true,
- "noFallthroughCasesInSwitch": true,
- },
- "files": [],
- "include": [],
- "references": [
- {
- "path": "./tsconfig.app.json",
- },
- {
- "path": "./tsconfig.editor.json",
- },
- ],
- "extends": "../../../tsconfig.base.json",
- "angularCompilerOptions": {
- "enableI18nLegacyMessageIdFormat": false,
- "strictInjectionParameters": true,
- "strictInputAccessModifiers": true,
- "strictTemplates": true,
- },
-}
diff --git a/apps/forms/41-control-value-accessor/.eslintrc.json b/apps/forms/41-control-value-accessor/.eslintrc.json
new file mode 100644
index 000000000..8ebcbfd59
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/forms/control-value-accessor/README.md b/apps/forms/41-control-value-accessor/README.md
similarity index 100%
rename from apps/forms/control-value-accessor/README.md
rename to apps/forms/41-control-value-accessor/README.md
diff --git a/apps/forms/41-control-value-accessor/jest.config.ts b/apps/forms/41-control-value-accessor/jest.config.ts
new file mode 100644
index 000000000..48769acef
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'forms-control-value-accessor',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/forms/41-control-value-accessor',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/forms/41-control-value-accessor/project.json b/apps/forms/41-control-value-accessor/project.json
new file mode 100644
index 000000000..a1ec26bac
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/project.json
@@ -0,0 +1,80 @@
+{
+ "name": "forms-control-value-accessor",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/forms/41-control-value-accessor/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/forms/41-control-value-accessor",
+ "index": "apps/forms/41-control-value-accessor/src/index.html",
+ "browser": "apps/forms/41-control-value-accessor/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/forms/41-control-value-accessor/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/forms/41-control-value-accessor/src/favicon.ico",
+ "apps/forms/41-control-value-accessor/src/assets"
+ ],
+ "styles": ["apps/forms/41-control-value-accessor/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "forms-control-value-accessor:build:production"
+ },
+ "development": {
+ "buildTarget": "forms-control-value-accessor:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "forms-control-value-accessor:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/forms/41-control-value-accessor/src/app/app.component.ts b/apps/forms/41-control-value-accessor/src/app/app.component.ts
new file mode 100644
index 000000000..69134b864
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/src/app/app.component.ts
@@ -0,0 +1,15 @@
+import { Component } from '@angular/core';
+import { FeedbackFormComponent } from './feedback-form/feedback-form.component';
+
+@Component({
+ imports: [FeedbackFormComponent],
+ selector: 'app-root',
+ template: `
+
+ `,
+})
+export class AppComponent {
+ apiCall(event: Record): void {
+ console.log(event);
+ }
+}
diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.html b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.html
similarity index 100%
rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.html
rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.html
diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.scss b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.scss
similarity index 100%
rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.scss
rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.scss
diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts
similarity index 98%
rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts
rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts
index d99700db1..4110d6cf7 100644
--- a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts
+++ b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts
@@ -8,7 +8,6 @@ import {
import { RatingControlComponent } from '../rating-control/rating-control.component';
@Component({
- standalone: true,
imports: [RatingControlComponent, ReactiveFormsModule],
selector: 'app-feedback-form',
templateUrl: 'feedback-form.component.html',
diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.html b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.html
similarity index 100%
rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.html
rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.html
diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.scss b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.scss
similarity index 100%
rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.scss
rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.scss
diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.ts b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.ts
similarity index 100%
rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.ts
rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.ts
diff --git a/apps/ngrx/effect-selector/src/assets/.gitkeep b/apps/forms/41-control-value-accessor/src/assets/.gitkeep
similarity index 100%
rename from apps/ngrx/effect-selector/src/assets/.gitkeep
rename to apps/forms/41-control-value-accessor/src/assets/.gitkeep
diff --git a/apps/performance/christmas-web-worker/src/favicon.ico b/apps/forms/41-control-value-accessor/src/favicon.ico
similarity index 100%
rename from apps/performance/christmas-web-worker/src/favicon.ico
rename to apps/forms/41-control-value-accessor/src/favicon.ico
diff --git a/apps/forms/control-value-accessor/src/index.html b/apps/forms/41-control-value-accessor/src/index.html
similarity index 100%
rename from apps/forms/control-value-accessor/src/index.html
rename to apps/forms/41-control-value-accessor/src/index.html
diff --git a/apps/performance/christmas-web-worker/src/main.ts b/apps/forms/41-control-value-accessor/src/main.ts
similarity index 100%
rename from apps/performance/christmas-web-worker/src/main.ts
rename to apps/forms/41-control-value-accessor/src/main.ts
diff --git a/apps/performance/memoized/src/styles.scss b/apps/forms/41-control-value-accessor/src/styles.scss
similarity index 100%
rename from apps/performance/memoized/src/styles.scss
rename to apps/forms/41-control-value-accessor/src/styles.scss
diff --git a/apps/testing/checkbox/src/test-setup.ts b/apps/forms/41-control-value-accessor/src/test-setup.ts
similarity index 100%
rename from apps/testing/checkbox/src/test-setup.ts
rename to apps/forms/41-control-value-accessor/src/test-setup.ts
diff --git a/apps/performance/ngfor-biglist/tailwind.config.js b/apps/forms/41-control-value-accessor/tailwind.config.js
similarity index 100%
rename from apps/performance/ngfor-biglist/tailwind.config.js
rename to apps/forms/41-control-value-accessor/tailwind.config.js
diff --git a/apps/performance/ngfor-biglist/tsconfig.app.json b/apps/forms/41-control-value-accessor/tsconfig.app.json
similarity index 100%
rename from apps/performance/ngfor-biglist/tsconfig.app.json
rename to apps/forms/41-control-value-accessor/tsconfig.app.json
diff --git a/apps/performance/ngfor-optimize/tsconfig.editor.json b/apps/forms/41-control-value-accessor/tsconfig.editor.json
similarity index 100%
rename from apps/performance/ngfor-optimize/tsconfig.editor.json
rename to apps/forms/41-control-value-accessor/tsconfig.editor.json
diff --git a/apps/forms/41-control-value-accessor/tsconfig.json b/apps/forms/41-control-value-accessor/tsconfig.json
new file mode 100644
index 000000000..25ca437b4
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ },
+ {
+ "path": "./tsconfig.editor.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/forms/41-control-value-accessor/tsconfig.spec.json b/apps/forms/41-control-value-accessor/tsconfig.spec.json
new file mode 100644
index 000000000..1a4817a7d
--- /dev/null
+++ b/apps/forms/41-control-value-accessor/tsconfig.spec.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["jest", "node", "@testing-library/jest-dom"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": [
+ "jest.config.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/apps/forms/48-avoid-losing-form-data/.eslintrc.json b/apps/forms/48-avoid-losing-form-data/.eslintrc.json
new file mode 100644
index 000000000..8ebcbfd59
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/forms/48-avoid-losing-form-data/README.md b/apps/forms/48-avoid-losing-form-data/README.md
new file mode 100644
index 000000000..1c0e90b35
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/README.md
@@ -0,0 +1,11 @@
+# Avoid losing form data
+
+> author: [Timothy Alcaide](https://github.com/alcaidio)
+
+### Run Application
+
+```bash
+npx nx serve forms-avoid-losing-form-data
+```
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/forms/48-forms-avoid-losing-form-data/).
diff --git a/apps/forms/48-avoid-losing-form-data/project.json b/apps/forms/48-avoid-losing-form-data/project.json
new file mode 100644
index 000000000..9517d3123
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/project.json
@@ -0,0 +1,72 @@
+{
+ "name": "forms-avoid-losing-form-data",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/forms/48-avoid-losing-form-data/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/forms/48-avoid-losing-form-data",
+ "index": "apps/forms/48-avoid-losing-form-data/src/index.html",
+ "browser": "apps/forms/48-avoid-losing-form-data/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/forms/48-avoid-losing-form-data/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/forms/48-avoid-losing-form-data/src/favicon.ico",
+ "apps/forms/48-avoid-losing-form-data/src/assets"
+ ],
+ "styles": [
+ "apps/forms/48-avoid-losing-form-data/src/styles.scss",
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "forms-avoid-losing-form-data:build:production"
+ },
+ "development": {
+ "buildTarget": "forms-avoid-losing-form-data:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "forms-avoid-losing-form-data:build"
+ }
+ }
+ }
+}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts
new file mode 100644
index 000000000..2b5adc443
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts
@@ -0,0 +1,19 @@
+import { Component } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+import { NavComponent } from './ui/nav.component';
+
+@Component({
+ imports: [RouterOutlet, NavComponent],
+ selector: 'app-root',
+ template: `
+
+ `,
+})
+export class AppComponent {}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts
new file mode 100644
index 000000000..a7c1007b9
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts
@@ -0,0 +1,7 @@
+import { ApplicationConfig } from '@angular/core';
+import { provideRouter, withComponentInputBinding } from '@angular/router';
+import { appRoutes } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideRouter(appRoutes, withComponentInputBinding())],
+};
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts
new file mode 100644
index 000000000..84be34b9a
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts
@@ -0,0 +1,29 @@
+import { Route } from '@angular/router';
+import { JoinComponent } from './pages/join.component';
+import { PageComponent } from './pages/page.component';
+
+export const appRoutes: Route[] = [
+ {
+ path: '',
+ pathMatch: 'full',
+ redirectTo: 'form',
+ },
+ {
+ path: 'form',
+ loadComponent: () => JoinComponent,
+ },
+ {
+ path: 'page-1',
+ data: {
+ title: 'Page 1',
+ },
+ loadComponent: () => PageComponent,
+ },
+ {
+ path: 'page-2',
+ data: {
+ title: 'Page 2',
+ },
+ loadComponent: () => PageComponent,
+ },
+];
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts
new file mode 100644
index 000000000..51449a7fb
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts
@@ -0,0 +1,15 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { FormComponent } from '../ui/form.component';
+
+@Component({
+ imports: [FormComponent],
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class JoinComponent {}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts
new file mode 100644
index 000000000..13f4e09c2
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts
@@ -0,0 +1,14 @@
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+
+@Component({
+ standalone: true,
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PageComponent {
+ title = input.required();
+}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts
new file mode 100644
index 000000000..661da9bcf
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts
@@ -0,0 +1,30 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+// NOTE : this is just the dialog content, you need to implement dialog logic
+
+@Component({
+ standalone: true,
+ template: `
+
+
+ You have unsaved information!
+
+
+
Do you want to continue and lose them?
+
+
+
+
+
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AlertDialogComponent {}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts
new file mode 100644
index 000000000..f3190d517
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts
@@ -0,0 +1,77 @@
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
+
+@Component({
+ selector: 'app-form',
+ imports: [ReactiveFormsModule],
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class FormComponent {
+ private fb = inject(FormBuilder);
+
+ form = this.fb.nonNullable.group({
+ name: ['', { validators: [Validators.required] }],
+ email: ['', [Validators.required, Validators.email]], // other syntax
+ phone: '',
+ message: '',
+ });
+
+ onSubmit() {
+ if (this.form.valid) this.form.reset();
+ }
+}
diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts
new file mode 100644
index 000000000..269297280
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts
@@ -0,0 +1,32 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { RouterLink, RouterLinkActive } from '@angular/router';
+
+@Component({
+ selector: 'app-nav',
+ imports: [RouterLink, RouterLinkActive],
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class NavComponent {}
diff --git a/apps/ngrx/notification/src/assets/.gitkeep b/apps/forms/48-avoid-losing-form-data/src/assets/.gitkeep
similarity index 100%
rename from apps/ngrx/notification/src/assets/.gitkeep
rename to apps/forms/48-avoid-losing-form-data/src/assets/.gitkeep
diff --git a/apps/performance/default-onpush/src/favicon.ico b/apps/forms/48-avoid-losing-form-data/src/favicon.ico
similarity index 100%
rename from apps/performance/default-onpush/src/favicon.ico
rename to apps/forms/48-avoid-losing-form-data/src/favicon.ico
diff --git a/apps/forms/48-avoid-losing-form-data/src/index.html b/apps/forms/48-avoid-losing-form-data/src/index.html
new file mode 100644
index 000000000..ed75bb39d
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ form-avoid-losing-form-data
+
+
+
+
+
+
+
+
diff --git a/apps/performance/ngfor-optimize/src/main.ts b/apps/forms/48-avoid-losing-form-data/src/main.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/main.ts
rename to apps/forms/48-avoid-losing-form-data/src/main.ts
diff --git a/apps/performance/ngfor-biglist/src/styles.scss b/apps/forms/48-avoid-losing-form-data/src/styles.scss
similarity index 100%
rename from apps/performance/ngfor-biglist/src/styles.scss
rename to apps/forms/48-avoid-losing-form-data/src/styles.scss
diff --git a/apps/forms/48-avoid-losing-form-data/tailwind.config.js b/apps/forms/48-avoid-losing-form-data/tailwind.config.js
new file mode 100644
index 000000000..16f83c7f4
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/tailwind.config.js
@@ -0,0 +1,14 @@
+const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind');
+const { join } = require('path');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'),
+ ...createGlobPatternsForDependencies(__dirname),
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [require('@tailwindcss/forms')],
+};
diff --git a/apps/performance/ngfor-optimize/tsconfig.app.json b/apps/forms/48-avoid-losing-form-data/tsconfig.app.json
similarity index 100%
rename from apps/performance/ngfor-optimize/tsconfig.app.json
rename to apps/forms/48-avoid-losing-form-data/tsconfig.app.json
diff --git a/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json b/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json
new file mode 100644
index 000000000..a8ac182c0
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {},
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/forms/48-avoid-losing-form-data/tsconfig.json b/apps/forms/48-avoid-losing-form-data/tsconfig.json
new file mode 100644
index 000000000..3df17b921
--- /dev/null
+++ b/apps/forms/48-avoid-losing-form-data/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.editor.json"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "extends": "../../../tsconfig.base.json",
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/apps/forms/control-value-accessor/jest.config.ts b/apps/forms/control-value-accessor/jest.config.ts
deleted file mode 100644
index a52c89870..000000000
--- a/apps/forms/control-value-accessor/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'forms-control-value-accessor',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/forms/control-value-accessor',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/forms/control-value-accessor/project.json b/apps/forms/control-value-accessor/project.json
deleted file mode 100644
index 3f232a934..000000000
--- a/apps/forms/control-value-accessor/project.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "name": "forms-control-value-accessor",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/forms/control-value-accessor/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/forms/control-value-accessor",
- "index": "apps/forms/control-value-accessor/src/index.html",
- "browser": "apps/forms/control-value-accessor/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/forms/control-value-accessor/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/forms/control-value-accessor/src/favicon.ico",
- "apps/forms/control-value-accessor/src/assets"
- ],
- "styles": ["apps/forms/control-value-accessor/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "forms-control-value-accessor:build:production"
- },
- "development": {
- "buildTarget": "forms-control-value-accessor:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "forms-control-value-accessor:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/forms/control-value-accessor/**/*.ts",
- "apps/forms/control-value-accessor/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/forms/control-value-accessor/jest.config.ts"
- }
- }
- }
-}
diff --git a/apps/forms/control-value-accessor/src/app/app.component.ts b/apps/forms/control-value-accessor/src/app/app.component.ts
deleted file mode 100644
index f56b5d7d9..000000000
--- a/apps/forms/control-value-accessor/src/app/app.component.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Component } from '@angular/core';
-import { FeedbackFormComponent } from './feedback-form/feedback-form.component';
-
-@Component({
- standalone: true,
- imports: [FeedbackFormComponent],
- selector: 'app-root',
- template: `
-
- `,
-})
-export class AppComponent {
- apiCall(event: Record): void {
- console.log(event);
- }
-}
diff --git a/apps/ngrx/effect-selector/README.md b/apps/ngrx/effect-selector/README.md
deleted file mode 100644
index b12a5341e..000000000
--- a/apps/ngrx/effect-selector/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Effect vs Selector
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve ngrx-effect-selector
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/2-effect-selector/).
diff --git a/apps/ngrx/effect-selector/jest.config.ts b/apps/ngrx/effect-selector/jest.config.ts
deleted file mode 100644
index 7e97f0ba2..000000000
--- a/apps/ngrx/effect-selector/jest.config.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'ngrx-effect-selector',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- globals: {},
- coverageDirectory: '../../../coverage/apps/ngrx/effect-selector',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/ngrx/effect-selector/project.json b/apps/ngrx/effect-selector/project.json
deleted file mode 100644
index f050ffaf0..000000000
--- a/apps/ngrx/effect-selector/project.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "name": "ngrx-effect-selector",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/ngrx/effect-selector/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/ngrx/effect-selector",
- "index": "apps/ngrx/effect-selector/src/index.html",
- "main": "apps/ngrx/effect-selector/src/main.ts",
- "polyfills": "apps/ngrx/effect-selector/src/polyfills.ts",
- "tsConfig": "apps/ngrx/effect-selector/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/ngrx/effect-selector/src/favicon.ico",
- "apps/ngrx/effect-selector/src/assets"
- ],
- "styles": ["apps/ngrx/effect-selector/src/styles.scss"],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "ngrx-effect-selector:build:production"
- },
- "development": {
- "buildTarget": "ngrx-effect-selector:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "ngrx-effect-selector:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/ngrx/effect-selector/**/*.ts",
- "apps/ngrx/effect-selector/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/ngrx/effect-selector/jest.config.ts"
- }
- }
- },
- "tags": []
-}
diff --git a/apps/ngrx/effect-selector/src/app/app.component.ts b/apps/ngrx/effect-selector/src/app/app.component.ts
deleted file mode 100644
index 1e4836644..000000000
--- a/apps/ngrx/effect-selector/src/app/app.component.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { AsyncPipe, NgFor } from '@angular/common';
-import {
- ChangeDetectionStrategy,
- Component,
- OnInit,
- inject,
-} from '@angular/core';
-import { Store } from '@ngrx/store';
-import { loadActivities } from './store/activity/activity.actions';
-import { ActivityType } from './store/activity/activity.model';
-import { selectActivities } from './store/activity/activity.selectors';
-import { loadStatuses } from './store/status/status.actions';
-import { selectAllTeachersByActivityType } from './store/status/status.selectors';
-import { loadUsers } from './store/user/user.actions';
-
-@Component({
- selector: 'app-root',
- standalone: true,
- imports: [NgFor, AsyncPipe],
- template: `
- Activity Board
-
-
-
Activity Name: {{ activity.name }}
-
Main teacher: {{ activity.teacher.name }}
-
All teachers available for : {{ activity.type }} are
-
- -
- {{ teacher.name }}
-
-
-
-
- `,
- styles: [
- `
- section {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 2px;
- }
-
- .card {
- display: flex;
- flex-direction: column;
- border: solid;
- border-width: 1px;
- border-color: black;
- padding: 2px;
- }
- `,
- ],
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class AppComponent implements OnInit {
- private store = inject(Store);
-
- activities$ = this.store.select(selectActivities);
-
- ngOnInit(): void {
- this.store.dispatch(loadActivities());
- this.store.dispatch(loadUsers());
- this.store.dispatch(loadStatuses());
- }
-
- getAllTeachersForActivityType$ = (type: ActivityType) =>
- this.store.select(selectAllTeachersByActivityType(type));
-}
diff --git a/apps/ngrx/effect-selector/src/app/app.config.ts b/apps/ngrx/effect-selector/src/app/app.config.ts
deleted file mode 100644
index d59c436ed..000000000
--- a/apps/ngrx/effect-selector/src/app/app.config.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { ApplicationConfig } from '@angular/core';
-import { provideEffects } from '@ngrx/effects';
-import { provideStore } from '@ngrx/store';
-import { ActivityEffects } from './store/activity/activity.effects';
-import {
- activityFeatureKey,
- activityReducer,
-} from './store/activity/activity.reducer';
-import { StatusEffects } from './store/status/status.effects';
-import { UserEffects } from './store/user/user.effects';
-
-import { statusFeatureKey, statusReducer } from './store/status/status.reducer';
-
-import { userFeatureKey, userReducer } from './store/user/user.reducer';
-
-const reducers = {
- [statusFeatureKey]: statusReducer,
- [activityFeatureKey]: activityReducer,
- [userFeatureKey]: userReducer,
-};
-
-export const appConfig: ApplicationConfig = {
- providers: [
- provideStore(reducers),
- provideEffects([ActivityEffects, UserEffects, StatusEffects]),
- ],
-};
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts
deleted file mode 100644
index c8affff54..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createAction, props } from '@ngrx/store';
-import { Activity } from './activity.model';
-
-export const loadActivities = createAction('[Activity Effect] Load Activities');
-
-export const loadActivitiesSuccess = createAction(
- '[Activity Effect] Load Activities Success',
- props<{ activities: Activity[] }>(),
-);
-
-export const loadActivitiesFailure = createAction(
- '[Activity Effect] Load Activities Failure',
- props<{ error: unknown }>(),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts
deleted file mode 100644
index 88f8b2317..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { of } from 'rxjs';
-import { catchError, concatMap, map } from 'rxjs/operators';
-import * as ActivityActions from './activity.actions';
-import { ActivityService } from './activity.service';
-
-@Injectable()
-export class ActivityEffects {
- loadActivities$ = createEffect(() => {
- return this.actions$.pipe(
- ofType(ActivityActions.loadActivities),
- concatMap(() =>
- this.ActivityService.fetchActivities().pipe(
- map((activities) =>
- ActivityActions.loadActivitiesSuccess({ activities }),
- ),
- catchError((error) =>
- of(ActivityActions.loadActivitiesFailure({ error })),
- ),
- ),
- ),
- );
- });
-
- constructor(
- private actions$: Actions,
- private ActivityService: ActivityService,
- ) {}
-}
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts
deleted file mode 100644
index 75f188132..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import {
- incrementalNumber,
- rand,
- randFirstName,
- randText,
-} from '@ngneat/falso';
-
-export const activityType = [
- 'Sport',
- 'Sciences',
- 'History',
- 'Maths',
- 'Physics',
-] as const;
-export type ActivityType = (typeof activityType)[number];
-
-export interface Person {
- id: number;
- name: string;
-}
-
-export interface Activity {
- id: number;
- name: string;
- type: ActivityType;
- teacher: Person;
-}
-
-const factoryPerson = incrementalNumber();
-
-export const randPerson = () => ({
- id: factoryPerson(),
- name: randFirstName(),
-});
-
-const factoryActivity = incrementalNumber();
-
-export const randActivity = (): Activity => ({
- id: factoryActivity(),
- name: randText(),
- type: rand(activityType),
- teacher: randPerson(),
-});
-
-export const activities: Activity[] = [
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
- randActivity(),
-];
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts
deleted file mode 100644
index b7285e8f6..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { createReducer, on } from '@ngrx/store';
-import * as ActivityActions from './activity.actions';
-import { Activity } from './activity.model';
-
-export const activityFeatureKey = 'Activity';
-
-export interface ActivityState {
- activities: Activity[];
-}
-
-export const initialState: ActivityState = {
- activities: [],
-};
-
-export const activityReducer = createReducer(
- initialState,
- on(ActivityActions.loadActivitiesSuccess, (state, { activities }) => ({
- ...state,
- activities,
- })),
- on(ActivityActions.loadActivitiesFailure, (state) => ({
- state,
- activities: [],
- })),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts
deleted file mode 100644
index 6c6a25a65..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createFeatureSelector, createSelector } from '@ngrx/store';
-import { ActivityState, activityFeatureKey } from './activity.reducer';
-
-export const selectActivityState =
- createFeatureSelector(activityFeatureKey);
-
-export const selectActivities = createSelector(
- selectActivityState,
- (state) => state.activities,
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts
deleted file mode 100644
index 07aa8f8ad..000000000
--- a/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Injectable } from '@angular/core';
-import { map, timer } from 'rxjs';
-import { activities } from './activity.model';
-
-@Injectable({
- providedIn: 'root',
-})
-export class ActivityService {
- fetchActivities = () => timer(500).pipe(map(() => activities));
-}
diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts b/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts
deleted file mode 100644
index 8fc2ddc49..000000000
--- a/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { createAction, props } from '@ngrx/store';
-import { Status } from './status.model';
-
-export const loadStatuses = createAction('[Status] Load Statuses');
-
-export const loadStatusesSuccess = createAction(
- '[Status] Load Statuses Success',
- props<{ statuses: Status[] }>(),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts b/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts
deleted file mode 100644
index 997eb0c1f..000000000
--- a/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { Store } from '@ngrx/store';
-import { combineLatest, concatMap, map } from 'rxjs';
-import { selectActivities } from '../activity/activity.selectors';
-import { selectUser } from '../user/user.selectors';
-import * as StatusActions from './status.actions';
-import { Status } from './status.model';
-
-@Injectable()
-export class StatusEffects {
- loadStatuses$ = createEffect(() => {
- return this.actions$.pipe(
- ofType(StatusActions.loadStatuses),
- concatMap(() =>
- combineLatest([
- this.store.select(selectUser),
- this.store.select(selectActivities),
- ]).pipe(
- map(([user, activities]): Status[] => {
- if (user?.isAdmin) {
- return activities.reduce(
- (status: Status[], activity): Status[] => {
- const index = status.findIndex(
- (s) => s.name === activity.type,
- );
- if (index === -1) {
- return [
- ...status,
- { name: activity.type, teachers: [activity.teacher] },
- ];
- } else {
- status[index].teachers.push(activity.teacher);
- return status;
- }
- },
- [],
- );
- }
- return [];
- }),
- map((statuses) => StatusActions.loadStatusesSuccess({ statuses })),
- ),
- ),
- );
- });
-
- constructor(
- private actions$: Actions,
- private store: Store,
- ) {}
-}
diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.model.ts b/apps/ngrx/effect-selector/src/app/store/status/status.model.ts
deleted file mode 100644
index 07733834a..000000000
--- a/apps/ngrx/effect-selector/src/app/store/status/status.model.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { ActivityType, Person } from '../activity/activity.model';
-
-export interface Status {
- name: ActivityType;
- teachers: Person[];
-}
diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts b/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts
deleted file mode 100644
index b91cbe2fb..000000000
--- a/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { createReducer, on } from '@ngrx/store';
-import { ActivityType, Person } from '../activity/activity.model';
-import * as StatusActions from './status.actions';
-import { Status } from './status.model';
-
-export const statusFeatureKey = 'status';
-
-export interface StatusState {
- statuses: Status[];
- teachersMap: Map;
-}
-
-export const initialState: StatusState = {
- statuses: [],
- teachersMap: new Map(),
-};
-
-export const statusReducer = createReducer(
- initialState,
- on(StatusActions.loadStatusesSuccess, (state, { statuses }): StatusState => {
- const map = new Map();
- statuses.forEach((s) => map.set(s.name, s.teachers));
- return {
- ...state,
- statuses,
- teachersMap: map,
- };
- }),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts b/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts
deleted file mode 100644
index 80ed059a6..000000000
--- a/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { createFeatureSelector, createSelector } from '@ngrx/store';
-import { ActivityType } from '../activity/activity.model';
-import { StatusState, statusFeatureKey } from './status.reducer';
-
-export const selectStatusState =
- createFeatureSelector(statusFeatureKey);
-
-export const selectStatuses = createSelector(
- selectStatusState,
- (state) => state.statuses,
-);
-
-export const selectAllTeachersByActivityType = (name: ActivityType) =>
- createSelector(
- selectStatusState,
- (state) => state.teachersMap.get(name) ?? [],
- );
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts b/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts
deleted file mode 100644
index a73147dce..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createAction, props } from '@ngrx/store';
-import { User } from './user.model';
-
-export const loadUsers = createAction('[User] Load Users');
-
-export const loadUsersSuccess = createAction(
- '[User] Load Users Success',
- props<{ user: User }>(),
-);
-
-export const loadUsersFailure = createAction(
- '[User] Load Users Failure',
- props<{ error: unknown }>(),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts b/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts
deleted file mode 100644
index fff3f6f6c..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { of } from 'rxjs';
-import { catchError, concatMap, map } from 'rxjs/operators';
-import * as UserActions from './user.actions';
-import { UserService } from './user.service';
-
-@Injectable()
-export class UserEffects {
- loadUsers$ = createEffect(() => {
- return this.actions$.pipe(
- ofType(UserActions.loadUsers),
- concatMap(() =>
- this.userService.fetchUser().pipe(
- map((user) => UserActions.loadUsersSuccess({ user })),
- catchError((error) => of(UserActions.loadUsersFailure({ error }))),
- ),
- ),
- );
- });
-
- constructor(
- private actions$: Actions,
- private userService: UserService,
- ) {}
-}
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.model.ts b/apps/ngrx/effect-selector/src/app/store/user/user.model.ts
deleted file mode 100644
index d7692041c..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.model.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { randFirstName, randLastName, randText } from '@ngneat/falso';
-
-export interface User {
- firstname: string;
- lastname: string;
- isAdmin: boolean;
- apiKey: string;
-}
-
-export const user: User = {
- firstname: randFirstName(),
- lastname: randLastName(),
- isAdmin: true,
- apiKey: randText(),
-};
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts b/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts
deleted file mode 100644
index 3f4768c18..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { createReducer, on } from '@ngrx/store';
-import * as UserActions from './user.actions';
-import { User } from './user.model';
-
-export const userFeatureKey = 'user';
-
-export interface UserState {
- user?: User;
-}
-
-export const initialState: UserState = {
- user: undefined,
-};
-
-export const userReducer = createReducer(
- initialState,
- on(UserActions.loadUsersSuccess, (state, { user }) => ({ ...state, user })),
- on(UserActions.loadUsersFailure, (state) => ({ ...state, user: undefined })),
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts b/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts
deleted file mode 100644
index 7970b0dfe..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { createFeatureSelector, createSelector } from '@ngrx/store';
-import { UserState, userFeatureKey } from './user.reducer';
-
-export const selectUserState = createFeatureSelector(userFeatureKey);
-
-export const selectUser = createSelector(
- selectUserState,
- (state) => state.user,
-);
diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.service.ts b/apps/ngrx/effect-selector/src/app/store/user/user.service.ts
deleted file mode 100644
index a407b020a..000000000
--- a/apps/ngrx/effect-selector/src/app/store/user/user.service.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Injectable } from '@angular/core';
-import { map, timer } from 'rxjs';
-import { user } from './user.model';
-
-@Injectable({
- providedIn: 'root',
-})
-export class UserService {
- fetchUser = () => timer(500).pipe(map(() => user));
-}
diff --git a/apps/ngrx/effect-selector/src/index.html b/apps/ngrx/effect-selector/src/index.html
deleted file mode 100644
index 21d573669..000000000
--- a/apps/ngrx/effect-selector/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Ngrx1
-
-
-
-
-
-
-
-
diff --git a/apps/ngrx/effect-selector/src/main.ts b/apps/ngrx/effect-selector/src/main.ts
deleted file mode 100644
index 31c2a3482..000000000
--- a/apps/ngrx/effect-selector/src/main.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { bootstrapApplication } from '@angular/platform-browser';
-import { appConfig } from './app/app.config';
-
-import { AppComponent } from './app/app.component';
-
-bootstrapApplication(AppComponent, appConfig);
diff --git a/apps/ngrx/effect-selector/src/polyfills.ts b/apps/ngrx/effect-selector/src/polyfills.ts
deleted file mode 100644
index e4555ed11..000000000
--- a/apps/ngrx/effect-selector/src/polyfills.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * This file includes polyfills needed by Angular and is loaded before the app.
- * You can add your own extra polyfills to this file.
- *
- * This file is divided into 2 sections:
- * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
- * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
- * file.
- *
- * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
- * automatically update themselves. This includes recent versions of Safari, Chrome (including
- * Opera), Edge on the desktop, and iOS and Chrome on mobile.
- *
- * Learn more in https://angular.io/guide/browser-support
- */
-
-/***************************************************************************************************
- * BROWSER POLYFILLS
- */
-
-/**
- * By default, zone.js will patch all possible macroTask and DomEvents
- * user can disable parts of macroTask/DomEvents patch by setting following flags
- * because those flags need to be set before `zone.js` being loaded, and webpack
- * will put import in the top of bundle, so user need to create a separate file
- * in this directory (for example: zone-flags.ts), and put the following flags
- * into that file, and then add the following code before importing zone.js.
- * import './zone-flags';
- *
- * The flags allowed in zone-flags.ts are listed here.
- *
- * The following flags will work for all browsers.
- *
- * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
- * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
- * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
- *
- * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
- * with the following flag, it will bypass `zone.js` patch for IE/Edge
- *
- * (window as any).__Zone_enable_cross_context_check = true;
- *
- */
-
-/***************************************************************************************************
- * Zone JS is required by default for Angular itself.
- */
-import 'zone.js'; // Included with Angular CLI.
-
-/***************************************************************************************************
- * APPLICATION IMPORTS
- */
diff --git a/apps/ngrx/effect-selector/tsconfig.app.json b/apps/ngrx/effect-selector/tsconfig.app.json
deleted file mode 100644
index 7a4dbc47e..000000000
--- a/apps/ngrx/effect-selector/tsconfig.app.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "outDir": "../../../dist/out-tsc",
- "types": [],
- "target": "ES2022",
- "useDefineForClassFields": false
- },
- "files": ["src/main.ts", "src/polyfills.ts"],
- "include": ["src/**/*.d.ts"],
- "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"]
-}
diff --git a/apps/ngrx/effect-selector/tsconfig.editor.json b/apps/ngrx/effect-selector/tsconfig.editor.json
deleted file mode 100644
index 20c4afdbf..000000000
--- a/apps/ngrx/effect-selector/tsconfig.editor.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "include": ["**/*.ts"],
- "compilerOptions": {
- "types": ["jest", "node"]
- }
-}
diff --git a/apps/ngrx/effect-selector/tsconfig.json b/apps/ngrx/effect-selector/tsconfig.json
deleted file mode 100644
index 52eb4f718..000000000
--- a/apps/ngrx/effect-selector/tsconfig.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "files": [],
- "include": [],
- "references": [
- {
- "path": "./tsconfig.app.json"
- },
- {
- "path": "./tsconfig.spec.json"
- },
- {
- "path": "./tsconfig.editor.json"
- }
- ],
- "compilerOptions": {
- "target": "es2020",
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "noImplicitOverride": true,
- "noPropertyAccessFromIndexSignature": true,
- "noImplicitReturns": true,
- "noFallthroughCasesInSwitch": true
- },
- "angularCompilerOptions": {
- "enableI18nLegacyMessageIdFormat": false,
- "strictInjectionParameters": true,
- "strictInputAccessModifiers": true,
- "strictTemplates": true
- }
-}
diff --git a/apps/ngrx/effect-selector/tsconfig.spec.json b/apps/ngrx/effect-selector/tsconfig.spec.json
deleted file mode 100644
index 7aa46d88c..000000000
--- a/apps/ngrx/effect-selector/tsconfig.spec.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "outDir": "../../../dist/out-tsc",
- "module": "commonjs",
- "types": ["jest", "node"]
- },
- "files": ["src/test-setup.ts"],
- "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
-}
diff --git a/apps/ngrx/notification/README.md b/apps/ngrx/notification/README.md
deleted file mode 100644
index 36acdab46..000000000
--- a/apps/ngrx/notification/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Power of Effect
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve ngrx-notification
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/7-power-effect/).
diff --git a/apps/ngrx/notification/project.json b/apps/ngrx/notification/project.json
deleted file mode 100644
index 5182ec85a..000000000
--- a/apps/ngrx/notification/project.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
- "name": "ngrx-notification",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/ngrx/notification/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/ngrx/notification",
- "index": "apps/ngrx/notification/src/index.html",
- "main": "apps/ngrx/notification/src/main.ts",
- "polyfills": "apps/ngrx/notification/src/polyfills.ts",
- "tsConfig": "apps/ngrx/notification/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/ngrx/notification/src/favicon.ico",
- "apps/ngrx/notification/src/assets"
- ],
- "styles": [
- "apps/ngrx/notification/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "ngrx-notification:build:production"
- },
- "development": {
- "buildTarget": "ngrx-notification:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "ngrx-notification:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "options": {
- "lintFilePatterns": [
- "apps/ngrx/notification/**/*.ts",
- "apps/ngrx/notification/**/*.html"
- ]
- }
- }
- },
- "tags": []
-}
diff --git a/apps/ngrx/notification/src/app/app.actions.ts b/apps/ngrx/notification/src/app/app.actions.ts
deleted file mode 100644
index 3dcba8134..000000000
--- a/apps/ngrx/notification/src/app/app.actions.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { createActionGroup, emptyProps } from '@ngrx/store';
-
-// This is the global actions.
-export const appActions = createActionGroup({
- source: 'App Component',
- events: {
- 'Init App': emptyProps(),
- },
-});
diff --git a/apps/ngrx/notification/src/app/app.component.ts b/apps/ngrx/notification/src/app/app.component.ts
deleted file mode 100644
index dc14376ac..000000000
--- a/apps/ngrx/notification/src/app/app.component.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Component, inject, OnInit } from '@angular/core';
-import { RouterLink, RouterOutlet } from '@angular/router';
-import { Store } from '@ngrx/store';
-import { appActions } from './app.actions';
-
-@Component({
- standalone: true,
- imports: [RouterOutlet, RouterLink],
- selector: 'app-root',
- template: `
-
-
-
- `,
- styles: [
- `
- :host {
- display: flex;
- flex-direction: column;
- gap: 20px;
-
- nav {
- display: flex;
- gap: 20px;
- }
- }
- `,
- ],
-})
-export class AppComponent implements OnInit {
- private store = inject(Store);
-
- ngOnInit(): void {
- this.store.dispatch(appActions.initApp());
- }
-}
diff --git a/apps/ngrx/notification/src/app/app.config.ts b/apps/ngrx/notification/src/app/app.config.ts
deleted file mode 100644
index b36822344..000000000
--- a/apps/ngrx/notification/src/app/app.config.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { FakeBackendService } from '@angular-challenges/ngrx-notification/backend';
-import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core';
-import { provideAnimations } from '@angular/platform-browser/animations';
-import { provideRouter } from '@angular/router';
-import { provideEffects } from '@ngrx/effects';
-import { provideStore } from '@ngrx/store';
-import { NotificationService } from './data-access/notification.service';
-import { ROUTES } from './routes';
-import { StudentEffects } from './student/store/student.effects';
-import {
- studentReducer,
- studentsFeatureKey,
-} from './student/store/student.reducer';
-import { TeacherEffects } from './teacher/store/teacher.effects';
-import {
- teacherReducer,
- teachersFeatureKey,
-} from './teacher/store/teacher.reducer';
-
-const REDUCERS = {
- [teachersFeatureKey]: teacherReducer,
- [studentsFeatureKey]: studentReducer,
-};
-
-export const appConfig: ApplicationConfig = {
- providers: [
- provideStore(REDUCERS),
- provideEffects([TeacherEffects, StudentEffects]),
- provideRouter(ROUTES),
- {
- provide: APP_INITIALIZER,
- multi: true,
- useFactory: () => {
- const service = inject(FakeBackendService);
- return () => service.start();
- },
- },
- {
- provide: APP_INITIALIZER,
- multi: true,
- useFactory: () => {
- const service = inject(NotificationService);
- return () => service.init();
- },
- },
- provideAnimations(),
- ],
-};
diff --git a/apps/ngrx/notification/src/app/data-access/http.service.ts b/apps/ngrx/notification/src/app/data-access/http.service.ts
deleted file mode 100644
index b5a59aab0..000000000
--- a/apps/ngrx/notification/src/app/data-access/http.service.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { FakeBackendService } from '@angular-challenges/ngrx-notification/backend';
-import { inject, Injectable } from '@angular/core';
-import { take } from 'rxjs';
-
-@Injectable({ providedIn: 'root' })
-export class HttpService {
- private fakeBackend = inject(FakeBackendService);
-
- getAllTeachers = () => this.fakeBackend.getAllTeachers().pipe(take(1));
-
- getAllStudents = () => this.fakeBackend.getAllStudents().pipe(take(1));
-
- getAllSchools = () => this.fakeBackend.getAllSchools().pipe(take(1));
-}
diff --git a/apps/ngrx/notification/src/app/data-access/notification.service.ts b/apps/ngrx/notification/src/app/data-access/notification.service.ts
deleted file mode 100644
index b11614054..000000000
--- a/apps/ngrx/notification/src/app/data-access/notification.service.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { PushService } from '@angular-challenges/ngrx-notification/backend';
-import {
- isSchool,
- isStudent,
- isTeacher,
- Push,
-} from '@angular-challenges/ngrx-notification/model';
-import { inject, Injectable } from '@angular/core';
-import { Store } from '@ngrx/store';
-import { filter } from 'rxjs';
-import { studentActions } from '../student/store/student.actions';
-import { teacherActions } from '../teacher/store/teacher.actions';
-
-@Injectable({ providedIn: 'root' })
-export class NotificationService {
- private pushService = inject(PushService);
- private store = inject(Store);
-
- init() {
- this.pushService.notification$
- .pipe(filter(Boolean))
- .subscribe((notification: Push) => {
- if (isTeacher(notification)) {
- this.store.dispatch(
- teacherActions.addOneTeacher({ teacher: notification }),
- );
- }
- if (isStudent(notification)) {
- this.store.dispatch(
- studentActions.addOneStudent({ student: notification }),
- );
- }
- if (isSchool(notification)) {
- // SchoolStore is a ComponentStore. We can't dispatch a school action here.
- // We are stuck. We must have done something wrong and need to refactor...
- }
- });
- }
-}
diff --git a/apps/ngrx/notification/src/app/routes.ts b/apps/ngrx/notification/src/app/routes.ts
deleted file mode 100644
index 7db44a4dc..000000000
--- a/apps/ngrx/notification/src/app/routes.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Route } from '@angular/router';
-import { TeacherComponent } from './teacher/teacher.component';
-
-export const ROUTES: Route[] = [
- { path: '', pathMatch: 'full', redirectTo: 'teacher' },
- {
- path: 'teacher',
- component: TeacherComponent,
- },
- {
- path: 'student',
- loadComponent: () =>
- import('./student/student.component').then((m) => m.StudentComponent),
- },
- {
- path: 'school',
- loadComponent: () =>
- import('./school/school.component').then((m) => m.SchoolComponent),
- },
-];
diff --git a/apps/ngrx/notification/src/app/school/school.component.ts b/apps/ngrx/notification/src/app/school/school.component.ts
deleted file mode 100644
index af58af9c1..000000000
--- a/apps/ngrx/notification/src/app/school/school.component.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/* eslint-disable @angular-eslint/component-selector */
-import { AsyncPipe, NgFor } from '@angular/common';
-import { Component, inject } from '@angular/core';
-import { provideComponentStore } from '@ngrx/component-store';
-import { SchoolStore } from './school.store';
-
-@Component({
- standalone: true,
- imports: [NgFor, AsyncPipe],
- providers: [provideComponentStore(SchoolStore)],
- selector: 'school',
- template: `
- SCHOOL
-
- {{ school.name }} - {{ school.version }}
-
- `,
- styles: [
- `
- :host {
- display: block;
- width: fit-content;
- height: fit-content;
- border: 1px solid red;
- padding: 4px;
- }
- `,
- ],
-})
-export class SchoolComponent {
- private store = inject(SchoolStore);
- school$ = this.store.schools$;
-}
diff --git a/apps/ngrx/notification/src/app/school/school.store.ts b/apps/ngrx/notification/src/app/school/school.store.ts
deleted file mode 100644
index 0fd31fa6d..000000000
--- a/apps/ngrx/notification/src/app/school/school.store.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { School } from '@angular-challenges/ngrx-notification/model';
-import { Injectable } from '@angular/core';
-import {
- ComponentStore,
- OnStoreInit,
- tapResponse,
-} from '@ngrx/component-store';
-import { pipe, switchMap } from 'rxjs';
-import { HttpService } from '../data-access/http.service';
-
-@Injectable()
-export class SchoolStore
- extends ComponentStore<{ schools: School[] }>
- implements OnStoreInit
-{
- readonly schools$ = this.select((state) => state.schools);
-
- constructor(private httpService: HttpService) {
- super({ schools: [] });
- }
-
- addSchool = this.updater((state, school: School) => ({
- ...state,
- schools: [...state.schools, school],
- }));
-
- updateSchool = this.updater((state, school: School) => ({
- ...state,
- schools: state.schools.map((t) => (t.id === school.id ? school : t)),
- }));
-
- private readonly loadSchools = this.effect(
- pipe(
- switchMap(() =>
- this.httpService.getAllSchools().pipe(
- tapResponse(
- (schools) => this.patchState({ schools }),
- (_) => _, // not handling the error
- ),
- ),
- ),
- ),
- );
-
- ngrxOnStoreInit() {
- this.loadSchools();
- }
-}
diff --git a/apps/ngrx/notification/src/app/student/store/student.actions.ts b/apps/ngrx/notification/src/app/student/store/student.actions.ts
deleted file mode 100644
index 52eda8ee0..000000000
--- a/apps/ngrx/notification/src/app/student/store/student.actions.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Student } from '@angular-challenges/ngrx-notification/model';
-import { createActionGroup, props } from '@ngrx/store';
-
-export const studentActions = createActionGroup({
- source: 'Student API',
- events: {
- 'Add One Student': props<{ student: Student }>(),
- 'Add All Students': props<{ students: Student[] }>(),
- },
-});
diff --git a/apps/ngrx/notification/src/app/student/store/student.effects.ts b/apps/ngrx/notification/src/app/student/store/student.effects.ts
deleted file mode 100644
index b741bd21d..000000000
--- a/apps/ngrx/notification/src/app/student/store/student.effects.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { inject, Injectable } from '@angular/core';
-import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { map, switchMap } from 'rxjs';
-import { appActions } from '../../app.actions';
-import { HttpService } from '../../data-access/http.service';
-import { studentActions } from './student.actions';
-
-@Injectable()
-export class StudentEffects {
- private actions$ = inject(Actions);
- private httpService = inject(HttpService);
-
- loadStudents$ = createEffect(() =>
- this.actions$.pipe(
- ofType(appActions.initApp),
- switchMap(() =>
- this.httpService
- .getAllStudents()
- .pipe(map((students) => studentActions.addAllStudents({ students }))),
- ),
- ),
- );
-}
diff --git a/apps/ngrx/notification/src/app/student/store/student.reducer.ts b/apps/ngrx/notification/src/app/student/store/student.reducer.ts
deleted file mode 100644
index 0b02cd322..000000000
--- a/apps/ngrx/notification/src/app/student/store/student.reducer.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Student } from '@angular-challenges/ngrx-notification/model';
-import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';
-import { createReducer, on } from '@ngrx/store';
-import { studentActions } from './student.actions';
-
-export const studentsFeatureKey = 'students';
-
-export type StudentState = EntityState;
-
-export const studentAdapter: EntityAdapter =
- createEntityAdapter();
-
-export const studentReducer = createReducer(
- studentAdapter.getInitialState(),
- on(studentActions.addOneStudent, (state, { student }) =>
- studentAdapter.upsertOne(student, state),
- ),
- on(studentActions.addAllStudents, (state, { students }) =>
- studentAdapter.setAll(students, state),
- ),
-);
-
-export const { selectIds, selectEntities, selectAll, selectTotal } =
- studentAdapter.getSelectors();
diff --git a/apps/ngrx/notification/src/app/student/store/student.selectors.ts b/apps/ngrx/notification/src/app/student/store/student.selectors.ts
deleted file mode 100644
index b041ff420..000000000
--- a/apps/ngrx/notification/src/app/student/store/student.selectors.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { createFeatureSelector, createSelector } from '@ngrx/store';
-import {
- StudentState,
- studentAdapter,
- studentsFeatureKey,
-} from './student.reducer';
-
-const selectStudentState =
- createFeatureSelector(studentsFeatureKey);
-
-export const { selectAll } = studentAdapter.getSelectors();
-
-const selectStudents = createSelector(selectStudentState, selectAll);
-
-export const StudentSelectors = {
- selectStudents,
-};
diff --git a/apps/ngrx/notification/src/app/student/student.component.ts b/apps/ngrx/notification/src/app/student/student.component.ts
deleted file mode 100644
index bbc45bfd7..000000000
--- a/apps/ngrx/notification/src/app/student/student.component.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/* eslint-disable @angular-eslint/component-selector */
-import { AsyncPipe, NgFor } from '@angular/common';
-import { Component, inject } from '@angular/core';
-import { Store } from '@ngrx/store';
-import { StudentSelectors } from './store/student.selectors';
-
-@Component({
- standalone: true,
- imports: [NgFor, AsyncPipe],
- selector: 'student',
- template: `
- STUDENTS
-
- {{ student.firstname }} {{ student.lastname }} - {{ student.version }}
-
- `,
- styles: [
- `
- :host {
- display: block;
- width: fit-content;
- height: fit-content;
- border: 1px solid red;
- padding: 4px;
- }
- `,
- ],
-})
-export class StudentComponent {
- private store = inject(Store);
- students$ = this.store.select(StudentSelectors.selectStudents);
-}
diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts
deleted file mode 100644
index ff41af34e..000000000
--- a/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Teacher } from '@angular-challenges/ngrx-notification/model';
-import { createActionGroup, props } from '@ngrx/store';
-
-export const teacherActions = createActionGroup({
- source: 'Teacher API',
- events: {
- 'Add One Teacher': props<{ teacher: Teacher }>(),
- 'Add All Teachers': props<{ teachers: Teacher[] }>(),
- },
-});
diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts
deleted file mode 100644
index 43c3fab0b..000000000
--- a/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { inject, Injectable } from '@angular/core';
-import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { map, switchMap } from 'rxjs';
-import { appActions } from '../../app.actions';
-import { HttpService } from '../../data-access/http.service';
-import { teacherActions } from './teacher.actions';
-
-@Injectable()
-export class TeacherEffects {
- private actions$ = inject(Actions);
- private httpService = inject(HttpService);
-
- loadTeachers$ = createEffect(() =>
- this.actions$.pipe(
- ofType(appActions.initApp),
- switchMap(() =>
- this.httpService
- .getAllTeachers()
- .pipe(map((teachers) => teacherActions.addAllTeachers({ teachers }))),
- ),
- ),
- );
-}
diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts
deleted file mode 100644
index d793b9646..000000000
--- a/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Teacher } from '@angular-challenges/ngrx-notification/model';
-import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';
-import { createReducer, on } from '@ngrx/store';
-import { teacherActions } from './teacher.actions';
-
-export const teachersFeatureKey = 'teachers';
-
-export type TeacherState = EntityState;
-
-export const teacherAdapter: EntityAdapter =
- createEntityAdapter();
-
-export const teacherReducer = createReducer(
- teacherAdapter.getInitialState(),
- on(teacherActions.addOneTeacher, (state, { teacher }) =>
- teacherAdapter.upsertOne(teacher, state),
- ),
- on(teacherActions.addAllTeachers, (state, { teachers }) =>
- teacherAdapter.setAll(teachers, state),
- ),
-);
-
-export const { selectIds, selectEntities, selectAll, selectTotal } =
- teacherAdapter.getSelectors();
diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts
deleted file mode 100644
index a32e82c2b..000000000
--- a/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { createFeatureSelector, createSelector } from '@ngrx/store';
-import {
- TeacherState,
- teacherAdapter,
- teachersFeatureKey,
-} from './teacher.reducer';
-
-const selectTeacherState =
- createFeatureSelector(teachersFeatureKey);
-
-export const { selectAll } = teacherAdapter.getSelectors();
-
-const selectTeachers = createSelector(selectTeacherState, selectAll);
-
-export const TeacherSelectors = {
- selectTeachers,
-};
diff --git a/apps/ngrx/notification/src/app/teacher/teacher.component.ts b/apps/ngrx/notification/src/app/teacher/teacher.component.ts
deleted file mode 100644
index 63e812200..000000000
--- a/apps/ngrx/notification/src/app/teacher/teacher.component.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/* eslint-disable @angular-eslint/component-selector */
-import { AsyncPipe, NgFor } from '@angular/common';
-import { Component } from '@angular/core';
-import { Store } from '@ngrx/store';
-import { TeacherSelectors } from './store/teacher.selectors';
-
-@Component({
- standalone: true,
- imports: [NgFor, AsyncPipe],
- selector: 'teacher',
- template: `
- TEACHERS
-
- {{ teacher.firstname }} {{ teacher.lastname }} - {{ teacher.version }}
-
- `,
- styles: [
- `
- :host {
- display: block;
- width: fit-content;
- height: fit-content;
- border: 1px solid red;
- padding: 4px;
- }
- `,
- ],
-})
-export class TeacherComponent {
- teacher$ = this.store.select(TeacherSelectors.selectTeachers);
-
- constructor(private store: Store) {}
-}
diff --git a/apps/ngrx/notification/src/index.html b/apps/ngrx/notification/src/index.html
deleted file mode 100644
index cc46b13b2..000000000
--- a/apps/ngrx/notification/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- NgrxNotification
-
-
-
-
-
-
-
-
diff --git a/apps/ngrx/notification/src/main.ts b/apps/ngrx/notification/src/main.ts
deleted file mode 100644
index 6f91f21a3..000000000
--- a/apps/ngrx/notification/src/main.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { appConfig } from './app/app.config';
-
-import { bootstrapApplication } from '@angular/platform-browser';
-
-import { AppComponent } from './app/app.component';
-
-bootstrapApplication(AppComponent, appConfig).catch((err) =>
- console.error(err),
-);
diff --git a/apps/ngrx/notification/src/polyfills.ts b/apps/ngrx/notification/src/polyfills.ts
deleted file mode 100644
index e4555ed11..000000000
--- a/apps/ngrx/notification/src/polyfills.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * This file includes polyfills needed by Angular and is loaded before the app.
- * You can add your own extra polyfills to this file.
- *
- * This file is divided into 2 sections:
- * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
- * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
- * file.
- *
- * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
- * automatically update themselves. This includes recent versions of Safari, Chrome (including
- * Opera), Edge on the desktop, and iOS and Chrome on mobile.
- *
- * Learn more in https://angular.io/guide/browser-support
- */
-
-/***************************************************************************************************
- * BROWSER POLYFILLS
- */
-
-/**
- * By default, zone.js will patch all possible macroTask and DomEvents
- * user can disable parts of macroTask/DomEvents patch by setting following flags
- * because those flags need to be set before `zone.js` being loaded, and webpack
- * will put import in the top of bundle, so user need to create a separate file
- * in this directory (for example: zone-flags.ts), and put the following flags
- * into that file, and then add the following code before importing zone.js.
- * import './zone-flags';
- *
- * The flags allowed in zone-flags.ts are listed here.
- *
- * The following flags will work for all browsers.
- *
- * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
- * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
- * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
- *
- * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
- * with the following flag, it will bypass `zone.js` patch for IE/Edge
- *
- * (window as any).__Zone_enable_cross_context_check = true;
- *
- */
-
-/***************************************************************************************************
- * Zone JS is required by default for Angular itself.
- */
-import 'zone.js'; // Included with Angular CLI.
-
-/***************************************************************************************************
- * APPLICATION IMPORTS
- */
diff --git a/apps/ngrx/notification/tsconfig.app.json b/apps/ngrx/notification/tsconfig.app.json
deleted file mode 100644
index 7a4dbc47e..000000000
--- a/apps/ngrx/notification/tsconfig.app.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "outDir": "../../../dist/out-tsc",
- "types": [],
- "target": "ES2022",
- "useDefineForClassFields": false
- },
- "files": ["src/main.ts", "src/polyfills.ts"],
- "include": ["src/**/*.d.ts"],
- "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"]
-}
diff --git a/apps/ngrx/notification/tsconfig.editor.json b/apps/ngrx/notification/tsconfig.editor.json
deleted file mode 100644
index 3d4f1db8b..000000000
--- a/apps/ngrx/notification/tsconfig.editor.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "include": [
- "**/*.ts",
- "../../../libs/ngrx-notification/backend/src/lib/fake-backend.service.ts"
- ],
- "compilerOptions": {
- "types": []
- }
-}
diff --git a/apps/ngrx/notification/tsconfig.json b/apps/ngrx/notification/tsconfig.json
deleted file mode 100644
index b2dbbf22e..000000000
--- a/apps/ngrx/notification/tsconfig.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "files": [],
- "include": [],
- "references": [
- {
- "path": "./tsconfig.app.json"
- },
- {
- "path": "./tsconfig.editor.json"
- }
- ],
- "compilerOptions": {
- "target": "es2020",
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "noImplicitOverride": true,
- "noPropertyAccessFromIndexSignature": true,
- "noImplicitReturns": true,
- "noFallthroughCasesInSwitch": true
- },
- "angularCompilerOptions": {
- "enableI18nLegacyMessageIdFormat": false,
- "strictInjectionParameters": true,
- "strictInputAccessModifiers": true,
- "strictTemplates": true
- }
-}
diff --git a/apps/nx/42-static-vs-dynamic-import/.eslintrc.json b/apps/nx/42-static-vs-dynamic-import/.eslintrc.json
new file mode 100644
index 000000000..8ebcbfd59
--- /dev/null
+++ b/apps/nx/42-static-vs-dynamic-import/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/nx/42-static-vs-dynamic-import/README.md b/apps/nx/42-static-vs-dynamic-import/README.md
new file mode 100644
index 000000000..a08abaa82
--- /dev/null
+++ b/apps/nx/42-static-vs-dynamic-import/README.md
@@ -0,0 +1,13 @@
+# Static vs Dynamic Import
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve nx-static-vs-dynamic-import
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/nx/42-static-dynamic-import/).
diff --git a/apps/nx/42-static-vs-dynamic-import/project.json b/apps/nx/42-static-vs-dynamic-import/project.json
new file mode 100644
index 000000000..7f45fb828
--- /dev/null
+++ b/apps/nx/42-static-vs-dynamic-import/project.json
@@ -0,0 +1,73 @@
+{
+ "name": "nx-static-vs-dynamic-import",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/nx/42-static-vs-dynamic-import/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/nx/42-static-vs-dynamic-import",
+ "index": "apps/nx/42-static-vs-dynamic-import/src/index.html",
+ "browser": "apps/nx/42-static-vs-dynamic-import/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/nx/42-static-vs-dynamic-import/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/nx/42-static-vs-dynamic-import/src/favicon.ico",
+ "apps/nx/42-static-vs-dynamic-import/src/assets"
+ ],
+ "styles": [
+ "apps/nx/42-static-vs-dynamic-import/src/styles.scss",
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all",
+ "sourceMap": true
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "nx-static-vs-dynamic-import:build:production"
+ },
+ "development": {
+ "buildTarget": "nx-static-vs-dynamic-import:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "nx-static-vs-dynamic-import:build"
+ }
+ }
+ }
+}
diff --git a/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts b/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts
new file mode 100644
index 000000000..59be617e8
--- /dev/null
+++ b/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts
@@ -0,0 +1,26 @@
+import {
+ UserComponent,
+ type User,
+} from '@angular-challenges/static-dynamic-import/users';
+import { Component } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+
+@Component({
+ imports: [UserComponent, RouterOutlet],
+ selector: 'app-root',
+ template: `
+ Author:
+
+
+ `,
+ host: {
+ class: 'flex flex-col',
+ },
+})
+export class AppComponent {
+ author: User = {
+ name: 'Thomas',
+ lastName: 'Laforge',
+ country: 'France',
+ };
+}
diff --git a/apps/nx/static-dynamic-import/src/app/app.config.ts b/apps/nx/42-static-vs-dynamic-import/src/app/app.config.ts
similarity index 100%
rename from apps/nx/static-dynamic-import/src/app/app.config.ts
rename to apps/nx/42-static-vs-dynamic-import/src/app/app.config.ts
diff --git a/apps/nx/static-dynamic-import/src/assets/.gitkeep b/apps/nx/42-static-vs-dynamic-import/src/assets/.gitkeep
similarity index 100%
rename from apps/nx/static-dynamic-import/src/assets/.gitkeep
rename to apps/nx/42-static-vs-dynamic-import/src/assets/.gitkeep
diff --git a/apps/performance/memoized/src/favicon.ico b/apps/nx/42-static-vs-dynamic-import/src/favicon.ico
similarity index 100%
rename from apps/performance/memoized/src/favicon.ico
rename to apps/nx/42-static-vs-dynamic-import/src/favicon.ico
diff --git a/apps/nx/42-static-vs-dynamic-import/src/index.html b/apps/nx/42-static-vs-dynamic-import/src/index.html
new file mode 100644
index 000000000..1b4f2a84b
--- /dev/null
+++ b/apps/nx/42-static-vs-dynamic-import/src/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+ nx-static-vs-dynamic-import
+
+
+
+
+
+
+
+
+
diff --git a/apps/rxjs/catch-error/src/main.ts b/apps/nx/42-static-vs-dynamic-import/src/main.ts
similarity index 100%
rename from apps/rxjs/catch-error/src/main.ts
rename to apps/nx/42-static-vs-dynamic-import/src/main.ts
diff --git a/apps/performance/ngfor-optimize/src/styles.scss b/apps/nx/42-static-vs-dynamic-import/src/styles.scss
similarity index 100%
rename from apps/performance/ngfor-optimize/src/styles.scss
rename to apps/nx/42-static-vs-dynamic-import/src/styles.scss
diff --git a/apps/performance/ngfor-optimize/tailwind.config.js b/apps/nx/42-static-vs-dynamic-import/tailwind.config.js
similarity index 100%
rename from apps/performance/ngfor-optimize/tailwind.config.js
rename to apps/nx/42-static-vs-dynamic-import/tailwind.config.js
diff --git a/apps/performance/scroll-cd/tsconfig.app.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.app.json
similarity index 100%
rename from apps/performance/scroll-cd/tsconfig.app.json
rename to apps/nx/42-static-vs-dynamic-import/tsconfig.app.json
diff --git a/apps/angular/view-transition/tsconfig.editor.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.editor.json
similarity index 100%
rename from apps/angular/view-transition/tsconfig.editor.json
rename to apps/nx/42-static-vs-dynamic-import/tsconfig.editor.json
diff --git a/apps/nx/static-dynamic-import/tsconfig.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.json
similarity index 100%
rename from apps/nx/static-dynamic-import/tsconfig.json
rename to apps/nx/42-static-vs-dynamic-import/tsconfig.json
diff --git a/apps/nx/static-dynamic-import/README.md b/apps/nx/static-dynamic-import/README.md
deleted file mode 100644
index 54691c75b..000000000
--- a/apps/nx/static-dynamic-import/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Static vs Dynamic Import
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve nx-static-dynamic-import
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/nx/42-static-dynamic-import/).
diff --git a/apps/nx/static-dynamic-import/project.json b/apps/nx/static-dynamic-import/project.json
deleted file mode 100644
index c0208b075..000000000
--- a/apps/nx/static-dynamic-import/project.json
+++ /dev/null
@@ -1,77 +0,0 @@
-{
- "name": "nx-static-dynamic-import",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/nx/static-dynamic-import/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/nx/static-dynamic-import",
- "index": "apps/nx/static-dynamic-import/src/index.html",
- "browser": "apps/nx/static-dynamic-import/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/nx/static-dynamic-import/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/nx/static-dynamic-import/src/favicon.ico",
- "apps/nx/static-dynamic-import/src/assets"
- ],
- "styles": [
- "apps/nx/static-dynamic-import/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all",
- "sourceMap": true
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "nx-static-dynamic-import:build:production"
- },
- "development": {
- "buildTarget": "nx-static-dynamic-import:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "nx-static-dynamic-import:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"]
- }
- }
-}
diff --git a/apps/nx/static-dynamic-import/src/app/app.component.ts b/apps/nx/static-dynamic-import/src/app/app.component.ts
deleted file mode 100644
index 9c5bd67d4..000000000
--- a/apps/nx/static-dynamic-import/src/app/app.component.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import {
- UserComponent,
- type User,
-} from '@angular-challenges/static-dynamic-import/users';
-import { Component } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-
-@Component({
- standalone: true,
- imports: [UserComponent, RouterOutlet],
- selector: 'app-root',
- template: `
- Author:
-
-
- `,
- host: {
- class: 'flex flex-col',
- },
-})
-export class AppComponent {
- author: User = {
- name: 'Thomas',
- lastName: 'Laforge',
- country: 'France',
- };
-}
diff --git a/apps/nx/static-dynamic-import/src/index.html b/apps/nx/static-dynamic-import/src/index.html
deleted file mode 100644
index 77adec4af..000000000
--- a/apps/nx/static-dynamic-import/src/index.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
- nx-static-dynamic-import
-
-
-
-
-
-
-
-
-
diff --git a/apps/angular/styling/.eslintrc.json b/apps/performance/12-optimize-change-detection/.eslintrc.json
similarity index 100%
rename from apps/angular/styling/.eslintrc.json
rename to apps/performance/12-optimize-change-detection/.eslintrc.json
diff --git a/apps/performance/12-optimize-change-detection/README.md b/apps/performance/12-optimize-change-detection/README.md
new file mode 100644
index 000000000..52fe319d7
--- /dev/null
+++ b/apps/performance/12-optimize-change-detection/README.md
@@ -0,0 +1,13 @@
+# Optimize Change Detection
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-optimize-change-detection
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/12-performance-optimize-change-detection/).
diff --git a/apps/performance/12-optimize-change-detection/jest.config.ts b/apps/performance/12-optimize-change-detection/jest.config.ts
new file mode 100644
index 000000000..dc22d99ea
--- /dev/null
+++ b/apps/performance/12-optimize-change-detection/jest.config.ts
@@ -0,0 +1,24 @@
+/* eslint-disable */
+export default {
+ displayName: 'performance-optimize-change-detection',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ globals: {},
+ coverageDirectory:
+ '../../../coverage/apps/performance/12-optimize-change-detection',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/performance/12-optimize-change-detection/project.json b/apps/performance/12-optimize-change-detection/project.json
new file mode 100644
index 000000000..188240700
--- /dev/null
+++ b/apps/performance/12-optimize-change-detection/project.json
@@ -0,0 +1,85 @@
+{
+ "name": "performance-optimize-change-detection",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/performance/12-optimize-change-detection/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/12-optimize-change-detection",
+ "index": "apps/performance/12-optimize-change-detection/src/index.html",
+ "main": "apps/performance/12-optimize-change-detection/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/12-optimize-change-detection/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/performance/12-optimize-change-detection/src/favicon.ico",
+ "apps/performance/12-optimize-change-detection/src/assets"
+ ],
+ "styles": [
+ "apps/performance/12-optimize-change-detection/src/styles.scss"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-optimize-change-detection:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-optimize-change-detection:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "performance-optimize-change-detection:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/performance/12-optimize-change-detection/src/app/app.component.ts b/apps/performance/12-optimize-change-detection/src/app/app.component.ts
new file mode 100644
index 000000000..dd818cad5
--- /dev/null
+++ b/apps/performance/12-optimize-change-detection/src/app/app.component.ts
@@ -0,0 +1,52 @@
+import { AsyncPipe, NgIf } from '@angular/common';
+import { Component, HostListener } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+
+@Component({
+ imports: [NgIf, AsyncPipe],
+ selector: 'app-root',
+ template: `
+ Top
+ Middle
+ Bottom
+
+ `,
+ styles: [
+ `
+ :host {
+ height: 1500px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ button {
+ position: fixed;
+ bottom: 1rem;
+ left: 1rem;
+ z-index: 1;
+ padding: 1rem;
+ }
+ }
+ `,
+ ],
+})
+export class AppComponent {
+ title = 'scroll-cd';
+
+ private displayButtonSubject = new BehaviorSubject(false);
+ displayButton$ = this.displayButtonSubject.asObservable();
+
+ @HostListener('window:scroll', ['$event'])
+ onScroll() {
+ const pos = window.pageYOffset;
+ this.displayButtonSubject.next(pos > 50);
+ }
+
+ goToTop() {
+ window.scroll({
+ top: 0,
+ left: 0,
+ behavior: 'smooth',
+ });
+ }
+}
diff --git a/apps/performance/christmas-web-worker/src/assets/.gitkeep b/apps/performance/12-optimize-change-detection/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/christmas-web-worker/src/assets/.gitkeep
rename to apps/performance/12-optimize-change-detection/src/assets/.gitkeep
diff --git a/apps/performance/ngfor-biglist/src/favicon.ico b/apps/performance/12-optimize-change-detection/src/favicon.ico
similarity index 100%
rename from apps/performance/ngfor-biglist/src/favicon.ico
rename to apps/performance/12-optimize-change-detection/src/favicon.ico
diff --git a/apps/performance/12-optimize-change-detection/src/index.html b/apps/performance/12-optimize-change-detection/src/index.html
new file mode 100644
index 000000000..c1cb61764
--- /dev/null
+++ b/apps/performance/12-optimize-change-detection/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-optimize-change-detection
+
+
+
+
+
+
+
+
diff --git a/apps/performance/scroll-cd/src/main.ts b/apps/performance/12-optimize-change-detection/src/main.ts
similarity index 100%
rename from apps/performance/scroll-cd/src/main.ts
rename to apps/performance/12-optimize-change-detection/src/main.ts
diff --git a/apps/ngrx/notification/src/styles.scss b/apps/performance/12-optimize-change-detection/src/styles.scss
similarity index 100%
rename from apps/ngrx/notification/src/styles.scss
rename to apps/performance/12-optimize-change-detection/src/styles.scss
diff --git a/apps/ngrx/effect-selector/src/test-setup.ts b/apps/performance/12-optimize-change-detection/src/test-setup.ts
similarity index 100%
rename from apps/ngrx/effect-selector/src/test-setup.ts
rename to apps/performance/12-optimize-change-detection/src/test-setup.ts
diff --git a/apps/rxjs/catch-error/tsconfig.app.json b/apps/performance/12-optimize-change-detection/tsconfig.app.json
similarity index 100%
rename from apps/rxjs/catch-error/tsconfig.app.json
rename to apps/performance/12-optimize-change-detection/tsconfig.app.json
diff --git a/apps/performance/scroll-cd/tsconfig.editor.json b/apps/performance/12-optimize-change-detection/tsconfig.editor.json
similarity index 100%
rename from apps/performance/scroll-cd/tsconfig.editor.json
rename to apps/performance/12-optimize-change-detection/tsconfig.editor.json
diff --git a/apps/angular/interop-rxjs-signal/tsconfig.json b/apps/performance/12-optimize-change-detection/tsconfig.json
similarity index 100%
rename from apps/angular/interop-rxjs-signal/tsconfig.json
rename to apps/performance/12-optimize-change-detection/tsconfig.json
diff --git a/apps/performance/scroll-cd/tsconfig.spec.json b/apps/performance/12-optimize-change-detection/tsconfig.spec.json
similarity index 100%
rename from apps/performance/scroll-cd/tsconfig.spec.json
rename to apps/performance/12-optimize-change-detection/tsconfig.spec.json
diff --git a/apps/performance/default-onpush/.eslintrc.json b/apps/performance/34-default-vs-onpush/.eslintrc.json
similarity index 100%
rename from apps/performance/default-onpush/.eslintrc.json
rename to apps/performance/34-default-vs-onpush/.eslintrc.json
diff --git a/apps/performance/34-default-vs-onpush/README.md b/apps/performance/34-default-vs-onpush/README.md
new file mode 100644
index 000000000..ab82704b5
--- /dev/null
+++ b/apps/performance/34-default-vs-onpush/README.md
@@ -0,0 +1,13 @@
+# Default vs OnPush
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-default-vs-onpush
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/34-default-onpush/).
diff --git a/apps/performance/34-default-vs-onpush/project.json b/apps/performance/34-default-vs-onpush/project.json
new file mode 100644
index 000000000..f81cb74a3
--- /dev/null
+++ b/apps/performance/34-default-vs-onpush/project.json
@@ -0,0 +1,75 @@
+{
+ "name": "performance-default-vs-onpush",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/performance/34-default-vs-onpush/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/34-default-vs-onpush",
+ "index": "apps/performance/34-default-vs-onpush/src/index.html",
+ "main": "apps/performance/34-default-vs-onpush/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/34-default-vs-onpush/tsconfig.app.json",
+ "assets": [
+ "apps/performance/34-default-vs-onpush/src/favicon.ico",
+ "apps/performance/34-default-vs-onpush/src/assets"
+ ],
+ "styles": [
+ "apps/performance/34-default-vs-onpush/src/styles.scss",
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-default-vs-onpush:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-default-vs-onpush:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "performance-default-vs-onpush:build"
+ }
+ }
+ }
+}
diff --git a/apps/performance/34-default-vs-onpush/src/app/app.component.ts b/apps/performance/34-default-vs-onpush/src/app/app.component.ts
new file mode 100644
index 000000000..88b0a6571
--- /dev/null
+++ b/apps/performance/34-default-vs-onpush/src/app/app.component.ts
@@ -0,0 +1,21 @@
+import { Component } from '@angular/core';
+import { randFirstName } from '@ngneat/falso';
+import { PersonListComponent } from './person-list.component';
+import { RandomComponent } from './random.component';
+
+@Component({
+ imports: [PersonListComponent, RandomComponent],
+ selector: 'app-root',
+ template: `
+
+
+
+ `,
+})
+export class AppComponent {
+ girlList = randFirstName({ gender: 'female', length: 10 });
+ boyList = randFirstName({ gender: 'male', length: 10 });
+}
diff --git a/apps/performance/default-onpush/src/app/app.config.ts b/apps/performance/34-default-vs-onpush/src/app/app.config.ts
similarity index 100%
rename from apps/performance/default-onpush/src/app/app.config.ts
rename to apps/performance/34-default-vs-onpush/src/app/app.config.ts
diff --git a/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts b/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts
new file mode 100644
index 000000000..4cd92396a
--- /dev/null
+++ b/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts
@@ -0,0 +1,67 @@
+import { Component, Input } from '@angular/core';
+
+import { CDFlashingDirective } from '@angular-challenges/shared/directives';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { MatListModule } from '@angular/material/list';
+
+@Component({
+ selector: 'app-person-list',
+ imports: [
+ CommonModule,
+ FormsModule,
+ MatListModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatChipsModule,
+ CDFlashingDirective,
+ ],
+ template: `
+
+ {{ title | titlecase }}
+
+
+
+
+
+
+
+ Empty list
+
+
+
+ {{ name }}
+
+
+
+
+
+ `,
+ host: {
+ class: 'w-full flex flex-col items-center',
+ },
+})
+export class PersonListComponent {
+ @Input() names: string[] = [];
+ @Input() title = '';
+
+ label = '';
+
+ handleKey(event: KeyboardEvent) {
+ if (event.key === 'Enter') {
+ this.names?.unshift(this.label);
+ this.label = '';
+ }
+ }
+}
diff --git a/apps/performance/default-onpush/src/app/random.component.ts b/apps/performance/34-default-vs-onpush/src/app/random.component.ts
similarity index 93%
rename from apps/performance/default-onpush/src/app/random.component.ts
rename to apps/performance/34-default-vs-onpush/src/app/random.component.ts
index d46cdd053..71479e28d 100644
--- a/apps/performance/default-onpush/src/app/random.component.ts
+++ b/apps/performance/34-default-vs-onpush/src/app/random.component.ts
@@ -3,7 +3,6 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-random',
- standalone: true,
template: `
I do nothing but I'm here
`,
diff --git a/apps/performance/default-onpush/src/assets/.gitkeep b/apps/performance/34-default-vs-onpush/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/default-onpush/src/assets/.gitkeep
rename to apps/performance/34-default-vs-onpush/src/assets/.gitkeep
diff --git a/apps/performance/ngfor-optimize/src/favicon.ico b/apps/performance/34-default-vs-onpush/src/favicon.ico
similarity index 100%
rename from apps/performance/ngfor-optimize/src/favicon.ico
rename to apps/performance/34-default-vs-onpush/src/favicon.ico
diff --git a/apps/performance/34-default-vs-onpush/src/index.html b/apps/performance/34-default-vs-onpush/src/index.html
new file mode 100644
index 000000000..251489ea3
--- /dev/null
+++ b/apps/performance/34-default-vs-onpush/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-default-vs-onpush
+
+
+
+
+
+
+
+
diff --git a/apps/testing/create-harness/src/main.ts b/apps/performance/34-default-vs-onpush/src/main.ts
similarity index 100%
rename from apps/testing/create-harness/src/main.ts
rename to apps/performance/34-default-vs-onpush/src/main.ts
diff --git a/apps/rxjs/catch-error/src/styles.scss b/apps/performance/34-default-vs-onpush/src/styles.scss
similarity index 100%
rename from apps/rxjs/catch-error/src/styles.scss
rename to apps/performance/34-default-vs-onpush/src/styles.scss
diff --git a/apps/rxjs/catch-error/tailwind.config.js b/apps/performance/34-default-vs-onpush/tailwind.config.js
similarity index 100%
rename from apps/rxjs/catch-error/tailwind.config.js
rename to apps/performance/34-default-vs-onpush/tailwind.config.js
diff --git a/apps/testing/checkbox/tsconfig.app.json b/apps/performance/34-default-vs-onpush/tsconfig.app.json
similarity index 100%
rename from apps/testing/checkbox/tsconfig.app.json
rename to apps/performance/34-default-vs-onpush/tsconfig.app.json
diff --git a/apps/performance/default-onpush/tsconfig.editor.json b/apps/performance/34-default-vs-onpush/tsconfig.editor.json
similarity index 100%
rename from apps/performance/default-onpush/tsconfig.editor.json
rename to apps/performance/34-default-vs-onpush/tsconfig.editor.json
diff --git a/apps/performance/christmas-web-worker/tsconfig.json b/apps/performance/34-default-vs-onpush/tsconfig.json
similarity index 100%
rename from apps/performance/christmas-web-worker/tsconfig.json
rename to apps/performance/34-default-vs-onpush/tsconfig.json
diff --git a/apps/performance/memoized/.eslintrc.json b/apps/performance/35-memoization/.eslintrc.json
similarity index 100%
rename from apps/performance/memoized/.eslintrc.json
rename to apps/performance/35-memoization/.eslintrc.json
diff --git a/apps/performance/35-memoization/README.md b/apps/performance/35-memoization/README.md
new file mode 100644
index 000000000..a06a0e91d
--- /dev/null
+++ b/apps/performance/35-memoization/README.md
@@ -0,0 +1,13 @@
+# Memoization
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-memoization
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/35-memoize/).
diff --git a/apps/performance/35-memoization/project.json b/apps/performance/35-memoization/project.json
new file mode 100644
index 000000000..041308626
--- /dev/null
+++ b/apps/performance/35-memoization/project.json
@@ -0,0 +1,75 @@
+{
+ "name": "performance-memoization",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/performance/35-memoization/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/35-memoization",
+ "index": "apps/performance/35-memoization/src/index.html",
+ "main": "apps/performance/35-memoization/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/35-memoization/tsconfig.app.json",
+ "assets": [
+ "apps/performance/35-memoization/src/favicon.ico",
+ "apps/performance/35-memoization/src/assets"
+ ],
+ "styles": [
+ "apps/performance/35-memoization/src/styles.scss",
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-memoization:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-memoization:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "performance-memoization:build"
+ }
+ }
+ }
+}
diff --git a/apps/performance/35-memoization/src/app/app.component.ts b/apps/performance/35-memoization/src/app/app.component.ts
new file mode 100644
index 000000000..04c7758fc
--- /dev/null
+++ b/apps/performance/35-memoization/src/app/app.component.ts
@@ -0,0 +1,27 @@
+import { NgIf } from '@angular/common';
+import { Component } from '@angular/core';
+import { generateList } from './generateList';
+import { PersonListComponent } from './person-list.component';
+
+@Component({
+ imports: [PersonListComponent, NgIf],
+ selector: 'app-root',
+ template: `
+ Performance is key!!
+
+
+
+ `,
+})
+export class AppComponent {
+ persons = generateList();
+ loadList = false;
+}
diff --git a/apps/performance/memoized/src/app/app.config.ts b/apps/performance/35-memoization/src/app/app.config.ts
similarity index 100%
rename from apps/performance/memoized/src/app/app.config.ts
rename to apps/performance/35-memoization/src/app/app.config.ts
diff --git a/apps/performance/memoized/src/app/generateList.ts b/apps/performance/35-memoization/src/app/generateList.ts
similarity index 100%
rename from apps/performance/memoized/src/app/generateList.ts
rename to apps/performance/35-memoization/src/app/generateList.ts
diff --git a/apps/performance/35-memoization/src/app/person-list.component.ts b/apps/performance/35-memoization/src/app/person-list.component.ts
new file mode 100644
index 000000000..28cbac267
--- /dev/null
+++ b/apps/performance/35-memoization/src/app/person-list.component.ts
@@ -0,0 +1,63 @@
+import { Component, Input } from '@angular/core';
+
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { MatListModule } from '@angular/material/list';
+import { Person } from './person.model';
+
+const fibonacci = (num: number): number => {
+ if (num === 1 || num === 2) {
+ return 1;
+ }
+ return fibonacci(num - 1) + fibonacci(num - 2);
+};
+
+@Component({
+ selector: 'app-person-list',
+ imports: [
+ CommonModule,
+ FormsModule,
+ MatListModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatChipsModule,
+ ],
+ template: `
+
+ {{ title | titlecase }}
+
+
+
+
+
+
+
+
+
+
{{ person.name }}
+ {{ calculate(person.fib) }}
+
+
+
+ `,
+ host: {
+ class: 'w-full flex flex-col items-center',
+ },
+})
+export class PersonListComponent {
+ @Input() persons: Person[] = [];
+ @Input() title = '';
+
+ label = '';
+
+ calculate(num: number) {
+ return fibonacci(num);
+ }
+}
diff --git a/apps/performance/memoized/src/app/person.model.ts b/apps/performance/35-memoization/src/app/person.model.ts
similarity index 100%
rename from apps/performance/memoized/src/app/person.model.ts
rename to apps/performance/35-memoization/src/app/person.model.ts
diff --git a/apps/performance/memoized/src/assets/.gitkeep b/apps/performance/35-memoization/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/memoized/src/assets/.gitkeep
rename to apps/performance/35-memoization/src/assets/.gitkeep
diff --git a/apps/performance/scroll-cd/src/favicon.ico b/apps/performance/35-memoization/src/favicon.ico
similarity index 100%
rename from apps/performance/scroll-cd/src/favicon.ico
rename to apps/performance/35-memoization/src/favicon.ico
diff --git a/apps/performance/35-memoization/src/index.html b/apps/performance/35-memoization/src/index.html
new file mode 100644
index 000000000..39ddb9045
--- /dev/null
+++ b/apps/performance/35-memoization/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-memoization
+
+
+
+
+
+
+
+
diff --git a/apps/testing/harness/src/main.ts b/apps/performance/35-memoization/src/main.ts
similarity index 100%
rename from apps/testing/harness/src/main.ts
rename to apps/performance/35-memoization/src/main.ts
diff --git a/apps/testing/checkbox/src/styles.scss b/apps/performance/35-memoization/src/styles.scss
similarity index 100%
rename from apps/testing/checkbox/src/styles.scss
rename to apps/performance/35-memoization/src/styles.scss
diff --git a/apps/testing/checkbox/tailwind.config.js b/apps/performance/35-memoization/tailwind.config.js
similarity index 100%
rename from apps/testing/checkbox/tailwind.config.js
rename to apps/performance/35-memoization/tailwind.config.js
diff --git a/apps/testing/create-harness/tsconfig.app.json b/apps/performance/35-memoization/tsconfig.app.json
similarity index 100%
rename from apps/testing/create-harness/tsconfig.app.json
rename to apps/performance/35-memoization/tsconfig.app.json
diff --git a/apps/nx/static-dynamic-import/tsconfig.editor.json b/apps/performance/35-memoization/tsconfig.editor.json
similarity index 100%
rename from apps/nx/static-dynamic-import/tsconfig.editor.json
rename to apps/performance/35-memoization/tsconfig.editor.json
diff --git a/apps/performance/default-onpush/tsconfig.json b/apps/performance/35-memoization/tsconfig.json
similarity index 100%
rename from apps/performance/default-onpush/tsconfig.json
rename to apps/performance/35-memoization/tsconfig.json
diff --git a/apps/performance/ngfor-biglist/.eslintrc.json b/apps/performance/36-ngfor-optimization/.eslintrc.json
similarity index 100%
rename from apps/performance/ngfor-biglist/.eslintrc.json
rename to apps/performance/36-ngfor-optimization/.eslintrc.json
diff --git a/apps/performance/36-ngfor-optimization/README.md b/apps/performance/36-ngfor-optimization/README.md
new file mode 100644
index 000000000..2ee0bb20e
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/README.md
@@ -0,0 +1,13 @@
+# NgFor Optimization
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-ngfor-optimization
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/36-ngfor-optimize/).
diff --git a/apps/performance/36-ngfor-optimization/jest.config.ts b/apps/performance/36-ngfor-optimization/jest.config.ts
new file mode 100644
index 000000000..2e138df90
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+ displayName: 'performance-ngfor-optimization',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ coverageDirectory: '../../../coverage/apps/performance/36-ngfor-optimization',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/performance/36-ngfor-optimization/project.json b/apps/performance/36-ngfor-optimization/project.json
new file mode 100644
index 000000000..05dfcd1e2
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/project.json
@@ -0,0 +1,86 @@
+{
+ "name": "performance-ngfor-optimization",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/performance/36-ngfor-optimization/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/36-ngfor-optimization",
+ "index": "apps/performance/36-ngfor-optimization/src/index.html",
+ "main": "apps/performance/36-ngfor-optimization/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/36-ngfor-optimization/tsconfig.app.json",
+ "assets": [
+ "apps/performance/36-ngfor-optimization/src/favicon.ico",
+ "apps/performance/36-ngfor-optimization/src/assets"
+ ],
+ "styles": [
+ "apps/performance/36-ngfor-optimization/src/styles.scss",
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
+ ],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-ngfor-optimization:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-ngfor-optimization:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "performance-ngfor-optimization:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/performance/36-ngfor-optimization/src/app/app.component.ts b/apps/performance/36-ngfor-optimization/src/app/app.component.ts
new file mode 100644
index 000000000..f1aa9f133
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/src/app/app.component.ts
@@ -0,0 +1,57 @@
+import { Component, OnInit, inject } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { PersonService } from './list.service';
+import { PersonListComponent } from './person-list.component';
+
+@Component({
+ imports: [
+ PersonListComponent,
+ FormsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ ],
+ providers: [PersonService],
+ selector: 'app-root',
+ template: `
+
+ List of Persons
+
+
+
+
+
+
+
+ `,
+ host: {
+ class: 'flex items-center flex-col gap-5',
+ },
+})
+export class AppComponent implements OnInit {
+ readonly personService = inject(PersonService);
+ readonly persons = this.personService.persons;
+
+ label = '';
+
+ ngOnInit(): void {
+ this.personService.loadPersons();
+ }
+
+ handleKey(event: any) {
+ if (event.keyCode === 13) {
+ this.personService.addPerson(this.label);
+ this.label = '';
+ }
+ }
+}
diff --git a/apps/performance/ngfor-biglist/src/app/app.config.ts b/apps/performance/36-ngfor-optimization/src/app/app.config.ts
similarity index 100%
rename from apps/performance/ngfor-biglist/src/app/app.config.ts
rename to apps/performance/36-ngfor-optimization/src/app/app.config.ts
diff --git a/apps/performance/ngfor-optimize/src/app/generateList.ts b/apps/performance/36-ngfor-optimization/src/app/generateList.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/app/generateList.ts
rename to apps/performance/36-ngfor-optimization/src/app/generateList.ts
diff --git a/apps/performance/ngfor-biglist/src/app/list.service.ts b/apps/performance/36-ngfor-optimization/src/app/list.service.ts
similarity index 100%
rename from apps/performance/ngfor-biglist/src/app/list.service.ts
rename to apps/performance/36-ngfor-optimization/src/app/list.service.ts
diff --git a/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts b/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts
new file mode 100644
index 000000000..6d9b2b4af
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts
@@ -0,0 +1,36 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+import { CommonModule } from '@angular/common';
+import { Person } from './person.model';
+
+@Component({
+ selector: 'app-person-list',
+ imports: [CommonModule],
+ template: `
+
+
{{ person.name }}
+
+
+
+
+
+ `,
+ host: {
+ class: 'w-full flex flex-col',
+ },
+})
+export class PersonListComponent {
+ @Input() persons: Person[] = [];
+ @Output() delete = new EventEmitter();
+ @Output() update = new EventEmitter();
+}
diff --git a/apps/performance/ngfor-biglist/src/app/person.model.ts b/apps/performance/36-ngfor-optimization/src/app/person.model.ts
similarity index 100%
rename from apps/performance/ngfor-biglist/src/app/person.model.ts
rename to apps/performance/36-ngfor-optimization/src/app/person.model.ts
diff --git a/apps/performance/ngfor-biglist/src/assets/.gitkeep b/apps/performance/36-ngfor-optimization/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/ngfor-biglist/src/assets/.gitkeep
rename to apps/performance/36-ngfor-optimization/src/assets/.gitkeep
diff --git a/apps/rxjs/catch-error/src/favicon.ico b/apps/performance/36-ngfor-optimization/src/favicon.ico
similarity index 100%
rename from apps/rxjs/catch-error/src/favicon.ico
rename to apps/performance/36-ngfor-optimization/src/favicon.ico
diff --git a/apps/performance/36-ngfor-optimization/src/index.html b/apps/performance/36-ngfor-optimization/src/index.html
new file mode 100644
index 000000000..07ec600a8
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-ngfor-optimization
+
+
+
+
+
+
+
+
diff --git a/apps/performance/36-ngfor-optimization/src/main.ts b/apps/performance/36-ngfor-optimization/src/main.ts
new file mode 100644
index 000000000..f3a7223da
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/src/main.ts
@@ -0,0 +1,7 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+import { appConfig } from './app/app.config';
+
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
+ console.error(err),
+);
diff --git a/apps/testing/modal/src/styles.scss b/apps/performance/36-ngfor-optimization/src/styles.scss
similarity index 100%
rename from apps/testing/modal/src/styles.scss
rename to apps/performance/36-ngfor-optimization/src/styles.scss
diff --git a/apps/testing/create-harness/src/test-setup.ts b/apps/performance/36-ngfor-optimization/src/test-setup.ts
similarity index 100%
rename from apps/testing/create-harness/src/test-setup.ts
rename to apps/performance/36-ngfor-optimization/src/test-setup.ts
diff --git a/apps/testing/create-harness/tailwind.config.js b/apps/performance/36-ngfor-optimization/tailwind.config.js
similarity index 100%
rename from apps/testing/create-harness/tailwind.config.js
rename to apps/performance/36-ngfor-optimization/tailwind.config.js
diff --git a/apps/testing/harness/tsconfig.app.json b/apps/performance/36-ngfor-optimization/tsconfig.app.json
similarity index 100%
rename from apps/testing/harness/tsconfig.app.json
rename to apps/performance/36-ngfor-optimization/tsconfig.app.json
diff --git a/apps/rxjs/catch-error/tsconfig.editor.json b/apps/performance/36-ngfor-optimization/tsconfig.editor.json
similarity index 100%
rename from apps/rxjs/catch-error/tsconfig.editor.json
rename to apps/performance/36-ngfor-optimization/tsconfig.editor.json
diff --git a/apps/performance/ngfor-optimize/tsconfig.json b/apps/performance/36-ngfor-optimization/tsconfig.json
similarity index 100%
rename from apps/performance/ngfor-optimize/tsconfig.json
rename to apps/performance/36-ngfor-optimization/tsconfig.json
diff --git a/apps/performance/36-ngfor-optimization/tsconfig.spec.json b/apps/performance/36-ngfor-optimization/tsconfig.spec.json
new file mode 100644
index 000000000..1a4817a7d
--- /dev/null
+++ b/apps/performance/36-ngfor-optimization/tsconfig.spec.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["jest", "node", "@testing-library/jest-dom"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": [
+ "jest.config.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/apps/performance/ngfor-optimize/.eslintrc.json b/apps/performance/37-optimize-big-list/.eslintrc.json
similarity index 100%
rename from apps/performance/ngfor-optimize/.eslintrc.json
rename to apps/performance/37-optimize-big-list/.eslintrc.json
diff --git a/apps/performance/37-optimize-big-list/README.md b/apps/performance/37-optimize-big-list/README.md
new file mode 100644
index 000000000..1d8e134c2
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/README.md
@@ -0,0 +1,13 @@
+# NgFor optimize big list
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-optimize-big-list
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/37-ngfor-biglist/).
diff --git a/apps/performance/37-optimize-big-list/project.json b/apps/performance/37-optimize-big-list/project.json
new file mode 100644
index 000000000..fbd03771e
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/project.json
@@ -0,0 +1,75 @@
+{
+ "name": "performance-optimize-big-list",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/performance/37-optimize-big-list/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/37-optimize-big-list",
+ "index": "apps/performance/37-optimize-big-list/src/index.html",
+ "main": "apps/performance/37-optimize-big-list/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/37-optimize-big-list/tsconfig.app.json",
+ "assets": [
+ "apps/performance/37-optimize-big-list/src/favicon.ico",
+ "apps/performance/37-optimize-big-list/src/assets"
+ ],
+ "styles": [
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
+ "apps/performance/37-optimize-big-list/src/styles.scss"
+ ],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-optimize-big-list:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-optimize-big-list:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "performance-optimize-big-list:build"
+ }
+ }
+ }
+}
diff --git a/apps/performance/37-optimize-big-list/src/app/app.component.ts b/apps/performance/37-optimize-big-list/src/app/app.component.ts
new file mode 100644
index 000000000..c441134df
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/src/app/app.component.ts
@@ -0,0 +1,41 @@
+import { NgIf } from '@angular/common';
+import { Component, signal } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { generateList } from './generateList';
+import { PersonService } from './list.service';
+import { PersonListComponent } from './person-list.component';
+
+@Component({
+ imports: [
+ NgIf,
+ PersonListComponent,
+ FormsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ ],
+ providers: [PersonService],
+ selector: 'app-root',
+ template: `
+
+
+
+ `,
+ host: {
+ class: 'flex items-center flex-col gap-5',
+ },
+})
+export class AppComponent {
+ readonly persons = signal(generateList());
+ readonly loadList = signal(false);
+
+ label = '';
+}
diff --git a/apps/performance/ngfor-optimize/src/app/app.config.ts b/apps/performance/37-optimize-big-list/src/app/app.config.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/app/app.config.ts
rename to apps/performance/37-optimize-big-list/src/app/app.config.ts
diff --git a/apps/performance/ngfor-biglist/src/app/generateList.ts b/apps/performance/37-optimize-big-list/src/app/generateList.ts
similarity index 100%
rename from apps/performance/ngfor-biglist/src/app/generateList.ts
rename to apps/performance/37-optimize-big-list/src/app/generateList.ts
diff --git a/apps/performance/ngfor-optimize/src/app/list.service.ts b/apps/performance/37-optimize-big-list/src/app/list.service.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/app/list.service.ts
rename to apps/performance/37-optimize-big-list/src/app/list.service.ts
diff --git a/apps/performance/37-optimize-big-list/src/app/person-list.component.ts b/apps/performance/37-optimize-big-list/src/app/person-list.component.ts
new file mode 100644
index 000000000..6159baaaa
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/src/app/person-list.component.ts
@@ -0,0 +1,29 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+import { NgForTrackByModule } from '@angular-challenges/shared/directives';
+import { CommonModule } from '@angular/common';
+import { Person } from './person.model';
+
+@Component({
+ selector: 'app-person-list',
+ imports: [CommonModule, NgForTrackByModule],
+ template: `
+
+ `,
+ host: {
+ class: 'w-full flex flex-col',
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PersonListComponent {
+ @Input() persons: Person[] = [];
+}
diff --git a/apps/performance/ngfor-optimize/src/app/person.model.ts b/apps/performance/37-optimize-big-list/src/app/person.model.ts
similarity index 100%
rename from apps/performance/ngfor-optimize/src/app/person.model.ts
rename to apps/performance/37-optimize-big-list/src/app/person.model.ts
diff --git a/apps/performance/ngfor-optimize/src/assets/.gitkeep b/apps/performance/37-optimize-big-list/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/ngfor-optimize/src/assets/.gitkeep
rename to apps/performance/37-optimize-big-list/src/assets/.gitkeep
diff --git a/apps/rxjs/pipe-bug/src/favicon.ico b/apps/performance/37-optimize-big-list/src/favicon.ico
similarity index 100%
rename from apps/rxjs/pipe-bug/src/favicon.ico
rename to apps/performance/37-optimize-big-list/src/favicon.ico
diff --git a/apps/performance/37-optimize-big-list/src/index.html b/apps/performance/37-optimize-big-list/src/index.html
new file mode 100644
index 000000000..f93d2d26f
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-optimize-big-list
+
+
+
+
+
+
+
+
diff --git a/apps/performance/37-optimize-big-list/src/main.ts b/apps/performance/37-optimize-big-list/src/main.ts
new file mode 100644
index 000000000..f3a7223da
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/src/main.ts
@@ -0,0 +1,7 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+import { appConfig } from './app/app.config';
+
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
+ console.error(err),
+);
diff --git a/apps/performance/37-optimize-big-list/src/styles.scss b/apps/performance/37-optimize-big-list/src/styles.scss
new file mode 100644
index 000000000..77e408aa8
--- /dev/null
+++ b/apps/performance/37-optimize-big-list/src/styles.scss
@@ -0,0 +1,5 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/testing/harness/tailwind.config.js b/apps/performance/37-optimize-big-list/tailwind.config.js
similarity index 100%
rename from apps/testing/harness/tailwind.config.js
rename to apps/performance/37-optimize-big-list/tailwind.config.js
diff --git a/apps/typescript/overload/tsconfig.app.json b/apps/performance/37-optimize-big-list/tsconfig.app.json
similarity index 100%
rename from apps/typescript/overload/tsconfig.app.json
rename to apps/performance/37-optimize-big-list/tsconfig.app.json
diff --git a/apps/performance/christmas-web-worker/tsconfig.editor.json b/apps/performance/37-optimize-big-list/tsconfig.editor.json
similarity index 100%
rename from apps/performance/christmas-web-worker/tsconfig.editor.json
rename to apps/performance/37-optimize-big-list/tsconfig.editor.json
diff --git a/apps/performance/memoized/tsconfig.json b/apps/performance/37-optimize-big-list/tsconfig.json
similarity index 100%
rename from apps/performance/memoized/tsconfig.json
rename to apps/performance/37-optimize-big-list/tsconfig.json
diff --git a/apps/performance/christmas-web-worker/.eslintrc.json b/apps/performance/40-web-workers/.eslintrc.json
similarity index 100%
rename from apps/performance/christmas-web-worker/.eslintrc.json
rename to apps/performance/40-web-workers/.eslintrc.json
diff --git a/apps/performance/40-web-workers/README.md b/apps/performance/40-web-workers/README.md
new file mode 100644
index 000000000..067777a8f
--- /dev/null
+++ b/apps/performance/40-web-workers/README.md
@@ -0,0 +1,13 @@
+# Web workers
+
+> Author: Thomas Laforge
+
+### Run Application
+
+```bash
+npx nx serve performance-web-workers
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/40-christmas-web-worker/).
diff --git a/apps/performance/40-web-workers/project.json b/apps/performance/40-web-workers/project.json
new file mode 100644
index 000000000..843a35c60
--- /dev/null
+++ b/apps/performance/40-web-workers/project.json
@@ -0,0 +1,69 @@
+{
+ "name": "performance-web-workers",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/performance/40-web-workers/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:application",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/performance/40-web-workers",
+ "index": "apps/performance/40-web-workers/src/index.html",
+ "browser": "apps/performance/40-web-workers/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/performance/40-web-workers/tsconfig.app.json",
+ "assets": [
+ "apps/performance/40-web-workers/src/favicon.ico",
+ "apps/performance/40-web-workers/src/assets"
+ ],
+ "styles": ["apps/performance/40-web-workers/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "performance-web-workers:build:production"
+ },
+ "development": {
+ "buildTarget": "performance-web-workers:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "performance-web-workers:build"
+ }
+ }
+ }
+}
diff --git a/apps/performance/40-web-workers/src/app/app.component.ts b/apps/performance/40-web-workers/src/app/app.component.ts
new file mode 100644
index 000000000..583572ed2
--- /dev/null
+++ b/apps/performance/40-web-workers/src/app/app.component.ts
@@ -0,0 +1,31 @@
+import { CommonModule } from '@angular/common';
+import { Component, inject } from '@angular/core';
+import { HeavyCalculationService } from './heavy-calculation.service';
+import { UnknownPersonComponent } from './unknown-person/unknown-person.component';
+
+@Component({
+ imports: [CommonModule, UnknownPersonComponent],
+ providers: [HeavyCalculationService],
+ selector: 'app-root',
+ template: `
+
+
+ Progress: {{ loadingPercentage() }}%
+ `,
+ host: {
+ class: `flex flex-col h-screen w-screen bg-[#1f75c0]`,
+ },
+})
+export class AppComponent {
+ private heavyCalculationService = inject(HeavyCalculationService);
+
+ readonly loadingPercentage = this.heavyCalculationService.loadingPercentage;
+
+ discover() {
+ this.heavyCalculationService.startLoading();
+ }
+}
diff --git a/apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts b/apps/performance/40-web-workers/src/app/heavy-calculation.service.ts
similarity index 100%
rename from apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts
rename to apps/performance/40-web-workers/src/app/heavy-calculation.service.ts
diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css b/apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.css
similarity index 100%
rename from apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css
rename to apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.css
diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts b/apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.ts
similarity index 100%
rename from apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts
rename to apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.ts
diff --git a/apps/performance/scroll-cd/src/assets/.gitkeep b/apps/performance/40-web-workers/src/assets/.gitkeep
similarity index 100%
rename from apps/performance/scroll-cd/src/assets/.gitkeep
rename to apps/performance/40-web-workers/src/assets/.gitkeep
diff --git a/apps/rxjs/race-condition/src/favicon.ico b/apps/performance/40-web-workers/src/favicon.ico
similarity index 100%
rename from apps/rxjs/race-condition/src/favicon.ico
rename to apps/performance/40-web-workers/src/favicon.ico
diff --git a/apps/performance/40-web-workers/src/index.html b/apps/performance/40-web-workers/src/index.html
new file mode 100644
index 000000000..fa0cf99ae
--- /dev/null
+++ b/apps/performance/40-web-workers/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ performance-web-worker
+
+
+
+
+
+
+
+
diff --git a/apps/rxjs/pipe-bug/src/main.ts b/apps/performance/40-web-workers/src/main.ts
similarity index 100%
rename from apps/rxjs/pipe-bug/src/main.ts
rename to apps/performance/40-web-workers/src/main.ts
diff --git a/apps/performance/40-web-workers/src/styles.scss b/apps/performance/40-web-workers/src/styles.scss
new file mode 100644
index 000000000..77e408aa8
--- /dev/null
+++ b/apps/performance/40-web-workers/src/styles.scss
@@ -0,0 +1,5 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/testing/modal/tailwind.config.js b/apps/performance/40-web-workers/tailwind.config.js
similarity index 100%
rename from apps/testing/modal/tailwind.config.js
rename to apps/performance/40-web-workers/tailwind.config.js
diff --git a/apps/performance/40-web-workers/tsconfig.app.json b/apps/performance/40-web-workers/tsconfig.app.json
new file mode 100644
index 000000000..58220429a
--- /dev/null
+++ b/apps/performance/40-web-workers/tsconfig.app.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"],
+ "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"]
+}
diff --git a/apps/performance/memoized/tsconfig.editor.json b/apps/performance/40-web-workers/tsconfig.editor.json
similarity index 100%
rename from apps/performance/memoized/tsconfig.editor.json
rename to apps/performance/40-web-workers/tsconfig.editor.json
diff --git a/apps/performance/ngfor-biglist/tsconfig.json b/apps/performance/40-web-workers/tsconfig.json
similarity index 100%
rename from apps/performance/ngfor-biglist/tsconfig.json
rename to apps/performance/40-web-workers/tsconfig.json
diff --git a/apps/performance/christmas-web-worker/README.md b/apps/performance/christmas-web-worker/README.md
deleted file mode 100644
index 6da93949a..000000000
--- a/apps/performance/christmas-web-worker/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Web workers
-
-> Author: Thomas Laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-christmas-web-worker
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/40-christmas-web-worker/).
diff --git a/apps/performance/christmas-web-worker/project.json b/apps/performance/christmas-web-worker/project.json
deleted file mode 100644
index a1eae3c67..000000000
--- a/apps/performance/christmas-web-worker/project.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "name": "performance-christmas-web-worker",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/performance/christmas-web-worker/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/christmas-web-worker",
- "index": "apps/performance/christmas-web-worker/src/index.html",
- "browser": "apps/performance/christmas-web-worker/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/christmas-web-worker/tsconfig.app.json",
- "assets": [
- "apps/performance/christmas-web-worker/src/favicon.ico",
- "apps/performance/christmas-web-worker/src/assets"
- ],
- "styles": ["apps/performance/christmas-web-worker/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "optimization": false,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-christmas-web-worker:build:production"
- },
- "development": {
- "buildTarget": "performance-christmas-web-worker:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "performance-christmas-web-worker:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/christmas-web-worker/**/*.ts",
- "apps/performance/christmas-web-worker/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/performance/christmas-web-worker/src/app/app.component.ts b/apps/performance/christmas-web-worker/src/app/app.component.ts
deleted file mode 100644
index 6b9846b13..000000000
--- a/apps/performance/christmas-web-worker/src/app/app.component.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { CommonModule } from '@angular/common';
-import { Component, inject } from '@angular/core';
-import { HeavyCalculationService } from './heavy-calculation.service';
-import { UnknownPersonComponent } from './unknown-person/unknown-person.component';
-
-@Component({
- standalone: true,
- imports: [CommonModule, UnknownPersonComponent],
- providers: [HeavyCalculationService],
- selector: 'app-root',
- template: `
-
-
- Progress: {{ loadingPercentage() }}%
- `,
- host: {
- class: `flex flex-col h-screen w-screen bg-[#1f75c0]`,
- },
-})
-export class AppComponent {
- private heavyCalculationService = inject(HeavyCalculationService);
-
- readonly loadingPercentage = this.heavyCalculationService.loadingPercentage;
-
- discover() {
- this.heavyCalculationService.startLoading();
- }
-}
diff --git a/apps/performance/christmas-web-worker/src/index.html b/apps/performance/christmas-web-worker/src/index.html
deleted file mode 100644
index 4ca378971..000000000
--- a/apps/performance/christmas-web-worker/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- performance-christmas-web-worker
-
-
-
-
-
-
-
-
diff --git a/apps/performance/default-onpush/README.md b/apps/performance/default-onpush/README.md
deleted file mode 100644
index 29d7696ff..000000000
--- a/apps/performance/default-onpush/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default vs OnPush
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-default-onpush
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/34-default-onpush/).
diff --git a/apps/performance/default-onpush/project.json b/apps/performance/default-onpush/project.json
deleted file mode 100644
index 2f819ee75..000000000
--- a/apps/performance/default-onpush/project.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
- "name": "performance-default-onpush",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/performance/default-onpush/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/default-onpush",
- "index": "apps/performance/default-onpush/src/index.html",
- "main": "apps/performance/default-onpush/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/default-onpush/tsconfig.app.json",
- "assets": [
- "apps/performance/default-onpush/src/favicon.ico",
- "apps/performance/default-onpush/src/assets"
- ],
- "styles": [
- "apps/performance/default-onpush/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-default-onpush:build:production"
- },
- "development": {
- "buildTarget": "performance-default-onpush:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "performance-default-onpush:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/default-onpush/**/*.ts",
- "apps/performance/default-onpush/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/performance/default-onpush/src/app/app.component.ts b/apps/performance/default-onpush/src/app/app.component.ts
deleted file mode 100644
index 1eab3c839..000000000
--- a/apps/performance/default-onpush/src/app/app.component.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Component } from '@angular/core';
-import { randFirstName } from '@ngneat/falso';
-import { PersonListComponent } from './person-list.component';
-import { RandomComponent } from './random.component';
-
-@Component({
- standalone: true,
- imports: [PersonListComponent, RandomComponent],
- selector: 'app-root',
- template: `
-
-
-
- `,
-})
-export class AppComponent {
- girlList = randFirstName({ gender: 'female', length: 10 });
- boyList = randFirstName({ gender: 'male', length: 10 });
-}
diff --git a/apps/performance/default-onpush/src/app/person-list.component.ts b/apps/performance/default-onpush/src/app/person-list.component.ts
deleted file mode 100644
index c4f556945..000000000
--- a/apps/performance/default-onpush/src/app/person-list.component.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { Component, Input } from '@angular/core';
-
-import { CDFlashingDirective } from '@angular-challenges/shared/directives';
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { MatChipsModule } from '@angular/material/chips';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { MatListModule } from '@angular/material/list';
-
-@Component({
- selector: 'app-person-list',
- standalone: true,
- imports: [
- CommonModule,
- FormsModule,
- MatListModule,
- MatFormFieldModule,
- MatInputModule,
- MatChipsModule,
- CDFlashingDirective,
- ],
- template: `
-
- {{ title | titlecase }}
-
-
-
-
-
-
-
- Empty list
-
-
-
- {{ name }}
-
-
-
-
-
- `,
- host: {
- class: 'w-full flex flex-col items-center',
- },
-})
-export class PersonListComponent {
- @Input() names: string[] = [];
- @Input() title = '';
-
- label = '';
-
- handleKey(event: any) {
- if (event.keyCode === 13) {
- this.names?.unshift(this.label);
- this.label = '';
- }
- }
-}
diff --git a/apps/performance/default-onpush/src/index.html b/apps/performance/default-onpush/src/index.html
deleted file mode 100644
index eecd767f7..000000000
--- a/apps/performance/default-onpush/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- Default OnPush
-
-
-
-
-
-
-
-
diff --git a/apps/performance/memoized/README.md b/apps/performance/memoized/README.md
deleted file mode 100644
index 520efb1f1..000000000
--- a/apps/performance/memoized/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Memoization
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-memoized
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/35-memoize/).
diff --git a/apps/performance/memoized/project.json b/apps/performance/memoized/project.json
deleted file mode 100644
index e613c1303..000000000
--- a/apps/performance/memoized/project.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
- "name": "performance-memoized",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/performance/memoized/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/memoized",
- "index": "apps/performance/memoized/src/index.html",
- "main": "apps/performance/memoized/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/memoized/tsconfig.app.json",
- "assets": [
- "apps/performance/memoized/src/favicon.ico",
- "apps/performance/memoized/src/assets"
- ],
- "styles": [
- "apps/performance/memoized/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-memoized:build:production"
- },
- "development": {
- "buildTarget": "performance-memoized:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "performance-memoized:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/memoized/**/*.ts",
- "apps/performance/memoized/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/performance/memoized/src/app/app.component.ts b/apps/performance/memoized/src/app/app.component.ts
deleted file mode 100644
index 4b24fced0..000000000
--- a/apps/performance/memoized/src/app/app.component.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { NgIf } from '@angular/common';
-import { Component } from '@angular/core';
-import { generateList } from './generateList';
-import { PersonListComponent } from './person-list.component';
-
-@Component({
- standalone: true,
- imports: [PersonListComponent, NgIf],
- selector: 'app-root',
- template: `
- Performance is key!!
-
-
-
- `,
-})
-export class AppComponent {
- persons = generateList();
- loadList = false;
-}
diff --git a/apps/performance/memoized/src/app/person-list.component.ts b/apps/performance/memoized/src/app/person-list.component.ts
deleted file mode 100644
index 4a425d4f2..000000000
--- a/apps/performance/memoized/src/app/person-list.component.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Component, Input } from '@angular/core';
-
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { MatChipsModule } from '@angular/material/chips';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { MatListModule } from '@angular/material/list';
-import { Person } from './person.model';
-
-const fibonacci = (num: number): number => {
- if (num === 1 || num === 2) {
- return 1;
- }
- return fibonacci(num - 1) + fibonacci(num - 2);
-};
-
-@Component({
- selector: 'app-person-list',
- standalone: true,
- imports: [
- CommonModule,
- FormsModule,
- MatListModule,
- MatFormFieldModule,
- MatInputModule,
- MatChipsModule,
- ],
- template: `
-
- {{ title | titlecase }}
-
-
-
-
-
-
-
-
-
-
{{ person.name }}
- {{ calculate(person.fib) }}
-
-
-
- `,
- host: {
- class: 'w-full flex flex-col items-center',
- },
-})
-export class PersonListComponent {
- @Input() persons: Person[] = [];
- @Input() title = '';
-
- label = '';
-
- calculate(num: number) {
- return fibonacci(num);
- }
-}
diff --git a/apps/performance/memoized/src/index.html b/apps/performance/memoized/src/index.html
deleted file mode 100644
index 1c07d985d..000000000
--- a/apps/performance/memoized/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- performance-memoized
-
-
-
-
-
-
-
-
diff --git a/apps/performance/ngfor-biglist/README.md b/apps/performance/ngfor-biglist/README.md
deleted file mode 100644
index 4d164f0c9..000000000
--- a/apps/performance/ngfor-biglist/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# NgFor optimize big list
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-ngfor-biglist
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/37-ngfor-biglist/).
diff --git a/apps/performance/ngfor-biglist/project.json b/apps/performance/ngfor-biglist/project.json
deleted file mode 100644
index 22d61fe16..000000000
--- a/apps/performance/ngfor-biglist/project.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
- "name": "performance-ngfor-biglist",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/performance/ngfor-biglist/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/ngfor-biglist",
- "index": "apps/performance/ngfor-biglist/src/index.html",
- "main": "apps/performance/ngfor-biglist/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/ngfor-biglist/tsconfig.app.json",
- "assets": [
- "apps/performance/ngfor-biglist/src/favicon.ico",
- "apps/performance/ngfor-biglist/src/assets"
- ],
- "styles": [
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
- "apps/performance/ngfor-biglist/src/styles.scss"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-ngfor-biglist:build:production"
- },
- "development": {
- "buildTarget": "performance-ngfor-biglist:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "performance-ngfor-biglist:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/ngfor-biglist/**/*.ts",
- "apps/performance/ngfor-biglist/**/*.html"
- ]
- }
- }
- }
-}
diff --git a/apps/performance/ngfor-biglist/src/app/app.component.ts b/apps/performance/ngfor-biglist/src/app/app.component.ts
deleted file mode 100644
index 9c26149b2..000000000
--- a/apps/performance/ngfor-biglist/src/app/app.component.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { NgIf } from '@angular/common';
-import { Component, signal } from '@angular/core';
-import { FormsModule } from '@angular/forms';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { generateList } from './generateList';
-import { PersonService } from './list.service';
-import { PersonListComponent } from './person-list.component';
-
-@Component({
- standalone: true,
- imports: [
- NgIf,
- PersonListComponent,
- FormsModule,
- MatFormFieldModule,
- MatInputModule,
- ],
- providers: [PersonService],
- selector: 'app-root',
- template: `
-
-
-
- `,
- host: {
- class: 'flex items-center flex-col gap-5',
- },
-})
-export class AppComponent {
- readonly persons = signal(generateList());
- readonly loadList = signal(false);
-
- label = '';
-}
diff --git a/apps/performance/ngfor-biglist/src/app/person-list.component.ts b/apps/performance/ngfor-biglist/src/app/person-list.component.ts
deleted file mode 100644
index 4d438e664..000000000
--- a/apps/performance/ngfor-biglist/src/app/person-list.component.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
-
-import { NgForTrackByModule } from '@angular-challenges/shared/directives';
-import { CommonModule } from '@angular/common';
-import { Person } from './person.model';
-
-@Component({
- selector: 'app-person-list',
- standalone: true,
- imports: [CommonModule, NgForTrackByModule],
- template: `
-
- `,
- host: {
- class: 'w-full flex flex-col',
- },
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class PersonListComponent {
- @Input() persons: Person[] = [];
-}
diff --git a/apps/performance/ngfor-biglist/src/index.html b/apps/performance/ngfor-biglist/src/index.html
deleted file mode 100644
index 1b058276a..000000000
--- a/apps/performance/ngfor-biglist/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- performance-ngfor-biglist
-
-
-
-
-
-
-
-
diff --git a/apps/performance/ngfor-optimize/README.md b/apps/performance/ngfor-optimize/README.md
deleted file mode 100644
index 1e9b2f833..000000000
--- a/apps/performance/ngfor-optimize/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# NgFor Optimization
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-ngfor-optimize
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/36-ngfor-optimize/).
diff --git a/apps/performance/ngfor-optimize/jest.config.ts b/apps/performance/ngfor-optimize/jest.config.ts
deleted file mode 100644
index 49ac9d7ac..000000000
--- a/apps/performance/ngfor-optimize/jest.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'performance-ngfor-optimize',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- coverageDirectory: '../../../coverage/apps/performance/ngfor-optimize',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/performance/ngfor-optimize/project.json b/apps/performance/ngfor-optimize/project.json
deleted file mode 100644
index 57538baa0..000000000
--- a/apps/performance/ngfor-optimize/project.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "name": "performance-ngfor-optimize",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "prefix": "app",
- "sourceRoot": "apps/performance/ngfor-optimize/src",
- "tags": [],
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/ngfor-optimize",
- "index": "apps/performance/ngfor-optimize/src/index.html",
- "main": "apps/performance/ngfor-optimize/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/ngfor-optimize/tsconfig.app.json",
- "assets": [
- "apps/performance/ngfor-optimize/src/favicon.ico",
- "apps/performance/ngfor-optimize/src/assets"
- ],
- "styles": [
- "apps/performance/ngfor-optimize/src/styles.scss",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": [],
- "allowedCommonJsDependencies": ["seedrandom"]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-ngfor-optimize:build:production"
- },
- "development": {
- "buildTarget": "performance-ngfor-optimize:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "performance-ngfor-optimize:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/ngfor-optimize/**/*.ts",
- "apps/performance/ngfor-optimize/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/performance/ngfor-optimize/jest.config.ts"
- }
- }
- }
-}
diff --git a/apps/performance/ngfor-optimize/src/app/app.component.ts b/apps/performance/ngfor-optimize/src/app/app.component.ts
deleted file mode 100644
index fb9e98516..000000000
--- a/apps/performance/ngfor-optimize/src/app/app.component.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Component, OnInit, inject } from '@angular/core';
-import { FormsModule } from '@angular/forms';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { PersonService } from './list.service';
-import { PersonListComponent } from './person-list.component';
-
-@Component({
- standalone: true,
- imports: [
- PersonListComponent,
- FormsModule,
- MatFormFieldModule,
- MatInputModule,
- ],
- providers: [PersonService],
- selector: 'app-root',
- template: `
-
- List of Persons
-
-
-
-
-
-
-
- `,
- host: {
- class: 'flex items-center flex-col gap-5',
- },
-})
-export class AppComponent implements OnInit {
- readonly personService = inject(PersonService);
- readonly persons = this.personService.persons;
-
- label = '';
-
- ngOnInit(): void {
- this.personService.loadPersons();
- }
-
- handleKey(event: any) {
- if (event.keyCode === 13) {
- this.personService.addPerson(this.label);
- this.label = '';
- }
- }
-}
diff --git a/apps/performance/ngfor-optimize/src/app/person-list.component.ts b/apps/performance/ngfor-optimize/src/app/person-list.component.ts
deleted file mode 100644
index ca04956d0..000000000
--- a/apps/performance/ngfor-optimize/src/app/person-list.component.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-
-import { CommonModule } from '@angular/common';
-import { Person } from './person.model';
-
-@Component({
- selector: 'app-person-list',
- standalone: true,
- imports: [CommonModule],
- template: `
-
-
{{ person.name }}
-
-
-
-
-
- `,
- host: {
- class: 'w-full flex flex-col',
- },
-})
-export class PersonListComponent {
- @Input() persons: Person[] = [];
- @Output() delete = new EventEmitter();
- @Output() update = new EventEmitter();
-}
diff --git a/apps/performance/ngfor-optimize/src/index.html b/apps/performance/ngfor-optimize/src/index.html
deleted file mode 100644
index e5b79903e..000000000
--- a/apps/performance/ngfor-optimize/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- performance-ngfor-optimize
-
-
-
-
-
-
-
-
diff --git a/apps/performance/scroll-cd/README.md b/apps/performance/scroll-cd/README.md
deleted file mode 100644
index dc0c31301..000000000
--- a/apps/performance/scroll-cd/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Optimize Change Detection
-
-> author: thomas-laforge
-
-### Run Application
-
-```bash
-npx nx serve performance-scroll-cd
-```
-
-### Documentation and Instruction
-
-Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/12-performance-scroll-cd/).
diff --git a/apps/performance/scroll-cd/jest.config.ts b/apps/performance/scroll-cd/jest.config.ts
deleted file mode 100644
index 7e8ea5b99..000000000
--- a/apps/performance/scroll-cd/jest.config.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-export default {
- displayName: 'performance-scroll-cd',
- preset: '../../../jest.preset.js',
- setupFilesAfterEnv: ['/src/subscription-setup.ts'],
- globals: {},
- coverageDirectory: '../../../coverage/apps/performance/scroll-cd',
- transform: {
- '^.+\\.(ts|mjs|js|html)$': [
- 'jest-preset-angular',
- {
- tsconfig: '/tsconfig.spec.json',
- stringifyContentPathRegex: '\\.(html|svg)$',
- },
- ],
- },
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
- snapshotSerializers: [
- 'jest-preset-angular/build/serializers/no-ng-attributes',
- 'jest-preset-angular/build/serializers/ng-snapshot',
- 'jest-preset-angular/build/serializers/html-comment',
- ],
-};
diff --git a/apps/performance/scroll-cd/project.json b/apps/performance/scroll-cd/project.json
deleted file mode 100644
index 9affd7c3e..000000000
--- a/apps/performance/scroll-cd/project.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "name": "performance-scroll-cd",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "projectType": "application",
- "sourceRoot": "apps/performance/scroll-cd/src",
- "prefix": "app",
- "targets": {
- "build": {
- "executor": "@angular-devkit/build-angular:browser",
- "outputs": ["{options.outputPath}"],
- "options": {
- "outputPath": "dist/apps/performance/scroll-cd",
- "index": "apps/performance/scroll-cd/src/index.html",
- "main": "apps/performance/scroll-cd/src/main.ts",
- "polyfills": ["zone.js"],
- "tsConfig": "apps/performance/scroll-cd/tsconfig.app.json",
- "inlineStyleLanguage": "scss",
- "assets": [
- "apps/performance/scroll-cd/src/favicon.ico",
- "apps/performance/scroll-cd/src/assets"
- ],
- "styles": ["apps/performance/scroll-cd/src/styles.scss"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "2kb",
- "maximumError": "4kb"
- }
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "executor": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "buildTarget": "performance-scroll-cd:build:production"
- },
- "development": {
- "buildTarget": "performance-scroll-cd:build:development"
- }
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "executor": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "buildTarget": "performance-scroll-cd:build"
- }
- },
- "lint": {
- "executor": "@nx/eslint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": [
- "apps/performance/scroll-cd/**/*.ts",
- "apps/performance/scroll-cd/**/*.html"
- ]
- }
- },
- "test": {
- "executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
- "options": {
- "jestConfig": "apps/performance/scroll-cd/jest.config.ts"
- }
- }
- },
- "tags": []
-}
diff --git a/apps/performance/scroll-cd/src/app/app.component.ts b/apps/performance/scroll-cd/src/app/app.component.ts
deleted file mode 100644
index e75ef991e..000000000
--- a/apps/performance/scroll-cd/src/app/app.component.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { AsyncPipe, NgIf } from '@angular/common';
-import { Component, HostListener } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
-
-@Component({
- standalone: true,
- imports: [NgIf, AsyncPipe],
- selector: 'app-root',
- template: `
- Top
- Middle
- Bottom
-
- `,
- styles: [
- `
- :host {
- height: 1500px;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-
- button {
- position: fixed;
- bottom: 1rem;
- left: 1rem;
- z-index: 1;
- padding: 1rem;
- }
- }
- `,
- ],
-})
-export class AppComponent {
- title = 'scroll-cd';
-
- private displayButtonSubject = new BehaviorSubject(false);
- displayButton$ = this.displayButtonSubject.asObservable();
-
- @HostListener('window:scroll', ['$event'])
- onScroll() {
- const pos = window.pageYOffset;
- this.displayButtonSubject.next(pos > 50);
- }
-
- goToTop() {
- window.scroll({
- top: 0,
- left: 0,
- behavior: 'smooth',
- });
- }
-}
diff --git a/apps/performance/scroll-cd/src/index.html b/apps/performance/scroll-cd/src/index.html
deleted file mode 100644
index 1d22cac27..000000000
--- a/apps/performance/scroll-cd/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- ScrollCd
-
-
-
-
-
-
-
-
diff --git a/apps/rxjs/11-high-order-operator-bug/.eslintrc.json b/apps/rxjs/11-high-order-operator-bug/.eslintrc.json
new file mode 100644
index 000000000..8ebcbfd59
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/rxjs/11-high-order-operator-bug/README.md b/apps/rxjs/11-high-order-operator-bug/README.md
new file mode 100644
index 000000000..5a4fa5512
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/README.md
@@ -0,0 +1,13 @@
+# High Order Operator Bug
+
+> author: thomas-laforge
+
+### Run Application
+
+```bash
+npx nx serve rxjs-high-order-operator-bug
+```
+
+### Documentation and Instruction
+
+Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/11-bug-chaining-operator/).
diff --git a/apps/rxjs/11-high-order-operator-bug/project.json b/apps/rxjs/11-high-order-operator-bug/project.json
new file mode 100644
index 000000000..e8e3f2045
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/project.json
@@ -0,0 +1,73 @@
+{
+ "name": "rxjs-high-order-operator-bug",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/rxjs/11-high-order-operator-bug/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/rxjs/11-high-order-operator-bug",
+ "index": "apps/rxjs/11-high-order-operator-bug/src/index.html",
+ "main": "apps/rxjs/11-high-order-operator-bug/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/rxjs/11-high-order-operator-bug/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/rxjs/11-high-order-operator-bug/src/favicon.ico",
+ "apps/rxjs/11-high-order-operator-bug/src/assets"
+ ],
+ "styles": ["apps/rxjs/11-high-order-operator-bug/src/styles.scss"],
+ "scripts": [],
+ "allowedCommonJsDependencies": ["seedrandom"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "rxjs-high-order-operator-bug:build:production"
+ },
+ "development": {
+ "buildTarget": "rxjs-high-order-operator-bug:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "rxjs-high-order-operator-bug:build"
+ }
+ }
+ }
+}
diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts
new file mode 100644
index 000000000..fb80fb2b6
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts
@@ -0,0 +1,52 @@
+/* eslint-disable @angular-eslint/component-selector */
+import { Component, inject, input, signal } from '@angular/core';
+import { take } from 'rxjs';
+import { AppService } from './app.service';
+import { TopicType } from './localDB.service';
+
+@Component({
+ selector: 'button-delete-topic',
+ template: `
+
+ {{ message() }}
+ `,
+})
+export class ButtonDeleteComponent {
+ readonly topic = input.required();
+
+ message = signal('');
+
+ private service = inject(AppService);
+
+ deleteTopic() {
+ this.service
+ .deleteOldTopics(this.topic())
+ .pipe(take(1))
+ .subscribe((result) =>
+ this.message.set(
+ result
+ ? `All ${this.topic()} have been deleted`
+ : `Error: deletion of some ${this.topic()} failed`,
+ ),
+ );
+ }
+}
+
+@Component({
+ imports: [ButtonDeleteComponent],
+ selector: 'app-root',
+ template: `
+ @for (info of allInfo(); track info.id) {
+ {{ info.id }} - {{ info.topic }}
+ }
+
+ Delete Food
+ Delete Sport
+ Delete Book
+ `,
+})
+export class AppComponent {
+ private service = inject(AppService);
+
+ allInfo = this.service.getAllInfo;
+}
diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts
new file mode 100644
index 000000000..df2269a89
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts
@@ -0,0 +1,19 @@
+import { inject, Injectable } from '@angular/core';
+import { merge, Observable, of } from 'rxjs';
+import { LocalDBService, TopicType } from './localDB.service';
+
+@Injectable({ providedIn: 'root' })
+export class AppService {
+ private dbService = inject(LocalDBService);
+
+ getAllInfo = this.dbService.infos;
+
+ deleteOldTopics(type: TopicType): Observable {
+ const infoByType = this.dbService.searchByType(type);
+ return infoByType.length > 0
+ ? infoByType
+ .map((t) => this.dbService.deleteOneTopic(t.id))
+ .reduce((acc, curr) => merge(acc, curr), of(true))
+ : of(true);
+ }
+}
diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts
new file mode 100644
index 000000000..5a035e087
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts
@@ -0,0 +1,53 @@
+/* eslint-disable @typescript-eslint/member-ordering */
+import { randomError } from '@angular-challenges/shared/utils';
+import { computed, Injectable, signal } from '@angular/core';
+import { of } from 'rxjs';
+
+export type TopicType = 'food' | 'book' | 'sport';
+
+interface Info {
+ id: number;
+ topic: TopicType;
+}
+
+interface DBState {
+ infos: Info[];
+}
+
+const initialState: DBState = {
+ infos: [
+ { id: 1, topic: 'book' },
+ { id: 2, topic: 'book' },
+ { id: 3, topic: 'book' },
+ { id: 4, topic: 'book' },
+ { id: 5, topic: 'food' },
+ { id: 6, topic: 'food' },
+ { id: 7, topic: 'book' },
+ { id: 8, topic: 'book' },
+ { id: 9, topic: 'book' },
+ { id: 10, topic: 'sport' },
+ ],
+};
+
+@Injectable({ providedIn: 'root' })
+export class LocalDBService {
+ private state = signal(initialState);
+
+ infos = computed(() => this.state().infos);
+
+ searchByType = (type: TopicType) =>
+ this.infos().filter((i) => i.topic === type);
+
+ deleteOne = (id: number) => {
+ this.state.set({ infos: this.state().infos.filter((i) => i.id !== id) });
+ };
+
+ deleteOneTopic = (id: number) =>
+ randomError({
+ success: () => {
+ this.deleteOne(id);
+ return of(true);
+ },
+ error: () => of(false),
+ });
+}
diff --git a/apps/rxjs/catch-error/src/assets/.gitkeep b/apps/rxjs/11-high-order-operator-bug/src/assets/.gitkeep
similarity index 100%
rename from apps/rxjs/catch-error/src/assets/.gitkeep
rename to apps/rxjs/11-high-order-operator-bug/src/assets/.gitkeep
diff --git a/apps/testing/checkbox/src/favicon.ico b/apps/rxjs/11-high-order-operator-bug/src/favicon.ico
similarity index 100%
rename from apps/testing/checkbox/src/favicon.ico
rename to apps/rxjs/11-high-order-operator-bug/src/favicon.ico
diff --git a/apps/rxjs/11-high-order-operator-bug/src/index.html b/apps/rxjs/11-high-order-operator-bug/src/index.html
new file mode 100644
index 000000000..148a16280
--- /dev/null
+++ b/apps/rxjs/11-high-order-operator-bug/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ rxjs-high-order-operator-bug
+
+
+
+
+
+
+
+
diff --git a/apps/testing/checkbox/src/main.ts b/apps/rxjs/11-high-order-operator-bug/src/main.ts
similarity index 100%
rename from apps/testing/checkbox/src/main.ts
rename to apps/rxjs/11-high-order-operator-bug/src/main.ts
diff --git a/apps/performance/scroll-cd/src/styles.scss b/apps/rxjs/11-high-order-operator-bug/src/styles.scss
similarity index 100%
rename from apps/performance/scroll-cd/src/styles.scss
rename to apps/rxjs/11-high-order-operator-bug/src/styles.scss
diff --git a/apps/rxjs/pipe-bug/tsconfig.app.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.app.json
similarity index 100%
rename from apps/rxjs/pipe-bug/tsconfig.app.json
rename to apps/rxjs/11-high-order-operator-bug/tsconfig.app.json
diff --git a/apps/rxjs/pipe-bug/tsconfig.editor.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.editor.json
similarity index 100%
rename from apps/rxjs/pipe-bug/tsconfig.editor.json
rename to apps/rxjs/11-high-order-operator-bug/tsconfig.editor.json
diff --git a/apps/rxjs/pipe-bug/tsconfig.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.json
similarity index 100%
rename from apps/rxjs/pipe-bug/tsconfig.json
rename to apps/rxjs/11-high-order-operator-bug/tsconfig.json
diff --git a/apps/performance/scroll-cd/.eslintrc.json b/apps/rxjs/14-race-condition/.eslintrc.json
similarity index 100%
rename from apps/performance/scroll-cd/.eslintrc.json
rename to apps/rxjs/14-race-condition/.eslintrc.json
diff --git a/apps/rxjs/race-condition/README.md b/apps/rxjs/14-race-condition/README.md
similarity index 100%
rename from apps/rxjs/race-condition/README.md
rename to apps/rxjs/14-race-condition/README.md
diff --git a/apps/rxjs/race-condition/cypress.config.ts b/apps/rxjs/14-race-condition/cypress.config.ts
similarity index 100%
rename from apps/rxjs/race-condition/cypress.config.ts
rename to apps/rxjs/14-race-condition/cypress.config.ts
diff --git a/apps/rxjs/race-condition/cypress/fixtures/example.json b/apps/rxjs/14-race-condition/cypress/fixtures/example.json
similarity index 100%
rename from apps/rxjs/race-condition/cypress/fixtures/example.json
rename to apps/rxjs/14-race-condition/cypress/fixtures/example.json
diff --git a/apps/rxjs/race-condition/cypress/support/commands.ts b/apps/rxjs/14-race-condition/cypress/support/commands.ts
similarity index 100%
rename from apps/rxjs/race-condition/cypress/support/commands.ts
rename to apps/rxjs/14-race-condition/cypress/support/commands.ts
diff --git a/apps/rxjs/race-condition/cypress/support/component-index.html b/apps/rxjs/14-race-condition/cypress/support/component-index.html
similarity index 100%
rename from apps/rxjs/race-condition/cypress/support/component-index.html
rename to apps/rxjs/14-race-condition/cypress/support/component-index.html
diff --git a/apps/rxjs/race-condition/cypress/support/component.ts b/apps/rxjs/14-race-condition/cypress/support/component.ts
similarity index 100%
rename from apps/rxjs/race-condition/cypress/support/component.ts
rename to apps/rxjs/14-race-condition/cypress/support/component.ts
diff --git a/apps/rxjs/race-condition/cypress/tsconfig.json b/apps/rxjs/14-race-condition/cypress/tsconfig.json
similarity index 100%
rename from apps/rxjs/race-condition/cypress/tsconfig.json
rename to apps/rxjs/14-race-condition/cypress/tsconfig.json
diff --git a/apps/rxjs/14-race-condition/jest.config.ts b/apps/rxjs/14-race-condition/jest.config.ts
new file mode 100644
index 000000000..493fb2452
--- /dev/null
+++ b/apps/rxjs/14-race-condition/jest.config.ts
@@ -0,0 +1,23 @@
+/* eslint-disable */
+export default {
+ displayName: 'rxjs-race-condition',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ globals: {},
+ coverageDirectory: '../../../coverage/apps/rxjs/14-race-condition',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/apps/rxjs/14-race-condition/project.json b/apps/rxjs/14-race-condition/project.json
new file mode 100644
index 000000000..f84ccf155
--- /dev/null
+++ b/apps/rxjs/14-race-condition/project.json
@@ -0,0 +1,83 @@
+{
+ "name": "rxjs-race-condition",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/rxjs/14-race-condition/src",
+ "prefix": "app",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/rxjs/14-race-condition",
+ "index": "apps/rxjs/14-race-condition/src/index.html",
+ "main": "apps/rxjs/14-race-condition/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/rxjs/14-race-condition/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/rxjs/14-race-condition/src/favicon.ico",
+ "apps/rxjs/14-race-condition/src/assets"
+ ],
+ "styles": ["apps/rxjs/14-race-condition/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "rxjs-race-condition:build:production"
+ },
+ "development": {
+ "buildTarget": "rxjs-race-condition:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "buildTarget": "rxjs-race-condition:build"
+ }
+ },
+ "test": {
+ "options": {
+ "passWithNoTests": true
+ },
+ "configurations": {
+ "ci": {
+ "ci": true,
+ "coverage": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/rxjs/race-condition/src/app/app.component.cy.ts b/apps/rxjs/14-race-condition/src/app/app.component.cy.ts
similarity index 100%
rename from apps/rxjs/race-condition/src/app/app.component.cy.ts
rename to apps/rxjs/14-race-condition/src/app/app.component.cy.ts
diff --git a/apps/rxjs/race-condition/src/app/app.component.ts b/apps/rxjs/14-race-condition/src/app/app.component.ts
similarity index 100%
rename from apps/rxjs/race-condition/src/app/app.component.ts
rename to apps/rxjs/14-race-condition/src/app/app.component.ts
diff --git a/apps/rxjs/race-condition/src/app/app.config.ts b/apps/rxjs/14-race-condition/src/app/app.config.ts
similarity index 100%
rename from apps/rxjs/race-condition/src/app/app.config.ts
rename to apps/rxjs/14-race-condition/src/app/app.config.ts
diff --git a/apps/rxjs/race-condition/src/app/topic-dialog.component.ts b/apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts
similarity index 97%
rename from apps/rxjs/race-condition/src/app/topic-dialog.component.ts
rename to apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts
index d63ed4ada..e01a69a01 100644
--- a/apps/rxjs/race-condition/src/app/topic-dialog.component.ts
+++ b/apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts
@@ -18,7 +18,6 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
`,
imports: [MatDialogModule, MatButtonModule, NgFor],
- standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TopicModalComponent {
diff --git a/apps/rxjs/race-condition/src/app/topic.service.ts b/apps/rxjs/14-race-condition/src/app/topic.service.ts
similarity index 100%
rename from apps/rxjs/race-condition/src/app/topic.service.ts
rename to apps/rxjs/14-race-condition/src/app/topic.service.ts
diff --git a/apps/rxjs/pipe-bug/src/assets/.gitkeep b/apps/rxjs/14-race-condition/src/assets/.gitkeep
similarity index 100%
rename from apps/rxjs/pipe-bug/src/assets/.gitkeep
rename to apps/rxjs/14-race-condition/src/assets/.gitkeep
diff --git a/apps/testing/create-harness/src/favicon.ico b/apps/rxjs/14-race-condition/src/favicon.ico
similarity index 100%
rename from apps/testing/create-harness/src/favicon.ico
rename to apps/rxjs/14-race-condition/src/favicon.ico
diff --git a/apps/rxjs/14-race-condition/src/index.html b/apps/rxjs/14-race-condition/src/index.html
new file mode 100644
index 000000000..629547b5b
--- /dev/null
+++ b/apps/rxjs/14-race-condition/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+