diff --git a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts index 30c8f88ec..125eac4a0 100644 --- a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts +++ b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts @@ -1,13 +1,57 @@ import { Component, OnInit } from '@angular/core'; +import { FakeHttpService, randomCity, randTeacher } from '../../data-access/fake-http.service'; +import { CardComponent } from '../../ui/card/card.component'; +import { City } from '../../model/city.model'; +import { CityStore } from '../../data-access/city.store'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-city-card', - template: 'TODO City', + template: ` + + + + + + + + + `, + styles: [ + ` + ::ng-deep .bg-light-orange { + background-color: orange; + } + `, + ], standalone: true, - imports: [], + imports: [CardComponent, ListItemComponent], }) export class CityCardComponent implements OnInit { - constructor() {} + cities: City[] = []; + + constructor( + private http: FakeHttpService, + private store: CityStore, + ) {} + + ngOnInit(): void { + this.http.fetchCities$.subscribe((t) => this.store.addAll(t)); + + this.store.cities$.subscribe((t) => (this.cities = t)); + } + onAddItem(){ + this.store.addOne(randomCity()); + } - ngOnInit(): void {} + onDeleteItem(id: number){ + this.store.deleteOne(id); + } } diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts index 441cda189..28fa58ad1 100644 --- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts +++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts @@ -1,17 +1,28 @@ import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { FakeHttpService, randStudent } 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'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-student-card', template: ` + (addItem)="onAddItem()" + customClass="bg-light-green"> + + + + + + + `, standalone: true, styles: [ @@ -21,11 +32,10 @@ import { CardComponent } from '../../ui/card/card.component'; } `, ], - imports: [CardComponent], + imports: [CardComponent, ListItemComponent], }) export class StudentCardComponent implements OnInit { students: Student[] = []; - cardType = CardType.STUDENT; constructor( private http: FakeHttpService, @@ -37,4 +47,12 @@ export class StudentCardComponent implements OnInit { this.store.students$.subscribe((s) => (this.students = s)); } + + onAddItem(){ + this.store.addOne(randStudent()); + } + + onDeleteItem(id: number){ + this.store.deleteOne(id); + } } diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts index 995cb7c2f..eaabd6a60 100644 --- a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts +++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts @@ -1,17 +1,29 @@ import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { FakeHttpService, randTeacher } 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'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-teacher-card', template: ` + (addItem)="onAddItem()" + customClass="bg-light-red"> + + + + + + + + `, styles: [ ` @@ -21,11 +33,10 @@ import { CardComponent } from '../../ui/card/card.component'; `, ], standalone: true, - imports: [CardComponent], + imports: [CardComponent, ListItemComponent], }) export class TeacherCardComponent implements OnInit { teachers: Teacher[] = []; - cardType = CardType.TEACHER; constructor( private http: FakeHttpService, @@ -37,4 +48,11 @@ export class TeacherCardComponent implements OnInit { this.store.teachers$.subscribe((t) => (this.teachers = t)); } + onAddItem(){ + this.store.addOne(randTeacher()); + } + + onDeleteItem(id: number){ + this.store.deleteOne(id); + } } diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts index f06c9ae00..8543a3438 100644 --- a/apps/angular/1-projection/src/app/ui/card/card.component.ts +++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts @@ -1,10 +1,5 @@ -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'; +import { CommonModule, NgFor, NgIf } from '@angular/common'; +import { Component, Input, Output, EventEmitter, ViewChild, TemplateRef, ContentChild } from '@angular/core'; @Component({ selector: 'app-card', @@ -12,22 +7,16 @@ import { ListItemComponent } from '../list-item/list-item.component';
- - -
- -
+ + + + + +
@@ -18,18 +15,10 @@ import { CardType } from '../../model/card.model'; export class ListItemComponent { @Input() id!: number; @Input() name!: string; - @Input() type!: CardType; + @Output() deleteItem = new EventEmitter() - 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); - } + constructor() {} + delete() { + this.deleteItem.emit() } } diff --git a/apps/angular/21-anchor-navigation/src/app/app.component.ts b/apps/angular/21-anchor-navigation/src/app/app.component.ts index 3fb7c5df0..77715aaf3 100644 --- a/apps/angular/21-anchor-navigation/src/app/app.component.ts +++ b/apps/angular/21-anchor-navigation/src/app/app.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; +import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'; @Component({ standalone: true, - imports: [RouterOutlet], + imports: [RouterOutlet,RouterLink, RouterLinkActive], selector: 'app-root', template: ` diff --git a/apps/angular/21-anchor-navigation/src/app/app.config.ts b/apps/angular/21-anchor-navigation/src/app/app.config.ts index 66ab7f73f..28a3a8f69 100644 --- a/apps/angular/21-anchor-navigation/src/app/app.config.ts +++ b/apps/angular/21-anchor-navigation/src/app/app.config.ts @@ -1,6 +1,13 @@ import { ApplicationConfig } from '@angular/core'; -import { provideRouter } from '@angular/router'; +import { provideRouter,withInMemoryScrolling, InMemoryScrollingOptions } from '@angular/router'; import { appRoutes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideRouter(appRoutes)], + providers: [ + provideRouter( + appRoutes, + withInMemoryScrolling({ + anchorScrolling: 'enabled', + scrollPositionRestoration: 'enabled', + }) + )], }; diff --git a/apps/angular/21-anchor-navigation/src/app/home.component.ts b/apps/angular/21-anchor-navigation/src/app/home.component.ts index 0f24ff6e7..4306de2bb 100644 --- a/apps/angular/21-anchor-navigation/src/app/home.component.ts +++ b/apps/angular/21-anchor-navigation/src/app/home.component.ts @@ -9,11 +9,11 @@ import { NavButtonComponent } from './nav-button.component'; Foo Page
Empty - Scroll Bottom + Scroll Bottom
I want to scroll each - Scroll Top + Scroll Top
`, }) diff --git a/apps/angular/21-anchor-navigation/src/app/nav-button.component.ts b/apps/angular/21-anchor-navigation/src/app/nav-button.component.ts index 9e3b6d42f..a6000f70a 100644 --- a/apps/angular/21-anchor-navigation/src/app/nav-button.component.ts +++ b/apps/angular/21-anchor-navigation/src/app/nav-button.component.ts @@ -1,10 +1,12 @@ /* eslint-disable @angular-eslint/component-selector */ import { Component, Input } from '@angular/core'; +import { RouterLink, RouterLinkWithHref } from '@angular/router'; @Component({ selector: 'nav-button', standalone: true, + imports: [RouterLink], template: ` - + `, @@ -14,4 +16,5 @@ import { Component, Input } from '@angular/core'; }) export class NavButtonComponent { @Input() href = ''; + @Input() anchor?: string = undefined; } diff --git a/apps/angular/21-anchor-navigation/src/index.html b/apps/angular/21-anchor-navigation/src/index.html index 06a706a0a..9d5bdcaf8 100644 --- a/apps/angular/21-anchor-navigation/src/index.html +++ b/apps/angular/21-anchor-navigation/src/index.html @@ -1,5 +1,5 @@ - + angular-anchor-navigation diff --git a/apps/angular/22-router-input/src/app/app.config.ts b/apps/angular/22-router-input/src/app/app.config.ts index ed404941f..a7c1007b9 100644 --- a/apps/angular/22-router-input/src/app/app.config.ts +++ b/apps/angular/22-router-input/src/app/app.config.ts @@ -1,7 +1,7 @@ import { ApplicationConfig } from '@angular/core'; -import { provideRouter } from '@angular/router'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; import { appRoutes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideRouter(appRoutes)], + providers: [provideRouter(appRoutes, withComponentInputBinding())], }; diff --git a/apps/angular/22-router-input/src/app/app.routes.ts b/apps/angular/22-router-input/src/app/app.routes.ts index f5d3487c4..592ab0d11 100644 --- a/apps/angular/22-router-input/src/app/app.routes.ts +++ b/apps/angular/22-router-input/src/app/app.routes.ts @@ -6,7 +6,7 @@ export const appRoutes: Route[] = [ loadComponent: () => import('./home.component'), }, { - path: 'subscription/:testId', + path: 'subscription/:id', loadComponent: () => import('./test.component'), data: { permission: 'admin', diff --git a/apps/angular/22-router-input/src/app/test.component.ts b/apps/angular/22-router-input/src/app/test.component.ts index 88c1465f3..be62aea96 100644 --- a/apps/angular/22-router-input/src/app/test.component.ts +++ b/apps/angular/22-router-input/src/app/test.component.ts @@ -1,22 +1,20 @@ import { AsyncPipe } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, inject, Input } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { map } from 'rxjs'; @Component({ selector: 'app-subscription', standalone: true, imports: [AsyncPipe], template: ` -
TestId: {{ testId$ | async }}
-
Permission: {{ permission$ | async }}
-
User: {{ user$ | async }}
+
TestId: {{ id }}
+
Permission: {{ permission }}
+
User: {{ user }}
`, }) 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'])); + @Input() id! : string ; + @Input() user! : string ; + @Input() permission! : string ; } diff --git a/apps/angular/3-directive-enhancement/src/app/app.component.ts b/apps/angular/3-directive-enhancement/src/app/app.component.ts index cd1d5f23c..b36b7ce73 100644 --- a/apps/angular/3-directive-enhancement/src/app/app.component.ts +++ b/apps/angular/3-directive-enhancement/src/app/app.component.ts @@ -1,5 +1,6 @@ import { NgFor, NgIf } from '@angular/common'; import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { NgForEmptyDirective } from './ngFor.directive'; interface Person { name: string; @@ -7,19 +8,23 @@ interface Person { @Component({ standalone: true, - imports: [NgFor, NgIf], + imports: [NgFor, NgIf, NgForEmptyDirective], selector: 'app-root', template: ` - -
+
{{ person.name }}
- The list is empty !! `, styles: [], changeDetection: ChangeDetectionStrategy.OnPush, }) export class AppComponent { - persons: Person[] = []; + persons: Person[] = [ + // { name: '123'}, + // { name: '456'}, + // { name: '789'}, + // { name: 'abc'}, + // { name: 'hiep'}, + ]; } diff --git a/apps/angular/3-directive-enhancement/src/app/ngFor.directive.ts b/apps/angular/3-directive-enhancement/src/app/ngFor.directive.ts new file mode 100644 index 000000000..8aa646e23 --- /dev/null +++ b/apps/angular/3-directive-enhancement/src/app/ngFor.directive.ts @@ -0,0 +1,25 @@ +import { Directive, DoCheck, EmbeddedViewRef, inject, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +@Directive({ + selector: '[ngFor]', + standalone: true, +}) +export class NgForEmptyDirective implements DoCheck { + private vcr = inject(ViewContainerRef); + + // same input as ngFor, we just need it to check if list is empty + @Input() ngForOf?: T[] = undefined; + + // reference of the empty template to display + @Input() ngForEmpty!: TemplateRef; + + private ref?: EmbeddedViewRef; + + ngDoCheck(): void { + this.ref?.destroy(); + console.log(this.ngForOf, this.ngForEmpty) + + if (!this.ngForOf || this.ngForOf.length === 0) { + this.ref = this.vcr.createEmbeddedView(this.ngForEmpty); + } + } +} diff --git a/apps/angular/6-structural-directive/src/app/dashboard/Guard/auth.guard.ts b/apps/angular/6-structural-directive/src/app/dashboard/Guard/auth.guard.ts new file mode 100644 index 000000000..5b81686ca --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/dashboard/Guard/auth.guard.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { CanMatch, Route, Router, UrlSegment } from '@angular/router'; +import { map } from 'rxjs'; +import { UserStore } from '../../user.store'; + +@Injectable({ providedIn: 'root' }) +export class AuthGuard implements CanMatch { + constructor( + public router: Router, + public store: UserStore, + ) {} + + public canMatch(route: Route, segments: UrlSegment[]) { + console.log('route ', route.data?.['roles'], segments); + + return this.store.hasRole(route.data?.['roles']).pipe( + map((permission: boolean) => { + return permission; + }), + ); + + + } +} diff --git a/apps/angular/6-structural-directive/src/app/dashboard/client.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/client.component.ts new file mode 100644 index 000000000..ac735cc58 --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/dashboard/client.component.ts @@ -0,0 +1,15 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ButtonComponent } from '../button.component'; + +@Component({ + selector: 'app-dashboard', + standalone: true, + imports: [RouterLink, ButtonComponent], + template: ` +

dashboard for CLIENT works!

+ + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ClientDashboardComponent {} diff --git a/apps/angular/6-structural-directive/src/app/dashboard/reader.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/reader.component.ts new file mode 100644 index 000000000..69dadbfc6 --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/dashboard/reader.component.ts @@ -0,0 +1,15 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ButtonComponent } from '../button.component'; + +@Component({ + selector: 'app-dashboard', + standalone: true, + imports: [RouterLink, ButtonComponent], + template: ` +

dashboard for READER works!

+ + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ReaderDashboardComponent {} diff --git a/apps/angular/6-structural-directive/src/app/dashboard/writer.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/writer.component.ts new file mode 100644 index 000000000..869e17dde --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/dashboard/writer.component.ts @@ -0,0 +1,15 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ButtonComponent } from '../button.component'; + +@Component({ + selector: 'app-dashboard', + standalone: true, + imports: [RouterLink, ButtonComponent], + template: ` +

dashboard for WRITER works!

+ + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class WriterDashboardComponent {} diff --git a/apps/angular/6-structural-directive/src/app/information.component.ts b/apps/angular/6-structural-directive/src/app/information.component.ts index e4adeb1b9..41bb6c151 100644 --- a/apps/angular/6-structural-directive/src/app/information.component.ts +++ b/apps/angular/6-structural-directive/src/app/information.component.ts @@ -1,19 +1,20 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { UserStore } from './user.store'; +import { HasRoleDirective } from './role.directive'; @Component({ selector: 'app-information', standalone: true, - imports: [CommonModule], + imports: [CommonModule, HasRoleDirective], template: `

Information Panel

-
visible only for super admin
-
visible if manager
-
visible if manager and/or reader
-
visible if manager and/or writer
-
visible if client
+
visible only for super admin
+
visible if manager
+
visible if manager and/or reader
+
visible if manager and/or writer
+
visible if client
visible for everyone
`, changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/apps/angular/6-structural-directive/src/app/login.component.ts b/apps/angular/6-structural-directive/src/app/login.component.ts index cd36d9603..5f4a7ad79 100644 --- a/apps/angular/6-structural-directive/src/app/login.component.ts +++ b/apps/angular/6-structural-directive/src/app/login.component.ts @@ -12,6 +12,7 @@ import { writer, } from './user.model'; import { UserStore } from './user.store'; +import { HasRoleDirective } from './role.directive'; @Component({ standalone: true, diff --git a/apps/angular/6-structural-directive/src/app/role.directive.ts b/apps/angular/6-structural-directive/src/app/role.directive.ts new file mode 100644 index 000000000..4718b94ef --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/role.directive.ts @@ -0,0 +1,36 @@ +/* eslint-disable @angular-eslint/directive-selector */ +import { Directive, inject, Input, OnInit, TemplateRef, ViewContainerRef } from "@angular/core"; +import { UserStore } from "./user.store"; +import { Role } from "./user.model"; +// import { takeUntil } from "rxjs/operators"; + +@Directive({ + selector: '[hasRole]', + standalone: true, +}) +class HasRoleDirective implements OnInit { + + @Input('hasRole') role: Role | Role[] | undefined = undefined; + + private templateRef = inject(TemplateRef); + private viewContainer = inject(ViewContainerRef); + private store = inject(UserStore); + + ngOnInit(): void { + this.store.hasRole(this.role).subscribe((hasPermission: boolean)=>{ + console.log('directive: ', hasPermission) + hasPermission? this.addTemplate() : this.clearTemplate() + }) + + } + private addTemplate() { + this.viewContainer.clear(); + this.viewContainer.createEmbeddedView(this.templateRef); + } + + private clearTemplate() { + this.viewContainer.clear(); + } +} + +export {HasRoleDirective }; diff --git a/apps/angular/6-structural-directive/src/app/routes.ts b/apps/angular/6-structural-directive/src/app/routes.ts index 4db203f3b..caaf0ac57 100644 --- a/apps/angular/6-structural-directive/src/app/routes.ts +++ b/apps/angular/6-structural-directive/src/app/routes.ts @@ -1,4 +1,7 @@ -export const APP_ROUTES = [ +import { Route } from '@angular/router'; +import { AuthGuard } from './dashboard/Guard/auth.guard'; + +export const APP_ROUTES: Route[] = [ { path: '', loadComponent: () => @@ -6,9 +9,58 @@ export const APP_ROUTES = [ }, { path: 'enter', + canMatch: [AuthGuard], + data: { + roles: ['ADMIN'], + }, loadComponent: () => import('./dashboard/admin.component').then( (m) => m.AdminDashboardComponent, ), }, + { + path: 'enter', + canMatch: [AuthGuard], + data: { + roles: ['MANAGER'], + }, + loadComponent: () => + import('./dashboard/manager.component').then( + (m) => m.ManagerDashboardComponent, + ), + }, + { + path: 'enter', + canMatch: [AuthGuard], + data: { + roles: ['READER'], + }, + loadComponent: () => + import('./dashboard/reader.component').then( + (m) => m.ReaderDashboardComponent, + ), + }, + { + path: 'enter', + canMatch: [AuthGuard], + data: { + roles: ['WRITER'], + }, + loadComponent: () => + import('./dashboard/writer.component').then( + (m) => m.WriterDashboardComponent, + ), + }, + { + path: 'enter', + canMatch: [AuthGuard], + data: { + roles: ['CLIENT'], + }, + loadComponent: () => + import('./dashboard/client.component').then( + (m) => m.ClientDashboardComponent, + ), + }, + { path: '**', redirectTo: '' }, ]; diff --git a/apps/angular/6-structural-directive/src/app/user.model.ts b/apps/angular/6-structural-directive/src/app/user.model.ts index 353a5e214..e68e9860c 100644 --- a/apps/angular/6-structural-directive/src/app/user.model.ts +++ b/apps/angular/6-structural-directive/src/app/user.model.ts @@ -1,4 +1,4 @@ -export type Role = 'MANAGER' | 'WRITER' | 'READER' | 'CLIENT'; +export type Role = 'MANAGER' | 'WRITER' | 'READER' | 'CLIENT' | 'ADMIN'; export interface User { name: string; @@ -9,7 +9,7 @@ export interface User { export const admin: User = { name: 'admin', isAdmin: true, - roles: [], + roles: ['ADMIN'], }; export const manager: User = { diff --git a/apps/angular/6-structural-directive/src/app/user.store.ts b/apps/angular/6-structural-directive/src/app/user.store.ts index 1b00288b7..b629130c2 100644 --- a/apps/angular/6-structural-directive/src/app/user.store.ts +++ b/apps/angular/6-structural-directive/src/app/user.store.ts @@ -1,15 +1,38 @@ import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { User } from './user.model'; +import { BehaviorSubject, map } from 'rxjs'; +import { User ,Role, everyone} from './user.model'; @Injectable({ providedIn: 'root', }) export class UserStore { - private user = new BehaviorSubject(undefined); + private user = new BehaviorSubject(undefined); user$ = this.user.asObservable(); add(user: User) { this.user.next(user); } + + hasRole(role: string | string[] | undefined) { + console.log(this.user) + return this.user.pipe( + map((user) => { + if (role?.length === 0) return false; + const userRoles = user?.roles; + if (!userRoles || userRoles?.length === 0) { + return false; + } + if(userRoles.includes('ADMIN')){ + return true; + } + if (Array.isArray(role)) { + return userRoles.some((userRole) => role.includes(userRole)); + } + if (typeof role === 'string') { + return userRoles.some((userRole) => role === userRole); + } + return false; + }) + ); + } } diff --git a/apps/angular/8-pure-pipe/src/app/app.component.ts b/apps/angular/8-pure-pipe/src/app/app.component.ts index 3c19fa169..fdc3d2eb0 100644 --- a/apps/angular/8-pure-pipe/src/app/app.component.ts +++ b/apps/angular/8-pure-pipe/src/app/app.component.ts @@ -1,21 +1,22 @@ import { NgFor } from '@angular/common'; import { Component } from '@angular/core'; +import { CustomPipe } from './custom.pipe'; @Component({ standalone: true, - imports: [NgFor], + imports: [NgFor, CustomPipe], selector: 'app-root', template: `
- {{ heavyComputation(person, index) }} + {{ person | custom: index }}
+ `, }) export class AppComponent { persons = ['toto', 'jack']; - - heavyComputation(name: string, index: number) { - // very heavy computation - return `${name} - ${index}`; + onclick(){ + this.persons[0]="tototo" + this.persons[2]="aaaaaa" } } diff --git a/apps/angular/8-pure-pipe/src/app/custom.pipe.ts b/apps/angular/8-pure-pipe/src/app/custom.pipe.ts new file mode 100644 index 000000000..77e0d58f7 --- /dev/null +++ b/apps/angular/8-pure-pipe/src/app/custom.pipe.ts @@ -0,0 +1,15 @@ +// custom.pipe.ts +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'custom', + standalone: true +}) +export class CustomPipe implements PipeTransform { + + transform(value: string, index: number): string { + if (!value) return value; + return `${value} - ${index}`; + } + +} diff --git a/apps/forms/41-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 index 9334b5bc9..b0dc85729 100644 --- a/apps/forms/41-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 @@ -13,7 +13,7 @@ [formControl]="feedbackForm.controls.email" placeholder="Email" type="email" /> - +