Угловая подписка Неопределенная проблема с проверкой - PullRequest
0 голосов
/ 08 июня 2019

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

Прежде всего, я хочу использовать его для возможности редактирования пользовательского профиля.Поля ввода должны быть загружены с текущими значениями профиля.То, что я хочу сделать через валидаторы, чтобы не было ошибок валидации.

Поэтому в constructor() моего profile.component.ts я вызываю этот метод:

readProfileData() {
 this.userService.getProfile()
   .pipe(first())
   .subscribe(
     userData => {
       this.firstname = userData.firstName;
       this.lastname = userData.lastName;
       this.username = userData.username;
       this.email = userData.email;
       this.dateOfBirth = userData.dateOfBirth;
       this.country = userData.location;
       this.profileImage = userData.profileImage;
       this.gender = userData.gender;
       this.lastUpdated = userData.lastUpdated;
       this.activated = userData.activated;
       this.userId = userData.userId;
       this.userService.profileImageUpdate$.next(this.profileImage);
     });
}

МетодgetProfile() get call:

getProfile() {
    return this.http.get<any>(this.GET_PROFILE_API);
}

В моем методе ngOnInit() я вызываю сборку формы:

public buildForm() {
 this.editForm = this.form.group({
   username: [this.username, [Validators.required, Validators.minLength(this.minLength), CustomValidators.validateCharacters], AlreadyTakenValidator.checkUsername(this.registrationService)],
   email: [this.email, [Validators.required, Validators.email, CustomValidators.validateCharacters], AlreadyTakenValidator.checkEmail(this.registrationService)],
   oldPassword: ['', [Validators.required]],
   newPassword: ['', [Validators.required]],
   newPasswordConf: ['', [Validators.required]],
   firstname: [this.firstname, [Validators.required, NoWhitespaceValidator()]],
   lastname: [this.lastname, [Validators.required, NoWhitespaceValidator()]],
   country: ['', [Validators.required]],
   dateOfBirth: ['', [Validators.required]],
   gender: ['', [Validators.required]],
 }
 , {
     validator: MustMatch('newPassword', 'newPasswordConf')
   })
}

Итак, как вы можете себе представить, проблема в том, что никакие значения неотображается в полях ввода, потому что они не определены.Если я пишу свои собственные значения непосредственно в поле перед валидатором, это работает.Так что это проблема подписки.Мне действительно нужны переменные для заполнения.

Я прочитал очень много вещей с map to res.json или что-то с toPromise, но ничего, что мне помогло.Я понимаю проблему, что она асинхронная и еще не загружена, но я не знаю, как предотвратить это, не позволяя пользователю застрять в процессе загрузки.

Ответы [ 2 ]

1 голос
/ 08 июня 2019

Как насчет того, чтобы мы делегировали ответственность за создание формы службе.

Таким образом, служба будет:

  1. Получать данные из API.
  2. Создайте форму.
  3. Заполните форму данными, которые она выбрала.
  4. Верните форму.

Компонент просто будет использовать форму.Имея это в виду, вот как вы реализуете сервис:

import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { FormBuilder, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class UserService {

  GET_PROFILE_API = 'https://jsonplaceholder.typicode.com/users/1';

  constructor(
    private readonly http: HttpClient,
    private readonly fb: FormBuilder
  ) { }

  getUserForm() {
    return this.getProfile()
      .pipe(
        map(userProfile => this.generateUserForm(userProfile))
      );
  }

  private generateUserForm(user) {
    return this.fb.group({
      name: [user.name, Validators.required],
      username: [user.username, Validators.required],
      email: [user.email, Validators.required],
      phone: [user.phone, Validators.required],
      website: [user.website, Validators.required],
    });
  }

  private getProfile() {
    return this.http.get<any>(this.GET_PROFILE_API);
  }

}

Ваш компонент будет выглядеть примерно так:

Шаблон:

<form 
  *ngIf="form$ | async as form" 
  [formGroup]="form">
  <div class="form-group">
    <label for="exampleInputEmail1">Name</label>
    <input type="text" formControlName="name" class="form-control" placeholder="Enter Name">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Username</label>
    <input type="text" formControlName="username" class="form-control" placeholder="Enter Username">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Email</label>
    <input type="text" formControlName="email" class="form-control" placeholder="Enter Email">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Phone</label>
    <input type="text" formControlName="phone" class="form-control" placeholder="Enter Phone">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Website</label>
    <input type="text" formControlName="website" class="form-control" placeholder="Enter Website">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

ИКласс компонента:

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { UserService } from './user.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form$: Observable<FormGroup>;

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.form$ = this.userService.getUserForm();
  }

}

Вот вам Рабочий образец StackBlitz для вашей ссылки.

0 голосов
/ 08 июня 2019

В вашем случае это происходит потому, что http.get является асинхронным по своей природе, это означает, что до того момента, как вы получите значения в ответе вашего подписчика, он уже вызвал бы ваш "buildForm ()"

Чтобы исправить то же самое, можно сделать любое из следующего:

a) Вызовите свой buildForm () внутри подписки.

b) Вы можете использовать async-await при определении метода readProfileData (), также ожидать при вызове функции readProfileData () и затем вызывать buildForm ()

в) Вы можете преобразовать их в обещание и решить только тогда, когда получите ответ

Вы можете сослаться:

глубокое погружение в асинхронное ожидание

выполнение обещаний

...