can-observation
Create observable values that derive their value from other observable values.
new Observation( fn [, context][, options] )
Creates an observable value from the return value of the given function called with this
as the context
.
The following creates a fullName
observation that derives its values from
the person
observable.
import Observation from "can-observation";
import observe from "can-observe";
const person = observe( { first: "Ramiya", last: "Meyer" } );
const fullName = new Observation( function() {
return person.first + " " + person.last;
} );
fullName.value; //-> "Ramiya Meyer";
fullName.on( function( newName ) {
newName; //-> "Bodhi Meyer"
} );
person.first = "Bodhi";
Parameters
- fn
{function}
:The function whose value is being observed.
- context
{Object}
:What
this
should be whenfn
is called. - options
{Object}
:An object that can configure the behavior of the observation with the following properties:
- priority
{Number}
- The priority this observation will be updated within can-queues. - isObservable
{Boolean}
- If reading this observable should call add.
- priority
Use Cases
can-observation
is used to derive values from other values without
having to explicitly bind. This is used many places within CanJS:
- can-define
getters
that cache their value. - can-stache's live binding.
Use
To use can-observation
, import it and create an observation that
reads from other observables and returns a value.
The following creates a fullName
observation that derives its values from
the person
observable.
import Observation from "can-observation";
import observe from "can-observe";
const person = observe( { first: "Ramiya", last: "Meyer" } );
var fullName = new Observation(function fullName(){
return person.first + " " + person.last;
});
fullName.value; //-> "Ramiya Meyer";
fullName.on( function( newName ) {
newName; //-> "Bodhi Meyer"
} );
person.first = "Bodhi";
Use off to unbind.
Debugging
Naming Functions
Observations name themselves using the name of the
function passed to them. If you are using a can-observation
directly, you should make sure the
function has a meaningful name.
This can be done by using function declarations like:
var fullName = new Observation(function fullName(){
return person.first + " " + person.last;
});
Instead of:
var fullName = new Observation(function(){
return person.first + " " + person.last;
});
You can also name functions as follows:
//!steal-remove-start
var fn = function(){ ... };
Object.defineProperty(fn, "name", {
value: "some meaningful name",
});
//!steal-remove-end
can-queues
If you use can-queues to debug, it's likely you'll see something like:
NOTIFY running : Observation<fullName>.onDependencyChange ▶ { ... } DERIVE running : Observation<fullName>.update ▶ { ... }
These tasks are when an observation noticed a dependency has changed and when it began to update
its value. If you expand the task object (▶ { ... }
), you should be able to see
exactly which dependency caused the observation to update.
How it works
can-observation
uses can-event-queue/value/value to implement its .on
, .off
methods and
call its internal .onBound
and .onUnbound
methods.
When bound for the first time, an observation calls its function between can-observation-recorder's
start and stop to see what dependencies have been
bound. It then uses recorder-dependency-helpers.js to bind those dependencies to it's dependencyChange
method.
When a dependency change happens, an observation adds its .update
method to the derive can-queues.
When the .update
happens, it repeats the process in the above paragraph, binding and unbind to whatever dependencies are
found with start and stop.
How it works: can-observation and can-observation-recorder
covers how can-observation
works.