Как заставить ScrollIntoView работать без использования setTimeout - PullRequest
0 голосов
/ 04 апреля 2020

Мое приложение имеет два родительских компонента, A и B, каждый в своих собственных модулях (модули A и B, соответственно). Компонент A включает дочерний компонент C из своего собственного модуля (модуль C). Компонент B включает дочерний компонент C (из модуля C) и дочерний компонент B1 из модуля B. Все взаимодействия и поведение между различными родительскими / дочерними компонентами работают нормально. Проблема, с которой я столкнулся, заключается в попытке заставить компонент (B1) прокрутить элемент (elemOfInterest) к вершине области просмотра в ответ на флаг (flagA), который компонент C излучает через службу обмена данными.

Когда я нажимаю кнопку отправки формы дочернего компонента C из шаблона компонента A, я перенаправляем на компонент B. Но scrollToView в дочернем компоненте B1 не работает без setTimeout. После запуска жизненного цикла компонента B1 ngOnInit нажатие кнопки отправки формы компонента C (на этот раз из шаблона компонента B) приводит к тому, что метод scrollToView работает идеально без использования setTimeout. Я не могу понять, почему ngOnInit мешает scrollToView в компоненте B1. Вот мой код:

Компонент C .component.ts:

export class ComponentC implements OnInit {
  constructor(private dataSharing: DataSharingService) {}
  ngOnInit() {
    doSomething(){
      this.dataSharing.transferData({'data':{'flagA':true}});
    }
  }
}

Компонент C .component. html:

<form class="mx-auto" [formGroup]="searchForm" (ngSubmit)="doSomething()">
  <div> … </div>
  <div> <button type="submit">Submit</button> </div>
</form>

КомпонентB1. component.ts

export class ComponentB1 implements OnDestroy, OnInit {
  subscriptions: Subscription = new Subscription();
  constructor(private dataSharing: DataSharingService) {}
  ngOnInit() {
    this.subscriptions.add(
      this.dataSharing.outgoingData$.subscribe(data => {
        this.onSharedData(data);
      })
    )
  }

  onSharedData(data) {
    if (Object.keys(data).length && Object.keys(data['data']).length) {
      switch (true) {
        case data['data']['flagA']:
          this.func1();
          break;
        case data['data']['flagB']:
          this.func2();
          break;
      }
    }
  }

  ngOnDestroy() {this.subscriptions.unsubscribe()}

  func1(){
    //do something simple, like set html element values, etc.
    setTimeout(()=>document.getElementById('elemOfInterest').scrollIntoView({behavior: 'smooth', block: 'start', inline: 'nearest'}));
  }
}

код службы обмена данными:

import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class DataSharingService {
  outgoingData$ = new ReplaySubject(1);
  constructor() {}
  transferData(incomingData: object){
    this.outgoingData$.next(incomingData);
  }
}

Для чего бы то ни было, я также попытался использовать jquery

$('html, body').animate({ scrollTop: $('#elemOfInterest).offset().top }, 'slow')

scrollToView, но все еще требует setTimeout, когда компонент B1 впервые запускается для правильной работы прокрутки. Любая идея, как выполнить sh поведение прокрутки без использования setTimeout?

1 Ответ

0 голосов
/ 04 апреля 2020

outgoingData$ является ReplaySubject, что означает, что он отправляет последнее значение каждому новому подписчику немедленно. Поэтому, если transferData было вызвано ранее приложением, этот субъект воспроизведения уже имеет некоторое значение (обратите внимание, что DataSharingService - это синглтон всего приложения в вашем фрагменте кода, он не воссоздается при навигации).

Теперь ComponentB1 подписывается на него внутри ngOnInit. Тема воспроизведения выдается сразу после подписки - прямо во время выполнения ngOnInit. На данный момент ComponentB1 еще не был обработан Angular, поэтому elemOfInterest, вероятно, еще не существует.

...