0

I have 3 streams. gradingResult and contextId depend on studentResponse. I need to fire an event and only one event (otherwise, this is trivial) when all 3 have the latest values.

I've tried #combineTemplate and #sampledBy studentResponse. Unfortunately, I always see the wrong data---gradingResult and contextId have the old values in the combined template. How can I wait for all streams to have the latest values?

Code is shown below:

var studentResponse = new Bacon.Bus();
var gradingResult = new Bacon.Bus();
var contextId = new Bacon.Bus();

studentResponse.onValue(function(f) {
   gradingResult.push(f);
   contextId.push(f);
});

Bacon.combineTemplate({
  studentResponse: studentResponse,
  gradingResult: gradingResult,
  contextId: contextId
}).sampledBy(studentResponse)
  .onValue(function(t) {
    console.log(t);
});

studentResponse.push(1);
studentResponse.push(2);
studentResponse.push(3);

Link to jsfiddle: https://jsfiddle.net/3o4c9sm8/1/

UPDATE: this is a contrived example. In the real code, gradingResult is an ajax request. Both gradingResult and contextId have time dependencies on studentResponse

U Avalos
  • 6,538
  • 7
  • 48
  • 81
  • Why do you need to push the studetResponse values to gradingResult and contextId? Also, Bacon.Bus provides a plug method to connect a stream to the Bus: https://github.com/baconjs/bacon.js/#bus-plug – JJuutila Sep 02 '15 at 11:59
  • This is a contrived example. In the real code, gradingResult is an ajax request. Yes, I'm aware of #plug. – U Avalos Sep 02 '15 at 13:23
  • Try not using `push` inside `onvalue`, I guess that's what is messing up atomicity. Rather use something like `map()`. It also might be beneficial if you could show us the relevant excerpt from your real code. – Bergi Sep 02 '15 at 17:44

2 Answers2

1

The solution is to sample by the stream that updates last. In this case, it's contextId. Changing the code to the following makes it work:

var studentResponse = new Bacon.Bus();
var gradingResult = new Bacon.Bus();
var contextId = new Bacon.Bus();

studentResponse.onValue(function(f) {
  gradingResult.push(f);
  contextId.push(f);
});

Bacon.combineTemplate({
 studentResponse: studentResponse,
 gradingResult: gradingResult,
 contextId: contextId
}).sampledBy(contextId) //Sampling by stream that updates last <---
.onValue(function(t) {
  console.log(t);
});

studentResponse.push(1);
studentResponse.push(2);
studentResponse.push(3);
U Avalos
  • 6,538
  • 7
  • 48
  • 81
0

Looks like plugging the Buses instead of pushing the value inside studentResponse.onValue does the trick:

var studentResponse = new Bacon.Bus();
var gradingResult = new Bacon.Bus();
var contextId = new Bacon.Bus();

gradingResult.plug(studentResponse);
contextId.plug(studentResponse);

Bacon.combineTemplate({
    studentResponse: studentResponse,
    gradingResult: gradingResult,
    contextId: contextId
}).sampledBy(studentResponse)
  .onValue(function(t) {
    console.log(t);
});

studentResponse.push(1);
studentResponse.push(2);
studentResponse.push(3);
JJuutila
  • 361
  • 1
  • 4
  • If it wasn't clear, this example is contrived. You removed the temporal dependency which I can't do in the real code – U Avalos Sep 02 '15 at 17:36