【问题标题】:How to Subscribe to a shared Service如何订阅共享服务
【发布时间】:2020-11-29 10:08:26
【问题描述】:

我无法理解如何在服务的 observable 中观察新值。 我的最终目标是结合拦截器、服务和指令,以便向用户显示加载信息。 我有一个监听 http 调用的拦截器:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http';
import { Observable, pipe } from 'rxjs';
import { LoadingService } from '../loading.service';
import { map, finalize } from 'rxjs/operators';

@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
  constructor(private loadingSrv: LoadingService) {}

  public intercept(req, next): Observable<HttpEvent<any>> {
    if (req.url === 'graphql') {
      console.log('first', req);
      this.loadingSrv.saveRequest(req);
    }
    return next.handle(req).pipe(
      map(el => {
        if (req.url === 'graphql') {
        }
        return el;
      }),
      finalize(() => {
        console.log('final', req);
      })
    );
  }
}

如果找到请求,他应该触发加载服务并触发保存功能。

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class LoadingService {
  public loadingQuerys: BehaviorSubject<[]> = new BehaviorSubject(null);
  constructor() {}
  saveRequest(req) {
    this.loadingQuerys.next(req);
    // this.requests[req.body.operationName] = new BehaviorSubject({ isLoading: true });
  }
}

加载服务应该向行为主体发出新的请求值。 现在我想从指令中订阅这个 BehaviorSubject。

import { Directive, Input, OnInit, TemplateRef, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { LoadingSpinnerComponent } from './loading-spinner.component';
import { LoadingService } from './loading.service';

@Directive({
  selector: '[showLoadingSpinner]'
})
export class ShowLoadingSpinnerDirective implements OnInit {
  @Input('showLoadingSpinner') query: any;

  constructor(
    private viewContainerRef: ViewContainerRef,
    private templateRef: TemplateRef<any>,
    private loadingSpinner: LoadingSpinnerComponent,
    private factoryResolver: ComponentFactoryResolver,
    public loadingSrv: LoadingService
  ) {}

  ngOnInit(): void {
    const factory = this.factoryResolver.resolveComponentFactory(LoadingSpinnerComponent);
    console.log(this.query);
    this.loadingSrv.loadingQuerys.subscribe(console.log);
  }
}

我现在的问题是,他没有在订阅中识别出新的价值。 也许是因为这里的服务是一个新的实例? 如何让指令监听任何更改以检测查询是否被触发并完成?

【问题讨论】:

  • 看起来你的指令应该能够访问服务的 observable。你确定你的 saveRequest() 方法被解雇了吗?
  • 是的。控制台日志显示我

标签: angular typescript rxjs interceptor


【解决方案1】:

这是一种可能适合您的模式。我无法准确说出发生了什么,但我会将BehaviorSubject 保留为私有。在您的组件中取消订阅也很重要。

在您的加载服务中使用:

export interface LoadingState {
  req: any;
}

let _state: LoadingState = {
  req: null,
};

@Injectable({
  providedIn: 'root',
})
export class LoadingService {
  private store = new BehaviorSubject<LoadingState>(_state);
  private state$ = this.store.asObservable();

  req$ = this.state$.pipe(
    map((state) => {
      return state.req;
    }),
    distinctUntilChanged()
  );

  constructor() {}
  saveRequest(req) {
    this.updateState({ ..._state, req });
  }

  private updateState(state: LoadingState) {
    this.store.next((_state = state));
  }
}

在你的组件中

  constructor(private loadingSrv: LoadingService) {}
  private onDestroy = new Subject<void>();
  req$: Observable<LoadingState> = this.loadingSrv.req$;
  ngOnInit() {
    this.req$.pipe(takeUntil(this.onDestroy)).subscribe((value) => {
      console.log(value);
    });
  }
  ngOnDestroy() {
    this.onDestroy.next();
    this.onDestroy.complete();
  }

【讨论】:

  • 不,这不起作用。最后我在控制台中获得了第一个新值,但在 updateState 被触发后没有新值。
  • 删除distinctUntilChanged() 有帮助吗?我还将 console.log 置于更新状态以确保正确更新。
【解决方案2】:

解决方案是将服务放入非延迟加载的模块中。

【讨论】:

  • 不建议在任何模块中使用任何服务。考虑改用@Injectable({ providedIn: 'root' })
猜你喜欢
  • 2016-08-23
  • 2017-01-20
  • 1970-01-01
  • 2014-02-07
  • 2018-01-03
  • 2021-06-09
  • 2021-11-28
  • 2018-06-03
  • 1970-01-01
相关资源
最近更新 更多