возвращаемое значение подписки angular2

Я подписываюсь на службу HTTP-запросов в моем методе validateUsernameIsUnique. Я пытаюсь манипулировать возвращаемым значением validateUsernameIsUnique() на основе кода внутри подписки. Я прочитал несколько статей для начинающих об асинхронном поведении. Поэтому я знаю, что приведенный ниже код не работает, потому что return ret; не определено. К сожалению, я не смог понять, как добиться того, что я пытаюсь сделать.

@Injectable()
export class ValidateService {

  constructor(private _authService: AuthService) { }

...

  validateUsernameIsUnique = (c: FormControl) => {

    let ret;
    if (c.value.length >= 3) {

        this._authService.uniqueUser({ username: c.value }).subscribe(data => {

          if (!data.success) {   // Username already exists       
            ret = { usernameIsTaken: true };          
          }
          else 
            ret = null;
        })

        return ret;
    }

  }

}

Служба аутентификации, на которую я подписываюсь, выглядит так:

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import 'rxjs/add/operator/map';


@Injectable()
export class AuthService {

  authToken: any;
  user: any;

  constructor(private _http: Http) { } 

  uniqueUser(user) {

    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return this._http.post('http://localhost:3000/users/username', user, { headers: headers })
      .map(res => res.json());
  }
}

Обновление 1:

Измененный код, как указано в комментариях к

  validateUsernameIsUnique = (c: FormControl) => {        
    if (c.value.length >= 3) {     
      return this._authService.uniqueUser({ username: 'zomh' }).map(res =>          
      {             
        if (!res.success) {   // Username already exists              
          return { usernameIsTaken: true };    
        }
        else
        {

          return null;
        }
      });

    }

  }

И звонок выглядит так

ngOnInit() {        
      this.frmRegisterUser = new FormGroup({
      name: new FormControl('',[Validators.required]),
      username: new FormControl('',[Validators.required, this._validateService.validateUsernameIsUnique, Validators.minLength(3), this._validateService.validateUsernamePattern]),
      email: new FormControl('',[Validators.required, this._validateService.validateEmailPattern]),
      password: new FormControl('',[Validators.required, Validators.minLength(6)]),
      acceptTerms: new FormControl(false,[Validators.required])
    });

Теперь я получаю объект, который выглядит так: Объект

Извините, но я все еще не понимаю, где я могу найти сопоставленные возвращаемые значения, например. { usernameIsTaken: true }

Обновление 2 @pixelbits

Это не сработало сразу: я не знаю, как это правильно отлаживать?, так как console.logs не будет печататься по асинхронным причинам во внутренних функциях. Я попытался указать имя пользователя «zomh», которое уже есть в базе данных (не уникально).

  uniqueName(): AsyncValidatorFn {
    console.log('i am here');
    return (control:AbstractControl): Promise<ValidationResult> => {

      let q = new Promise<ValidationResult>(
        (resolve, reject)=>  { 
            var name = 'zomh';
            if (name == '') {
              resolve(null);
            }
            else {

              this._authService.uniqueUser({ username: 'zomh' })
                .map(t=>t.json())
                .subscribe(response=> {
                    if (response.success === false) {

                      resolve(response);  
                    }

                      else 
                        resolve(null);

                });
            }
        });

        return q;
    }
  }

Я получаю "i am here" в консоли, но это почти все. Я получаю нуль, хотя этого не должно быть с существующим именем пользователя. Я могу убедиться, что AuthService работает правильно (протестировал его с базовой подпиской и именем пользователя «zomh»).


person user3169083    schedule 23.02.2017    source источник
comment
Ваш код не работает, потому что .subscribe асинхронный. Наблюдаемые в целом асинхронны, поэтому вы не можете возвращать их данные за пределы их области.   -  person Adam    schedule 24.02.2017
comment
comment
Я думаю, что вы смешиваете синхронизирующие и асинхронные валидаторы в третьем параметре. Второй параметр предназначен для валидаторов синхронизации, третий параметр — для асинхронных валидаторов. Вам нужно отделить их.   -  person pixelbits    schedule 24.02.2017


Ответы (1)


Похоже, вам нужно реализовать асинхронный валидатор как фабрику:

import {  AbstractControl, AsyncValidatorFn } from '@angular/forms';
import { Http } from '@angular/http';
import { Injectable, Inject } from '@angular/core';
import 'rxjs/add/operator/map';


interface ValidationResult {
 [key:string]:boolean;
}
@Injectable()
export class ValidationService {
   constructor(private _authService: AuthService)  {

  }
  validateUsernameIsUnique(): AsyncValidatorFn {
    return (control:AbstractControl): Promise<ValidationResult> => {

      let q = new Promise<ValidationResult>(
        (resolve, reject)=>  { 
            var name = control.value;
            if (name == '') {
              resolve(null);
            }
            else {

              this._authService.uniqueUser({ username: control.value })
                //.map(t=>t.json()) // Auth Service already returning json
                .subscribe(response=> {
                    if (response.success === false) 
                        resolve({ usernameIsTaken: true });                  
                      else 
                        resolve(null);

                });
            }
        });


        return q;
    }
  }
}

Убедитесь, что вы передаете валидатор в качестве третьего параметра (вот куда идут асинхронные валидаторы, второй параметр для синхронных валидаторов)

    this.formGroup = this.fb.group( {
     'username': ['hello',, this.validationService.validateUsernameIsUnique()]
    });
person pixelbits    schedule 23.02.2017
comment
Попробую это реализовать. Я своего рода новичок, и большинство, что я вижу здесь, для меня - колдовство. Сомневаюсь, что когда-нибудь смогу понять это :/. Хотя заранее спасибо - person user3169083; 24.02.2017
comment
Это фабричная функция, поэтому ее нужно вызывать - см. обновленный ответ. - person pixelbits; 24.02.2017
comment
Теперь он работает, я отредактировал 2 небольшие вещи в вашем коде. Большое спасибо, я отмечу это как ответ. Тем не менее я должен узнать кое-что о фабриках и обещаниях. Благодарю вас! - person user3169083; 24.02.2017