baconjs / bacon.js Goto Github PK
View Code? Open in Web Editor NEWFunctional reactive programming library for TypeScript and JavaScript
Home Page: https://baconjs.github.io
License: MIT License
Functional reactive programming library for TypeScript and JavaScript
Home Page: https://baconjs.github.io
License: MIT License
Hi! For example, I have a class with bus:
class SomeClass
constructor: (@node) -> # @node istanceof jQuery
@bus = new Bacon.Bus()
render: (data) ->
@node.get(0).innerHTML = "<!--some template HTML rendered by data-->"
@stream = @node.children().asEventStream("click")
.map(".currentTarget")
@bus.plug @stream
reRender: (data) ->
@node.get(0).innerHTML = ""
#???
render (data)
This is what I have to do: I need to re-render @node
contains (it calls by another event) so I need to unplug current stream and replug it in render function call inside reRender function (there is subscriber on bus, so I don't need to catch events of multiple streams; same time I can't create stream until @node
doesn't have any children to listen to).
How to unplug stream inside reRender function or how to improve this code?
Thanks
for example: Bacon.fromArray([1,6,7]).fold((a,b)->a.concat(b+1), []) will lead to stream with [1,7,8] value
The array in key
is converted into object with array indices as keys: {0: {x: 1}, 1: {x: 2}}
Bacon.combineTemplate({
key: [{ x: 1 }, { x: 2 }]
})
Temporary fix to prevent this:
var constArray = Bacon.constant([{ x: 1 }, { x: 2 }])
Bacon.combineTemplate({ key: constArray })
From the name, I expect "throttle" to mean: only send 1 change per N milliseconds.
But actually the method waits for a "quiet period" of N milliseconds.
I would call it waitUntilStable() or waitUntilStableFor(). Other options are skipUntilStable() or filterUntilStable(), but it doesn't really skip the value, it just holds it until the time has passed.
Initial value string becomes a single character:
Bacon.combineTemplate({
lol: new Bacon.Bus().toProperty('wut')
}).onValue(function(e){console.log(e.lol)})
=> 'w'
... and an initial value of false
becomes undefined
:
Bacon.combineTemplate({
lol: new Bacon.Bus().toProperty(false)
}).onValue(function(e){console.log(e.lol)})
=> undefined
When two or more properties are used, it works as expected:
Bacon.combineTemplate({
lol: new Bacon.Bus().toProperty('lol'),
wut: new Bacon.Bus().toProperty('wut')
}).onValue(function(e){console.log(e.lol, e.wut)})
=> 'lol wut'
As pointed out in #69, It would be great to be able to build a custom minified version of Bacon. That would allow us to include more features into the core without bloating the end-user library.
Any ideas how to do this?
It is unclear to me whether the "current value" of a property should be sent to a new onValue
subscriber of a property at the instant that they subscribe.
It seems to me that they should receive the "current" value, but maybe there's a reason they shouldn't.
Even so the actual behaviour seems inconsistent. A first subscriber on a stream will not receive the current value, but later subscribers will. Am I missing something or is this a bug?
I have created an example here: http://jsbin.com/itujas/3/edit but the behaviour is below as well.
Basically:
1
but it doesn't do anything until I push another value onto the bus.var bus = new Bacon.Bus();
var property = bus.toProperty();
bus.push(1);
bus.push(2);
property.onValue(function(value) { alert(value) });
//=> Nothing happens here?
bus.push(3); //=> Alert "3"
If I register a subscriber, then push a value, then register a second subscriber, the second subscriber receives the latest value on subscribing.
var bus = new Bacon.Bus();
var property = bus.toProperty();
property.onValue(function(value) { alert("First subscriber "+value) });
bus.push(1); //=> receive alert "First subscriber 1"
bus.push(2); //=> receive alert "First subscriber 2"
property.onValue(function(value) { alert("Second subscriber "+value) });
//=> receive alert "Second subscriber 2"
var bus = new Bacon.Bus();
var property = bus.toProperty();
property.onValue();
bus.push(1);
bus.push(2);
property.onValue(function(value) { alert(value) });
//=> receive alert "2" as I expect.
According to your documentation for takeUntil, it stops when it sees a Next event, specifically. However, your test for this EventStream requires that either: Bacon.repeatedly immediately sends an Initial event, or that takeUntil should stop upon an Initial event as well.
The way my JBacon library originally implemented everything, it would send the Initial event after the given delay to repeatedly, so the actual values the test should have expected would have been [1, 2, 3, 1] when takeUntil stops upon a Next event. I had to change my code so that the Initial event is sent immediately, and the amount of time before the stopper fires needed to be 5 in order to get the same expected values.
Like ".currentTarget.id" for extracting the id property of the currentTarget property of the stream value.
Options include
Topic says it all.
Sometimes it would be convenient to use multi-valued functions in side effects. I'd like to be able to combine a bunch of properties and do something in a function that accepts each property value as a param like
name // Property
age // Property
sex // Property
Bacon.combineAsArray(name, age, sex).onValues(function(name, age, sex) {
...
...
})
Sorry for the stupid example :)
The building/testing system is a bit confusing right now.
What we should have is a bit less options, I'd say. Should we ditch the Cakefile and go with grunt and npm? Should we make the gruntfile the entry point to all building and testing? What we definitely need is clear instructions for building and testing.
Opinions?
No problems reported so far (except do/switch that have already been renamed), but just to make sure we're safe, an automated browser test setup would be great.
Sometimes I've missed the ability to filter a stream by the current value of a Property.
Why shouldn't EventStream.map and filter also accept a Property as a parameter?
Bacon.js should have a decent build system (maybe based on grunt?) and a C.I (maybe Travis?). Someone should just do it. Is it you?
Suppose your UI produces a changing list of Things, that themselves are changing. We might model this as a
things :: Property([Property Thing])
in Haskellish, or a "Property whose value is an array of Properties, each of which has a Thing as a value".
I propose we add Property.flatten, which will convert this property into
things' :: Property([Thing])
I've already got the implementation in the Property.flatten branch. I'll merge it into master if anybody finds use for it.
Note that this is fully recursive so it will flatten any nested structures containing mixed static and dynamic data, and will make combineTemplate support the same kind of recursive combination. Actually flatten() is just a combination of flatMapLatest and combineTemplate.
Both Bus and EventStream have methods named end. This breaks bus.decorateWith
and property.sampledBy(bus)
behavior, as the implementation calls end
on the sampled stream.
As a workaround Property::sampledBy could be fixed to always call EventStream::end or filter given stream with true, but I guess either one needs to be renamed to avoid confusion.
Bacon.combineTemplate({
'first': (new Bacon.Bus()).toProperty(false),
'second': (new Bacon.Bus()).toProperty([]),
'third': (new Bacon.Bus()).toProperty(false)
}).map(function(triple) {
console.log(triple)
return [triple.first, triple.second, triple.third]
}).onValue(function(e) {console.log('value', e)})
=>
'value [false, false, undefined]'
When the initial value array has something in it the value locations are not messed up, but the value is taken out from the array:
Bacon.combineTemplate({
'first': (new Bacon.Bus()).toProperty(false),
'second': (new Bacon.Bus()).toProperty(['initialval']),
'third': (new Bacon.Bus()).toProperty(false)
}).map(function(triple) {
console.log(triple)
return [triple.first, triple.second, triple.third]
}).onValue(function(e) {console.log('value', e)})
=>
'value [false, "initialval", false]'
filter(id).sample(50) and sample(50).filter(id) gives different results
var allKeyUps = $(document).asEventStream("keyup")
var allKeyDowns = $(document).asEventStream("keydown")
function always(value) { return function (_) { return value } }
function keyCodeIs(keyCode) { return function (event) { return event.keyCode == keyCode } }
function keyDowns(keyCode) { return allKeyDowns.filter(keyCodeIs(keyCode)) }
function keyUps(keyCode) { return allKeyUps.filter(keyCodeIs(keyCode)) }
function concat(a1, a2) { return a1.concat(a2) }
function keyState(keyCode, value) {
return keyDowns(keyCode).map(always([value])).merge(keyUps(keyCode).map(always([]))).toProperty([0])
}
function head(array) { return array[0] }
var direction = keyState(38, 1)
.combine(keyState(40, 1), concat)
.combine(keyState(37, 1), concat)
.combine(keyState(39, 1), concat)
.map(head)
function id(x) { return x }
var movements = direction.sample(50).filter(id) // !!! filter(id).sample(50) works fine
movements.log()
bacon.js: 25.11.2012 from repo
JQuery: 1.8.3
JQuery UI: 1.9.2
If I comment out bacon.js autocomplete starts working.
Can be reproduced with:
$(".ajax").hide()
titleField = $("input#title")
title = Bacon.UI.textFieldValue(titleField)
title.log()
titleRequest = title.changes().filter(nonEmpty).throttle(300).map(
function(title) {
return {
url : "thingy/" + title
}
}
)
titleResponse = titleRequest.ajax()
titlesToShow = titleResponse.toProperty(true)
var titles = []
$.each(titlesToShow, function(i, val) {
titles.push(val.title);
})
$("input#title").autocomplete({source:titles})
I need a "switch-case" combinator like this:
var a = Bacon.constant("a")
var b = Bacon.constant("b")
var selector = Bacon.constant("a")
var result = selector.switchCase({"a": a, "b": b})
So the idea is to map, for instance, radio button selections to values from different source Properties. The implementation could be extremely simple:
Bacon.Property.prototype.switchCase = function(cases) {
var data = Bacon.combineTemplate(cases)
return this.combine(data, function(key, data) {
return data[key]
})
}
Now the question is: what would be the best name? I know there's a switchCase in RxJs but I don't know what it does and don't have docs :)
Would this be a better name?
This name would clearly link the method to flatMap. Also, it doesn't cause conflict with the switch
keyword.
Better suggestions?
Possibly add
Current release is 0.0.10.
I guess we should be nearer to 1.0.
Should we say we are at 0.9.0?
You tell me.
If I add bacon to my component.json file:
"dependencies": {
"bacon": "~0.0.4"
}
running bower install
fails because there are no tags for versions in the repo.
bower cloning git://github.com/raimohanska/bacon.js
bower cached git://github.com/raimohanska/bacon.js
bower fetching bacon
bower error Can not find tag satisfying: bacon#~0.0.4
Bacon.constant emits the value and then an end. This causes issues when you combine with other properties using .and() or .or()
I'm finding I need this a lot. Should this be in the main bacon library?
Bacon.EventStream.prototype.eventToValue = ->
@map (e) -> e.target.value
Currently, Property#filter returns a Property. This Property is not well-behaved; observers attached using onValue are not guaranteed to be called:
bus = new Bacon.Bus()
bus.toProperty(0).filter((i) -> i > 0).onValue (v) -> console.log(v)
Further, calling toProperty
on this Property is a no-op, so one can't create a new default value.
It seems like this should return an EventStream instead, and be closer to changes().filter(...)
, since there is no guarantee that any value will ever match the predicate. However, changes
still isn't quite appropriate because the initial value is ignored.
Please let me know your thoughts on this issue. I'd be happy to make the changes myself if you agree.
Assume you have properties A and B and property C = A + B. Assume that both A and B depend on D, so that when D changes, both A and B will change too.
When D changes d1 -> d2
, the value of A a1 -> a2
and B changes b1 -> b2
simultaneously, you'd like C to update atomically so that it would go directly a1+b1 -> a2+b2
. Unfortunately, Bacon.js does not recognize simultaneous events/updates and C will have a transitional state like a1+b1 -> a2+b1 -> a2+b2
Tests whether the current value 'is' the test value. Creates really clean code.
Bacon.Observable.prototype.is = (test) ->
@map (v) -> v is test
numberStream.is(3.14).toProperty(false)
Hi, I can't tell from the readme: is this a library for js or cs?
The value property of the Initlal/Next events should be changed to a function, to allow more flexibility in the implementation.
I don't expect too much problems in application code, as this does not affect the typical APIs. It only affects those who use the value field directly, as in
stream.subscribe(function(event) {
if (event.hasValue()) {
doStuffWith(event.value)
}
})
The main benefits would be on the performance side: huge combineTemplate systems would only be evaluated only when the value is actually accessed, for example when hitting a filter(..) or an onValue(..)
I want to change this before we release 1.0.0, because this is a compatibility breaker for some apps.
Would be convenient.
The only question is, should we delay the Init value. I suppose we shouldn't.
Opinions?
So far people have filed issues when they need support, and that's been fine. It might however be smarter to separate support requests from actual bugs / improvements.
General discussion around FRP, Bacon.js and related stuff might also be directed to some other forum than the closed issue #51 :)
Should we use Google Groups for general discussion, and encourage the use of Stack Overflow or Google Groups for support too?
Return this
npm test sporadically fails with the following:
Failures:
1) also accepts a field name instead of combinator function
Message:
Expected true to equal false.
Stacktrace:
Error: Expected true to equal false.
at new jasmine.ExpectationResult (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:102:32)
at null.toEqual (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:1171:29)
at verifyCleanup (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:924:43)
at expectPropertyEvents (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:836:14)
and
Failures:
1) returns events in bursts, passing through errors
Message:
Expected [ '<error>', [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ] to equal [ '<error>', [ 1, 2, 3, 4 ], [ 5, 6, 7 ] ].
Stacktrace:
Error: Expected [ '<error>', [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ] to equal [ '<error>', [ 1, 2, 3, 4 ], [ 5, 6, 7 ] ].
at new jasmine.ExpectationResult (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:102:32)
at null.toEqual (/Users/mtkopone/dev/bacon.js/node_modules/jasmine-node/lib/jasmine-node/jasmine-2.0.0.rc1.js:1171:29)
at verifySwitching (/Users/mtkopone/dev/bacon.js/spec/BaconSpec.coffee:885:22)
Now if you subscribe to an ended stream, you won't get any callback. Ever. Neither is there any way to query whether your stream has exhausted.
Should we send out an End event to any subscriber that comes in after the stream has ended?
hi,
To learn bacon.js I've implemented the "wallet war" of http://alfredodinapoli.wordpress.com/2011/12/24/functional-reactive-programming-kick-starter-guide with bacon.js
http://jsfiddle.net/bika/wGDp8/
but there is one thing I don't like, and would find a better way to handle it
walletChange.onValue(function(ev){
$fatherWallet.val(ev.target.valueAsNumber+10);
})
eventClick.onValue(function(val){
$sonWallet.val(parseFloat($sonWallet.val())+val);
$sonWallet.change()
})
As I trigger walletChange.onValue using $sonWallet.change, the jquery event is passed on, instead of the value of $sonWallet.
I'm not sure whether this can be overcome on the side of jQuery or Bacon, but would like to hear your idea on how to get the value of $sonWallet to be passed into walletChange.onValue.
Otherwise, I'm sending this issue in order to provide a very simple example for bacon.js. Especially having it compared with the corresponding Haskell code, the bacon.js implementation is much easier to grasp (I think).
var position = movements.scan(startPos, function (pos, move) { return pos + move })
var test = position.combine(position.skip(1), function (r, l) { return { left: l, right: r, toString: function () { return '{left:' + this.left + ', right:' + this.right + '}' } } })
test.log()
expected result is
{left:1,right:2}
{left:2,right:3}
{left:3,right:4}
but the actual result is
{left:1, right:1}
{left:1, right:2}
{left:2, right:2}
{left:2, right:3}
{left:3, right:3}
var allKeyDowns = $(document).asEventStream("keydown")
function always(value) { return function (_) { return value } }
function keyCodeIs(keyCode) { return function (event) { return event.keyCode == keyCode } }
function keyDowns(keyCode) { return allKeyDowns.filter(keyCodeIs(keyCode)) }
function concat(a1, a2) { return a1.concat(a2) }
function keyState(keyCode, value) {
return keyDowns(keyCode).map(always([value])).toProperty([0])
}
function head(array) { return array[0] }
var direction = keyState(38, 1)
.combine(keyState(40, 1), concat)
.combine(keyState(37, 1), concat)
.combine(keyState(39, 1), concat)
.map(head)
function id(x) { return x }
var movements = direction.filter(id).toEventStream()
var position = movements.scan(5, function (pos, move) { return pos + move })
function combine(r, l) { return { left: l, right: r, toString: function () { return '{left:' + this.left + ', right:' + this.right + '}' } } }
var test = position.combine(position.skip(1), combine)
test.log()
No problems with performance so far, but it might still be interesting to see how many events a sec you can pump through a bacon system like
src.filter(f1).map(f2).flatMap(f3)
Having that metrics established it would be possible to tweak the fat out of it. If we did this with as many browsers as possible, we'd also know something about browser compatibility. But a command-line node-based metric would be a good start.
Similar to is, but works with arrays.
Bacon.Observable.prototype.in = (test) ->
@map (v) -> test.indexOf(v) isnt -1
housingStream.in(['apartment', 'condo']).toProperty(false)
I'm planning on setting up a website for bacon.js. So far, I've got some ideas.
This is something I'll need help with. I ain't got mad skillzz with Photoshop, for instance.
I'm thinking something more in the spirit of
than
JQuery attr does not work like expected in 'Function Construction rules'
"disableButton.onValue(
Enabling works only by using removeAttr("disabled")
Also quoted in your blog post.
e.g. https://github.com/Reactive-Extensions/rxjs-jquery/blob/master/examples/KonamiCode.html
I might take a stab at this at some point, opening the issue to make sure people think it's a good idea.
my use case:
steps = new Bacon.Bus()
stepStarts = new Bacon.Bus()
stepEnds = new Bacon.Bus()
steps.windowWithCount(2).onValues (oldStep, newStep) ->
stepEnds.push(oldStep) if oldStep
stepStarts.push(newStep) if newStep
(then I could throw out this code):
do ->
oldStep = null
steps.onValue (newStep) ->
stepEnds.push(oldStep) if oldStep
stepStarts.push(newStep) if newStep
oldStep = newStep
Extensions. Libs that add something to Bacon. Something we don't care to include to the core.
For instance, there's Bacon.UI.js. I'd like to have more, like bacon.matchers, bacon.model etc.
Should figure out a smart way to build an extension like this, so that we could run automatic tests, build coffee->minified js, run jslint etc. I'd like to have AMD and Node.js compatibility for all modules too.
I think it would make sense to make a "bacon extension template" that could be used as a starting point for easily making and extension lib with all the aforementioned niceties.
This is not my strong area, so help would be appreciated here :)
Hi,
there is a callback for async callback in map and other functions?
for example
$().ready(function () {
$(".ss").asEventStream("click").map(function(e,cb) {
setTimeout(function() {
cb(5000)
},1000);
}).log();
});
function log should write 5000
Is it suitable to use the native map, filter, forEach, indexOf functions
in _.map, _.filter, _.each, _.contains
if browsers support these features?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.