Skip to content

Commit

Permalink
Merge pull request knockout#929 from SteveSanderson/382-optionsAfterR…
Browse files Browse the repository at this point in the history
…ender

add optionsAfterRender binding parameter for the options binding
  • Loading branch information
rniemeyer committed May 13, 2013
2 parents 56c0436 + c182b07 commit d386f14
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
20 changes: 20 additions & 0 deletions spec/defaultBindings/optionsBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,24 @@ describe('Binding: Options', function() {
expect(testNode.childNodes[0].selectedIndex).toEqual(2);
expect(testNode.childNodes[0]).toHaveTexts(["-", "Annie", "Bob"]);
});

it('Should call an optionsAfterRender callback function and not cause updates if an observable accessed in the callback is changed', function () {
testNode.innerHTML = "<select data-bind=\"options: someItems, optionsText: 'childprop', optionsAfterRender: callback\"></select>";
var callbackObservable = ko.observable(1),
someItems = ko.observableArray([{ childprop: 'first child' }]),
callbacks = 0;
ko.applyBindings({ someItems: someItems, callback: function() { callbackObservable(); callbacks++; } }, testNode);
expect(callbacks).toEqual(1);

// Change the array, but don't update the observableArray so that the options binding isn't updated
someItems().push({ childprop: 'hidden child'});
expect(testNode.childNodes[0]).toContainText('first child');
// Update callback observable and check that the binding wasn't updated
callbackObservable(2);
expect(testNode.childNodes[0]).toContainText('first child');
// Update the observableArray and verify that the binding is now updated
someItems.valueHasMutated();
expect(testNode.childNodes[0]).toContainText('first childhidden child');
expect(callbacks).toEqual(2);
});
});
13 changes: 12 additions & 1 deletion src/binding/defaultBindings/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ ko.bindingHandlers['options'] = {
while (element.length > 0) {
element.remove(0);
}

// Ensures that the binding processor doesn't try to bind the options
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindingsAccessor) {
var selectWasPreviouslyEmpty = element.length == 0;
Expand Down Expand Up @@ -101,7 +104,15 @@ ko.bindingHandlers['options'] = {
}
}

ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, null, setSelectionCallback);
var callback = setSelectionCallback;
if (allBindings['optionsAfterRender']) {
callback = function(arrayEntry, newOptions) {
setSelectionCallback(arrayEntry, newOptions);
ko.dependencyDetection.ignore(allBindings['optionsAfterRender'], null, [newOptions[0], arrayEntry !== caption ? arrayEntry : undefined]);
}
}

ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, null, callback);

// Clear previousSelectedValues so that future updates to individual objects don't get stale data
previousSelectedValues = null;
Expand Down

0 comments on commit d386f14

Please sign in to comment.