# Broadcastable / Receivable

A broadcastable and receivable are `observable` values that allow you to share data and state between two different areas of your application. They are based off of `observables` and work by proxying their values over a namespace bus.

As you might have guessed, it has two parts:

- receivable: observable that receives its value from a broadcastable.

- broadcastable: observable that broadcasts, or syncs its value/state with other areas of your application.

    // setup observable that broadcasts its value
    var broadcast = fw.observable('Hello').broadcast('broadcast', 'myNamespace');

    // receive the value being broadcast
    var receive = fw.observable().receive('broadcast', 'myNamespace');

    // The receive observable is now held in sync with the broadcast observable
    // receive() === 'Hello'

Note

Please be aware that there are some notes on instantiation order, and other context/use specific details that are covered in the usage notes section.

## Receivable

Receivables are `observables` that subscribe to and listen for a `broadcastable` on a `namespace`, keeping its value in sync. They are created by calling `.receive(varName, namespace)` on an `observable`:

    // create the broadcastable that sends/sync with the receivable
    var myName = fw.observable('Smith').broadcast('myName', 'someNamespace');

    // The receivable which receives/syncs with the broadcastable
    var receivedName = fw.observable().receive('myName', 'someNamespace');
    // receivedName() === 'Smith'

    // write to myName (the broadcastable) which then updates receivedName
    myName('Jack');
    // receivedName() === 'Jack'

Tip

You can also pass a namespace instance as the second parameter:

    var someNamespace = fw.namespace('someNamespace');
    var myName = fw.observable().receive('myName', someNamespace);

### Writing To Receivables

Receivables can be written to just like any other observable property. Depending on the configuration of its corresponding broadcastable, there are two scenarios to be aware of:

- The corresponding broadcastable is not configured to be writable or not instantiated

  If you write to a receivable when its broadcastable is not configured to be writable, or no corresponding broadcastable is instantiated, then the value is not changed. This is because it updates only when the corresponding broadcastable sends it a new value.

  If no broadcastable is listening, or it is not configured to be writable, then the value is not written to it (and thus does not propogate back to any receivables).

- The corresponding broadcastable is configured to be writable

  If you write to a receivable whos broadcastable is configured to be writable, then the value is written to the broadcastable and propogates out to any corresponding receivables (including the one that was written to).

For more information see: Writable Broadcastables

## Broadcastable

Broadcastables are created by calling `.broadcast(varName, namespace)` on an `observable`. The `varName` is the name which the other side will listen for, and the `namespace` is the bus to broadcast the value over.

    var myName = fw.observable('test').broadcast('myName', 'someNamespace');

There are two primary modes a broadcastable can be created in:

- Read-Only

  Sync is one way, from broadcastable to receivable. Values written to the broadcastable propogate to its receivables but not vice-versa.

- Writable

  Sync can occur in both directions. Values written to a receivable propogate back to its corresponding broadcastable.

Tip

- Just like with receivables, you can also pass a namespace instance as the second parameter:

      var someNamespace = fw.namespace('someNamespace');
      var myName = fw.observable().broadcast('myName', someNamespace);

- If you are creating a `broadcastable` from within the context of a viewModel, dataModel, or router then you can also pass it the instance and it will use its `namespace`:

      function MyViewModel () {
        var self = fw.viewModel.boot(this, {
          namespace: 'MyViewModel'
        });

        this.myName = fw.observable().broadcast('myName', self);
      }

  This can be especially helpful when you have several properties to broadcast and want to keep your code DRY.

### Read-Only Broadcastable

By default a broadcastable is read-only. This means that it broadcasts only (syncing is one-way, from broadcastable to receivable). A receivable cannot write back to a read-only broadcastable.

    var myName = fw.observable('test').broadcast('myName', 'someNamespace');

As a general rule is its best to use the same variable name when broadcasting. This helps avoid confusion when wiring up any corresponding receivables for it.

### Writable Broadcastables

You can optionally pass a 3rd boolean parameter to `.broadcast` which (if true) makes it a writable `broadcastable`. A writable `broadcastable` will allow any `receivable` to write back to it.

For example, we can create a writable broadcastable like so:

    var myName = fw.observable('Smith').broadcast('myName', 'Person', true);

We can then create a receivable which receives/syncs with the broadcastable:

    var receivedName = fw.observable().receive('myName', 'Person');
    // receivedName() === 'Smith'

`receivedName` is instantiated and is set to the current value of `myName` (its corresponding broadcastable).

If we then write to `receivedName` (the receivable), the value is written to the broadcastable which then propogates back to the receivable receivedName.

    receivedName('Jack');
    // myName() === 'Jack'
    // receivedName() === 'Jack'

## Usage Notes

There are a few special conditions where the behavior of a broadcastable and receivable need to be defined:

### Instantiation Order

When a `receivable` is instantiated it will request the current value from its corresponding `broadcastable`. This means it does not matter the order in which you instantiate them.

Creating the broadcastable first:

    var myName = fw.observable('Jerry').broadcast('myName', 'someNamespace');

    var receivedName = fw.observable().receive('myName', 'someNamespace');
    // receivedName() === 'Jerry'

The above example shows that when a `receivable` is instantiated it retrieves the current value from its corresponding `broadcastable` (if it exists).

Creating the receivable first:

    var receivedName = fw.observable().receive('myName', 'someNamespace');
    // receivedName() === undefined

    var myName = fw.observable('Jerry').broadcast('myName', 'someNamespace');
    // receivedName() === 'Jerry'

The example above shows when `myName` is initialized it then updates `receivedName` even though the `myName` is created after `receivedName`. This is because upon instantiation, a `broadcastable` broadcasts the current value which any listening `receivables` then is updated with.

### Multiple Broadcastables

If you create multiple `broadcastable` instances that all point to the same variable, then:

- Each `broadcastable` retains their local value, regardless of what the other broadcastables are set as.
- When instantiated, `receivables` will receive all of the current broadcastable values, but only retain the last.
- The `receivables` will have the most recently broadcasted value.

### Using Non-Primitive Types

Non-primitive types (such as `Arrays` or `Objects`) are passed by reference. This means that if you broadcast/receive one of these pass-by-reference values, each side will have a direct reference.

For example:

    var thisThing = fw.observable().broadcast('thisThing', 'someNamespace');
    var thatThing = fw.observable().receive('thisThing', 'someNamespace');

    // log any changes to thatThing to the console
    thatThing.subscribe(function(newThings) {
      console.log(newThings);
    });

    // modify thisThing which then propogates to thatThing, which then gets logged
    thisThing(['this array', 'of values', 'is not', 'a primitive']);
    // console logs: ['this array', 'of values', 'is not', 'a primitive']

If you then modify the observables value directly, the other side will not be notified of the changed:

    var thisThingData = thisThing();

    // modify thisThing, but directly.
    thisThingData.push('it was modified');
    // console does not log anything
    // thatThing() === ['this array', 'of values', 'is not', 'a primitive', 'it was modified']

Above you can see that when we modify the underlying reference to the `thisThing` (which happens to be an `Array`) the value of `thatThing` is also updated...but nothing is logged to the console because we modified the underlying reference to the value...which Footwork doesn't know about.

This may be OK for your application, as long as you are aware of its consequences. You can avoid this issue by only using `broadcast` and `receive` with primitive values.

## Lifecycle

Both receivables and broadcastables make a subscription to the designated `namespace` bus, because of this they need to be disposed of before they can be garbage collected (and freed from memory).

To dispose of them, you call the `dispose` method:

    var receivedName = fw.observable().receive('myName', 'someNamespace');

    // ... some time later
    receivedName.dispose();

Note

If your `receivable`/`broadcastable` is attached to a viewModel, dataModel, or router instance then it will be disposed of along with it (just like all other properties).