Angular & Rx JS Повторяющийся код с подписками - перенос кода на услугу, типы и отмена подписки - PullRequest
1 голос
/ 14 июля 2020

У меня есть дублированный код в нескольких моих компонентах ... Я упростил код, но в основном это набор строк:

// code in my components
phoneNumberChanges$: any;

ngOnInit(): void {
    // watch the phone number
    this.subscribeToPhoneNumberChanges();
}


ngOnDestroy(): void {
    if (this.phoneNumberChanges$) {
      this.phoneNumberChanges$.unsubscribe();
    }
}

subscribeToPhoneNumberChanges(): void {
    const phoneNumberControl = this.addPhoneForm.controls['phoneNumber'];
    this.phoneNumberChanges$ = phoneNumberControl.valueChanges
      .pipe(debounceTime(0))
      .subscribe((phoneNumber) => {
        if (phoneNumber.length < 5 || phoneNumber.charAt(0) !== '+') {
          // set the error message
          // set the form control to invalid
          phoneNumberControl.setErrors({ invalid: true });
        } else if (phoneNumberControl.errors && phoneNumberControl.errors.invalid) {
          delete phoneNumberControl.errors.invalid;
        }
      });
  }

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

// service file
subscribeToPhoneNumberChanges(parentForm: FormGroup): any {
    const phoneNumberControl = parentForm.controls['phoneNumber'];
    return phoneNumberControl.valueChanges
      .pipe(debounceTime(0))
      .subscribe((phoneNumber) => {
        if (phoneNumber.length < 5 || phoneNumber.charAt(0) !== '+') {
          // set the error message
          // set the form control to invalid
          phoneNumberControl.setErrors({ invalid: true });
        } else if (phoneNumberControl.errors && phoneNumberControl.errors.invalid) {
          delete phoneNumberControl.errors.invalid;
        }
      });
  }

, тогда в моем исходном компоненте я мог бы вызвать метод обслуживания

// component file
ngOnInit(): void {
    // watch the phone number
    this.phoneNumberChanges$ = this.subscribeToPhoneNumberChanges();
}

похоже, это работает, но у меня есть три вопроса ...

  1. В моем файле компонентов, какой тип я должен указать для своей собственности phoneNumberChanges$?

  2. какой тип возврата мой метод обслуживания, я не могу просто вернуть? subscribeToPhoneNumberChanges(parentForm. FormGroup): any

  3. Должен ли я помещать отказ от подписки в свой компонент или служебный файл?

Сохранять ли это в файле компонента

ngOnDestroy(): void {
    if (this.phoneNumberChanges$) {
      this.phoneNumberChanges$.unsubscribe();
    }
}

или в служебный файл что то добавить? Я предполагаю, что файл компонента из-за крючка жизненного цикла?

заранее большое спасибо, извините за такие глупые вопросы, и если я не объяснил себя хорошо, скажите это, и я переделаю свой вопрос

1 Ответ

0 голосов
/ 14 июля 2020

tldr;

  1. Observable<any>
  2. Observable<any>
  3. Файл компонента

I позволит компоненту выполнять подписку. В противном случае вы не сможете добавить пользовательский лог c (например, больше операторов) в свой osbervable, не подписавшись на второе время. Это хорошая практика, поскольку наблюдаемые объекты ленивы, и вызывающий может решить, когда он хочет подписаться. Измените метод обслуживания на этот:

  subscribeToPhoneNumberChanges(parentForm: FormGroup): Observable<any> {
    const phoneNumberControl = parentForm.controls["phoneNumber"];
    return phoneNumberControl.valueChanges.pipe(
      debounceTime(0),
      tap(phoneNumber => {
        if (phoneNumber.length < 5 || phoneNumber.charAt(0) !== "+") {
          // set the error message
          // set the form control to invalid
          phoneNumberControl.setErrors({ invalid: true });
        } else if (
          phoneNumberControl.errors &&
          phoneNumberControl.errors.invalid
        ) {
          delete phoneNumberControl.errors.invalid;
        }
      })
    );
  }

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

  ngOnInit(): void {
    this.phoneNumberChanges$ = this.service.subscribeToPhoneNumberChanges();
    this.subscription = this.phoneNumberChanges$.subscribe();
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

Или я предпочитаю создать наблюдаемый объект уведомления об уничтожении:

 private destroy$ = new Subject<boolean>();

  ngOnInit(): void {
    this.phoneNumberChanges$ = this.service.subscribeToPhoneNumberChanges();
    this.phoneNumberChanges$
      .pipe(takeUntil(this.destroy$))
      .subscribe();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

Другой возможностью было бы передать notifier Observable объекту service и добавьте туда оператор takeUntil.

...