Search code examples
frpbacon.js

How can I create a Bacon.Property representing a property in a referenced object?


I have started playing with Bacon.js, and I have come across a problem I can't find any example for.

I have a set of nodes, which may reference other nodes.

It looks like this in imperative code:

alice = { name: "Alice" }
bob   = { name: "Bob" }
carol = { name: "Carol" }

alice.likes = bob
bob.likes = carol
alice.likes.name //=> "Bob"

bob.name = "Bobby"
alice.likes.name //=> "Bobby"

alice.likes = carol
alice.likes.name //=> "Carol"

Now, I would like to have a Property for alice.likes.name, which has to change whenever alice.likes points to a different object, or the name property of the current object in alice.likes changes.

I have come up with the code below (LiveScript syntax), which correctly logs 3 messages: Bob, Bobby, Carol.

I'm using Bus for testing purposes.

mkBus = (initialValue) ->
  bus = new Bacon.Bus()
  property = bus.toProperty(initialValue)
  property.push = (newValue) -> bus.push(newValue)
  property

alice = { pName: mkBus("Alice"), pLikes: mkBus(null) }
bob   = { pName: mkBus("Bob"),   pLikes: mkBus(null) }
carol = { pName: mkBus("Carol"), pLikes: mkBus(null) }

alice.pLikes.onValue (person) ->
  if person
    person.pName.onValue (vName) ->
      console.log vName

alice.pLikes.push(bob)
bob.pLikes.push(carol)

# Change name
bob.pName.push("Bobby")

# Change reference
alice.pLikes.push(carol)

Question: How can I make a Property that represents the name of alice.likes.name?

I.e:

nameOfAlicesFavourite.onValue (vName) ->
  console.log vName

I'm new to FRP, so let me know if I'm doing something horribly wrong.


Solution

  • Thanks @Bergi for pointing me to flatMap.

    flatMap creates a new stream for every event in the source. I used flatMapLatest, so that only the name changes from the latest liked person are transmitted on the output stream.

    Here's the code:

    nameOfAlicesFavourite = alice.pLikes.flatMapLatest (person) ->
      if person
        person.pName
      else
        Bacon.never!