Arhn - архитектура программирования

асинхронная проверка формы angular2

Я пытаюсь выполнить часть проверки формы с помощью Angular2.

Я пытаюсь выяснить с помощью асинхронного вызова, было ли имя пользователя уже занято и использовано в моей базе данных.

Вот мой код:

КОМПОНЕНТ ФОРМЫ:

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])],

....
}

СЛУЖБА ВАЛИДАЦИИ:

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 }); }
            })
    });
}
}

НОВЫЙ КОД (ОБНОВЛЕНО x2). ControlGroup возвращает неопределенное значение.

    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>
06.04.2016

Ответы:


1

Вы должны определить свой асинхронный валидатор следующим образом:

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

А не методом Validators.compose. Собственно говоря, вот каким параметрам соответствуют:

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

Кроме того, вы должны разрешать с нулевым значением, когда имя пользователя не занято вместо `{taken: false}

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

Подробнее см. в этой статье (раздел «Асинхронная проверка полей»):

Изменить

Возможно, мой ответ недостаточно ясен. Вам по-прежнему нужно использовать Validators.compose, но только когда у вас есть несколько синхронных валидаторов:

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]
  });         
};

Изменить1

Вам нужно использовать ngFormControl вместо ngControl, потому что вы определяете свои элементы управления, используя класс 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>

Смотрите эту статью для более подробной информации:

06.04.2016
  • Привет, Тьерри. Спасибо. Я добавил свой код выше, но все еще не могу заставить его сработать. :( 07.04.2016
  • Пожалуйста! Да, в вашем коде все еще есть проблемы. Я обновил свой ответ... 07.04.2016
  • Продвигается. Вот обновленный код, однако я не могу получить доступ к группе управления. 07.04.2016
  • Я обновил свой ответ. Вы должны использовать ngFormControl вместо ngControl. Что такое control-messages? Пользовательский компонент, который вы внедрили? 07.04.2016
  • Да, контрольные сообщения — это настраиваемый компонент, который я реализовал. Тем не менее, я пытаюсь сначала заставить *ngIf работать, прежде чем пытаться включить новую проверку в управляющие сообщения. 07.04.2016
  • Пытаюсь поболтать с вами, но недостаточно репутации. ;-) Похоже, я получаю сообщение об ошибке. VM27684:76 ИСКЛЮЧЕНИЕ: Не удается найти элемент управления «[object Object]» в [model.userName в AccountFormComponent@16:70]. Это связано с тем, что моя форма использует [ngFormModel] вместо варианта Ng-Control? 07.04.2016
  • Ваше сообщение немного странное, так как model.userName соответствует ngModel, а не элементам управления. Не могли бы вы проверить выражения, которые вы используете для элементов управления и внутри ngIf? 07.04.2016
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..