diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a1c73e1..5116451 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; import { TieredMenuModule } from 'primeng/tieredmenu'; import { AppRoutingModule } from './app-routing.module'; @@ -18,7 +19,7 @@ import { DialogModule } from 'primeng/dialog'; @NgModule({ declarations: [ - AppComponent, + AppComponent ], imports: [ BrowserModule, @@ -30,6 +31,7 @@ import { DialogModule } from 'primeng/dialog'; HttpClientModule, AppRoutingModule, FormsModule, + ReactiveFormsModule, NflModule, NbaModule, NhlModule, diff --git a/src/app/common/validators/year-range.ts b/src/app/common/validators/year-range.ts new file mode 100644 index 0000000..a64940c --- /dev/null +++ b/src/app/common/validators/year-range.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidatorFn } from '@angular/forms'; + +// Custom validator function to validate year range +export function yearRangeValidator(minYear: number, maxYear: number): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } | null => { + const value = control.value; + if (value && (value < minYear || value > maxYear)) { + return { 'yearRange': { min: minYear, max: maxYear } }; + } + return null; + }; +} diff --git a/src/app/nhl/components/roster/roster.component.html b/src/app/nhl/components/roster/roster.component.html index 71643d3..eaf9050 100644 --- a/src/app/nhl/components/roster/roster.component.html +++ b/src/app/nhl/components/roster/roster.component.html @@ -49,53 +49,61 @@

National Hockey League - Team Rosters

- -
+ +
- +
- +
- +
- +
- +
- - + + +
+
Drafted Year is required. +
+
Drafted Year must be a 4-digit + year.
+
Drafted Year must be between + 1900 - Current Year.
+
- +
- +
- +
- +
- - + +
diff --git a/src/app/nhl/components/roster/roster.component.ts b/src/app/nhl/components/roster/roster.component.ts index 225ac23..11d77a4 100644 --- a/src/app/nhl/components/roster/roster.component.ts +++ b/src/app/nhl/components/roster/roster.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { NhlService } from '../../services/nhl.service'; import { NHLRosterDto } from '../../services/nhl'; +import { yearRangeValidator } from 'src/app/common/validators/year-range'; @Component({ selector: 'sports-roster', @@ -9,6 +11,7 @@ import { NHLRosterDto } from '../../services/nhl'; ] }) export class RosterComponent implements OnInit { + nhlForm!: FormGroup; roster: NHLRosterDto[] = []; isLoading: boolean = false; errMessage: string = ""; @@ -21,6 +24,24 @@ export class RosterComponent implements OnInit { ) { } ngOnInit(): void { + const currentYear = new Date().getFullYear(); + this.nhlForm = new FormGroup({ + team: new FormControl(''), + name: new FormControl(''), + position: new FormControl(''), + number: new FormControl(''), + handed: new FormControl(''), + drafted: new FormControl(null, + [Validators.required, + yearRangeValidator(1900, currentYear), // Use the custom validator + Validators.pattern('^[0-9]{4}$')] + ), + birthCountry: new FormControl(''), + birthPlace: new FormControl(''), + age: new FormControl(''), + playerID: new FormControl({ value: '', disabled: true }) + }); + this.isLoading = true; this.loadRoster(); this.isLoading = false; @@ -29,6 +50,7 @@ export class RosterComponent implements OnInit { resetAction() { this.errMessage = ""; this.isAdding = false; + this.nhlForm.reset(); } loadRoster() { @@ -51,6 +73,7 @@ export class RosterComponent implements OnInit { editRow(row: any) { this.resetAction(); this.selectedRow = { ...row }; // Create a copy of the row to edit + this.setFormValues(row); this.display = true; } @@ -61,33 +84,42 @@ export class RosterComponent implements OnInit { } save() { - this.nhlService.SaveRoster(this.selectedRow).subscribe({ - next: data => { - console.log('Player saved successfully', data); - this.loadRoster(); // reload the grid - this.display = false; - }, - error: error => { - console.error('There was an error saving the player!', error); - this.errMessage = "There was an error saving the player. Please try again."; - this.display = true; - } - }) + if (this.nhlForm.valid) { + // Update the selectedRow with the form values + this.refreshSelectedRow(); + + this.nhlService.SaveRoster(this.selectedRow).subscribe({ + next: data => { + console.log('Player saved successfully', data); + this.loadRoster(); // reload the grid + this.display = false; + }, + error: error => { + console.error('There was an error saving the player!', error); + this.errMessage = "There was an error saving the player. Please try again."; + this.display = true; + } + }); + } } add() { - this.nhlService.AddRoster(this.selectedRow).subscribe({ - next: data => { - console.log('Player added successfully', data); - this.loadRoster(); // reload the grid - this.display = false; - }, - error: error => { - console.error('There was an error adding the player!', error); - this.errMessage = "There was an error adding the player. Please try again."; - this.display = true; - } - }) + + if (this.nhlForm.valid) { + + this.nhlService.AddRoster(this.nhlForm.value).subscribe({ + next: data => { + console.log('Player added successfully', data); + this.loadRoster(); // reload the grid + this.display = false; + }, + error: error => { + console.error('There was an error adding the player!', error); + this.errMessage = "There was an error adding the player. Please try again."; + this.display = true; + } + }); + } } delete(playerID: string) { @@ -118,5 +150,30 @@ export class RosterComponent implements OnInit { onDialogHide() { this.selectedRow = {} }; + + setFormValues(row: any) { + + this.nhlForm.setValue({ + team: row.team || '', + name: row.name || '', + position: row.position || '', + number: row.number || '', + handed: row.handed || '', + drafted: row.drafted || '', + birthCountry: row.birthCountry || '', + birthPlace: row.birthPlace || '', + age: row.age || '', + playerID: row.playerID || '' + }); + + } + + refreshSelectedRow() { + this.selectedRow = { + ...this.nhlForm.value, // Get all the current form values + playerID: this.selectedRow.playerID + }; + } } + diff --git a/src/app/nhl/nhl.module.ts b/src/app/nhl/nhl.module.ts index 1ae5eeb..81f49b1 100644 --- a/src/app/nhl/nhl.module.ts +++ b/src/app/nhl/nhl.module.ts @@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common'; import { TableModule } from 'primeng/table'; import { DialogModule } from 'primeng/dialog'; import { FormsModule } from '@angular/forms'; // Import FormsModule +import { ReactiveFormsModule } from '@angular/forms'; // Import ReactiveFormsModule import { NhlRoutingModule } from './nhl-routing.module'; @@ -20,6 +21,7 @@ import { RosterComponent } from './components/roster/roster.component'; TableModule, DialogModule, FormsModule, + ReactiveFormsModule, NhlRoutingModule ] }) diff --git a/src/styles.css b/src/styles.css index 8ec4fb4..f8d42e6 100644 --- a/src/styles.css +++ b/src/styles.css @@ -141,3 +141,10 @@ td.actions { align-items: center; justify-content: center; } + +/* Styling for field-specific errors */ +.field-error { + color: #d9534f; + font-size: 0.875rem; + margin-top: 0.25rem; +}