Skip to content

Commit b7753ae

Browse files
committed
Work toward compiling with Angular 21.
1 parent f295582 commit b7753ae

File tree

10 files changed

+304
-275
lines changed

10 files changed

+304
-275
lines changed

ANGULAR-21-MIGRATION.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Angular 21 Migration Plan
2+
3+
## Overview
4+
This document outlines the comprehensive migration of RangerTrak from Angular with legacy patterns to Angular 21 with modern features including signals, standalone components, and signal-based forms.
5+
6+
## Migration Phases
7+
8+
### Phase 1: Foundation & Cleanup ✓ IN PROGRESS
9+
**Goal:** Remove incompatible dependencies and set up modern infrastructure
10+
11+
#### 1.1 Remove Incompatible Packages
12+
- [x] Remove `@angular-material-components/datetime-picker` (incompatible with Angular 21)
13+
- [x] Remove `@angular-material-components/color-picker` (incompatible with Angular 21)
14+
- [ ] Replace with native Angular Material components or custom implementations
15+
16+
#### 1.2 Update Package.json
17+
- [ ] Clean up overrides section
18+
- [ ] Add any missing Angular 21 packages
19+
- [ ] Update tsconfig for Angular 21 features
20+
21+
### Phase 2: Convert to Standalone Components
22+
**Goal:** Eliminate NgModules and adopt standalone architecture
23+
24+
#### 2.1 Module Analysis
25+
Current modules to convert:
26+
- `AppModule` → Standalone bootstrap
27+
- `MaterialModule` → Direct component imports
28+
- `LazyModule` → Standalone lazy routes
29+
30+
#### 2.2 Conversion Steps
31+
1. Convert all components to standalone
32+
2. Add explicit imports to each component
33+
3. Update routing to use standalone components
34+
4. Remove all NgModule declarations
35+
5. Update main.ts to bootstrap standalone component
36+
37+
### Phase 3: Implement Signals for State Management
38+
**Goal:** Replace RxJS patterns with signals where appropriate
39+
40+
#### 3.1 Services to Migrate
41+
- `DataService` - Convert BehaviorSubjects to signals
42+
- `FieldReportService` - Use signals for report state
43+
- `RangerService` - Use signals for ranger data
44+
- `ClockService` - Convert to signal-based time updates
45+
- `SettingsService` - Migrate settings to signals
46+
- `InstallableService` - Convert observable patterns
47+
48+
#### 3.2 Signal Patterns
49+
```typescript
50+
// Before
51+
private dataSubject = new BehaviorSubject<Data[]>([]);
52+
data$ = this.dataSubject.asObservable();
53+
54+
// After
55+
readonly data = signal<Data[]>([]);
56+
readonly dataComputed = computed(() => this.data().filter(...));
57+
```
58+
59+
### Phase 4: Modern Control Flow Syntax
60+
**Goal:** Replace structural directives with built-in control flow
61+
62+
#### 4.1 Template Updates
63+
- Replace `*ngIf` with `@if`
64+
- Replace `*ngFor` with `@for`
65+
- Replace `*ngSwitch` with `@switch`
66+
- Use `@empty` for empty state handling
67+
68+
#### 4.2 Components to Update
69+
- All HTML templates (58+ component templates)
70+
71+
### Phase 5: Modernize Dependency Injection
72+
**Goal:** Use inject() function instead of constructor injection
73+
74+
#### 5.1 Pattern
75+
```typescript
76+
// Before
77+
constructor(
78+
private http: HttpClient,
79+
private router: Router
80+
) {}
81+
82+
// After
83+
private http = inject(HttpClient);
84+
private router = inject(Router);
85+
```
86+
87+
### Phase 6: Signal-Based Forms
88+
**Goal:** Integrate signals with reactive forms
89+
90+
#### 6.1 Forms to Migrate
91+
- `EntryComponent` - Field report entry form
92+
- `LocationComponent` - Location input form
93+
- `SettingsComponent` - Settings editor form
94+
- `TimePickerComponent` - Time selection form
95+
96+
#### 6.2 Modern Form Patterns
97+
```typescript
98+
// Use signal inputs
99+
readonly initialValue = input<string>('');
100+
101+
// Use signal outputs
102+
readonly formSubmit = output<FormData>();
103+
104+
// Create form with signals
105+
readonly form = new FormGroup({
106+
field: new FormControl(this.initialValue())
107+
});
108+
109+
// React to form changes with effects
110+
constructor() {
111+
effect(() => {
112+
const value = this.initialValue();
113+
this.form.patchValue({ field: value });
114+
});
115+
}
116+
```
117+
118+
### Phase 7: Component Modernization
119+
**Goal:** Use modern component features
120+
121+
#### 7.1 Signal Inputs/Outputs
122+
- Convert `@Input()` to `input()` signals
123+
- Convert `@Output()` to `output()` signals
124+
- Use `model()` for two-way binding
125+
126+
#### 7.2 Components Priority List
127+
1. Shared components (Header, Footer, Navbar)
128+
2. Core components (Entry, FieldReports, Rangers)
129+
3. Map components (GMap, LMap)
130+
4. Settings components
131+
5. Utility components
132+
133+
### Phase 8: Routing & Lazy Loading
134+
**Goal:** Modern routing with standalone components
135+
136+
#### 8.1 Route Updates
137+
```typescript
138+
// Before
139+
{
140+
path: 'about',
141+
loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
142+
}
143+
144+
// After
145+
{
146+
path: 'about',
147+
loadComponent: () => import('./lazy/about/about.component').then(m => m.AboutComponent)
148+
}
149+
```
150+
151+
### Phase 9: Testing & Validation
152+
**Goal:** Ensure all features work correctly
153+
154+
#### 9.1 Test Areas
155+
- [ ] Form submissions
156+
- [ ] Data persistence
157+
- [ ] Map interactions
158+
- [ ] Service worker functionality
159+
- [ ] Offline capabilities
160+
- [ ] Settings management
161+
162+
## Breaking Changes to Address
163+
164+
### Removed Angular Material APIs
165+
The following APIs used by deprecated packages need alternatives:
166+
167+
1. **DateTime Picker**
168+
- Use native `MatDatepicker` with time input
169+
- Create custom time picker component if needed
170+
171+
2. **Color Picker**
172+
- Use native HTML `<input type="color">`
173+
- Or use alternative library (ngx-colors)
174+
- Or create custom color picker
175+
176+
### Template Syntax Changes
177+
- `[formGroup]` only works on `<form>` elements
178+
- New control flow syntax is required
179+
- Router directives need imports
180+
181+
## Implementation Order
182+
183+
1.**Remove incompatible packages** (Phase 1.1)
184+
2. **Fix immediate errors** (Add missing imports)
185+
3. **Convert to standalone** (Phase 2)
186+
4. **Update control flow** (Phase 4) - Can be done during conversion
187+
5. **Modernize DI** (Phase 5) - Can be done during conversion
188+
6. **Implement signals** (Phase 3) - Iterative process
189+
7. **Update forms** (Phase 6) - After signals are in place
190+
8. **Update routing** (Phase 8)
191+
9. **Test thoroughly** (Phase 9)
192+
193+
## Estimated Timeline
194+
- **Phase 1:** 1-2 hours (removing packages, fixing imports)
195+
- **Phase 2:** 4-6 hours (standalone conversion)
196+
- **Phase 3:** 6-8 hours (signal implementation)
197+
- **Phase 4:** 2-3 hours (control flow updates)
198+
- **Phase 5:** 3-4 hours (DI modernization)
199+
- **Phase 6:** 4-5 hours (form updates)
200+
- **Phase 7:** 3-4 hours (component modernization)
201+
- **Phase 8:** 2-3 hours (routing updates)
202+
- **Phase 9:** 3-4 hours (testing)
203+
204+
**Total:** ~30-40 hours of development time
205+
206+
## Notes
207+
- This is a significant refactoring that touches most files
208+
- Each phase should be tested before moving to the next
209+
- Some phases can be done incrementally
210+
- Git commits should be made after each successful phase
211+
- Consider feature branches for major changes
212+
213+
## Resources
214+
- [Angular Signals Guide](https://angular.dev/guide/signals)
215+
- [Standalone Components](https://angular.dev/guide/components/importing)
216+
- [Built-in Control Flow](https://angular.dev/guide/templates/control-flow)
217+
- [Modern Dependency Injection](https://angular.dev/guide/di/dependency-injection)

package-lock.json

Lines changed: 0 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
},
2222
"private": true,
2323
"dependencies": {
24-
"@angular-material-components/color-picker": "^16.0.1",
25-
"@angular-material-components/datetime-picker": "^16.0.1",
2624
"@angular/animations": "^21.0.6",
2725
"@angular/cdk": "^21.0.5",
2826
"@angular/cli": "^21.0.4",
@@ -101,27 +99,5 @@
10199
"style": "module",
102100
"options": {}
103101
}
104-
},
105-
"overrides": {
106-
"@angular-material-components/datetime-picker": {
107-
"@angular/platform-browser": "$@angular/platform-browser",
108-
"@angular/common": "$@angular/common",
109-
"@angular/core": "$@angular/core",
110-
"@angular/forms": "$@angular/forms",
111-
"@angular/material": "$@angular/material",
112-
"@angular/cdk": "$@angular/cdk"
113-
},
114-
"@angular-material-components/color-picker": {
115-
"@angular/platform-browser": "$@angular/platform-browser",
116-
"@angular/common": "$@angular/common",
117-
"@angular/core": "$@angular/core",
118-
"@angular/forms": "$@angular/forms",
119-
"@angular/material": "$@angular/material",
120-
"@angular/cdk": "$@angular/cdk"
121-
},
122-
"@angular-material-components/moment-adapter": {
123-
"@angular/common": "$@angular/common",
124-
"@angular/core": "$@angular/core"
125-
}
126102
}
127103
}

src/app/app.module.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
import {
2-
MAT_COLOR_FORMATS, NGX_MAT_COLOR_FORMATS, NgxMatColorPickerModule
3-
} from '@angular-material-components/color-picker'
4-
//import { MatDatepickerModule } from '@matheo/datepicker'
5-
//import { MatNativeDateModule } from '@matheo/datepicker/core'
6-
import {
7-
NgxMatDatetimePickerModule, NgxMatNativeDateModule, NgxMatTimepickerModule
8-
} from '@angular-material-components/datetime-picker'
91
import { CommonModule } from '@angular/common'
102
import { HttpClientModule } from '@angular/common/http'
113
import { NgModule, isDevMode } from '@angular/core'
@@ -73,10 +65,6 @@ import { HeaderComponent, AlertsComponent, FooterComponent, IconsComponent, Inst
7365
// https://angular.io/guide/ngmodule-faq#what-is-the-forroot-method: singleton
7466
// AgmCoreModule.forRoot({ apiKey: 'API_KEY_GOES_HERE' }),
7567
LazyModule,
76-
NgxMatColorPickerModule,
77-
NgxMatDatetimePickerModule,
78-
NgxMatTimepickerModule,
79-
NgxMatNativeDateModule,
8068
RouterModule,
8169
ServiceWorkerModule.register('ngsw-worker.js', {
8270
enabled: environment.production || !isDevMode(),
Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,9 @@
1-
<!--div #container class="color"-->
2-
<!-- tabindex="0" (click)="onClick($event)" (mousedown)="onMouseDown($event)" (keydown)="onKeyDown($event)" -->
3-
4-
<!-- https://h2qutc.github.io/angular-material-components/colorpicker-->
5-
6-
<!--mat-card >
7-
<span [style.background-color]="colorCtr.value?.rgba">HEX: {{colorCtr.value?.hex}} &nbsp;&nbsp; RGBA: {{colorCtr.value?.rgba}}</span>
8-
<br>
9-
Warning: 1) Cclick the small color palette icon on the right.<br>
10-
2) Select your color.<br>
11-
3) Click just a bit to to the left of the color palette to <br>
12-
'set' the color & dismiss the dialog.
13-
</mat-card-->
14-
15-
<mat-card appearance="outlined">
16-
<mat-form-field id="colorFormField" appearance="fill">
17-
<!-- [disabled]="colorCntlDisabled" causes warning -->
18-
<input matInput [ngxMatColorPicker]="picker"
19-
[formControl]="colorCtr" (click)="onClick($event)" id="colorTextField">
20-
<ngx-mat-color-toggle matSuffix [for]="picker" id="colorIconToggleArea"></ngx-mat-color-toggle>
21-
22-
<ngx-mat-color-picker #picker [touchUi]="touchUi" [color]="colorPalette" (closed)="onColorCtrClosed()" class="colorPickerIcon" > BBBBB
23-
<!--button >howNow?!</button>
24-
<ng-template>
25-
<mat-icon>star</mat-icon>
26-
<span>OK</span>
27-
</ng-template-->
28-
</ngx-mat-color-picker>
29-
30-
</mat-form-field>
31-
32-
<!--hr class="symbol" [style.hr.border-color]="colorCtr.value?.rgba"-->
33-
34-
<!--span [style.background-color]="colorCtr.value?.rgba">HEX: {{colorCtr.value?.hex}} &nbsp;&nbsp; {{colorCtr.value?.rgba}}</span-->
35-
</mat-card>
36-
<!--mat-card >
37-
<span [style.background-color]="colorCtr.value?.rgba">HEX: {{colorCtr.value?.hex}} &nbsp;&nbsp; RGBA: {{colorCtr.value?.rgba}}</span>
38-
</mat-card-->
39-
40-
<!--/div-->
41-
1+
<!-- Simplified color picker using native HTML color input -->
2+
<mat-card appearance="outlined">
3+
<mat-form-field id="colorFormField" appearance="fill">
4+
<mat-label>Select Color</mat-label>
5+
<input matInput type="color" [formControl]="colorCtr" (change)="onColorChange()" id="colorTextField"
6+
class="color-input">
7+
<mat-hint>Current: {{colorCtr.value}}</mat-hint>
8+
</mat-form-field>
9+
</mat-card>

0 commit comments

Comments
 (0)