我正在处理现有的Angular
应用程序。版本为Angular 4
。
该应用程序会从许多不同的组件中HTTP
调用REST API
。
我想为每个HTTP
请求显示自定义微调器。由于这是一个现有的应用程序,因此很多地方都会调用REST API
。在每个地方更改代码都不是一个可行的选择。
我想实现一个解决这个问题的抽象解决方案。
请建议是否有任何选择。
答案 0 :(得分:16)
@jornare在他的解决方案中有一个好主意。他正在处理多个请求的案件。但是,可以编写更简单的代码,而无需创建新的可观察到的请求并将请求存储在内存中。下面的代码还将RxJS 6与可管道运算符一起使用:
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
fun andAlso (block : (String) -> Int): Int{
return block(firstProperty)
}
}
fun main(args : Array<String>) {
InitOrderDemo("hello").andAlso(String::length).also(::println)
}
答案 1 :(得分:5)
在Angular 5中出现HttpClient
模块。您可以找到 more information there 。
使用此模块,来一个名为interceptors
的东西。
它们允许您为每个HTTP请求执行某些操作。
如果从Http迁移到HttpClient(你应该弃用Http),你可以创建一个可以处理共享服务中变量的拦截器:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.sharedService.loading = true;
return next
.handle(req)
.finally(() => this.sharedService.loading = false);
}
现在您只需将此变量用于模板即可。
<spinner *ngIf="sharedService.loading"></spinner>
(务必在显示此微调器的组件中注入您的服务)
答案 2 :(得分:4)
Angular 4+有一个新的HttpClient支持HttpInterceptors。这允许您插入在发出HTTP请求时将运行的代码。
重要的是要注意HttpRequest不是长寿命的Observable,但它们在响应之后终止。此外,如果在响应返回之前取消订阅了observable,则取消请求并且不处理任何处理程序。因此,您可能最终得到一个&#34;悬挂&#34;装载机酒吧,永远不会消失。如果您在应用程序中快速导航,通常会发生这种情况。
为了解决最后一个问题,我们需要创建一个新的Observable来附加拆卸逻辑。
我们返回此而不是原始的Observable。我们还需要跟踪所有请求,因为我们可能一次运行多个请求。
我们还需要一种服务,可以保存和分享我们是否有未决请求的状态。
@Injectable()
export class MyLoaderService {
// A BehaviourSubject is an Observable with a default value
public isLoading = new BehaviorSubject<boolean>(false);
constructor() {}
}
Interceptor使用MyLoaderService
@Injectable()
export class MyLoaderInterceptor implements HttpInterceptor {
private requests: HttpRequest<any>[] = [];
constructor(private loaderService: MyLoaderService) { }
removeRequest(req: HttpRequest<any>) {
const i = this.requests.indexOf(req);
this.requests.splice(i, 1);
this.loaderService.isLoading.next(this.requests.length > 0);
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.requests.push(req);
this.loaderService.isLoading.next(true);
return Observable.create(observer => {
const subscription = next.handle(req)
.subscribe(
event => {
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
},
err => { this.removeRequest(req); observer.error(err); },
() => { this.removeRequest(req); observer.complete(); });
// teardown logic in case of cancelled requests
return () => {
this.removeRequest(req);
subscription.unsubscribe();
};
});
}
}
最后,在我们的Component中,我们可以使用相同的MyLoaderService和async运算符,我们甚至不需要订阅。由于我们要使用的源值来自服务,因此它应该作为Observable共享,以便它获得使用它的渲染范围/区域。如果它只是一个值,它可能无法按需更新您的GUI。
@Component({...})
export class MyComponent {
constructor(public myLoaderService: MyLoaderService) {}
}
使用async
的示例模板<div class="myLoadBar" *ngIf="myLoaderService.isLoading | async">Loading!</div>
我假设您知道如何正确提供服务和设置模块。 您还可以在Stackblitz
查看一个有效的示例答案 3 :(得分:2)
这是一个基本的加载对话框,可以使用angular属性进行切换。只需将*ngIf="loader"
添加到中心加载器并相应地设置属性
.center-loader {
font-size: large;
position:absolute;
z-index:1000;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
@keyframes blink {50% { color: transparent }}
.loader__dot { animation: 1s blink infinite; font-size: x-large;}
.loader__dot:nth-child(2) { animation-delay: 250ms; font-size: x-large;}
.loader__dot:nth-child(3) { animation-delay: 500ms; font-size: x-large;}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div class="center-loader">
<strong>Loading
<span class="loader__dot">.</span>
<span class="loader__dot">.</span>
<span class="loader__dot">.</span></strong>
</div>
&#13;
为每个页面初始化加载程序为true,然后在服务完成后设置为false:
组件顶部:
export class MyComponent implements OnInit {
loader:boolean = true;
//...
<强>的OnInit():强>
await this.myService
.yourServiceCall()
.then(result => {
this.resultsSet=result);
this.loader = false; // <- hide the loader
}
.catch(error => console.log(error));
答案 4 :(得分:0)
您可以使用一些css / gif来显示微调器,并将其用于拦截器类,也可以只使用tur false来显示gif。
<root-app>
<div class="app-loading show">
<div class="spinner"></div>
</div>
</root-app>
答案 5 :(得分:0)
取决于您使用 REST服务
的方法我的方法是
# Start SSM automation execution
ssm_client.start_automation_execution(DocumentName=your_automation_document_name,Parameters={"InstanceId": [INSTANCE_ID],"VolumeId":[volume_id],"AutomationAssumeRole":[ssm_automation_role_arn]}
并将其放置在应用程序级别的某个位置。 Create a component
与 Create a service
和 increment
方法相反。
此服务应按照以下步骤决定是否显示 decrements
。
为来自客户端的一个请求增加计数器。
减少每个响应
loader(component)
和success
上的计数器
答案 6 :(得分:0)
角度拦截器可以在工作时以多种方式使用 在处理和管理HTTP调用进行通信方面表现出色 我们是从客户端Web应用程序制作的。我们可以创建一个 实用程序以使用Interceptor显示Mouse Loader。
请浏览以下帖子,了解LoaderInterceptor
的实现:-
Show Loader/Spinner On HTTP Request In Angular using Interceptor
答案 7 :(得分:0)
我正在寻找每个组件都可以使用的东西。 我放了一个计数器,所以微调器在每个请求完成后停止。
这很好用:
export class LoadingStatus{
public counter: number = 0;
public isLoading = new Subject<boolean>();
public reset(){
this.counter = 0;
this.isLoading.next(false);
}
}
export function triggerLoading<T>(status: LoadingStatus): (source: Observable<T>) => Observable<T> {
return (source: Observable<T>): Observable<T> => source.pipe(
prepare(() => {
if(status != null){
status.counter++;
status.isLoading.next(true)
}
} ),
finalize(() => {
if(status != null){
status.counter--;
// if there is something like a flikering, maybe use a delay.
if(status.counter <= 0) {
status.counter = 0;
status.isLoading.next(false)
}
}
})
)
}
然后像这样调用它:
public loadingStatus $ =新的LoadingStatus();
public makeRequest(){
this.myService.load()
.pipe(triggerLoading(this.loadingStatus$))
.subscribe(v => {});
}
HTML:
<div class="loading-spinner" *ngIf="loadingStatus$?.isLoading | async"></div>