Last active
February 12, 2018 11:40
-
-
Save petyosi/2cc6d2f629c52eb75b62121a6ab7cd85 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {BrowserModule} from '@angular/platform-browser'; | |
import {NgModule} from '@angular/core'; | |
import {HttpModule} from '@angular/http'; | |
import {FormsModule} from '@angular/forms'; | |
import {AgGridModule} from 'ag-grid-angular'; | |
import {AthleteService} from './services/athlete.service'; | |
import {StaticDataService} from './services/static-data.service'; | |
import {AppComponent} from './app.component'; | |
import {GridComponent} from './grid/grid.component'; | |
import {AthleteEditScreenComponent} from './athlete-edit-screen/athlete-edit-screen.component'; | |
@NgModule({ | |
declarations: [ | |
AppComponent, | |
GridComponent, | |
AthleteEditScreenComponent | |
], | |
imports: [ | |
BrowserModule, | |
HttpModule, | |
FormsModule, | |
AgGridModule.withComponents([]) | |
], | |
providers: [ | |
AthleteService, | |
StaticDataService | |
], | |
bootstrap: [AppComponent] | |
}) | |
export class AppModule { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.input-panel { | |
border-radius: 5px; | |
border: solid lightgray 1px; | |
margin: 15px; | |
padding: 15px; | |
} | |
.submit-pane { | |
overflow: hidden; | |
margin-top: 10px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="input-panel"> | |
<div style="display: inline-block"> | |
<div style="float: left"> | |
Name: <input [(ngModel)]="name"/> | |
</div> | |
<div style="float: left; padding-left: 10px"> | |
Country: | |
<select [(ngModel)]="country" [compareWith]="countryComparator"> | |
<option disabled selected>Country...</option> | |
<option *ngFor="let country of countries" [ngValue]="country">{{ country.name }}</option> | |
</select> | |
</div> | |
</div> | |
<div> | |
<button (click)="insertNewResult()" class="action-button">Insert New Result</button> | |
<ag-grid-angular style="width: 100%; height: 200px;" | |
class="ag-theme-balham" | |
[columnDefs]="columnDefs" | |
[rowData]="rowData" | |
(gridReady)="onGridReady($event)" | |
(rowValueChanged)="onRowValueChanged($event)"> | |
</ag-grid-angular> | |
</div> | |
<div class="submit-pane"> | |
<button (click)="saveAthlete()" [disabled]="!isValidAthlete()" class="action-button" style="float: right">Save | |
Athlete | |
</button> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |
import {ColDef, ColumnApi, GridApi} from 'ag-grid'; | |
import {StaticDataService} from '../services/static-data.service'; | |
import {Result} from '../model/result.model'; | |
import {Sport} from '../model/sport.model'; | |
import {Country} from '../model/country.model'; | |
import {Athlete} from '../model/athlete.model'; | |
@Component({ | |
selector: 'app-athlete-edit-screen', | |
templateUrl: './athlete-edit-screen.component.html', | |
styleUrls: ['./athlete-edit-screen.component.css'] | |
}) | |
export class AthleteEditScreenComponent implements OnInit { | |
// gridApi and columnApi | |
private api: GridApi; | |
private columnApi: ColumnApi; | |
// static data | |
private sports: Sport[]; | |
private countries: Country[]; | |
// interim/form data | |
private name: string; | |
private country: Country; | |
private rowData: Result[] = []; | |
// the results sub-table columns | |
private columnDefs: ColDef[]; | |
@Input() athlete: Athlete = null; | |
@Output() onAthleteSaved = new EventEmitter<Athlete>(); | |
constructor(staticDataService: StaticDataService) { | |
staticDataService.countries().subscribe( | |
countries => this.countries = countries.sort(StaticDataService.alphabeticalSort()), | |
error => console.log(error) | |
); | |
staticDataService.sports().subscribe( | |
sports => { | |
// store reference to sports, after sorting alphabetically | |
this.sports = sports.sort(StaticDataService.alphabeticalSort()); | |
// create the column defs | |
this.columnDefs = this.createColumnDefs(this.sports) | |
}, | |
error => console.log(error) | |
); | |
} | |
ngOnInit() { | |
if (this.athlete) { | |
this.name = this.athlete.name; | |
this.country = this.athlete.country; | |
this.rowData = this.athlete.results.slice(0); | |
} | |
} | |
countryComparator(c1: Country, c2: Country): boolean { | |
return c1 && c2 ? c1.id === c2.id : false; | |
} | |
insertNewResult() { | |
// insert a blank new row, providing the first sport as a default in the sport column | |
const updates = this.api.updateRowData( | |
{ | |
add: [{ | |
sport: this.sports[0] | |
}] | |
} | |
); | |
this.api.startEditingCell({ | |
rowIndex: updates.add[0].rowIndex, | |
colKey: 'age' | |
}); | |
} | |
isValidAthlete() { | |
return this.name && this.name !== '' && | |
this.country; | |
} | |
saveAthlete() { | |
const athlete = new Athlete(); | |
athlete.id = this.athlete ? this.athlete.id : null; | |
athlete.name = this.name; | |
athlete.country = this.country; | |
athlete.results = []; | |
this.api.forEachNode((node) => { | |
const {data} = node; | |
athlete.results.push(<Result> { | |
id: data.id, | |
age: data.age, | |
year: data.year, | |
date: data.date, | |
bronze: data.bronze, | |
silver: data.silver, | |
gold: data.gold, | |
sport: data.sport | |
}); | |
}); | |
this.onAthleteSaved.emit(athlete); | |
} | |
onGridReady(params): void { | |
this.api = params.api; | |
this.columnApi = params.columnApi; | |
this.api.sizeColumnsToFit(); | |
// temp fix until AG-1181 is fixed | |
this.api.hideOverlay(); | |
} | |
// create some simple column definitions | |
private createColumnDefs(sports: Sport[]) { | |
return [ | |
{ | |
field: 'age', | |
editable: true | |
}, | |
{ | |
field: 'year', | |
editable: true | |
}, | |
{ | |
field: 'date', | |
editable: true | |
}, | |
{ | |
field: 'bronze', | |
editable: true | |
}, | |
{ | |
field: 'silver', | |
editable: true | |
}, | |
{ | |
field: 'gold', | |
editable: true | |
}, | |
{ | |
field: 'sport', | |
cellRenderer: (params) => params.data.sport.name, | |
editable: true, | |
cellEditor: 'richSelect', | |
cellEditorParams: { | |
values: sports, | |
cellRenderer: (params) => params.value.name | |
} | |
} | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Country} from './country.model'; | |
import {Result} from './result.model'; | |
export class Athlete { | |
id: number; | |
version: number; | |
name: string; | |
country: Country; | |
results: Result[]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Injectable} from '@angular/core'; | |
import {Athlete} from '../model/athlete.model'; | |
import {Headers, Http, RequestOptions, Response} from '@angular/http'; | |
import 'rxjs/add/operator/map' | |
import 'rxjs/add/operator/catch'; | |
import {Observable} from 'rxjs/Observable'; | |
@Injectable() | |
export class AthleteService { | |
static REQUEST_OPTIONS: RequestOptions = new RequestOptions({headers: new Headers({'Content-Type': 'application/json'})}); | |
private apiRootUrl = 'http://localhost:8080'; | |
private findAllUrl = this.apiRootUrl + '/athletes'; | |
private findByIdUrl = this.apiRootUrl + '/athlete'; | |
private saveUpdateUrl = this.apiRootUrl + '/saveAthlete'; | |
private deleteUrl = this.apiRootUrl + '/deleteAthlete'; | |
constructor(private http: Http) { | |
} | |
findAll(): Observable<Athlete[]> { | |
return this.http.get(this.findAllUrl) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
findById(id: number): Observable<Athlete> { | |
return this.http.get(this.findByIdUrl + '/' + id) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
save(athlete: Athlete): Observable<Athlete> { | |
return this.http.post(this.saveUpdateUrl, athlete, AthleteService.REQUEST_OPTIONS) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
delete(athlete: Athlete): Observable<boolean> { | |
return this.http.post(this.deleteUrl, athlete.id, AthleteService.REQUEST_OPTIONS) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
private defaultErrorHandler() { | |
return (error: any) => { | |
console.log(error); | |
return Observable.throw(error.json().error || 'Server error') | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {StaticData} from './static-data.model'; | |
export class Country implements StaticData { | |
id: number; | |
name: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div> | |
<button (click)="insertNewRow()" [disabled]="editInProgress" class="action-button">Insert New Row</button> | |
<button (click)="deleteSelectedRows()" [disabled]="!rowsSelected() || editInProgress" class="action-button">Delete | |
Selected Row | |
</button> | |
</div> | |
<div> | |
<ag-grid-angular style="width: 100%; height: 00px;" | |
class="ag-theme-balham" | |
[columnDefs]="columnDefs" | |
[rowData]="rowData" | |
rowSelection="multiple" | |
suppressRowClickSelection | |
suppressHorizontalScroll | |
suppressClickEdit | |
(gridReady)="onGridReady($event)" | |
(rowDoubleClicked)="onRowDoubleClicked($event)"> | |
</ag-grid-angular> | |
</div> | |
<ng-template [ngIf]="editInProgress"> | |
<app-athlete-edit-screen [athlete]="athleteBeingEdited" | |
(onAthleteSaved)="onAthleteSaved($event)"></app-athlete-edit-screen> | |
</ng-template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, OnInit} from '@angular/core'; | |
import {Observable} from 'rxjs/Observable'; | |
import 'rxjs/add/observable/forkJoin'; | |
import {ColDef, ColumnApi, GridApi} from 'ag-grid'; | |
import {AthleteService} from '../services/athlete.service'; | |
import {Athlete} from '../model/athlete.model'; | |
import {StaticDataService} from '../services/static-data.service'; | |
import {Country} from '../model/country.model'; | |
// we need to import this as we're making use of enterprise features, such as the richSelect cell editor | |
import 'ag-grid-enterprise'; | |
@Component({ | |
selector: 'app-grid', | |
templateUrl: './grid.component.html', | |
styleUrls: ['./grid.component.css'] | |
}) | |
export class GridComponent implements OnInit { | |
// row data and column definitions | |
private rowData: Athlete[]; | |
private columnDefs: ColDef[]; | |
// gridApi and columnApi | |
private api: GridApi; | |
private columnApi: ColumnApi; | |
private editInProgress: boolean = false; | |
private athleteBeingEdited: Athlete = null; | |
// inject the athleteService | |
constructor(private athleteService: AthleteService, | |
staticDataService: StaticDataService) { | |
staticDataService.countries().subscribe( | |
countries => this.columnDefs = this.createColumnDefs(countries), | |
error => console.log(error) | |
); | |
} | |
// on init, read to the athlete data | |
ngOnInit() { | |
this.setAthleteRowData(); | |
} | |
setAthleteRowData() { | |
this.athleteService.findAll().subscribe( | |
athletes => this.rowData = athletes, | |
error => console.log(error) | |
) | |
} | |
onAthleteSaved(savedAthlete: Athlete) { | |
this.athleteService.save(savedAthlete) | |
.subscribe( | |
success => { | |
console.log('Athlete saved'); | |
this.setAthleteRowData(); | |
}, | |
error => console.log(error) | |
); | |
this.athleteBeingEdited = null; | |
this.editInProgress = false; | |
} | |
// one grid initialisation, grab the APIs and auto resize the columns to fit the available space | |
onGridReady(params): void { | |
this.api = params.api; | |
this.columnApi = params.columnApi; | |
this.api.sizeColumnsToFit(); | |
} | |
// create some simple column definitions | |
private createColumnDefs(countries: Country[]) { | |
return [ | |
{ | |
field: 'name', | |
editable: true, | |
checkboxSelection: true | |
}, | |
{ | |
field: 'country', | |
cellRenderer: (params) => params.data.country.name, | |
editable: true, | |
cellEditor: 'richSelect', | |
cellEditorParams: { | |
values: countries, | |
cellRenderer: (params) => params.value.name | |
} | |
}, | |
{ | |
field: 'results', | |
valueGetter: (params) => params.data.results.length | |
} | |
] | |
} | |
onRowDoubleClicked(params: any) { | |
if (this.editInProgress) { | |
return; | |
} | |
this.athleteBeingEdited = <Athlete>params.data; | |
this.editInProgress = true; | |
} | |
insertNewRow() { | |
this.editInProgress = true; | |
} | |
rowsSelected() { | |
return this.api && this.api.getSelectedRows().length > 0; | |
} | |
deleteSelectedRows() { | |
const selectRows = this.api.getSelectedRows(); | |
// create an Observable for each row to delete | |
const deleteSubscriptions = selectRows.map((rowToDelete) => { | |
return this.athleteService.delete(rowToDelete); | |
}); | |
// then subscribe to these and once all done, refresh the grid data | |
Observable.forkJoin(...deleteSubscriptions).subscribe(results => this.setAthleteRowData()) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Sport} from './sport.model'; | |
export class Result { | |
id: number; | |
version: number; | |
age: number; | |
year: number; | |
date: string; | |
gold: number; | |
silver: number; | |
bronze: number; | |
sport: Sport; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {StaticData} from './static-data.model'; | |
export class Sport implements StaticData { | |
id: number; | |
name: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface StaticData { | |
name: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Injectable} from '@angular/core'; | |
import {Http, Response} from '@angular/http'; | |
import 'rxjs/add/operator/map' | |
import 'rxjs/add/operator/catch'; | |
import {Observable} from 'rxjs/Observable'; | |
import {Sport} from '../model/sport.model'; | |
import {Country} from '../model/country.model'; | |
import {StaticData} from '../model/static-data.model'; | |
@Injectable() | |
export class StaticDataService { | |
private apiRootUrl = 'http://localhost:8080'; | |
private countriesUrl = this.apiRootUrl + '/countries'; | |
private sportsUrl = this.apiRootUrl + '/sports'; | |
static alphabeticalSort() { | |
return (a: StaticData, b: StaticData) => a.name.localeCompare(b.name); | |
} | |
constructor(private http: Http) { | |
} | |
countries(): Observable<Country[]> { | |
return this.http.get(this.countriesUrl) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
sports(): Observable<Sport[]> { | |
return this.http.get(this.sportsUrl) | |
.map((response: Response) => response.json()) | |
.catch(this.defaultErrorHandler()); | |
} | |
private defaultErrorHandler() { | |
return (error: any) => Observable.throw(error.json().error || 'Server error'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment