我正在使用ngx-progressbar,它与从服务,组件或解析器中启动的http请求一起使用时效果很好。
请注意,在http请求期间不需要手动触发进度条(通过服务等)。它是自动触发的。
不幸的是,当从NGXS状态内发出http请求时,它无法按预期方式工作:
我为每种情况创建了一个按钮:
这并没有工作,没有出现进度条(或出现,但挂起,未完成100%)
@Action(LoadUrl)
load({ setState }: StateContext<string>) {
return this.http.get<any>('https://jsonplaceholder.typicode.com/posts/1').pipe(tap(res => console.log(res)));
}
Run Code Online (Sandbox Code Playgroud)
这确实按预期工作,出现进度条
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
我问了ngx-progressbar的开发人员,他实际上找到了问题并通过将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();
});
}
}
Run Code Online (Sandbox Code Playgroud)
由于我希望进度条随每个http请求一起出现,因此解决此问题的正确方法是什么?
有没有办法告诉NGXS在区域内运行每个http请求?
目前,出于性能原因,ngxs会在角度区域外运行所有操作。如果您订阅动作流或store.select,则默认情况下将在角度区域执行您的订阅。State对象中的动作处理程序在角度区域之外运行。这是ngxs的默认行为。我认为关闭此“在区域外运行”功能是一项有效的要求。请您记录一个要求此功能的github问题。
回到您的迫在眉睫的问题,我制作了一个Http拦截器,您可以添加它以强制http调用返回到角度区域(您只需要此即可触发更改检测)。我分叉了您的stackblitz并将其添加到此处: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()); }
});
});
};
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
795 次 |
| 最近记录: |