我正在使用ngx-progressbar,它与从服务,组件或解析器中启动的http请求一起正常工作。
请注意,在http请求期间无需手动触发进度条(通过服务等)。它会自动触发。
不幸的是,当从NGXS状态内发出http请求时,它无法按预期工作:
我为每种情况创建了一个按钮:
这不起作用,没有进度条出现(或出现,但挂起并且未完成到100%)
import java.util.Scanner;
public class Practice {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int number1 = (int)(System.currentTimeMillis() % 10);
int number2 = (int)(System.currentTimeMillis() / 10 % 10);
int answer = in.nextInt();
System.out.print("What is " + number1 + " + " + number2 + "?");
System.out.println(number1 + " + " + number2 + " = " + answer + " is " + (number1 + number2 == answer));
}
}
这确实按预期工作,出现进度栏
@Action(LoadUrl)
load({ setState }: StateContext<string>) {
return this.http.get<any>('https://jsonplaceholder.typicode.com/posts/1').pipe(tap(res => console.log(res)));
}
我问ngx-progressbar的开发人员,他实际上发现了问题并通过将http调用包装在区域中来解决了。确实可以,进度条出现:
@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();
}
}
由于我希望进度条随每个http请求一起出现,因此解决此问题的正确方法是什么?
有没有办法告诉NGXS在区域内运行每个http请求?
答案 0 :(得分:4)
由于性能原因,当前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()); }
});
});
};
}
希望这会有所帮助!