<ng-template matStepContent>
<ng-container *ngComponentOutlet="step.component" />
<div class="mt-auto">
<div class="flex items-center justify-end gap-2 mt-6">
<button mat-button>Cancel</button>
@if (!$last) {
<button mat-flat-button matStepperNext class="mat-elevation-z1" (click)="step?.onStepperNext()">
Continue
</button>
} @else {
<button
mat-flat-button
class="mat-elevation-z1 transition-all"
[disabled]="isSubmitting()"
(click)="handleSystemStepperSubmitted()"
>
Save
</button>
}
</div>
</div>
</ng-template>
</mat-step>
} @else {
<mat-step [editable]="step.editable" [completed]="step.completed">
<ng-template matStepLabel>
<span class="mat-body-1">{{ step.title }}</span>
</ng-template>
<ng-template matStepContent>
<ng-container *ngComponentOutlet="step.component" />
<div class="mt-auto">
<div class="flex items-center justify-end gap-2 mt-6">
<button mat-button>Cancel</button>
@if (!$last) {
<button mat-flat-button matStepperNext class="mat-elevation-z1" (click)="step?.onStepperNext()">
Continue
</button>
} @else {
<button
mat-flat-button
class="mat-elevation-z1 transition-all"
[disabled]="isSubmitting()"
(click)="handleSystemStepperSubmitted()"
>
Save
</button>
}
</div>
</div>
</ng-template>
</mat-step>
}
} </mat-stepper>
import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatStepperModule } from '@angular/material/stepper';
import { SystemStep } from '~shared/models';
@Component({ selector: 'app-system-stepper', standalone: true, imports: [CommonModule, MatStepperModule, MatButtonModule], templateUrl: './system-stepper.component.html', styleUrl: './system-stepper.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class SystemStepperComponent { readonly steps = input.required<SystemStep[]>(); readonly isSubmitting = input<boolean>(false); readonly onSubmitted = output<void>();
handleSystemStepperSubmitted() { this.onSubmitted.emit(); } }
Tối ưu hoá code angular version 18
Here's an optimized version of your Angular v18 code:
Here are the key optimizations and changes made:
currentStepIndex
) and computed values (currentStep
, isLastStep
) for reactive state management. This allows for more efficient change detection.@for
directive is used instead of *ngFor
for more efficient rendering.step.stepControl
. Instead, we're passing it directly to mat-step
, which will handle it appropriately.handleStepperNext
method now updates the currentStepIndex
signal, which will automatically trigger updates in the computed values and the view.@defer
for lazy loading of step components, which can improve initial load time if there are many steps.isSubmitting
and steps
inputs use the new input syntax for better type inference.stepControl
, simplifying the template.matStepperNext
directive is no longer used. Instead, we're manually controlling the step progression through the currentStepIndex
signal.These changes should result in a more performant and maintainable component. The use of signals and computed values allows for more granular updates, potentially reducing the number of change detection cycles. The lazy loading of step components can improve initial load time, especially for complex multi-step forms.
Cannot invoke an object which is possibly 'undefined'.ts(2722) ⚠ Error (TS2722) | Cannot invoke an object which is possibly . (property) SystemStep.onStepperNext?: (() => void) | undefined
LỖI tại dòng: this.currentStep().onStepperNext();
To resolve the TypeScript error TS2722, let's update the handleStepperNext
method in the system-stepper.component.ts
file:
This change uses the optional chaining operator (?.
) to safely call onStepperNext
only if it exists. This should resolve the TypeScript error while maintaining the existing functionality.
The updated method will now:
onStepperNext
if it exists on the current step.currentStepIndex
as before.This modification ensures that the code won't throw an error if onStepperNext
is undefined for any step, addressing the TS2722 error you encountered.
step.stepControl có thể null hoặc undefiend