Observables: Creating a mock http request

2019-08-19 07:07发布

问题:

I'm trying to test my front-end code without the back-end api using observables. In my component's template I have a textarea. Ultimately I need to send the textarea content to back-end api using http.post and receive back the validation for the content.

In the constructor of my component.ts I define an observable which does some very basic checks and creates mock results after a timeout of 2000ms (like http.post/http.get):

private obsVal: Observable < any >;
private obsChange: Observable < any >;

constructor() {

   this.obsVal = Observable.create(observer => {

       setTimeout(() => {
          let errorInfo = {};
          let val = Math.floor(Math.random() * 10) + 1;

          if (val < 6) {
              errorInfo['error'] = true;
              errorInfo['info'] = "Error! Unknown expression encountered.";
          } else {
              errorInfo['error'] = false;
          }
          observer.next(errorInfo);

      }, 1000)
  });

On any change inside the textarea the following function is called (creating another observable and subscribing to it):

textarea.on('change', () => {
     this.obsChange = Observable.create(observer => {
             observer.next("some text inside textarea");
             })

     this.obsChange.pipe(
         debounceTime(400),
         distinctUntilChanged(),
         switchMap((text) => {
             return this.obsVal
         })
     )
     .subscribe(errorResp => {
         this.addPanel(errorResp)
     });
  })

addPanel adds a DOM element in document to show the response.

I have used debounceTime, distinctUntilChanged and switchMap so that only the latest request is rendered if the user types continuously. However, it seems that these operators in pipe are not working as i'm receiving all the responses one after another.

Surely I'm making some big conceptual mistake here. Can somebody please point it out?

Note: The textarea element is created dynamically inside the component so i can't access (change)="doSomething()" event on this.

Update: I tried to update my code like this post.

Rather than passing the subscribe on every change, I created a subject and called its subscription in ngOnInit():

ngOnInit() {
this.subscription = this.obsChange.pipe( //obsChange is  the subject
             debounceTime(400),
             distinctUntilChanged(),
             switchMap((text) => {
                 return this.obsVal
             })
         )
         .subscribe(errorResp => {
             this.addPanel(errorResp)
         });
}

And on change event, rather than creating a new obsChange observable I call next() to existing one:

textarea.on('change', () => {
         this.obsChange.next("some text");
      })

This works for the first time, but on further changes next() is called but it doesn't trigger obsChange in ngOnInit().