[Switcher] Initialize on timeout

Initialize view switcher state on a timeout; this avoids
infinite digest cycles when deeply-nesting views.
WTD-689.
This commit is contained in:
Victor Woeltjen 2015-01-16 10:28:35 -08:00
parent 86c2cda7a2
commit 2bd896580e
3 changed files with 25 additions and 7 deletions

View File

@ -49,7 +49,7 @@
{
"key": "ViewSwitcherController",
"implementation": "controllers/ViewSwitcherController.js",
"depends": [ "$scope" ]
"depends": [ "$scope", "$timeout" ]
},
{
"key": "BottomBarController",

View File

@ -13,7 +13,7 @@ define(
* of applicable views for a represented domain object.
* @constructor
*/
function ViewSwitcherController($scope) {
function ViewSwitcherController($scope, $timeout) {
// If the view capability gets refreshed, try to
// keep the same option chosen.
function findMatchingOption(options, selected) {
@ -32,10 +32,12 @@ define(
// Get list of views, read from capability
function updateOptions(views) {
$scope.ngModel.selected = findMatchingOption(
views || [],
($scope.ngModel || {}).selected
);
$timeout(function () {
$scope.ngModel.selected = findMatchingOption(
views || [],
($scope.ngModel || {}).selected
);
}, 0);
}
// Update view options when the in-scope results of using the

View File

@ -10,12 +10,15 @@ define(
describe("The view switcher controller", function () {
var mockScope,
mockTimeout,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", [ "$watch" ]);
mockTimeout = jasmine.createSpy("$timeout");
mockTimeout.andCallFake(function (cb) { cb(); });
mockScope.ngModel = {};
controller = new ViewSwitcherController(mockScope);
controller = new ViewSwitcherController(mockScope, mockTimeout);
});
it("watches for changes in applicable views", function () {
@ -71,6 +74,19 @@ define(
expect(mockScope.ngModel.selected).not.toEqual(views[1]);
});
// Use of a timeout avoids infinite digest problems when deeply
// nesting switcher-driven views (e.g. in a layout.) See WTD-689
it("updates initial selection on a timeout", function () {
// Verify precondition
expect(mockTimeout).not.toHaveBeenCalled();
// Invoke the watch for set of views
mockScope.$watch.mostRecentCall.args[1]([]);
// Should have run on a timeout
expect(mockTimeout).toHaveBeenCalled();
});
});
}
);