Joeker
Joeker

Reputation: 95

Angular2 custom observables with some sequential subscribes

do you know a solution for my problem? I need a flexible sequence of subscribes capsuled in a observable like here:

saveData() {
    return new Observable((observer) => {
      let success = true;

      if(example === true) {
        this.saveCallbarrings().subscribe((response) => {
          // this response was ignored from angular
          success = (response === true);
        });
      }

      if(example2 === true) {
        this.saveCallbarrings().subscribe((response) => {
          // this response was ignored from angular too
           success = (response === true);
        });
      }

      // and so on ... in the end I need a result of all responses
      observer.next(success);
    });
  }

In the end I called the result of this "response-collection" in my submit method:

onSubmit() {
// Validations and others
...
if(this.isNew) {
        observable = this.create();
      } else {
        observable = this.update();
      }

      return observable.subscribe(success => {
        if(success == true) {
          let subscription = this.saveData().subscribe(successFinished => {
            // And here is the problem, because this var doesnt have the correct response
            if(successFinished === true) {
              this.alertService.success('ALERT.success_saved', {value: 'ALERT.success_edit_user', param: {user: this.user.username}});
            }
          });

          subscription.unsubscribe();
        }
      });

The main problem is that angular doesn't waiting until the "success" var is subscribed in the the first code block. Why and what is the better solution for me?

Upvotes: 1

Views: 200

Answers (1)

olivarra1
olivarra1

Reputation: 3399

1st question: Why is it not working?

Because every subscribe is asynchronous. When you do this.saveCallbarrings().subscribe(...) the thing inside subscribe can happen at any time (maybe never!), so the program continues to the next instruction, that's observer.next(success);, that has the initial value of success.

2nd question: What is the best solution for me?

Rx.Observables have so many operators to deal with this asynchronous stuff. In your case, the operator you need is forkJoin. This operator lets you pass him an array of streams, and it will subscribe to all of them and when all of them finish it will give you an array with each one of the resuts for each stream. So your code would become:

saveData() {
    return Rx.Observable.defer(() => {
        let streams = [];
        if(example === true) {
            streams.push(this.saveCallbarrings());
        }
        if(example2 === true) {
            streams.push(this.saveCallbarrings());
        }

        // And so on

        return Rx.Observable.forkJoin(streams);
    });
}

Having said that, I'm not sure why you make many subscriptions to the same this.saveCallbarrings(), I guess it's just to make the question simpler, as an example.

Also, here I used .defer() instead of create. With this you can just return another stream and it will subscribe to it and pass it to the observers. The difference between doing defer and doing nothing (i.e. setting up the streams and just returning the forkJoin) is that defer won't execute any of the code until someone subscribes to it, so you get less side effects.

Upvotes: 1

Related Questions