From 1a2a32e312fc1b1633089e9ca8cca0601d8f5f0f Mon Sep 17 00:00:00 2001 From: lukasss88 Date: Sun, 30 Nov 2025 13:12:12 +0100 Subject: [PATCH 1/3] feat: solution --- .../src/app/app.component.ts | 14 +++---- .../src/app/person-list.component.ts | 32 ++------------- .../src/app/person.component.ts | 36 +++++++++++++++++ .../src/app/person.form.component.ts | 40 +++++++++++++++++++ .../src/app/person.service.ts | 20 ++++++++++ .../src/app/random.component.ts | 3 +- 6 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 apps/performance/34-default-vs-onpush/src/app/person.component.ts create mode 100644 apps/performance/34-default-vs-onpush/src/app/person.form.component.ts create mode 100644 apps/performance/34-default-vs-onpush/src/app/person.service.ts 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 index 88b0a6571..2e9ac1669 100644 --- a/apps/performance/34-default-vs-onpush/src/app/app.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/app.component.ts @@ -1,21 +1,17 @@ import { Component } from '@angular/core'; -import { randFirstName } from '@ngneat/falso'; -import { PersonListComponent } from './person-list.component'; +import { PersonComponent } from './person.component'; import { RandomComponent } from './random.component'; @Component({ - imports: [PersonListComponent, RandomComponent], + imports: [RandomComponent, PersonComponent], selector: 'app-root', template: `
- - + +
`, }) -export class AppComponent { - girlList = randFirstName({ gender: 'female', length: 10 }); - boyList = randFirstName({ gender: 'male', length: 10 }); -} +export class AppComponent {} 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 index e34a39e87..770b1e13f 100644 --- 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 @@ -1,7 +1,6 @@ -import { Component, input } from '@angular/core'; +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { CDFlashingDirective } from '@angular-challenges/shared/directives'; -import { TitleCasePipe } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { MatChipsModule } from '@angular/material/chips'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -17,24 +16,10 @@ import { MatListModule } from '@angular/material/list'; MatInputModule, MatChipsModule, CDFlashingDirective, - TitleCasePipe, ], template: ` -

- {{ title() | titlecase }} -

- - - - - - @if (names()?.length === 0) { + @if (names().length === 0) {
Empty list
} @for (name of names(); track name) { @@ -46,7 +31,7 @@ import { MatListModule } from '@angular/material/list'; } - @if (names()?.length !== 0) { + @if (names().length !== 0) { }
@@ -54,17 +39,8 @@ import { MatListModule } from '@angular/material/list'; host: { class: 'w-full flex flex-col items-center', }, + changeDetection: ChangeDetectionStrategy.OnPush, }) export class PersonListComponent { names = input([]); - title = input(''); - - label = ''; - - handleKey(event: KeyboardEvent) { - if (event.key === 'Enter') { - this.names()?.unshift(this.label); - this.label = ''; - } - } } diff --git a/apps/performance/34-default-vs-onpush/src/app/person.component.ts b/apps/performance/34-default-vs-onpush/src/app/person.component.ts new file mode 100644 index 000000000..31736ebf1 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/app/person.component.ts @@ -0,0 +1,36 @@ +import { TitleCasePipe } from '@angular/common'; +import { Component, inject, input, OnInit } from '@angular/core'; +import { PersonListComponent } from './person-list.component'; +import { PersonFormComponent } from './person.form.component'; +import { PersonService } from './person.service'; + +@Component({ + selector: 'app-person', + imports: [TitleCasePipe, PersonListComponent, PersonFormComponent], + template: ` +

+ {{ title() | titlecase }} +

+ + + + `, + host: { + class: 'w-full flex flex-col items-center', + }, + providers: [PersonService], +}) +export class PersonComponent implements OnInit { + service = inject(PersonService); + title = input(''); + gender = input<'male' | 'female'>('male'); + names = this.service.list; + + ngOnInit(): void { + this.service.initList(this.gender()); + } + + onAddLabel(label: string) { + this.service.add(label); + } +} diff --git a/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts b/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts new file mode 100644 index 000000000..421dcb4b9 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts @@ -0,0 +1,40 @@ +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { ChangeDetectionStrategy, Component, output } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; + +@Component({ + selector: 'person-form', + imports: [ + FormsModule, + MatFormFieldModule, + MatInputModule, + CDFlashingDirective, + ], + template: ` + + + + `, + host: { + class: 'w-full flex flex-col items-center', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PersonFormComponent { + label = ''; + addLabel = output(); + + handleKey(event: KeyboardEvent) { + if (event.key === 'Enter') { + this.addLabel.emit(this.label); + this.label = ''; + } + } +} diff --git a/apps/performance/34-default-vs-onpush/src/app/person.service.ts b/apps/performance/34-default-vs-onpush/src/app/person.service.ts new file mode 100644 index 000000000..31e5a13c4 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/app/person.service.ts @@ -0,0 +1,20 @@ +import { Injectable, signal } from '@angular/core'; +import { randFirstName } from '@ngneat/falso'; + +@Injectable() +export class PersonService { + private _list = signal([]); + list = this._list.asReadonly(); + + initList(gender: 'male' | 'female') { + if (gender === 'male') { + this._list.set(randFirstName({ gender: 'male', length: 10 })); + } else { + this._list.set(randFirstName({ gender: 'female', length: 10 })); + } + } + + add(name: string) { + this._list.update((names) => [...names, name]); + } +} diff --git a/apps/performance/34-default-vs-onpush/src/app/random.component.ts b/apps/performance/34-default-vs-onpush/src/app/random.component.ts index 71479e28d..1e36352ac 100644 --- a/apps/performance/34-default-vs-onpush/src/app/random.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/random.component.ts @@ -1,5 +1,5 @@ import { CDFlashingDirective } from '@angular-challenges/shared/directives'; -import { Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ selector: 'app-random', @@ -7,5 +7,6 @@ import { Component } from '@angular/core';
I do nothing but I'm here
`, imports: [CDFlashingDirective], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class RandomComponent {} From e47953a89ec0f091241639c4fdfc25eea0567391 Mon Sep 17 00:00:00 2001 From: lukasss88 Date: Tue, 30 Dec 2025 17:33:54 +0100 Subject: [PATCH 2/3] fix(code review fixes): refactor changes --- .../src/app/app.component.ts | 4 ++-- .../src/app/person.component.ts | 18 ++++++++++++------ .../src/app/person.form.component.ts | 13 +++++++++---- .../src/app/person.service.ts | 6 +----- 4 files changed, 24 insertions(+), 17 deletions(-) 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 index 2e9ac1669..abba0f35a 100644 --- a/apps/performance/34-default-vs-onpush/src/app/app.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/app.component.ts @@ -9,8 +9,8 @@ import { RandomComponent } from './random.component';
- - + +
`, }) diff --git a/apps/performance/34-default-vs-onpush/src/app/person.component.ts b/apps/performance/34-default-vs-onpush/src/app/person.component.ts index 31736ebf1..07e383f08 100644 --- a/apps/performance/34-default-vs-onpush/src/app/person.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/person.component.ts @@ -1,5 +1,11 @@ import { TitleCasePipe } from '@angular/common'; -import { Component, inject, input, OnInit } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + effect, + inject, + input, +} from '@angular/core'; import { PersonListComponent } from './person-list.component'; import { PersonFormComponent } from './person.form.component'; import { PersonService } from './person.service'; @@ -9,7 +15,7 @@ import { PersonService } from './person.service'; imports: [TitleCasePipe, PersonListComponent, PersonFormComponent], template: `

- {{ title() | titlecase }} + {{ gender() | titlecase }}

@@ -19,15 +25,15 @@ import { PersonService } from './person.service'; class: 'w-full flex flex-col items-center', }, providers: [PersonService], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class PersonComponent implements OnInit { +export class PersonComponent { service = inject(PersonService); - title = input(''); gender = input<'male' | 'female'>('male'); names = this.service.list; - ngOnInit(): void { - this.service.initList(this.gender()); + constructor() { + effect(() => this.service.initList(this.gender())); } onAddLabel(label: string) { diff --git a/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts b/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts index 421dcb4b9..63c2e0825 100644 --- a/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/person.form.component.ts @@ -1,5 +1,10 @@ import { CDFlashingDirective } from '@angular-challenges/shared/directives'; -import { ChangeDetectionStrategy, Component, output } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + model, + output, +} from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; @@ -28,13 +33,13 @@ import { MatInputModule } from '@angular/material/input'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class PersonFormComponent { - label = ''; + label = model(''); addLabel = output(); handleKey(event: KeyboardEvent) { if (event.key === 'Enter') { - this.addLabel.emit(this.label); - this.label = ''; + this.addLabel.emit(this.label()); + this.label.set(''); } } } diff --git a/apps/performance/34-default-vs-onpush/src/app/person.service.ts b/apps/performance/34-default-vs-onpush/src/app/person.service.ts index 31e5a13c4..82f5bfaeb 100644 --- a/apps/performance/34-default-vs-onpush/src/app/person.service.ts +++ b/apps/performance/34-default-vs-onpush/src/app/person.service.ts @@ -7,11 +7,7 @@ export class PersonService { list = this._list.asReadonly(); initList(gender: 'male' | 'female') { - if (gender === 'male') { - this._list.set(randFirstName({ gender: 'male', length: 10 })); - } else { - this._list.set(randFirstName({ gender: 'female', length: 10 })); - } + this._list.set(randFirstName({ gender, length: 10 })); } add(name: string) { From 6ad6a97502fda102214f136ddc320b3a3aec1d51 Mon Sep 17 00:00:00 2001 From: lukasss88 Date: Thu, 1 Jan 2026 15:09:33 +0100 Subject: [PATCH 3/3] fix(): remove unnecessary ifs --- .../34-default-vs-onpush/src/app/person-list.component.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 index 770b1e13f..cd984d550 100644 --- 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 @@ -19,9 +19,6 @@ import { MatListModule } from '@angular/material/list'; ], template: ` - @if (names().length === 0) { -
Empty list
- } @for (name of names(); track name) {
@@ -30,9 +27,9 @@ import { MatListModule } from '@angular/material/list';
- } - @if (names().length !== 0) { + } @empty { +
Empty list
}
`,