代码之家  ›  专栏  ›  技术社区  ›  Wolf359

从NGXS状态发出的HTTP请求未被Angular检测到(与区域相关的问题)

  •  0
  • Wolf359  · 技术社区  · 7 年前

    我使用的是ngx progressbar,它可以很好地处理从服务、组件或解析程序中启动的HTTP请求。

    注意,在HTTP请求期间不需要手动触发进度条(通过服务等)。自动触发。

    不幸的是,在NGXS状态下发出HTTP请求时,它无法按预期工作:

    stackblitz :

    我为每个案例创建了一个按钮:

    • 发出请求(发送到存储,不带区域)

    是的。 工作,不显示进度条(或显示但挂起且未完成100%)。

    @Action(LoadUrl)
        load({ setState }: StateContext<string>) {
            return this.http.get<any>('https://jsonplaceholder.typicode.com/posts/1').pipe(tap(res => console.log(res)));
        }
    
    • “提出请求(组件)”

    这确实按预期工作,出现进度条

    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
    // ...
      makeRequestComponent() {
        this.http.get<any>('https://jsonplaceholder.typicode.com/posts/1').pipe(tap(res => console.log(res))).subscribe();
      }
    }
    
    • 提出请求(发送到仓库,带区域)

    我问了NGXProgressBar的开发人员,他发现了这个问题,并通过在区域内包装HTTP调用解决了这个问题。这确实有效,进度条显示:

    @State<string>({
      name: 'testState',
      defaults: ''
    })
    export class TestUrlState {
    
      constructor(private http: HttpClient, private zone: NgZone) { }
    
      @Action(LoadUrl)
      load({ setState }: StateContext<string>) {
    
        this.zone.run(() => {
    
          this.http.get<any>('https://reqres.in/api/users?delay=2').pipe(
            tap(res => console.log(res))
          ).subscribe();
    
        });
      }
    }
    

    既然我希望每个HTTP请求都出现进度条,那么解决这个问题的正确方法是什么?

    有没有办法告诉NGXS在区域内运行每个HTTP请求?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Mark Whitfeld    7 年前

    https://stackblitz.com/edit/ngx-progressbar-inzone?file=src%2Fapp%2FNgZoneHttpInterceptor.ts

    import { Injectable, Optional, Inject, NgZone, NgModule, ModuleWithProviders } from '@angular/core';
    import { HTTP_INTERCEPTORS, HttpInterceptor, HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http';
    import { Observable, Observer } from 'rxjs';
    
    @NgModule({
    })
    export class NgZoneHttpInterceptorModule {
      static forRoot(): ModuleWithProviders {
        return {
          ngModule: NgZoneHttpInterceptorModule,
          providers: [
            { provide: HTTP_INTERCEPTORS, useClass: NgZoneHttpInterceptor, multi: true }
          ]
        };
      }
    }
    
    @Injectable()
    export class NgZoneHttpInterceptor implements HttpInterceptor {
    
      constructor(private _ngZone: NgZone) { }
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {    
        return this._ngZone.run(() => {
          return next.handle(req).pipe(enterZone(this._ngZone));
        });
      }
    }
    
    
    function enterZone<T>(zone: NgZone) {
      return (source: Observable<T>) => {
        return new Observable((sink: Observer<T>) => {
          return source.subscribe({
            next(x) { zone.run(() => sink.next(x)); },
            error(e) { zone.run(() => sink.error(e)); },
            complete() { zone.run(() => sink.complete()); }
          });
        });
      };
    }
    

    推荐文章