-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Challenge 56 multi step reactive form and signals (#1030)
feat: challenge 55 form and signal
- Loading branch information
1 parent
45353aa
commit ddb5036
Showing
26 changed files
with
505 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": {} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# forms and signal | ||
|
||
> author: thomas-laforge | ||
### Run Application | ||
|
||
```bash | ||
npx nx serve signal-forms-and-signal | ||
``` | ||
|
||
### Documentation and Instruction | ||
|
||
Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/56-forms-and-signal/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{ | ||
"name": "signal-forms-and-signal", | ||
"$schema": "../../../node_modules/nx/schemas/project-schema.json", | ||
"projectType": "application", | ||
"prefix": "app", | ||
"sourceRoot": "apps/signal/56-forms-and-signal/src", | ||
"tags": [], | ||
"targets": { | ||
"build": { | ||
"executor": "@angular-devkit/build-angular:application", | ||
"outputs": ["{options.outputPath}"], | ||
"options": { | ||
"outputPath": "dist/apps/signal/56-forms-and-signal", | ||
"index": "apps/signal/56-forms-and-signal/src/index.html", | ||
"browser": "apps/signal/56-forms-and-signal/src/main.ts", | ||
"polyfills": ["zone.js"], | ||
"tsConfig": "apps/signal/56-forms-and-signal/tsconfig.app.json", | ||
"inlineStyleLanguage": "scss", | ||
"assets": [ | ||
{ | ||
"glob": "**/*", | ||
"input": "apps/signal/56-forms-and-signal/public" | ||
} | ||
], | ||
"styles": ["apps/signal/56-forms-and-signal/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": "signal-forms-and-signal:build:production" | ||
}, | ||
"development": { | ||
"buildTarget": "signal-forms-and-signal:build:development" | ||
} | ||
}, | ||
"defaultConfiguration": "development" | ||
}, | ||
"extract-i18n": { | ||
"executor": "@angular-devkit/build-angular:extract-i18n", | ||
"options": { | ||
"buildTarget": "signal-forms-and-signal:build" | ||
} | ||
}, | ||
"lint": { | ||
"executor": "@nx/eslint:lint" | ||
} | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Component } from '@angular/core'; | ||
import { RouterOutlet } from '@angular/router'; | ||
|
||
@Component({ | ||
standalone: true, | ||
imports: [RouterOutlet], | ||
selector: 'app-root', | ||
template: ` | ||
<h1 class="text-3xl">Shop</h1> | ||
<div class="w-[500px] "> | ||
<router-outlet /> | ||
</div> | ||
`, | ||
host: { | ||
class: 'w-full flex justify-center flex-col items-center p-4 gap-10', | ||
}, | ||
}) | ||
export class AppComponent {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; | ||
import { provideRouter, withComponentInputBinding } from '@angular/router'; | ||
import { routes } from './app.routes'; | ||
|
||
export const appConfig: ApplicationConfig = { | ||
providers: [ | ||
provideZoneChangeDetection({ eventCoalescing: true }), | ||
provideRouter(routes, withComponentInputBinding()), | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Routes } from '@angular/router'; | ||
|
||
export const routes: Routes = [ | ||
{ | ||
path: '', | ||
redirectTo: 'dashboard', | ||
pathMatch: 'full', | ||
}, | ||
{ | ||
path: 'dashboard', | ||
loadComponent: () => import('./dashboard.component'), | ||
}, | ||
{ | ||
path: 'order', | ||
loadComponent: () => import('./order.component'), | ||
}, | ||
{ | ||
path: 'checkout', | ||
loadComponent: () => import('./checkout.component'), | ||
}, | ||
{ | ||
path: 'payment', | ||
loadComponent: () => import('./payment.component'), | ||
}, | ||
{ | ||
path: '**', | ||
redirectTo: 'dashboard', | ||
}, | ||
]; |
56 changes: 56 additions & 0 deletions
56
apps/signal/56-forms-and-signal/src/app/checkout.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
Component, | ||
computed, | ||
input, | ||
} from '@angular/core'; | ||
import { RouterLink } from '@angular/router'; | ||
import { products } from './products'; | ||
|
||
@Component({ | ||
selector: 'app-dashboard', | ||
standalone: true, | ||
imports: [RouterLink], | ||
template: ` | ||
<h2 class="mb-1 w-full bg-gray-400 p-2 text-white">Checkout</h2> | ||
<button | ||
routerLink="/order" | ||
queryParamsHandling="merge" | ||
class="mb-5 text-blue-400"> | ||
< back to order | ||
</button> | ||
<section class="mb-5 flex justify-between"> | ||
<div class="font-bold">Your order:</div> | ||
<div> | ||
{{ quantity() }} x {{ product()?.name }}: {{ product()?.price }}€ | ||
</div> | ||
</section> | ||
<div>Billing Information</div> | ||
<div>...</div> | ||
<div>...</div> | ||
<div>...</div> | ||
<div>...</div> | ||
<div>...</div> | ||
<button | ||
routerLink="/payment" | ||
[queryParams]="{ quantity: quantity() }" | ||
queryParamsHandling="merge" | ||
class="w-full rounded-full border bg-blue-500 p-2 text-white"> | ||
Pay | ||
</button> | ||
`, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export default class DashboardComponent { | ||
quantity = input(1); | ||
productId = input('1'); | ||
|
||
product = computed(() => | ||
products.find((product) => product.id === this.productId()), | ||
); | ||
totalWithVAT = computed( | ||
() => this.quantity() * (this.product()?.price ?? 0) * 1.21, | ||
); | ||
} |
31 changes: 31 additions & 0 deletions
31
apps/signal/56-forms-and-signal/src/app/dashboard.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { ChangeDetectionStrategy, Component } from '@angular/core'; | ||
import { RouterLink } from '@angular/router'; | ||
import { products } from './products'; | ||
|
||
@Component({ | ||
selector: 'app-dashboard', | ||
standalone: true, | ||
imports: [RouterLink], | ||
template: ` | ||
<h2 class="mb-5 w-full bg-gray-400 p-2 text-white">List of Products</h2> | ||
<ul class="w-full *:border-b *:border-l *:border-r *:p-4"> | ||
@for (product of products; track product.id) { | ||
<li [class.border-t]="$first"> | ||
<div class="flex w-full justify-between"> | ||
{{ product.name }} ({{ product.price }}€) | ||
<button | ||
class="w-20 rounded-full border bg-blue-500 p-2 text-white" | ||
routerLink="/order" | ||
[queryParams]="{ productId: product.id }"> | ||
Buy | ||
</button> | ||
</div> | ||
</li> | ||
} | ||
</ul> | ||
`, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export default class DashboardComponent { | ||
products = products; | ||
} |
72 changes: 72 additions & 0 deletions
72
apps/signal/56-forms-and-signal/src/app/order.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
Component, | ||
computed, | ||
input, | ||
} from '@angular/core'; | ||
import { toSignal } from '@angular/core/rxjs-interop'; | ||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; | ||
import { RouterLink } from '@angular/router'; | ||
import { products } from './products'; | ||
|
||
@Component({ | ||
selector: 'app-order', | ||
standalone: true, | ||
imports: [RouterLink, ReactiveFormsModule], | ||
template: ` | ||
<h2 class="mb-5 w-full bg-gray-400 p-2 text-white">Order</h2> | ||
<section class="flex flex-col gap-5"> | ||
<form class="flex items-center justify-between gap-5" [formGroup]="form"> | ||
<label for="countries" class="mb-2 block text-nowrap text-gray-900"> | ||
Select a quantity | ||
</label> | ||
<select | ||
formControlName="quantity" | ||
id="countries" | ||
class="block w-32 rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500"> | ||
<option value="1">1</option> | ||
<option value="2">2</option> | ||
<option value="3">3</option> | ||
<option value="4">4</option> | ||
<option value="5">5</option> | ||
</select> | ||
</form> | ||
<div class="flex justify-between"> | ||
<div>SubTotal</div> | ||
<div>{{ totalWihoutVat() }} €</div> | ||
</div> | ||
<div class="flex justify-between"> | ||
<div>VAT (21%)</div> | ||
<div>{{ vat() }} €</div> | ||
</div> | ||
<div class="flex justify-between"> | ||
<div>Total</div> | ||
<div>{{ total() }} €</div> | ||
</div> | ||
<button | ||
routerLink="/checkout" | ||
[queryParams]="{ quantity: quantity() }" | ||
queryParamsHandling="merge" | ||
class="w-full rounded-full border bg-blue-500 p-2 text-white"> | ||
Checkout | ||
</button> | ||
</section> | ||
`, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export default class OrderComponent { | ||
form = new FormGroup({ | ||
quantity: new FormControl(1, { nonNullable: true }), | ||
}); | ||
|
||
productId = input('1'); | ||
price = computed( | ||
() => products.find((p) => p.id === this.productId())?.price ?? 0, | ||
); | ||
quantity = toSignal(this.form.controls.quantity.valueChanges, { | ||
initialValue: this.form.getRawValue().quantity, | ||
}); | ||
totalWihoutVat = computed(() => Number(this.price()) * this.quantity()); | ||
vat = computed(() => this.totalWihoutVat() * 0.21); | ||
total = computed(() => this.totalWihoutVat() + this.vat()); | ||
} |
19 changes: 19 additions & 0 deletions
19
apps/signal/56-forms-and-signal/src/app/payment.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { ChangeDetectionStrategy, Component } from '@angular/core'; | ||
import { RouterLink } from '@angular/router'; | ||
|
||
@Component({ | ||
selector: 'app-dashboard', | ||
standalone: true, | ||
imports: [RouterLink], | ||
template: ` | ||
<h2 class="mb-1 w-full bg-green-700 p-2 text-white">Payment Success</h2> | ||
<button | ||
routerLink="/dashboard" | ||
class="w-full rounded-full border bg-blue-500 p-2 text-white"> | ||
Back to Shop | ||
</button> | ||
`, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export default class DashboardComponent {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export const products = [ | ||
{ | ||
id: '1', | ||
name: 'Computer', | ||
price: 2000, | ||
}, | ||
{ | ||
id: '2', | ||
name: 'Mouse', | ||
price: 40, | ||
}, | ||
{ | ||
id: '3', | ||
name: 'Keyboard', | ||
price: 80, | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title>signal-forms-and-signal</title> | ||
<base href="/" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link rel="icon" type="image/x-icon" href="favicon.ico" /> | ||
</head> | ||
<body> | ||
<app-root></app-root> | ||
</body> | ||
</html> |
Oops, something went wrong.