Angular просмотр ng Не отображать наблюдаемую коллекцию после ее обновления в ngOnInit - PullRequest
1 голос
/ 06 марта 2020

У меня есть приложение Angular 9, использующее NGRX, которое по большей части использует наблюдаемые / субъекты и трубу assyn c.

У меня есть компонент navbar, который имеет следующее HTML:

<ul class="navbar-nav">
    <li class="nav-item" *ngFor="let menuItem of navbarMenuItems | async">
      <a id="{{ menuItem.id }}" [routerLink]="menuItem.routerLink" class="nav-link">
        <span><i class="icon" [className]="menuItem.iconClass"></i>{{ menuItem.translationKey | translate }}</span>
    </a>
  </li>
</ul> 

navbarMenuItems - это наблюдаемый массив, который я присоединяю в своем компоненте методом ngOnInit:

this.navbarMenuItems = this.navbarService.getNavbarMenuItems();

NavbarService выглядит так:

@Injectable({
  providedIn: "root"
})
export class NavbarService {

  public navbarMenuItems = new Subject<NavbarActionModel[]>();

  constructor(
  ) { }

  updateNavbarMenuItems(items: NavbarActionModel[]) {
    this.navbarMenuItems.next(items);
  }

  getNavbarMenuItems(): Observable<any> {
    return this.navbarMenuItems.asObservable();
  }
}

Все отлично работает при вызове метода updateNavbarMenuItems () NavbarService из любого другого компонента (т.е. navbar обновляет и показывает действия, которые вы отправляете).

Однако, если я вызываю updateNavbarMenuItems () в NavbarComponent (то есть с метод HTML) ngOnInit HTML не обновляется. НО если я вызову метод обновления в методе ngAfterViewInit (), они появляются.

Мой коллега помог мне решить проблему и сказал, что это из-за состояния гонки, когда * ngFor не отображается вовремя, что кажется правильным. Тем не менее, это кажется мне действительно странным, и я чувствую, что, должно быть, я делаю что-то еще неправильно, и в моем коде есть другая ошибка / лучшая практика, которой не следуют, если кто-то может помочь?

1 Ответ

1 голос
/ 07 марта 2020

Subject не возвращает никакого значения на Subscription, оно запускает только новое значение, выданное .next(value).

BehaviorSubject возвращает также последнее выданное значение на каждом новом Subscription.

В этом случае вы должны использовать BehaviorSubject, чтобы быть уверенным, что значение будет отправлено в новое время, когда труба async подпишется на наблюдаемое.

Проверьте это Stackblitz demo .

Вы можете видеть, что если мы смоделируем задержку (с помощью setTimeout или HTTP запроса ...), значение будет выдано после инициализации представления, следовательно, async pipe уже подписан.

В случае BehaviorSubject, когда представление инициализировано, navbarMenuItems | async получит текущее значение (уже созданное во время инициализации просмотра), а затем явно пометит представление как грязное (требуется обновление).

ОБНОВЛЕНИЕ (дополнительное объяснение):

OnInit вызывается только в начале процесса рендеринга. Позже директива Pipe связывается, и вызывается метод transform. Во время этого первого вызова AsyncPipe подписывается на Observable.

Следовательно, AsyncPipe подписывается на Observable после выполнения OnInit.

Но в нашем случае значение из Observable уже был выпущен один раз.

...