0

I'm using a forkJoin of observables but I'm having troubles to pass arguments in my observables. Lines of code worth a thousand words:

for(var key in pdfObjects){
    let pdf = {pdfObjects[key]};
    observables.push(new Observable(observer => {
        this.createPDF(pdf).subscribe((pdfFile) => {
            // Do something with my pdfFile
            observer.complete();
        })
    })
}
Observable.forkJoin(observables).subscribe(
    (next) => {},
    (error) => {},
    (completed) => {
        console.log('completed');
    }
);

(I have simplified the code for better clarity)

As you can see here, the problem is that when the code executes the observables, the pdf variable is equal to the last pdfObjects instead of being a different variable for each observable.

The question is how can I 'pass' and 'copy' my pdf variable so it's a diffent one for each observable?

Nate
  • 7,606
  • 23
  • 72
  • 124
  • Did you mean to surround the value with brackets in the let, creating a new object with a key of 'pdfObjects', or is that a typo when simplifying? – Jason Goemaat Jun 13 '16 at 07:16

2 Answers2

4

You should call the next method instead of the complete one:

observables.push(new Observable(observer => {
  this.createPDF(pdf).subscribe((pdfFile) => {
    // Do something with my pdfFile
    observer.next(pdf); // <-----
  });
})

Edit

Your problem is related to the use of closures within loops.

You could break with a method:

createObservable(pdf:any) {
  return new Observable(observer => {
    this.createPDF(pdf).subscribe((pdfFile) => {
      // Do something with my pdfFile
      observer.complete();
    });
  });
}

otherMethod() {
  for(var key in pdfObjects){
    let pdf = {pdfObjects[key]};
    observables.push(this.createObservable(pdf));
  }
  (...)
}

See this question for more details:

See this plunkr: https://plnkr.co/edit/P4BfwnA1HEw7KU4i3RbN?p=preview.

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks but it doesn't solve the problem here... `observer.next()` will simply return the pdf value in the `subscribe` of the `forkJoin`! What I need is that each observable has its own `pdf` variable as it argument. – Nate Jun 13 '16 at 05:51
  • I think that your problem is related to the use of closures within loops. I updated my answer accordingly... – Thierry Templier Jun 13 '16 at 05:59
  • Will the observables have a different `pdf` argument? The problem I see is that you're pushing the function with a `pdf` reference and that reference will change (it will be equal to the last pdfObjects item) when it will be executed by the `forkJoin`. – Nate Jun 13 '16 at 06:04
  • Am I missing something? – Nate Jun 13 '16 at 06:12
  • In fact, in this case, the variable wouldn't be bound to the variable outside the inner function (your problem). I added a plunkr in my answer ;-) – Thierry Templier Jun 13 '16 at 07:21
0

@Thierry is right, here's an example to show what's going on (fiddle)

var pdfObjects = {
  a: 'Object A',
  b: 'Object B',
  c: 'Object C'
};

for(let key in pdfObjects) {
  let pdf = pdfObjects[key];
  function createObservable(p) {
    console.log('createObservable:', p, pdf, key);
    return Rx.Observable.create(observer => {
      console.log('createObservable.create:', p, pdf, key);
      observer.onNext({ p: p, pdf: pdf, key: key});
      observer.onCompleted();
    });
  }
  observables.push(createObservable(pdf));
}

Result:

createObservable: Object A Object A a
createObservable: Object B Object B b
createObservable: Object C Object C c
createObservable.create: Object A Object C c
createObservable.create: Object B Object C c
createObservable.create: Object C Object C c

When createObservable is called, each value is as you would expect. But when you subscribe to your observables, the anonymous function that takes observer is called by RxJs and is using the current values for pdf and key which are what they were the last time through the loop. But because you're creating a function, there's a new scope and the argument 'p' in that scope is the value the function was called with.

Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113