每个 http 请求上的 Angular 2 加载器

Posted

技术标签:

【中文标题】每个 http 请求上的 Angular 2 加载器【英文标题】:Angular 2 loader on each http request 【发布时间】:2016-11-03 19:42:28 【问题描述】:

我想做的是: 每当发生 http 请求时,我都想使用微调器。换句话说,我希望用户在我的 app.component 中发生 http 请求时看到加载屏幕。 我的 spinner.component 和 spinner-service 文件与this 问题中的答案相同。 而我的 app.component 的组件是

@Component(
    selector: 'todoApi',
    template: `
        <div class="foo">
            <spinner-component></spinner-component>
            <h1>Internship Project</h1>
            <a [routerLink]="['Dashboard']">Dashboard</a>
            <a [routerLink]="['Tasks']">List</a>
            <router-outlet></router-outlet>
        <div>
    `,
    directives: [ROUTER_DIRECTIVES,SpinnerComponent],
    providers: [
        ROUTER_PROVIDERS,
    ]
)

@RouteConfig([
    
        path: '/dashboard',
        name: 'Dashboard',
        component: DashboardComponent,
        useAsDefault: true
    ,
        path: '/tasks',
        name: 'Tasks',
        component: TaskComponent
    ,
        path: '/detail/:id',
        name: 'TaskDetail',
        component: TaskDetailComponent
    ,
])

总之,每当在这些路由之一中发生 http 请求时,我想向用户显示微调器。我知道这是一个不好的问题,但我是 angular 2 的新手,如果有人能帮助我,我将不胜感激。 非常感谢! 编辑!: Günther 回答的解决方案: 我将httpspinner-service 包装到HttpClient 组件中,并使用它而不是常规的http 模块。这是我的HttpClient 组件:

import  Injectable  from '@angular/core';
import  Http, Headers  from '@angular/http';
import  SpinnerService from './spinner-service';

@Injectable()
export class HttpClient 
  constructor(
      private http: Http,
      public spinner: SpinnerService
    )

  

  createAuthorizationHeader(headers:Headers) 
    headers.append('Authorization', 'Basic ' + btoa('username:password')); 
  

  get(url) 
    this.spinner.start();
    let headers = new Headers();
    this.createAuthorizationHeader(headers);
    return this.http.get(url,  headers: headers ).do(data=> this.spinner.stop());
  

  post(url, data) 
    this.spinner.start();
    let headers = new Headers();
    this.createAuthorizationHeader(headers);
    return this.http.post(url, data,  headers: headers ).do(data=> this.spinner.stop());
  

【问题讨论】:

也许您创建自定义服务来执行扩展 Angular 提供的 HttpClass 的 http 请求,并在每次请求时跟踪自定义服务中的 isBusy 状态。 【参考方案1】:

使用Http(已经有答案如何将Http 包装在您自己的类中)和&lt;spinner-component&gt; 之间共享的服务。 另见https://angular.io/docs/ts/latest/cookbook/component-communication.html

在共享服务中维护已启动(增加)和已完成/失败的 HTTP 请求的计数器,并在每次计数器从 0 更改为 &gt;0 或从 &gt;0 更改为 0 时通知 &lt;spinner-component&gt;启用或禁用自身。

【讨论】:

这对我 Günter 来说是一个非常有用的答案!非常感谢!我会尽我所能,看看包装Http是否能解决问题。 请问你能创建一个例子吗? 对不起,我没有足够的时间。【参考方案2】:

感谢您的回答 Günter Zöchbauer,我根据需要构建的示例。我没有使用更易于使用的 HTTP 包装器,但是,根据您的反建议,此示例适用于多个服务调用。希望它可以帮助某人:)

    创建加载器服务。

    import  Injectable  from '@angular/core';
    import  BehaviorSubject  from 'rxjs/BehaviorSubject';
    
    @Injectable()
    
    export class LoaderService 
        public loaderCounter: BehaviorSubject<number> = new BehaviorSubject<number>(0);
        displayLoader(value: boolean) 
          let counter = value ? this.loaderCounter.value + 1 : this.loaderCounter.value - 1;
          this.loaderCounter.next(counter);
        
    
    

    在您的主要模块文件的提供者中包含该服务 (例如:AppModule)

    在您的主组件文件(例如:AppComponent)中,订阅 更改并反映到加载程序(在我的情况下,它是一个单独的 组件)。

    //Imports
    import  Subscription  from 'rxjs/Subscription';
    import  LoaderService  from './core/loader.service';
    ..
    @Component(
      selector: 'my-app',
      template: `
        <div class="container-fluid content">
          <router-outlet></router-outlet>
        </div>
        <spinner [visible]="displayLoader"></spinner>
      `
    )
    
    export class AppComponent implements OnInit, OnDestroy 
        displayLoader: boolean;
        loaderSubscription: Subscription;
        constructor(private loaderService: LoaderService) 
    
        ngOnInit() 
            this.loaderSubscription = this.loaderService.loaderCounter.subscribe((counter: number) => 
                this.displayLoader = counter != 0;
            );
        
    
        ngOnDestroy() 
            this.loaderSubscription.unsubscribe();
        
    
    

    使用加载器服务:

     import  LoaderService  from './core/loader.service';
        ..
        export class SampleComponent implements OnInit 
            constructor(private _service: SomeService, private loader: LoaderService)  
    
        ngOnInit() 
            this.loader.displayLoader(true);
            this._service.getBalance().subscribe(
                response => ..do something..,
                () => .. error..,
                () => this.loader.displayLoader(false)
            );
        
    
    

【讨论】:

非常酷...但是为什么您的 ajax 调用在组件内部?我认为您应该在进行 ajax 调用的另一个服务中调用加载器服务方法,不是吗? 根据我对 Angular 2 的了解,您有一个服务,您只需在组件级别调用并绑定到您拥有的值。我不太清楚为什么您需要多个服务,因为您仍然需要将响应与组件内的模型/变量绑定。 @MarkCutajar 但问题是在这里我们打算在组件中完全加载加载器,因为它缺乏问题的独创性。 @k11k2 同意,上面的代码并不适用于每个 HttpRequest,这样做,创建 HttpWrapper,并从 HttpWrapper 本身调用加载器服务,正如 MadCatm2 指出的那样。通过发布的代码,它可以更好地控制何时显示它,具体取决于所需的用例。【参考方案3】:

只为从现在开始来到这里的人...

使用此解决方案,微调器不会在 http 请求出错的情况下停止。 请确保执行以下操作:

...
return this.http.post(url, data,  headers: headers )
  .do(data=> this.spinner.stop(),
  err=> this.spinner.stop());
...

【讨论】:

【参考方案4】:

你也可以使用Pace.js

很容易添加

<head>
  <script src="/pace/pace.js"></script>
  <link href="/pace/themes/pace-theme-barber-shop.css" rel="stylesheet" />
</head>

您可以在此处找到文档:http://github.hubspot.com/pace/

【讨论】:

以上是关于每个 http 请求上的 Angular 2 加载器的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 - 如何在等待 http 请求完成时阻止 GUI 渲染

如何在 Angular 2 中发出启用 CORS 的 HTTP 请求?

如何将 url 参数(查询字符串)传递给 Angular 上的 HTTP 请求?

Angular 2,轮询 http 请求并等待缓慢的响应

如何使用构造函数上的异步调用注入服务,Angular 2

Angular2 http post请求到另一个端口上的nodejs服务器