Dart DocumentationobserveObservableMixin

ObservableMixin abstract class

Mixin for implementing Observable objects.

When a field, property, or indexable item is changed, a derived class should call notifyPropertyChange. See that method for an example.

abstract class ObservableMixin implements Observable {
 StreamController _broadcastController;
 List<ChangeRecord> _changes;

 Stream<List<ChangeRecord>> get changes {
   if (_broadcastController == null) {
     _broadcastController =
         new StreamController<List<ChangeRecord>>.broadcast(sync: true);
   }
   return _broadcastController.stream;
 }

 void _deliverChanges() {
   var changes = _changes;
   _changes = null;
   if (hasObservers && changes != null) {
     // TODO(jmesserly): make "changes" immutable
     _broadcastController.add(changes);
   }
 }

 /**
  * True if this object has any observers, and should call
  * [notifyPropertyChange] for changes.
  */
 bool get hasObservers => _broadcastController != null &&
                          _broadcastController.hasListener;

 /**
  * Notify that the field [name] of this object has been changed.
  *
  * The [oldValue] and [newValue] are also recorded. If the two values are
  * identical, no change will be recorded.
  *
  * For convenience this returns [newValue]. This makes it easy to use in a
  * setter:
  *
  *     var _myField;
  *     get myField => _myField;
  *     set myField(value) {
  *       _myField = notifyPropertyChange(
  *           const Symbol('myField'), _myField, value);
  *     }
  */
 // TODO(jmesserly): should this be == instead of identical, to prevent
 // spurious loops?
 notifyPropertyChange(Symbol field, Object oldValue, Object newValue) {
   if (hasObservers && !identical(oldValue, newValue)) {
     notifyChange(new PropertyChangeRecord(field));
   }
   return newValue;
 }

 /**
  * Notify observers of a change. For most objects [notifyPropertyChange] is
  * more convenient, but collections sometimes deliver other types of changes
  * such as a [ListChangeRecord].
  */
 void notifyChange(ChangeRecord record) {
   if (!hasObservers) return;

   if (_changes == null) {
     _changes = [];
     queueChangeRecords(_deliverChanges);
   }
   _changes.add(record);
 }
}

Subclasses

ObservableBase

Implements

Observable

Properties

final Stream<List<ChangeRecord>> changes #

The stream of change records to this object.

Changes should be delivered in asynchronous batches by calling queueChangeRecords.

deliverChangeRecords can be called to force delivery.

docs inherited from Observable
Stream<List<ChangeRecord>> get changes {
 if (_broadcastController == null) {
   _broadcastController =
       new StreamController<List<ChangeRecord>>.broadcast(sync: true);
 }
 return _broadcastController.stream;
}

final bool hasObservers #

True if this object has any observers, and should call notifyPropertyChange for changes.

bool get hasObservers => _broadcastController != null &&
                        _broadcastController.hasListener;

Methods

void notifyChange(ChangeRecord record) #

Notify observers of a change. For most objects notifyPropertyChange is more convenient, but collections sometimes deliver other types of changes such as a ListChangeRecord.

void notifyChange(ChangeRecord record) {
 if (!hasObservers) return;

 if (_changes == null) {
   _changes = [];
   queueChangeRecords(_deliverChanges);
 }
 _changes.add(record);
}

dynamic notifyPropertyChange(Symbol field, Object oldValue, Object newValue) #

Notify that the field name of this object has been changed.

The oldValue and newValue are also recorded. If the two values are identical, no change will be recorded.

For convenience this returns newValue. This makes it easy to use in a setter:

var _myField;
get myField => _myField;
set myField(value) {
  _myField = notifyPropertyChange(
      const Symbol('myField'), _myField, value);
}
notifyPropertyChange(Symbol field, Object oldValue, Object newValue) {
 if (hasObservers && !identical(oldValue, newValue)) {
   notifyChange(new PropertyChangeRecord(field));
 }
 return newValue;
}