Сообщение об ошибке проверки не отображается для пользовательской проверки в Angular 2

У меня есть регистрационная форма, в которой пользователю необходимо указать имя пользователя. Когда клиент вводит имя пользователя, я хочу показать сообщение об ошибке проверки, если это имя пользователя уже существует в БД или нет.

register.html

 <-- code here-->
<div class="form-group">
            <label for="username" class="col-sm-3 control-label">UserName</label>
            <div class=" col-sm-6">
             <input type="text" ngControl="userName" maxlength="45" class="form-control" [(ngModel)]="parent.userName" placeholder="UserName" #userName="ngForm" required data-is-unique/>
                <validation-message control="userName"></validation-message>
            </div>
        </div>
 <--code here-->

register.component.ts

import {Component} from 'angular2/core';
import {NgForm, FormBuilder, Validators, FORM_DIRECTIVES} from  'angular2/common';
   import {ValidationService} from '../services/validation.service';
  import {ValidationMessages} from './validation-messages.component';
  @Component({
    selector: 'register',
    templateUrl: './views/register.html',
    directives: [ROUTER_DIRECTIVES, ValidationMessages, FORM_DIRECTIVES],
    providers: []
   })
  export class ParentSignUpComponent {
   parentSignUpForm: any;
   constructor(private _formBuilder: FormBuilder) {
    this._stateService.isAuthenticatedEvent.subscribe(value => {
        this.onAuthenticationEvent(value);
    });
    this.parent = new ParentSignUpModel();
    this.parentSignUpForm = this._formBuilder.group({
        'firstName': ['', Validators.compose([Validators.required, Validators.maxLength(45), ValidationService.nameValidator])],
        'middleName': ['', Validators.compose([Validators.maxLength(45), ValidationService.nameValidator])],
        'lastName': ['', Validators.compose([Validators.required, Validators.maxLength(45), ValidationService.nameValidator])],
        'userName': ['', Validators.compose([Validators.required, ValidationService.checkUserName])]
    });
}
}

validation-message.component

import {Component, Host} from 'angular2/core';
import {NgFormModel} from 'angular2/common';
import {ValidationService} from '../services/validation.service';

@Component({
   selector: 'validation-message',
   inputs: ['validationName: control'],
   template: `<div *ngIf="errorMessage !== null" class="error-message"> {{errorMessage}}</div>`
    })
     export class ValidationMessages {
    private validationName: string;
    constructor (@Host() private _formDir: NgFormModel) {}
    get errorMessage() {
    let control = this._formDir.form.find(this.validationName);
    for (let propertyName in control.errors) {
        if (control.errors.hasOwnProperty(propertyName) && control.touched)   {
            return ValidationService.getValidatorErrorMessage(propertyName);
        }
      }
    return null;
  }
 }

валидация-service.ts

  import {Injectable, Injector} from 'angular2/core';
  import {Control} from 'angular2/common';
  import {Observable} from 'rxjs/Observable';
  import {Http, Response, HTTP_PROVIDERS} from 'angular2/http';
  import 'rxjs/Rx';       
  interface ValidationResult {
    [key:string]:boolean;
    }
 @Injectable()
 export class ValidationService {
   static getValidatorErrorMessage(code: string) {
    let config = {
      'required': 'This field is required!',
      'maxLength': 'Field is too long!',
      'invalidName': 'This field can contain only alphabets, space, dot, hyphen, and apostrophe.',
      'userAlreadyInUse': 'UserName selected already in use! Please try another.'
};
return config[code];
}
static checkUserName(control: Control): Promise<ValidationResult> {
    let injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
    let http = injector.get(Http);
    let alreadyExists: boolean;
    if (control.value) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            http.get('/isUserNameUnique/' + control.value).map(response => response.json()).subscribe(result => {
                if (result === false) {
                    resolve({'userAlreadyInUse': true});
                } else {
                    resolve(null);
                }
            });
        }, 1000);
    });
    }
}
 }

Теперь, когда я запускаю и даю имя пользователя, которое уже существует в БД, значение переменной «результат» я получаю как ложное, что ожидается и правильно. Но сообщение об ошибке проверки не отображается. Я могу запустить и получить сообщение об ошибке проверки для других пользовательских функций проверки. Я использую Angular 2.0.0-beta.15. Может ли кто-нибудь помочь мне понять, в чем может быть проблема?


person revathi    schedule 02.06.2016    source источник


Ответы (2)


Есть некоторые известные проблемы с асинхронной проверкой.


Этот код можно упростить

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      http.get('/isUserNameUnique/' + control.value).map(response => response.json())
      .subscribe(result => {
        if (result === false) {
          resolve({'userAlreadyInUse': true});
        } else {
          resolve(null);
        }
      });
    }, 1000);
  });

to

  return http.get('/isUserNameUnique/' + control.value).map(response => response.json())
  .timeout(200, new Error('Timeout has occurred.'));
  .map(result => {
    if (result === false) {
      resolve({'userAlreadyInUse': true});
    } else {
      resolve(null);
    }
  }).toPromise();

Не забудьте импортировать map, timeout и toPromise.

Если вы используете subscribe() вместо then() на сайте вызывающего абонента, вы можете опустить событие toPromise()

person Günter Zöchbauer    schedule 02.06.2016
comment
return http.get('/isUserNameUnique/' + control.value).map(response =› response.json()) .timeout(200, новая ошибка('Произошло время ожидания.')); .subscribe(result =› { if (result === false) { разрешить ({'userAlreadyInUse': true}); } else { разрешить (null); } }); ты это имел в виду? потому что я не могу тогда увидеть или подписаться на ваш фрагмент кода. Спасибо, что сообщили мне больше об этой проблеме. Я ходил по ссылкам и не мог найти подсказки. - person revathi; 02.06.2016
comment
then или subscribe должен использоваться вызывающим абонентом checkUserName checkUserName(c).then(...) или checkUserName(c).subscribe(...). Это то, что формы Angular делают для асинхронных валидаторов (я не знаю, требуют ли асинхронные валидаторы возвращать Promise или они также работают с Observable) - person Günter Zöchbauer; 02.06.2016
comment
Моя проблема решилась. Это не из-за этого метода checkUserName. если вы посмотрите на это - 'userName': ['', Validators.compose([Validators.required, ValidationService.checkUserName])] }); -- вы можете видеть, что я использую синхронную и асинхронную проверки вместе. Когда я изменил метод для checkUserName, например «Validators.composeAsync (ValidationService.checkUserName)» вместо метода Validators.compose, появилось сообщение об ошибке. :) - person revathi; 02.06.2016
comment
Отлично, спасибо за отзыв. Просто опубликуйте это как ответ и примите его, чтобы было очевидно, что на этот вопрос дан ответ и он решен. - person Günter Zöchbauer; 02.06.2016

если вы посмотрите на это -

'userName': ['', Validators.compose([Validators.required, ValidationService.checkUserName])] });

-- вы можете видеть, что я использую синхронную и асинхронную проверки вместе. Когда я изменил метод для checkUserName, например 'Validators.composeAsync(ValidationService.checkUserName)' вместо метода Validators.compose, появилось сообщение об ошибке.

person revathi    schedule 02.06.2016