在 ngoninit 中使用异步管道

发布于 2025-01-11 13:06:02 字数 2264 浏览 0 评论 0原文

我的角度应用程序中有许多 api 调用,如果数据来自服务器,我想在其中显示加载组件。

为此,我有一个像这样的加载器服务:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class LoaderService {
  isLoading = new Subject<boolean>();

  show() {
    this.isLoading.next(true);
  }

  hide() {
    this.isLoading.next(false);
  }
}

我也有一个 httpInterceptor ,我在其中使用 showhide 方法,如下所示

intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    this.loaderService.show();

    return new Observable((observer) => {
      next.handle(request).subscribe(
        (res) => {
          observer.next(res);
        },
        (err: HttpErrorResponse) => {
          this.loaderService.hide();
          if (err.error.message) {
            this.customNotificationService.showNotification(
              err.error.message,
              3000,
              'error'
            );
          } else {
            this.customNotificationService.showNotification(
              'Ismeretlen eredetű hiba. Lépj kapcsolatba a rendszer üzemeltetőjével.',
              3000,
              'error'
            );
          }
        },
        () => {
          this.loaderService.hide();
        }
      );
    });
  }

:组件,我想在其中使用加载组件,我在模板中有这个:

<loading-overlay
  [visible]="loadingOverlayVisible | async"
  loadingText=""
></loading-overlay>

并且在 ts 中:

loadingOverlayVisible: Subject<boolean> = this.loaderService.isLoading;

除了一种情况之外,此方法有效:ngOnInit。当组件加载时,我会像这样加载初始数据:

ngOnInit() {
    this.gridData = { data: [], total: 0 };
    this.userService.getUsers().subscribe((users) => {
      users.forEach((user) => {
        // we get this as string from the backend
        user.lastLoginDateDisplay = new Date(user.lastLoginDateDisplay!);
      });
      this.gridData = { data: users, total: users.length };
    });
  }

数据已加载,但没有任何加载指示器。如果我更改逻辑并使用标准的 subscribe/unsubscribe 方式,它就可以工作。但使用异步管道会更干净/更智能。

那么,问题是:如何做到这一点?

I have in my angular app many api calls, where I want to show a loading component, if data is coming from server.

For this I have a loader service like this:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class LoaderService {
  isLoading = new Subject<boolean>();

  show() {
    this.isLoading.next(true);
  }

  hide() {
    this.isLoading.next(false);
  }
}

I have an httpInterceptor too, where I use the show and hide methods like this:

intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    this.loaderService.show();

    return new Observable((observer) => {
      next.handle(request).subscribe(
        (res) => {
          observer.next(res);
        },
        (err: HttpErrorResponse) => {
          this.loaderService.hide();
          if (err.error.message) {
            this.customNotificationService.showNotification(
              err.error.message,
              3000,
              'error'
            );
          } else {
            this.customNotificationService.showNotification(
              'Ismeretlen eredetű hiba. Lépj kapcsolatba a rendszer üzemeltetőjével.',
              3000,
              'error'
            );
          }
        },
        () => {
          this.loaderService.hide();
        }
      );
    });
  }

In the component, where I want to use the loading component, I have this in the template:

<loading-overlay
  [visible]="loadingOverlayVisible | async"
  loadingText=""
></loading-overlay>

And in the ts:

loadingOverlayVisible: Subject<boolean> = this.loaderService.isLoading;

This works except one case: ngOnInit. When the component loads, I load the initial data like this:

ngOnInit() {
    this.gridData = { data: [], total: 0 };
    this.userService.getUsers().subscribe((users) => {
      users.forEach((user) => {
        // we get this as string from the backend
        user.lastLoginDateDisplay = new Date(user.lastLoginDateDisplay!);
      });
      this.gridData = { data: users, total: users.length };
    });
  }

The data gets loaded, but without any loading indicator. If I change the logic and use the standard subscribe/unsubscribe way, it works. But it would be more cleaner/smarter with the async pipe.

So, the question is: how to do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青芜 2025-01-18 13:06:02

LoaderService.isLoading 应该是BehaviorSubject。我不确定,但我认为 ngInit 在首次评估模板之前完成。如果我是对的,那么 LoaderService.isLoading 已经发出 true,当您的异步管道订阅时,为时已晚。

LoaderService.isLoading should be a BehaviorSubject instead. I'm not sure, but I think ngInit finishes before the template is first evaluated. If I'm right, then LoaderService.isLoading has already emitted true, and when your async pipe subscribes, it's too late.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文