TL;DR
I want to set up an angular (v15 atm) app that acts as an advent calendar. This would:
- Allow me to route to a specific year (e.g.
<url>/calendar/2021
) - Allow me to open windows in individual years
I've got this working. However! In my current version, if I open day 1 in 2021, then switch to 2022, day 1 in 2022 will already be open!
I'm trying to figure out how to clear the memory of what I've done on previous versions of a component, which possibly means creating that component fresh each time. Can any of you help?
Background
Lets say I'm making an advent calendar in Angular, and I want it to span multiple years.
I might have an app-routing.module.ts
that looks like this:
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'calendar/:year', component: CalendarComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
...and a calendar.component.ts
that looks like this:
@Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.scss']
})
export class CalendarComponent {
title = environment.appName;
showYear = 0;
showDays = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25];
constructor(
private route: ActivatedRoute) {
this.route.params.subscribe(params => {
this.showYear = params['year'];
this.title = environment.appName ': ' params['year'];
});
}
}
...with html:
<div >
<div *ngFor="let day of showDays">
<aoc-window [year]="showYear"
[day]="day">
</aoc-window>
</div>
</div>
The window.component.ts
looks like the following:
@Component({
selector: 'aoc-window',
templateUrl: './window.component.html',
styleUrls: ['./window.component.scss']
})
export class WindowComponent {
@Input() year: number = 0;
@Input() day: number = 0;
aocResponse?: AOCResponse | undefined;
isOpen: boolean = false;
constructor(private aocService: WindowService) { }
open() {
this.isOpen = true;
this.getAOCResponse();
}
getAOCResponse() {
let callPath = environment.aocPath '/' this.year '/' this.day
this.aocService.getAOCAnswer(callPath)
.subscribe(aocResponse => {
this.aocResponse = aocResponse;
}, error => {
console.error(error);
this.aocResponse = { answer: 'Failed' }
});
}
}
...with html:
<div >
<button id="windowClosed" *ngIf="!isOpen" (click)="open()">{{ day }}</button>
<div *ngIf="isOpen">
<div *ngIf="aocResponse">{{ aocResponse.answer }}</div>
<div *ngIf="!aocResponse">Loading answer...</div>
</div>
</div>
Question
So far, everything works. I can navigate to 2021, and get answers for that page. However, if I open doors 1-3 in 2021, then switch to 2022, those doors are still open.
How do I get angular components to "forget" what they know?
There might be two answers:
- Close all open panels loading 2022 (i.e. forget everything)
- Understand the difference between 2021 & 2022 panels
I'm fine with either answer!
Thanks!
Additional files
homepage.component.html
<mat-sidenav-container >
<mat-sidenav #sidenav mode="side" opened >
<mat-nav-list>
<a mat-list-item [routerLink]="'/dashboard'"> Dashboard </a>
<a mat-list-item [routerLink]="'/calendar/2021'"> 2021 </a>
<a mat-list-item [routerLink]="'/calendar/2022'"> 2022 </a>
<a mat-list-item [routerLink]="'/calendar/2023'"> 2023 (future) </a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content >
<div>
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
app.module.ts
@NgModule({
declarations: [
HomepageComponent,
WindowComponent,
DashboardComponent,
CalendarComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
HttpClientModule,
MaterialModule,
MatNativeDateModule
],
providers: [],
bootstrap: [HomepageComponent]
})
export class AppModule { }
CodePudding user response:
If i got it right, the problem is that your inputs are remaining with the 2021 values when you change the url to 2022 is that correct? If that´s it, you can change your inputs() to "input() set", that way you can get new values every time it gets updated. So it wourld be something like this:
Change
@Input() year: number = 0;
@Input() day: number = 0;
To
@Input() set year(year: number) {
this.internalYear = year;
}
private internalYear: number = 0;
@Input() set day(day: number) {
this.internalDay = day;
}
private internalDay: number = 0;
This way when you update the 'showYear' property with the new year, your input will update its value as well.