Add model driven form form 'forms' app
							parent
							
								
									17c89875dc
								
							
						
					
					
						commit
						1d9c108bfb
					
				|  | @ -5,9 +5,9 @@ | ||||||
|       "title": "Ersten Prototyp mit Angular 2.0 entwickeln", |       "title": "Ersten Prototyp mit Angular 2.0 entwickeln", | ||||||
|       "description": "Der Prototyp soll zeigen, wie Routing und HTTP-Anbindung umgesetzt werden können.", |       "description": "Der Prototyp soll zeigen, wie Routing und HTTP-Anbindung umgesetzt werden können.", | ||||||
|       "tags": [], |       "tags": [], | ||||||
|       "state": "IN_PROGRESS", |       "state": "BACKLOG", | ||||||
|       "assignee": { |       "assignee": { | ||||||
|         "name": "Christoph Höller", |         "name": "Christoph Höllers", | ||||||
|         "email": "" |         "email": "" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  | @ -40,18 +40,18 @@ | ||||||
|       "change_settings": true |       "change_settings": true | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "id" : 302, |       "id": 302, | ||||||
|       "name": "user_edit", |       "name": "user_edit", | ||||||
|       "password": "ea847988ba59727dbf4e34ee75726dc3", |       "password": "ea847988ba59727dbf4e34ee75726dc3", | ||||||
|       "edit_tasks": true, |       "edit_tasks": true, | ||||||
|       "change_settings": false |       "change_settings": false | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "id" : 303, |       "id": 303, | ||||||
|       "name": "user", |       "name": "user", | ||||||
|       "password": "5ebe2294ecd0e0f08eab7690d2a6ee69", |       "password": "5ebe2294ecd0e0f08eab7690d2a6ee69", | ||||||
|       "edit_tasks": false, |       "edit_tasks": false, | ||||||
|       "change_settings": false |       "change_settings": false | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|  | @ -31,6 +31,9 @@ | ||||||
|           <li routerLinkActive="active"> |           <li routerLinkActive="active"> | ||||||
|             <a routerLink='/blog' class="link">Blog</a> |             <a routerLink='/blog' class="link">Blog</a> | ||||||
|           </li> |           </li> | ||||||
|  |           <li routerLinkActive="active"> | ||||||
|  |             <a routerLink='/model-form' class="link">Model Form</a> | ||||||
|  |           </li> | ||||||
|           <!-- |           <!-- | ||||||
|           <li routerLinkActive="active"> |           <li routerLinkActive="active"> | ||||||
|             <a routerLink='/tasks/new' class="link">Neue Aufgabe anlegen</a> |             <a routerLink='/tasks/new' class="link">Neue Aufgabe anlegen</a> | ||||||
|  |  | ||||||
|  | @ -16,6 +16,8 @@ import {SOCKET_IO, AUTH_ENABLED} from './app.tokens'; | ||||||
| import {environment} from '../environments/environment'; | import {environment} from '../environments/environment'; | ||||||
| import {mockIO} from './mocks/mock-socket'; | import {mockIO} from './mocks/mock-socket'; | ||||||
| import {TaskItemComponent} from './tasks/task-list/task-item.component'; | import {TaskItemComponent} from './tasks/task-list/task-item.component'; | ||||||
|  | import {UserService} from "./services/user-service/user.service"; | ||||||
|  | import {ShowErrorComponentModelDriven} from "./show-error/show-error-model-driven.component"; | ||||||
| 
 | 
 | ||||||
| export function socketIoFactory() { | export function socketIoFactory() { | ||||||
|   if (environment.e2eMode) { |   if (environment.e2eMode) { | ||||||
|  | @ -29,6 +31,7 @@ const enableAuthentication = !environment.e2eMode; | ||||||
| @NgModule({ | @NgModule({ | ||||||
|   imports: [BrowserModule, FormsModule, ReactiveFormsModule, appRouting, HttpModule], |   imports: [BrowserModule, FormsModule, ReactiveFormsModule, appRouting, HttpModule], | ||||||
|   providers: [LoginService, |   providers: [LoginService, | ||||||
|  |     UserService, | ||||||
|     UserStore, |     UserStore, | ||||||
|     TaskService, |     TaskService, | ||||||
|     TaskStore, |     TaskStore, | ||||||
|  | @ -41,6 +44,7 @@ const enableAuthentication = !environment.e2eMode; | ||||||
|     routingComponents, |     routingComponents, | ||||||
|     TaskItemComponent, |     TaskItemComponent, | ||||||
|     ShowErrorComponent, |     ShowErrorComponent, | ||||||
|  |     ShowErrorComponentModelDriven, | ||||||
|     APPLICATION_VALIDATORS], |     APPLICATION_VALIDATORS], | ||||||
|   bootstrap: [AppComponent] |   bootstrap: [AppComponent] | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -10,15 +10,16 @@ import {tasksRoutes, tasksRoutingComponents, tasksRoutingProviders} from './task | ||||||
| import {RxDemoComponent} from './rxdemo/rxdemo.component'; | import {RxDemoComponent} from './rxdemo/rxdemo.component'; | ||||||
| import {LoginGuard} from './login/login.guard'; | import {LoginGuard} from './login/login.guard'; | ||||||
| import {blogRoutingComponents} from "./blog/blog.routing"; | import {blogRoutingComponents} from "./blog/blog.routing"; | ||||||
|  | import {ModelDrivenFormComponent} from "./model-driven-form/model-driven-form.component"; | ||||||
| 
 | 
 | ||||||
| export const appRoutes: Routes = [ | export const appRoutes: Routes = [ | ||||||
|   {path: 'dashboard', component: DashboardComponent, data: {title: 'Startseite'}}, |   {path: 'dashboard', component: DashboardComponent, data: {title: 'Startseite'}}, | ||||||
|   {path: '', redirectTo: '/dashboard', pathMatch: 'full'}, |   {path: '', redirectTo: '/dashboard', pathMatch: 'full'}, | ||||||
|   {path: 'settings', component: SettingsComponent, data: { title: 'Einstellungen' }, |   {path: 'settings', component: SettingsComponent, data: { title: 'Einstellungen' }}, | ||||||
|   }, |  | ||||||
|   {path: 'about', component: AboutComponent, data: {title: 'Über uns'}}, |   {path: 'about', component: AboutComponent, data: {title: 'Über uns'}}, | ||||||
|   {path: 'rxdemo', component: RxDemoComponent, data: {title: 'RxJS Demo'}}, |   {path: 'rxdemo', component: RxDemoComponent, data: {title: 'RxJS Demo'}}, | ||||||
|   {path: 'blog', component: BlogComponent, data: {title: 'Blog'}}, |   {path: 'blog', component: BlogComponent, data: {title: 'Blog'}}, | ||||||
|  |   {path: 'model-form', component: ModelDrivenFormComponent, data: { title: 'Model Driven Task Form' }}, | ||||||
| 
 | 
 | ||||||
|   {path: 'login', component: LoginComponent}, |   {path: 'login', component: LoginComponent}, | ||||||
| 
 | 
 | ||||||
|  | @ -34,7 +35,7 @@ export const appRoutes: Routes = [ | ||||||
| export const appRouting = RouterModule.forRoot(appRoutes); | export const appRouting = RouterModule.forRoot(appRoutes); | ||||||
| 
 | 
 | ||||||
| export const routingComponents = [DashboardComponent, SettingsComponent, AboutComponent, LoginComponent, NotFoundComponent, | export const routingComponents = [DashboardComponent, SettingsComponent, AboutComponent, LoginComponent, NotFoundComponent, | ||||||
|   RxDemoComponent, ...blogRoutingComponents, ...tasksRoutingComponents]; |   RxDemoComponent, ModelDrivenFormComponent, ...blogRoutingComponents, ...tasksRoutingComponents]; | ||||||
| 
 | 
 | ||||||
| export const routingProviders = [LoginGuard, | export const routingProviders = [LoginGuard, | ||||||
|   ...tasksRoutingProviders]; |   ...tasksRoutingProviders]; | ||||||
|  |  | ||||||
|  | @ -2,8 +2,8 @@ import {TestBed} from "@angular/core/testing"; | ||||||
| import {LoginComponent} from "./login.component"; | import {LoginComponent} from "./login.component"; | ||||||
| import {RouterTestingModule} from "@angular/router/testing"; | import {RouterTestingModule} from "@angular/router/testing"; | ||||||
| import {LoginService} from "../services/login-service/login-service"; | import {LoginService} from "../services/login-service/login-service"; | ||||||
| import {MockLoginService} from "../mocks/mock-login-service.spec"; |  | ||||||
| import {FormsModule} from "@angular/forms"; | import {FormsModule} from "@angular/forms"; | ||||||
|  | import {MockLoginService} from "../mocks/mock-login-service.spec"; | ||||||
| import Spy = jasmine.Spy; | import Spy = jasmine.Spy; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -32,8 +32,7 @@ describe('Login Component Template Driven Form Test with Spy', () => { | ||||||
| 
 | 
 | ||||||
|     // Login ausfuellen und absenden
 |     // Login ausfuellen und absenden
 | ||||||
|     loginFixture.whenStable().then(() => { |     loginFixture.whenStable().then(() => { | ||||||
|       // Spy anmelden
 |       // Spy anmelden, die eigentliche Methode wird nicht mehr aufgerufen
 | ||||||
|       // sobald Spy angemeldet ist, wird der eigentliche Methodenrumpf nicht mehr aufgerufen
 |  | ||||||
|       const spy = spyOn(loginInstance, 'login'); |       const spy = spyOn(loginInstance, 'login'); | ||||||
| 
 | 
 | ||||||
|       // Formular Eingabe
 |       // Formular Eingabe
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,87 @@ | ||||||
|  | <h2 *ngIf="!task.id">Neue Aufgabe anlegen</h2> | ||||||
|  | <h2 *ngIf="task.id">Aufgabe bearbeiten</h2> | ||||||
|  | 
 | ||||||
|  | <form novalidate [formGroup]="taskForm" | ||||||
|  |       (ngSubmit)="saveTask(taskForm.value)"> | ||||||
|  |   <div class="form-group"> | ||||||
|  |     <label>Titel</label> | ||||||
|  |     <input class="form-control" formControlName="title"/> | ||||||
|  |   </div> | ||||||
|  |   <pjm-show-error text="Titel" path="title"></pjm-show-error> | ||||||
|  |   <div class="form-group"> | ||||||
|  |     <label>Beschreibung</label> | ||||||
|  |     <textarea class="form-control" formControlName="description"> | ||||||
|  |     </textarea> | ||||||
|  |     <pjm-show-error text="Beschreibung" path="description"></pjm-show-error> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <label>Tags</label> | ||||||
|  |   <div formArrayName="tags"> | ||||||
|  |     <div *ngFor="let tag of tagsArray.controls; let i = index"> | ||||||
|  |       <div class="tag-controls" [formGroupName]="i"> | ||||||
|  |         <input class="form-control" formControlName="label"> | ||||||
|  |         <button class="btn btn-danger" (click)="removeTag(i)"> | ||||||
|  |           Tag entfernen | ||||||
|  |         </button> | ||||||
|  |         <pjm-show-error text="Ein Tag" path="tags.{{i}}.label"></pjm-show-error> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  |   <div class="form-group"> | ||||||
|  |     <button class="btn btn-success" (click)="addTag()"> + </button> | ||||||
|  |   </div> | ||||||
|  |   <div class="form-group"> | ||||||
|  |     <label>Status</label> | ||||||
|  |     <select formControlName="state" class="form-control"> | ||||||
|  |         <option *ngFor="let state of model.states" [value]="state"> | ||||||
|  |           {{model.stateTexts[state]}} | ||||||
|  |         </option> | ||||||
|  |     </select> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <div class="checkbox"> | ||||||
|  |     <label> | ||||||
|  |       <input type="checkbox" formControlName="favorite"> | ||||||
|  |       Zu Favoriten hinzufügen | ||||||
|  |     </label> | ||||||
|  |   </div> | ||||||
|  |   <br> | ||||||
|  |   <h4>Zuständiger</h4> | ||||||
|  |   <div formGroupName="assignee"> | ||||||
|  |     <div class="form-group"> | ||||||
|  |       <label>Name</label> | ||||||
|  |       <input type="text" class="form-control" | ||||||
|  |              formControlName="name"/> | ||||||
|  |       <pjm-show-error path="assignee/name" text="Name"></pjm-show-error> | ||||||
|  |     </div> | ||||||
|  |     <div class="form-group"> | ||||||
|  |       <label>E-Mail</label> | ||||||
|  |       <input type="text" class="form-control" | ||||||
|  |              formControlName="email"/> | ||||||
|  |       <pjm-show-error path="assignee.email"></pjm-show-error> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <div *ngIf="taskForm.hasError('assigneeRequired')" | ||||||
|  |          class="alert alert-danger"> | ||||||
|  |       Der Task befindet sich nicht mehr im Backlog <br> | ||||||
|  |       Bitte geben Sie einen Zuständigen an. | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | 
 | ||||||
|  |   <button type="submit" | ||||||
|  |           class="btn btn-default" | ||||||
|  |           [disabled]="!taskForm.valid"> | ||||||
|  |     Aufgabe speichern | ||||||
|  |   </button> | ||||||
|  | </form> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <button (click)="loadTask(1)" | ||||||
|  |         class="btn btn-default"> | ||||||
|  |   Task 1 laden | ||||||
|  | </button> | ||||||
|  | <button (click)="loadTask(2)" | ||||||
|  |         class="btn btn-default"> | ||||||
|  |   Task 2 laden | ||||||
|  | </button> | ||||||
|  | @ -0,0 +1,66 @@ | ||||||
|  | import {ReactiveFormsModule} from '@angular/forms'; | ||||||
|  | import {TestBed, ComponentFixture} from '@angular/core/testing'; | ||||||
|  | import {ModelDrivenFormComponent} from './model-driven-form.component'; | ||||||
|  | import {TaskService} from '../services/task-service/task.service'; | ||||||
|  | import {UserService} from '../services/user-service/user.service'; | ||||||
|  | 
 | ||||||
|  | beforeEach(() => { | ||||||
|  |   TestBed.configureTestingModule({ | ||||||
|  |     imports: [ReactiveFormsModule], | ||||||
|  |     providers: [TaskService, UserService], | ||||||
|  |     declarations: [ModelDrivenFormComponent] | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | describe('Model Driven Form', () => { | ||||||
|  |   it('should validate the title directly', () => { | ||||||
|  | 
 | ||||||
|  |     const fixture = TestBed.createComponent(ModelDrivenFormComponent); | ||||||
|  |     const form = fixture.componentInstance.taskForm; | ||||||
|  | 
 | ||||||
|  |     const titleControl = form.get('title'); | ||||||
|  |     expect(titleControl.errors['required']).toBeTruthy(); // Cannot read property 'errors' of undefined
 | ||||||
|  | 
 | ||||||
|  |     titleControl.setValue('Task'); | ||||||
|  |     expect(titleControl.errors['required']).toBeUndefined(); | ||||||
|  |     const minError = {requiredLength: 5, actualLength: 4}; | ||||||
|  | 
 | ||||||
|  |     expect(titleControl.errors['minlength']).toEqual(minError); | ||||||
|  |     titleControl.setValue('Task 1'); | ||||||
|  |     expect(titleControl.errors).toBeNull(); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |   it('should validate the whole form ', fakeAsync(() => { | ||||||
|  | 
 | ||||||
|  |     const fixture = TestBed.createComponent(ModelDrivenFormComponent); | ||||||
|  | 
 | ||||||
|  |     const form = fixture.componentInstance.taskForm; | ||||||
|  | 
 | ||||||
|  |     console.log(form.patchValue({title: 'Task123'})); | ||||||
|  |     fixture.detectChanges(); | ||||||
|  |     tick(5000); | ||||||
|  |     fixture.detectChanges(); | ||||||
|  |     tick(50000); | ||||||
|  |     console.log(form.valid) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   })); | ||||||
|  | 
 | ||||||
|  |   it('should be able to work with Observable.delay', fakeAsync(() => { | ||||||
|  |     const actuallyDone=false; | ||||||
|  |     const source = Observable.of(true).delay(10); | ||||||
|  |     source.subscribe( | ||||||
|  |       val => { | ||||||
|  |         actuallyDone = true; | ||||||
|  |       }, | ||||||
|  |       err => fail(err) | ||||||
|  |     ); | ||||||
|  |     tick(100); | ||||||
|  |     expect(actuallyDone).toBeTruthy(); // Expected false to be truthy.
 | ||||||
|  | 
 | ||||||
|  |     discardPeriodicTasks(); | ||||||
|  |   })); | ||||||
|  | */ | ||||||
|  |   ); | ||||||
|  | @ -0,0 +1,117 @@ | ||||||
|  | import {Component} from '@angular/core'; | ||||||
|  | import {FormGroup, FormArray, FormControl, FormBuilder, Validators} from '@angular/forms'; | ||||||
|  | import {Task, createInitialTask} from '../models/model-interfaces'; | ||||||
|  | import * as model from '../models/model-interfaces'; | ||||||
|  | import {ifNotBacklogThanAssignee,  emailValidator, UserExistsValidatorDirective} from '../models/app-validators'; | ||||||
|  | import {TaskService} from '../services/task-service/task.service'; | ||||||
|  | import {UserService} from '../services/user-service/user.service'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'pjm-model-driven-form', | ||||||
|  |   templateUrl: './model-driven-form.component.html' | ||||||
|  | }) | ||||||
|  | export class ModelDrivenFormComponent { | ||||||
|  | 
 | ||||||
|  |   model = model; | ||||||
|  |   task: Task = createInitialTask(); | ||||||
|  | 
 | ||||||
|  |   taskForm: FormGroup; | ||||||
|  |   tagsArray: FormArray; | ||||||
|  | 
 | ||||||
|  |   constructor(private taskService: TaskService, | ||||||
|  |               private userService: UserService, | ||||||
|  |               fb: FormBuilder) { | ||||||
|  |     this.taskForm = fb.group({ | ||||||
|  |       title: ['', [Validators.required, Validators.minLength(5)]], | ||||||
|  |       description: ['', Validators.maxLength(2000)], | ||||||
|  |       favorite: [false], | ||||||
|  |       state: ['BACKLOG'], | ||||||
|  |       tags: fb.array([ | ||||||
|  |         this.createTagControl() | ||||||
|  |       ]), | ||||||
|  |       assignee: fb.group({ | ||||||
|  |         name: ['', null, this.userExistsValidatorReused], | ||||||
|  |         email: ['', emailValidator], | ||||||
|  |       }) | ||||||
|  |     }, {validator: ifNotBacklogThanAssignee}); | ||||||
|  | 
 | ||||||
|  |     this.taskForm.valueChanges.subscribe((value) => { | ||||||
|  |       Object.assign(this.task, value); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     this.tagsArray = <FormArray>this.taskForm.controls['tags']; | ||||||
|  | 
 | ||||||
|  |     /* | ||||||
|  |     this.taskForm = new FormGroup({ | ||||||
|  |       title: new FormControl(''), | ||||||
|  |       description: new FormControl(''), | ||||||
|  |       favorite: new FormControl(false), | ||||||
|  |       state: new FormControl('BACKLOG'), | ||||||
|  |       tags: new FormArray([ | ||||||
|  |         new FormGroup({ | ||||||
|  |           label: new FormControl('') | ||||||
|  |         }) | ||||||
|  |       ]), | ||||||
|  |       assignee: new FormGroup({ | ||||||
|  |         name: new FormControl(''), | ||||||
|  |         email: new FormControl('') | ||||||
|  |       }), | ||||||
|  |     });*/ | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private createTagControl(): FormGroup { | ||||||
|  |     return new FormGroup({ | ||||||
|  |       label: new FormControl('', Validators.minLength(3)) | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addTag() { | ||||||
|  |     this.tagsArray.push(this.createTagControl()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   removeTag(i: number) { | ||||||
|  |     this.tagsArray.removeAt(i); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   saveTask(value: any) { | ||||||
|  |     console.log(value); | ||||||
|  |     Object.assign(this.task, value); | ||||||
|  |     this.taskService.saveTask(this.task); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   loadTask(id: number) { | ||||||
|  |     const task : Task = this.taskService.getTask(id); | ||||||
|  |     this.adjustTagsArray(task.tags); | ||||||
|  |     this.taskForm.patchValue(task); | ||||||
|  |     this.task = task; | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private adjustTagsArray(tags: any[]) { | ||||||
|  |     const tagCount = tags ? tags.length : 0; | ||||||
|  |     while (tagCount > this.tagsArray.controls.length) { | ||||||
|  |       this.addTag(); | ||||||
|  |     } | ||||||
|  |     while (tagCount <  this.tagsArray.controls.length) { | ||||||
|  |       this.removeTag(0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   userExistsValidator = (control) => { | ||||||
|  |     return this.userService.checkUserExists(control.value) | ||||||
|  |       .map(checkResult => { | ||||||
|  |         return (checkResult === false) ? {userNotFound: true} : null; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   userExistsValidatorReused = (control) => { | ||||||
|  |     const validator = new UserExistsValidatorDirective(this.userService); | ||||||
|  |     return validator.validate(control); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | import {ModelDrivenFormComponent} from "./model-driven-form.component"; | ||||||
|  | 
 | ||||||
|  | export const modelDrivenFormRoutingComponent = [ModelDrivenFormComponent]; | ||||||
|  | @ -2,8 +2,10 @@ import {Directive, forwardRef} from '@angular/core'; | ||||||
| import { | import { | ||||||
|   FormControl, |   FormControl, | ||||||
|   AbstractControl, |   AbstractControl, | ||||||
|   NG_VALIDATORS |   NG_VALIDATORS, NG_ASYNC_VALIDATORS | ||||||
| } from '@angular/forms'; | } from '@angular/forms'; | ||||||
|  | import {UserService} from "../services/user-service/user.service"; | ||||||
|  | import {Observable} from "rxjs"; | ||||||
| 
 | 
 | ||||||
| export function asyncIfNotBacklogThenAssignee(control): Promise<any> { | export function asyncIfNotBacklogThenAssignee(control): Promise<any> { | ||||||
|   const promise = new Promise((resolve, reject) => { |   const promise = new Promise((resolve, reject) => { | ||||||
|  | @ -82,6 +84,27 @@ export function emailValidator2(control): {[key: string]: any} { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Directive({ | ||||||
|  |   selector: '[pjmUserExistsValidator]', | ||||||
|  |   providers: [ | ||||||
|  |     { | ||||||
|  |       provide: NG_ASYNC_VALIDATORS, | ||||||
|  |       useExisting: forwardRef(() => UserExistsValidatorDirective), multi: true | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | }) | ||||||
|  | export class UserExistsValidatorDirective { | ||||||
|  |   constructor(private userService: UserService) { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   validate(control: AbstractControl): Observable<any> { | ||||||
|  |     return this.userService.checkUserExists(control.value) | ||||||
|  |       .map(userExists => { | ||||||
|  |         return (userExists === false) ? {userNotFound: true} :null; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Directive({ | @Directive({ | ||||||
|   selector: '[emailValidator]', |   selector: '[emailValidator]', | ||||||
|   providers: [ |   providers: [ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | 
 | ||||||
|  | import {Observable} from 'rxjs/Observable'; | ||||||
|  | export class UserService { | ||||||
|  |   checkUserExists(name: string): Observable<boolean> { | ||||||
|  |     const result = name == null || name.toLowerCase() !== 'johnny incognito'; | ||||||
|  |     return Observable.of(result).delay(250); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,61 @@ | ||||||
|  | import {Component, Input, Optional} from '@angular/core'; | ||||||
|  | import {NgForm, FormGroup, FormGroupDirective} from '@angular/forms'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'pjm-show-error', | ||||||
|  |   template: ` | ||||||
|  |     <div *ngIf="errorMessages" class="alert alert-danger"> | ||||||
|  |         <div *ngFor="let errorMessage of errorMessages"> | ||||||
|  |             {{errorMessage}} | ||||||
|  |         </div> | ||||||
|  |     </div>` })
 | ||||||
|  | export class ShowErrorComponentModelDriven { | ||||||
|  | 
 | ||||||
|  |   @Input('path') path; | ||||||
|  |   @Input('text') displayName = ''; | ||||||
|  | 
 | ||||||
|  |   constructor(@Optional() private ngForm: NgForm, | ||||||
|  |               @Optional() private formGroup: FormGroupDirective) { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   get errorMessages(): string[] { | ||||||
|  |     let form: FormGroup; | ||||||
|  |     if (this.ngForm) { | ||||||
|  |       form = this.ngForm.form; | ||||||
|  |     } else  { | ||||||
|  |       form = this.formGroup.form; | ||||||
|  |     } | ||||||
|  |     const control = form.get(this.path); | ||||||
|  |     const messages = []; | ||||||
|  |     if (!control || !(control.touched) || !control.errors) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |     for (const code in control.errors) { | ||||||
|  |       if (control.errors.hasOwnProperty(code)) { | ||||||
|  |         const error = control.errors[code]; | ||||||
|  |         let message = ''; | ||||||
|  |         switch (code) { | ||||||
|  |           case 'required': | ||||||
|  |             message = `${this.displayName} ist ein Pflichtfeld`; | ||||||
|  |             break; | ||||||
|  |           case 'minlength': | ||||||
|  |             message = `${this.displayName} muss mindestens ${error.requiredLength} Zeichen enthalten`; | ||||||
|  |             break; | ||||||
|  |           case 'maxlength': | ||||||
|  |             message = `${this.displayName} darf maximal ${error.requiredLength} Zeichen enthalten`; | ||||||
|  |             break; | ||||||
|  |           case 'invalidEMail': | ||||||
|  |             message = `Bitte geben Sie eine gültige E-Mail-Adresse an`; | ||||||
|  |             break; | ||||||
|  |           case 'userNotFound': | ||||||
|  |             message = `Der eingetragene Benutzer existiert nicht.`; | ||||||
|  |             break; | ||||||
|  |           default: | ||||||
|  |             message = `${name} ist nicht valide`; | ||||||
|  |         } | ||||||
|  |         messages.push(message); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return messages; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -4,7 +4,6 @@ import {EditTaskComponent} from './edit-task/edit-task.component'; | ||||||
| import {EditTaskGuard} from './edit-task/edit-task.guard'; | import {EditTaskGuard} from './edit-task/edit-task.guard'; | ||||||
| import {TaskOverviewComponent} from './task-overview/task-overview.component'; | import {TaskOverviewComponent} from './task-overview/task-overview.component'; | ||||||
| import {TasksComponent} from './tasks.component'; | import {TasksComponent} from './tasks.component'; | ||||||
| import {LoginGuard} from '../login/login.guard'; |  | ||||||
| 
 | 
 | ||||||
| export const tasksRoutes: Routes = [{ | export const tasksRoutes: Routes = [{ | ||||||
|   path: '', component: TasksComponent, |   path: '', component: TasksComponent, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue