0

I have an angular application that uses a service to populate an array to use in a table, but the results need a second transformation before they are ready for presentation. I'm calling another service to do so, but how so I know when I am completely finished with all transformations before I alert the UI that I'm finished? I tried this (naive approach) but it has a flaw:

this.dataService.getData().subscribe(result => {
  result['entries'].forEach(entry => {
    let fieldToTransform = entry['fieldToTransform'];
    this.transformService.transform(fieldToTransform).subscribe(transformedField => {
      entry['fieldToTransform'] = transformedField;
    });// hmm, can't alert UI here
  });// not here either
});

But it's pretty clear that each iteration of the loop will call the service and will finish at different times. How can I know when they are all done?

2 Answers 2

1

Avoid multiple subscriptions if you can help it. In this case, I think you can.

I hope this example make sense. There are many ways/operators to achieve variations of what you need. I used concatMap(), toArray(), map() in the example below. This example assumes that your second async service call always return 1 value.

// simulates first async service call
const sourceOne = Rx.Observable.of(1,2,3);
// simulates second async service call
const sourceTwo = Rx.Observable.of('something-from-two');

// for each value from source one, process it after getting a value from source two
const example = sourceOne.concatMap(sourceOneValue => {
  return sourceTwo.map(sourceTwoValue => '---' + sourceOneValue + ':' + sourceTwoValue + '---')
})

// as separate values
example.subscribe(val => console.log(val));
// as a single array
// example.toArray().subscribe(val => console.log(val));

See this runnable example and tweak to meet your needs.

This is actually a question about RxJS, and I recommend further reading on that topic to meet your specific use case if the example is not sufficient.

Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly what I'm looking for. How will I adjust this if one observable has a dependency on the elements of the array? E.g. sourceTwo's observable required an input from sourceOne's elements.
0

Inside your second, nested Observable subscription, you have results from both of your calls.

this.dataService.getData().subscribe(result => {
  result['entries'].forEach(entry => {
    let fieldToTransform = entry['fieldToTransform'];
    this.transformService.transform(fieldToTransform).subscribe(transformedField => {
      entry['fieldToTransform'] = transformedField;
      // <<< --- maybe here? you have results from both of your service methods
    });// hmm, can't alert UI here
  });// not here either
});

Edit:

Then you should probably use some kind of merging Observable operator.

http://reactivex.io/documentation/operators.html @Combining Observables

Here is an example (I can not verify it right now, but maybe it can help give you an idea):

this.dataService.getData().subscribe(result => {
  let transformSubscriptions = [];

  result['entries'].forEach(entry => {

    let fieldToTransform = entry['fieldToTransform'];

    const sub = this.transformService.transform(fieldToTransform)
      .do(transformedField => {
        entry['fieldToTransform'] = transformedField;
      })

    transformSubscriptions.push(sub);
  });

  Observable.combineLatest(transformSubscriptions)
    .subscribe(results => window.alert('All transfers happened (at least once)'));
});

3 Comments

Wouldn't this give me a bunch of alerts since this is called for every element of the loop? When I get the first one, that would mean that I just finished the fastest one, not all of them.
Oh, so you want to alert your UI just once after you get an array of results from your dataService and transformations on all items completes?
Yes, I would like to wait until everything is ready for presentation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.