【问题标题】:angular2 subscribe return valueangular2 订阅返回值
【发布时间】:2017-07-14 13:49:30
【问题描述】:

我确实在 validateUsernameIsUnique 方法中订阅了 http 请求服务。我正在尝试根据订阅内的代码来操作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:

将 cmets 中提到的代码更改为

  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",但仅此而已。即使它不应该使用现有的用户名,我也会返回 null。我可以验证 AuthService 是否正常工作(使用基本订阅和用户名“zomh”对其进行了测试)。

【问题讨论】:

  • 您的代码不起作用,因为.subscribe 是异步的。 Observables 完全是异步的,所以你不能在它们的范围之外返回它们的数据。
  • 我认为您在第三个参数中混合了同步和异步验证器。第二个参数用于同步验证器,第三个参数用于异步验证器。您需要将它们分开。

标签: angular typescript subscribe


【解决方案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()]
    });

【讨论】:

  • 让我尝试实现这一点。我有点初学者,我在这里看到的大多数对我来说都是巫术。我怀疑我是否能理解这一点:/。不过提前谢谢
  • 它是一个工厂函数,因此需要调用它 - 请参阅更新的答案。
  • 它现在可以工作了,我确实编辑了您的代码的 2 个小东西。非常感谢我将其标记为答案 ofc。我仍然必须学习一些关于工厂和承诺的知识。谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-11-19
  • 2018-04-27
  • 1970-01-01
  • 2019-12-09
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 2017-10-28
相关资源
最近更新 更多