[Tree] Check for change before scope.$apply

TreeView's observers will be called when the selected domain object
changes, which can occur for one of two reasons:

1. Because a new value was set externally, from mct-tree.
2. Because a new value was selected, by the user.

In the latter case a $apply is needed, but in the former it is not
(and causes an error.) However, when that case occurs, the value in
scope will be up to date already (it was a watch that triggered the
call to treeView.value) so no assignment or $apply is necessary.

Fixes #1114.
This commit is contained in:
Victor Woeltjen 2016-08-15 15:14:17 -07:00
parent 2100c5717e
commit 4e5887d9ec
2 changed files with 39 additions and 3 deletions

View File

@ -28,8 +28,10 @@ define([
function link(scope, element) {
var treeView = new TreeView(gestureService),
unobserve = treeView.observe(function (domainObject) {
scope.mctModel = domainObject;
scope.$apply();
if (scope.mctModel !== domainObject) {
scope.mctModel = domainObject;
scope.$apply();
}
});
element.append(angular.element(treeView.elements()));

View File

@ -29,6 +29,18 @@ define([
mockExpr,
mctTree;
function makeMockDomainObject(id) {
var mockDomainObject = jasmine.createSpyObj('domainObject-' + id, [
'getId',
'getModel',
'getCapability',
'hasCapability'
]);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn({});
return mockDomainObject;
}
beforeEach(function () {
mockGestureService = jasmine.createSpyObj(
'gestureService',
@ -56,7 +68,8 @@ define([
testAttrs;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']);
mockScope =
jasmine.createSpyObj('$scope', ['$watch', '$on', '$apply']);
mockElement = jasmine.createSpyObj('element', ['append']);
testAttrs = { mctModel: "some-expression" };
mockScope.$parent =
@ -88,6 +101,27 @@ define([
jasmine.any(Function)
);
});
// https://github.com/nasa/openmct/issues/1114
it("does not trigger $apply during $watches", function () {
mockScope.mctObject = makeMockDomainObject('root');
mockScope.mctMode = makeMockDomainObject('selection');
mockScope.$watch.calls.forEach(function (call) {
call.args[1](mockScope[call.args[0]]);
});
expect(mockScope.$apply).not.toHaveBeenCalled();
});
it("does trigger $apply from other value changes", function () {
// White-boxy; we know this is the setter for the tree's value
var treeValueFn = mockScope.$watch.calls[0].args[1];
mockScope.mctObject = makeMockDomainObject('root');
mockScope.mctMode = makeMockDomainObject('selection');
treeValueFn(makeMockDomainObject('other'));
expect(mockScope.$apply).toHaveBeenCalled();
});
});
});