I have a form, which has many image urls - the back-end persists url strings and the images are uploaded directly to S3. I'd like to use Bacon.js streams to handle disabling/enabling the form's submit button while uploads are in-progress.
I've tried various approaches (using a stream of streams of Bacon.fromPromises, using a stream of fromPromise-d deferreds and a bus of raw deferreds and trying to manually diff the two) but haven't found a solution that a) works as intended and b) feels like I'm not fighting the library.
This is where things stand, but as noted, the submit button is prematurely re-enabled.
function toResultStream(promise) {
return Bacon.fromPromise(promise)
}
var deferreds = $('a').asEventStream('click', function (event) {
event.preventDefault();
var deferred = $.Deferred();
// simulate upload
setTimeout(function () {
deferred.resolve(true);
}, _.random(200, 1600))
setTimeout(function () {
deferred.rejectWith(false);
}, _.random(200, 1600))
return deferred;
});
deferreds.onValue(function () {
$('#submit').attr('disabled', true);
})
// only takes completed deferreds into consideration
var ongoingSearch = deferreds.flatMap(function (d) {
return toResultStream(d);
})
.mapError(true)
.onValue(function () {
$('#submit').attr('disabled', false);
});
Fiddle
*Update
@mjs2600's answer was enough to nudge me towards a solution.
Here's what I ended up doing:
var bus = new Bacon.Bus();
var deferreds = $('a').asEventStream('click', function (event) {
// ...
bus.push(-1);
// ...
});
var ongoingSearch = deferreds
.flatMap(toResultStream)
.mapError(1)
.merge(bus)
.scan(0, function (memo, n) { return memo + n; })
.onValue(function (value) {
var disabled = value < 0;
$('#submit').attr('disabled', disabled);
});
Updated Fiddle
I know using Buses is frowned upon, so if anyone has a suggestion as to how I could achieve the same behavior with streams, I'd very much like to see it.
If you know the number of urls to upload, you could add skip
like this to ignore the responses from all but the last url.
var numStreams = 1;
var ongoingSearch = deferreds.flatMap(function (d) {
return toResultStream(d);
})
.mapError(true)
.skip(numSteams-1)
.onValue(function () {
alert('fooo');
$('#submit').attr('disabled', false);
});
One thing I find a little worrisome about the code you posted is that these streams never terminate. You might consider refactoring such that the ongoingSearch is created by the click and terminates once all the streams are complete. (For example, merge
the upload streams and re-enable the button in the onEnd
of that merge.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With