[Core] Allow listening for mutation

Allow listeners to register with a domain object's
mutation capability to detect changes to that
domain object. Allows other components to respond
to these changes without resorting to polling on
timestamp or similar. WTD-1329.
This commit is contained in:
Victor Woeltjen 2015-06-24 10:20:49 -07:00
parent 47647f4ada
commit c668fa041a
2 changed files with 49 additions and 3 deletions

View File

@ -72,6 +72,13 @@ define(
* @constructor
*/
function MutationCapability(now, domainObject) {
var listeners = [];
function notifyListeners(model) {
listeners.forEach(function (listener) {
listener(model);
});
}
function mutate(mutator, timestamp) {
// Get the object's model and clone it, so the
@ -96,6 +103,7 @@ define(
copyValues(model, result);
}
model.modified = useTimestamp ? timestamp : now();
notifyListeners(model);
}
// Report the result of the mutation
@ -107,6 +115,15 @@ define(
return fastPromise(mutator(clone)).then(handleMutation);
}
function listen(listener) {
listeners.push(listener);
return function unlisten() {
listeners = listeners.filter(function (l) {
return l !== listener;
});
};
}
return {
/**
* Alias of `mutate`, used to support useCapability.
@ -139,10 +156,19 @@ define(
* @returns {Promise.<boolean>} a promise for the result
* of the mutation; true if changes were made.
*/
mutate: mutate
mutate: mutate,
/**
* Listen for mutations of this domain object's model.
* The provided listener will be invoked with the domain
* object's new model after any changes. To stop listening,
* invoke the function returned by this method.
* @param {Function} listener function to call on mutation
* @returns {Function} a function to stop listening
*/
listen: listen
};
}
return MutationCapability;
}
);
);

View File

@ -83,6 +83,26 @@ define(
// Should have gotten a timestamp from 'now'
expect(testModel.modified).toEqual(42);
});
it("notifies listeners of mutation", function () {
var mockCallback = jasmine.createSpy('callback');
mutation.listen(mockCallback);
mutation.invoke(function (m) {
m.number = 8;
});
expect(mockCallback).toHaveBeenCalled();
expect(mockCallback.mostRecentCall.args[0].number)
.toEqual(8);
});
it("allows listeners to stop listening", function () {
var mockCallback = jasmine.createSpy('callback');
mutation.listen(mockCallback)(); // Unlisten immediately
mutation.invoke(function (m) {
m.number = 8;
});
expect(mockCallback).not.toHaveBeenCalled();
});
});
}
);
);