Angular 7: почему я должен дважды вызывать мой метод подписки, чтобы он вступил в силу - PullRequest
0 голосов
/ 23 марта 2019

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

Я создаю службу проверки, предназначенную для проверки доступности имени пользователя.Служба validationService вызывается при отправке формы и отображает сообщение об ошибке, если имя пользователя недоступно.Проблема в том, что мне нужно дважды отправить форму, чтобы она заработала.

validationService выполняет http-вызов бэкэнда, который возвращает логическое значение.У меня есть локальная переменная «availableUsername», для которой я хочу установить результат, чтобы я мог использовать его в другом месте.Внутри функции подписки все работает нормально, я получаю результат и устанавливаю его в эту переменную.Но когда я покидаю область действия метода подписки, переменная не определена.Но когда я снова вызываю submit, это работает.

Я добавил ниже службы validationService и userService.

validationService.ts

import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';

import { AlertService } from './../services/alert.service';
import { UserService } from './../services/user.service';

@Injectable({
  providedIn: 'root'
})
export class ValidationService {

  availableUsername: boolean;
  availableEmail: boolean;

  constructor(
    private alertService: AlertService,
    private userService: UserService
    ) { }

  validateUsername(controls: any): boolean {

    const username = controls.username.value;

    this.isUsernameAvailable(username);

    if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);
      return true;
    }
    return false;
  }

  private isUsernameAvailable(username: string) {

    if (username === undefined || username === '') {
      return;
    }

    this.userService.isUserNameAvailable(username)
      .subscribe((result) => {
        this.availableUsername = result;
    },
    error => {
      this.alertService.error(error);
      return;
    });
  }

}

userService.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { environment } from './../../environments/environment';

@Injectable({ providedIn: 'root' })
export class UserService {

  apiUrl: string = environment.apiUrl;

  constructor(private http: HttpClient) { }

  isUserNameAvailable(username: string) {
    return this.http.get<boolean>(`${this.apiUrl}/users/checkUsernameAvailability/${username}`);
  }

}

Ответы [ 2 ]

0 голосов
/ 23 марта 2019
this.isUsernameAvailable(username); 

Когда приведенная выше строка кода выполняется, она будет выполняться асинхронно, поэтому перед присвоением значения this.availableUsername = result; по подписке будет работать код ниже

 if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);
      return true;
    }
    return false;
  }

Чтобы избежать этого, нужно проверить это условие внутри подписки, как это

     this.userService.isUserNameAvailable(username)
          .subscribe((result) => {
            this.availableUsername = result;
        },
        error => {
          this.alertService.error(error);
          return;
        }
         ()=>{
 if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);

    }
}
);
      }

    }
0 голосов
/ 23 марта 2019

Проблема в вашем коде заключается в том, что вы пытаетесь использовать асинхронный поток синхронно значение свойства availableUsername будет установлено только при вызове обратного вызова subscribe, что приведет квскоре после if (!this.availableUsername).

, в этом случае вы можете использовать asyncValidartor , созданный для этих случаев.

Другая (менее рекомендуемая) альтернатива - заставить ваш код работатьсинхронно используйте async и await.

...