2016-04-06 33 views
5

Sto tentando di eseguire un pezzo di convalida di un modulo con Angular2.validazione modulo asincrono angolare2

Sto cercando di scoprire, tramite una chiamata asincrona, se un nome utente è già stato preso e utilizzato nel mio database.

Ecco il mio codice finora:

forma di componente:

import {Component, OnInit} from 'angular2/core'; 
import {FORM_PROVIDERS, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common'; 
import {Http, Headers, RequestOptions} from 'angular2/http'; 
import {ROUTER_DIRECTIVES, Router, RouteParams} from 'angular2/router'; 
import {ControlMessages} from './control.messages'; 
import {ValidationService} from './validation.service'; 

@Component({ 
    selector: 'account-form', 
    templateUrl: './app/account/account.form.component.html', 
    providers: [ROUTER_DIRECTIVES, CaseDataService], 
    directives: [ControlMessages] 
}) 

accountForm: ControlGroup; 

constructor(private _accountService: AccountDataService, 
    private _formBuilder: FormBuilder, private _router: Router, private _params?: RouteParams) { 
    this.model = this._accountService.getUser(); 

    this.accountForm = this._formBuilder.group({ 
     'firstName': ['', Validators.required], 
     'lastName': ['', Validators.required], 
     'userName': ['', Validators.compose([ValidationService.userNameValidator, ValidationService.userNameIsTaken])], 

.... 
} 

Validation Service:

export class ValidationService { 


static getValidatorErrorMessage(code: string) { 
    let config = { 
     'required': 'Required', 
     'invalidEmailAddress': 'Invalid email address', 
     'invalidPassword': 'Invalid password. Password must be at least 6 characters long, and contain a number.', 
     'mismatchedPasswords': 'Passwords do not match.', 
     'startsWithNumber': 'Username cannot start with a number.' 
    }; 
    return config[code]; 
} 

static userNameValidator(control, service, Headers) { 
    // Username cannot start with a number 
    if (!control.value.match(/^(?:[0-9])/)) { 
     return null; 
    } else { 
     return { 'startsWithNumber': true }; 
    } 
} 
    // NEEDS TO BE AN ASYNC CALL TO DATABASE to check if userName exists. 
// COULD userNameIsTaken be combined with userNameValidator?? 

static userNameIsTaken(control: Control) { 
    return new Promise(resolve => { 
     let headers = new Headers(); 
     headers.append('Content-Type', 'application/json') 

     // needs to call api route - _http will be my data service. How to include that? 

     this._http.get('ROUTE GOES HERE', { headers: headers }) 
      .map(res => res.json()) 
      .subscribe(data => { 
       console.log(data); 
       if (data.userName == true) { 
        resolve({ taken: true }) 
       } 
       else { resolve({ taken: false }); } 
      }) 
    }); 
} 
} 

NUOVO CODICE (x2 AGGIORNATO). ControlGroup restituisce undefined.

this.form = this.accountForm; 
    this.accountForm = this._formBuilder.group({ 
     'firstName': ['', Validators.required], 
     'lastName': ['', Validators.required], 
     'userName': ['', Validators.compose([Validators.required, this.accountValidationService.userNameValidator]), this.userNameIsTaken(this.form, 'userName')], 
     'email': ['', Validators.compose([Validators.required, this.accountValidationService.emailValidator])], 
     'password': ['', Validators.compose([Validators.required, this.accountValidationService.passwordValidator])], 
     'confirm': ['', Validators.required] 
    });   
}; 

userNameIsTaken(group: any, userName: string) { 
    return new Promise(resolve => { 

     this._accountService.read('/username/' + group.controls[userName].value) 
      .subscribe(data => { 
       data = data 
       if (data) { 
        resolve({ taken: true }) 
       } else { 
        resolve(null); 
       } 
      }); 
    }) 
}; 

HTML:

<div class="input-group"> 
    <span class="input-group-label">Username</span> 
    <input class="input-group-field" type="text" required [(ngModel)]="model.userName" ngControl="userName" #userName="ngForm"> 
    <control-messages control="userName"></control-messages> 
    <div *ngIf="taken">Username is already in use.</div> 
</div> 

risposta

5

Si dovrebbe definire l'asincrona validatore in questo modo:

'userName': ['', ValidationService.userNameValidator, 
     ValidationService.userNameIsTaken], 

E non con il metodo Validators.compose. È un dato di fatto, ecco quali parametri corrispondono a:

'<field-name>': [ '', syncValidators, asyncValidators ] 

Inoltre si dovrebbe risolvere con null quando il nome utente non è preso invece di `{preso: true}

if (data.userName == true) { 
    resolve({ taken: true }) 
} else { 
    resolve(null); 
} 

See questo articolo per maggiori dettagli (sezione "validazione asincrono per i campi"):

Modifica

Forse la mia risposta non è abbastanza chiara. Hai ancora bisogno di usare Validators.compose ma solo quando si dispone di diversi validatori sincroni:

this.accountForm = this._formBuilder.group({ 
    'firstName': ['', Validators.required], 
    'lastName': ['', Validators.required], 
    'userName': ['', Validators.compose([ 
      Validators.required, 
      this.accountValidationService.userNameValidator 
      ], this.userNameIsTaken], 
    'email': ['', Validators.compose([ 
      Validators.required, 
      this.accountValidationService.emailValidator 
      ]], 
    'password': ['', Validators.compose([ 
      Validators.required, 
      this.accountValidationService.passwordValidator 
      ]], 
    'confirm': ['', Validators.required] 
    });   
}; 

Edit1

È necessario sfruttare la ngFormControl al posto del ngControl uno perché si definiscono i controlli utilizzando la classe FormBuilder.

<div class="input-group"> 
    <span class="input-group-label">Username</span> 
    <input class="input-group-field" type="text" required [(ngModel)]="model.userName" [ngControl]="accountForm.controls.userName" > 
    <control-messages [control]="accountForm.controls.userName"></control-messages> 
    <div *ngIf="accountForm.controls.userName.errors && accountForm.controls.userName.errors.taken">Username is already in use.</div> 
</div> 

veda questo articolo per maggiori informazioni:

+0

Hi Thierry - Grazie. Ho aggiunto il mio codice sopra, ma non riesco ancora a farlo sparare. :( – wjfieseler

+0

Prego, ci sono ancora problemi nel codice Ho aggiornato la mia risposta ... –

+0

Fare progressi Ecco il codice aggiornato, tuttavia, non riesco ad accedere al gruppo di controllo – wjfieseler