- Notifications
You must be signed in to change notification settings - Fork 3
Angular 21 standalone #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @PieterjanDeClippel, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request performs a comprehensive upgrade of the project to Angular 21. It involves significant refactoring to align with the latest Angular practices, including adjustments to standalone component usage, a move towards direct component imports over NgModules, and the adoption of Angular Signals for reactive programming. The changes also address compatibility issues with host bindings in Angular 21. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
| View your CI Pipeline Execution ↗ for commit 45b9a63 ☁️ Nx Cloud last updated this comment at |
| View your CI Pipeline Execution ↗ for commit e340b2f ☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request appears to be a major refactoring effort to upgrade to Angular 21 and adopt standalone components. Many changes, such as migrating to the Signals API, updating dependencies, and moving from NgModules to standalone component imports, are positive steps. However, there's a critical and widespread issue: standalone: true has been removed from numerous components, yet they retain the imports property. In Angular, a component can only have an imports property if it is marked as standalone: true. Without this flag, the application will fail to compile. This needs to be rectified across all affected components. Given the PR's title and other changes, it seems the intention was to use standalone components, so standalone: true should likely be added back. I've added a specific comment on app.component.ts as an example of this issue. Additionally, I've noted some minor issues regarding the removal of private modifiers and changes to host listeners.
| templateUrl: './app.component.html', | ||
| styleUrls: ['./app.component.scss'], | ||
| standalone: true, | ||
| imports: [RouterOutlet, RouterLink, BsNavbarModule, NavbarRouterLinkActiveDirective], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The standalone: true flag has been removed from the AppComponent, but it still has an imports array. A component can only use the imports array if it is a standalone component. Since this is the root component of a standalone application, it must have standalone: true. Please add standalone: true back. This issue is present in many other components in this PR.
| imports: [RouterOutlet, RouterLink, BsNavbarModule, NavbarRouterLinkActiveDirective], | |
| standalone: true, | |
| imports: [RouterOutlet, RouterLink, BsNavbarModule, NavbarRouterLinkActiveDirective], |
| constructor() { | ||
| this.example$ | ||
| .pipe(map(example => deepClone(example, true, [Object]))) | ||
| // .pipe(map((clone) => JSON.stringify(clone))) | ||
| .pipe(takeUntilDestroyed()) | ||
| .subscribe(console.log); | ||
| effect(() => { | ||
| const example = this.example(); | ||
| if (example === null) { | ||
| return; | ||
| } | ||
| const clone = deepClone(example, true, [Object]); | ||
| console.log(clone); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // @Component({ | ||
| // selector: "demo-hello", | ||
| // template: `Hello {{ name }}!`, | ||
| // | ||
| // schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
| // imports: [], | ||
| // }) | ||
| // export class HelloComponent { | ||
| // @Input() name!: string; | ||
| | ||
| @HostBinding('class.d-inline-block') | ||
| @HostBinding('class.border') | ||
| @HostBinding('class.mw-100') | ||
| classes = true; | ||
| // @HostBinding('class.d-inline-block') | ||
| // @HostBinding('class.border') | ||
| // @HostBinding('class.mw-100') | ||
| // classes = true; | ||
| | ||
| @HostBinding("$.style.padding.px") | ||
| @HostListener("$.style.padding.px") | ||
| readonly test = interval(1000).pipe(tap(console.log)); | ||
| // @HostBinding("$.style.padding.px") | ||
| // @HostListener("$.style.padding.px") | ||
| // readonly test = interval(1000).pipe(tap(console.log)); | ||
| | ||
| @HostBinding("$.class.fw-bold") | ||
| @HostListener("$.class.fw-bold") | ||
| readonly active = this.test.pipe(map(v => v % 2)); | ||
| } | ||
| // @HostBinding("$.class.fw-bold") | ||
| // @HostListener("$.class.fw-bold") | ||
| // readonly active = this.test.pipe(map(v => v % 2)); | ||
| // } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HelloComponent and its related async host bindings have been commented out. Since async host bindings are no longer supported in Angular 21, this is the correct approach to avoid compilation errors. However, it would be better to completely remove the dead code instead of just commenting it out to keep the codebase clean.
| canExit = () => { | ||
| if (this.allowExit === true) { | ||
| sub.next(true); | ||
| return true; | ||
| } else { | ||
| if (confirm(this.navigationLock.exitMessage ?? 'Are you sure you want to leave this page?')) { | ||
| sub.next(true); | ||
| return true; | ||
| } else { | ||
| sub.next(false); | ||
| return false; | ||
| } | ||
| } | ||
| }); | ||
| // canExit = () => { | ||
| // if (this.allowExit === true) { | ||
| // return true; | ||
| // } else { | ||
| // if (confirm(this.navigationLock.exitMessage ?? 'Are you sure you want to leave this page?')) { | ||
| // return true; | ||
| // } else { | ||
| // return false; | ||
| // } | ||
| // } | ||
| // }; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of canExit has been changed from an Observable to a function. This is a significant API change. While the new implementation is valid, ensure this change is intentional and all call sites are updated accordingly. The previous implementation using Observable was also valid and might offer more flexibility in some scenarios.
| @HostBinding('class.d-block') | ||
| @HostBinding('class.overflow-hidden') | ||
| private progressClass = true; | ||
| progressClass = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| | ||
| | ||
| @HostListener('window:blur') private onBlur() { | ||
| @HostListener('window:blur') onBlur() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The private modifier was removed from the onBlur method. If this method is not intended to be called from outside the directive, it should be kept private to encapsulate the directive's internal logic.
| @HostListener('window:blur') onBlur() { | |
| @HostListener('window:blur') private onBlur() { |
| //#endregion | ||
| | ||
| @HostListener('window:blur') private onBlur() { | ||
| @HostListener('window:blur') onBlur() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The private modifier was removed from the onBlur method. If this method is not intended to be called from outside the directive, it should be kept private to encapsulate the directive's internal logic.
| @HostListener('window:blur') onBlur() { | |
| @HostListener('window:blur') private onBlur() { |
| | ||
| @HostListener('document:keydown', ['$event']) | ||
| private onKeyDown(ev: KeyboardEvent) { | ||
| onKeyDown(ev: KeyboardEvent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private overlayRef: OverlayRef | null = null; | ||
| | ||
| @HostListener('window:blur') private onBlur() { | ||
| @HostListener('window:blur') onBlur() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The private modifier was removed from the onBlur method. If this method is not intended to be called from outside the directive, it should be kept private to encapsulate the directive's internal logic.
| @HostListener('window:blur') onBlur() { | |
| @HostListener('window:blur') private onBlur() { |
| @HostListener('document:keydown.ArrowRight', ['$event']) | ||
| @HostListener('document:keydown.ArrowUp', ['$event']) | ||
| @HostListener('document:keydown.ArrowDown', ['$event']) | ||
| @HostListener('document:keydown', ['$event']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @HostListeners for specific arrow keys have been replaced with a single listener for keydown. While this works, it's less efficient as it will trigger on every keydown event, not just the ones it's interested in. It's better to keep the more specific listeners for performance reasons.
@HostListener('document:keydown.ArrowLeft', ['$event']) @HostListener('document:keydown.ArrowRight', ['$event']) @HostListener('document:keydown.ArrowUp', ['$event']) @HostListener('document:keydown.ArrowDown', ['$event']) onKeyPress(ev: KeyboardEvent) {
No description provided.