diff --git a/.prettierignore b/.prettierignore
index d0b804d..61a17b5 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -2,3 +2,5 @@
/dist
/coverage
+
+.angular
diff --git a/README.md b/README.md
index 6d2e42e..a2f98b8 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ This goal of this project is to help you get better at Angular and NgRx by resol
+
diff --git a/apps/router-input/.eslintrc.json b/apps/router-input/.eslintrc.json
new file mode 100644
index 0000000..b428c22
--- /dev/null
+++ b/apps/router-input/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ },
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ]
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/router-input/README.md b/apps/router-input/README.md
new file mode 100644
index 0000000..d5404f4
--- /dev/null
+++ b/apps/router-input/README.md
@@ -0,0 +1,26 @@
+
Router Input
+
+> Author: Thomas Laforge
+
+### Statement
+
+In this small application, you can pass data though routing to `TestComponent`. v16 of Angular introduiced `RouterInput`. The goal of this exercice is to refactor the code to use the new `RouterInput` strategy.
+
+### Submitting your work
+
+1. Fork the project
+2. clone it
+3. npm install
+4. `npx nx serve router-input`
+5. _...work on it_
+6. Commit your work
+7. Submit a PR with a title beginning with **Answer:22** that I will review and other dev can review.
+
+
+
+
+
+
+
+
+_You can ask any question on_
diff --git a/apps/router-input/project.json b/apps/router-input/project.json
new file mode 100644
index 0000000..a5f0a8c
--- /dev/null
+++ b/apps/router-input/project.json
@@ -0,0 +1,81 @@
+{
+ "name": "router-input",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "prefix": "app",
+ "sourceRoot": "apps/router-input/src",
+ "tags": [],
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/router-input",
+ "index": "apps/router-input/src/index.html",
+ "main": "apps/router-input/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/router-input/tsconfig.app.json",
+ "assets": [
+ "apps/router-input/src/favicon.ico",
+ "apps/router-input/src/assets"
+ ],
+ "styles": ["apps/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": {
+ "browserTarget": "router-input:build:production"
+ },
+ "development": {
+ "browserTarget": "router-input:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "router-input:build"
+ }
+ },
+ "lint": {
+ "executor": "@nx/linter:eslint",
+ "outputs": ["{options.outputFile}"],
+ "options": {
+ "lintFilePatterns": [
+ "apps/router-input/**/*.ts",
+ "apps/router-input/**/*.html"
+ ]
+ }
+ }
+ }
+}
diff --git a/apps/router-input/src/app/app.component.ts b/apps/router-input/src/app/app.component.ts
new file mode 100644
index 0000000..1883309
--- /dev/null
+++ b/apps/router-input/src/app/app.component.ts
@@ -0,0 +1,24 @@
+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/router-input/src/app/app.config.ts b/apps/router-input/src/app/app.config.ts
new file mode 100644
index 0000000..ed40494
--- /dev/null
+++ b/apps/router-input/src/app/app.config.ts
@@ -0,0 +1,7 @@
+import { ApplicationConfig } from '@angular/core';
+import { provideRouter } from '@angular/router';
+import { appRoutes } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideRouter(appRoutes)],
+};
diff --git a/apps/router-input/src/app/app.routes.ts b/apps/router-input/src/app/app.routes.ts
new file mode 100644
index 0000000..215c016
--- /dev/null
+++ b/apps/router-input/src/app/app.routes.ts
@@ -0,0 +1,15 @@
+import { Route } from '@angular/router';
+
+export const appRoutes: Route[] = [
+ {
+ path: '',
+ loadComponent: () => import('./home.component'),
+ },
+ {
+ path: 'test/:testId',
+ loadComponent: () => import('./test.component'),
+ data: {
+ permission: 'admin',
+ },
+ },
+];
diff --git a/apps/router-input/src/app/home.component.ts b/apps/router-input/src/app/home.component.ts
new file mode 100644
index 0000000..be6a891
--- /dev/null
+++ b/apps/router-input/src/app/home.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+@Component({
+ selector: 'app-home',
+ standalone: true,
+ imports: [],
+ template: `Home
`,
+})
+export default class HomeComponent {}
diff --git a/apps/router-input/src/app/test.component.ts b/apps/router-input/src/app/test.component.ts
new file mode 100644
index 0000000..56ac3f7
--- /dev/null
+++ b/apps/router-input/src/app/test.component.ts
@@ -0,0 +1,21 @@
+import { AsyncPipe } from '@angular/common';
+import { Component, inject } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { map } from 'rxjs';
+@Component({
+ selector: 'app-test',
+ standalone: true,
+ imports: [AsyncPipe],
+ template: `
+ TestId: {{ testId$ | async }}
+ Permission: {{ permission$ | async }}
+ User: {{ user$ | async }}
+ `,
+})
+export default class TestComponent {
+ private activatedRoute = inject(ActivatedRoute);
+
+ testId$ = this.activatedRoute.params.pipe(map((p) => p['testId']));
+ permission$ = this.activatedRoute.data.pipe(map((d) => d['permission']));
+ user$ = this.activatedRoute.queryParams.pipe(map((q) => q['user']));
+}
diff --git a/apps/router-input/src/assets/.gitkeep b/apps/router-input/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/apps/router-input/src/favicon.ico b/apps/router-input/src/favicon.ico
new file mode 100644
index 0000000..317ebcb
Binary files /dev/null and b/apps/router-input/src/favicon.ico differ
diff --git a/apps/router-input/src/index.html b/apps/router-input/src/index.html
new file mode 100644
index 0000000..43f4b79
--- /dev/null
+++ b/apps/router-input/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ router-input
+
+
+
+
+
+
+
+
diff --git a/apps/router-input/src/main.ts b/apps/router-input/src/main.ts
new file mode 100644
index 0000000..514c89a
--- /dev/null
+++ b/apps/router-input/src/main.ts
@@ -0,0 +1,7 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { appConfig } from './app/app.config';
+import { AppComponent } from './app/app.component';
+
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
+ console.error(err)
+);
diff --git a/apps/router-input/src/styles.scss b/apps/router-input/src/styles.scss
new file mode 100644
index 0000000..90d4ee0
--- /dev/null
+++ b/apps/router-input/src/styles.scss
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/router-input/tsconfig.app.json b/apps/router-input/tsconfig.app.json
new file mode 100644
index 0000000..fff4a41
--- /dev/null
+++ b/apps/router-input/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/router-input/tsconfig.editor.json b/apps/router-input/tsconfig.editor.json
new file mode 100644
index 0000000..4ee6393
--- /dev/null
+++ b/apps/router-input/tsconfig.editor.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*.ts"],
+ "compilerOptions": {
+ "types": []
+ }
+}
diff --git a/apps/router-input/tsconfig.json b/apps/router-input/tsconfig.json
new file mode 100644
index 0000000..0731542
--- /dev/null
+++ b/apps/router-input/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "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
+ }
+}