0

我的目标是在 Ionic 3 项目中使用 RxJs switchMap,如果服务器离线,则取消任何正在进行的登录尝试,并仅使用最新请求。否则我以后会得到一些不需要的异步副作用。

在我的视图层中,我submitStream$用于捕获按钮点击流,然后将其作为方法参数传递给服务层。在服务层中,我response$通过 aswitchMap将传递的参数submitStream$Observable<Response>this.webServiceUtil.testLogin().

我尝试实现此代码:

HTML 标记

<button #submit type="submit">Submit</button>

打字稿:视图层

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import { ElementRef, ViewChild } from '@angular/core';
export class LoginPage {
  @ViewChild('submit') button: ElementRef
  submitStream$:any;
  ...
  ionViewDidLoad() {
    this.submitStream$ = 
    Observable.fromEvent(this.button.nativeElement, 'click')
  }
  ...
}

打字稿:服务层(submitStream$ 作为方法参数进来)

this.response$ = submitStream$.switchMap(click =>
    this.webServiceUtil.testLogin())

我也尝试过this.submitStream$ngAfterViewInit()

当事情不起作用时,我还尝试将其附加到 Observable.fromEvent:

 .subscribe(ev => {
    console.log('LoginPage: ionViewDidLoad() submitStream$.subscribe(): ev:', ev);}
  )

如何克服' ERROR TypeError: Invalid event target '

4

2 回答 2

0

似乎你必须做一些时髦的事情来制作你订阅的内容,在 RxJs 的眼中看起来是正确的......

所以这就是我为解决 ERROR TypeError: Invalid event target 所做的事情:

  @ViewChild('submit') button: any;

    this.submitClickStream$ = 
      Observable.fromEvent(this.button._elementRef.nativeElement  , 'click')
      .subscribe(ev => {
        console.log('ev: ', ev);},
        (err) => {console.error(err);}
      );

AuthService中,从 @ViewChild 传递submitClickStream$或 button 元素,并从 AuthService 中对其执行 Observable.fromEvent ,我无法通过控制台记录事件来获取订阅,从而永远触发。

所以,我介绍了一个 BehaviourSubject 中介。

我可以在LoginPage.html的元素中(click)='onSubmit()'再次使用常规。<button>

LoginPage.ts的 onSubmit() 方法中,我可以直接将 BehaviourSubject 与this.clickStream$.next('');.

这消除了 Observable.fromEvent 和 ViewChild 的复杂性。

switchMap 终于奏效了,取消了之前正在进行的请求而没有混乱的取消订阅逻辑。

登录页面.ts

import { BehaviorSubject }     from 'rxjs/BehaviorSubject';
import { AuthService }         from './../../providers/auth-service';
import { LoginCredentials }    from './../../model/loginCredentials';
export class LoginPage {

  private clickStream$:BehaviorSubject<any>;

  constructor(
   private authService:AuthService,
  ) {
     this.clickStream$ = new BehaviorSubject('');
  }

  onSubmit():void {
    console.log('LoginPage: onSumbit()');
    this.clickStream$.next('');
    this.authService
      .login(this.prepareCredentials(), 
             this.clickStream$
            );
  }

}

身份验证服务

import { BehaviorSubject }      from 'rxjs/BehaviorSubject';
import { LoginCredentials }     from './../../model/loginCredentials';
import { WebServiceUtil }       from './web-service-util';

@Injectable()
export class AuthService {

 login(
    loginCredentials: LoginCredentials, 
    clickStream$: BehaviorSubject<any>
  ) {
     this.response$ = clickStream$.switchMap(click =>  {
                      console.log('AuthService: login() : click: ', click);
                      return this.webServiceUtil.testLogin();
                                                       }
                                            );
     this.response$.subscribe(
         (response:Response) => {....},
          (err) => {console.error(err); ....}

  }
}

WebServiceUtil

@Injectable()
export class WebServiceUtil {

  testLogin(
  ): Observable<Response> {
  ...
  }

}
于 2017-09-02T15:31:18.243 回答
0

你非常亲近。请使用下面给出的开关图。希望这有帮助!

this.submitStream$ = Rx.Observable.fromEvent(this.button._elementRef.nativeElement, 'click');

this.submitStream$
      .switchMap(click => {
        return this.dummyAPIResponse(); // this should return observalbe(i.e new observalbe)...
      })
      .subscribe((res) => {
        console.log(res);
      });


dummyAPIResponse(){
 return Rx.Observable.create(observer => {
      setTimeout(() => {
        observer.next([1, 2, 3, 4]);
      }, 10000);
    });
}
于 2017-09-03T09:53:32.153 回答