Consider the following Bacon.js code sample (loosely based on the code here, uses bacon.model & bacon.jquery):
<input id="total" type="text" placeholder="total">
/
<input id="quantity" type="text" placeholder="quantity" value="1">
=
<span id="price"></span>
<script>
var $total = Bacon.$.textFieldValue($("#total")).changes();
var quantity = Bacon.$.textFieldValue($("#quantity"));
var price = Bacon.when(
[$total, quantity], function(x,y) { return x/y; }
).toProperty(0);
price.onValue(function (p) {
$('#price').text(p);
});
</script>
What happens here is that the stream $total
and the property quantity
are joined into a property price
. Both $total
and quantity
get their input from a text input field, but only $total
prompts price
to be updated. (I.e. quantity
is sampled but not part of the synchronization pattern.)
I am trying to achieve this same behavior using RxJS instead of Bacon.js, but all I can come up with is super ugly solutions. I reckon I must be overlooking something…?
My best shot so far (behavior not identical, but you get the idea):
var totalChange = Rx.Observable.fromEvent($('#total'), 'input');
var totalValue = totalChange.map(function () {
return parseInt($('#total').val(), 10);
});
var quantityValue = totalChange.map(function () {
return parseInt($('#quantity').val(), 10);
});
var price = Rx.Observable.zip(
totalValue,
quantityValue,
function (x,y) {
return x/y;
}
);
price.subscribe(function (p) {
$('#price').text(p);
});
Because neither combineLatest
or zip
offer the desired behavior on observables that represent the two text fields directly, all I can think of is to create an observable for quantity based on input events in the text field for total. Which works, but it feels pretty far-fetched.
Any suggestions for alternative approaches?
Use the recently added withLatestFrom
instead of combineLatest
.
var price = totalValue.withLatestFrom(quantityValue, (x,y) => x/y);
Compare their diagrams: