-
Notifications
You must be signed in to change notification settings - Fork 0
Example: Observing Property Values
The intent of this example is to create an IObservable
that contains the values of a property as they change over time.
Our class looks like this:
public class BankAccount extends EventDispatcher
{
[Bindable]
public function var balance : Number;
}
Our requirements is to have a sequence that contains the values of the balance property, and has the following specifications:
- It should emit new values when the property changes
- It should start with the current value
Flex supports property change notification using the PropertyChangeEvent
event, so let’s start with that:
var propertyValues : IObservable = Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE);
There are a few problems with just using the event alone:
- It contains all property change events, not just the “balance” property
- It contains
PropertyChangeEvent
values, notNumber
values - It doesn’t contain the current value (it won’t emit a value until the property changes)
Let’s start by filtering the events using filter:
var propertyValues : IObservable = Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE)
.filter(function(ev : PropertyChangeEvent) : Boolean { return ev.property == "balance"; });
Then we can use map to project the value of the property, replacing the event value:
var propertyValues : IObservable = Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE)
.filter(function(ev : PropertyChangeEvent) : Boolean { return ev.property == "balance"; })
.map(funtion(ev : PropertyChangeEvent) : Number { return ev.newValue; });
Finally, we will return the current value of the property using startWith:
var propertyValues : IObservable = Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE)
.filter(function(ev : PropertyChangeEvent) : Boolean { return ev.property == "balance"; })
.map(funtion(ev : PropertyChangeEvent) : Number { return ev.newValue; })
.startWith(account.balance);
Now we can put it all together:
var account : Account = new Account();
account.balance = 50;
getAccountBalanceValues(account).subscribe(function(balance : Number) : void
{
trace("The balance is now " + balance);
});
account.balance = 100;
account.balance = 0;
account.balance = 25;
private function getAccountBalanceValues(account : Account) : IObservable
{
return Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE)
.filter(function(ev : PropertyChangeEvent) : Boolean { return ev.property == "balance"; })
.map(funtion(ev : PropertyChangeEvent) : Number { return ev.newValue; })
.startWith(account.balance);
}
The trace output of this application is:
The balance is now 50
The balance is now 100
The balance is now 0
The balance is now 25
In the above example, we used startWith
to include the current value at the start of the stream. The problem with passing the value straight in is that it is evaluated when getAccountBalanceValues
is called, not when the IObservable
is subscribed to. This is fine when they occur consequtively, but not when the IObservable
is stored as subscribed to later.
To avoid this bug, let’s use defer to resolve the value when the subsciption occurs. We can still use startWith as it converts it’s argument to a sequence using toObservable, which means we can pass it an IObservable
and it will start with that:
private function getAccountBalanceValues(account : Account) : IObservable
{
return Observable.fromEvent(account, PropertyChangeEvent.PROPERTY_CHANGE)
.filter(function(ev : PropertyChangeEvent) : Boolean { return ev.property == "balance"; })
.map(funtion(ev : PropertyChangeEvent) : Number { return ev.newValue; })
.startWith(Observable.defer(function():IObservable
{
return Observable.value(account.balance);
});
}
Here are some ways you could use the IObservable
of property values that we’ve created:
- Combine two different property values using combineLatest to be notified when either property changes
- Use filter to have a sequence that notifies only when the account balance goes below 0