Reputation: 1945
I have select list in my html binded to observable array
<select data-bind="options: myData, optionsText: 'Name', value: selectedId"></select>
When i load my page i set value to observable selectedId
But when i set value it immediately calls its subscribe event
selectedId.subscribe(function (row) {
// some logic for retrieving data
});
I dont want subscribe event to call when value is being set programatically but only want to call when user selects something from list.
Is it possible to do? Cant find any good examples.
Update1
i set value to my observable selectedId
in this way
selectedId(ko.utils.arrayFirst(data(), function(item) {
return item.id=== 5;
}));
I think because of this its firing subscribe event
Upvotes: 0
Views: 411
Reputation: 45135
If you set the initial value before you actually subscribe, then you shouldn't get a subscription event firing. For example:
function ViewModel() {
var self = this;
self.selectedID = ko.observable();
self.selectedID(10); // this won't fire the event because we haven't subscribed yet
self.selectedID.subscribe(function(value) {
alert("value changed by user");
});
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="number" data-bind="value: selectedID" />
Now if you want to solve the general case, where the value might change programmatically later and you don't want the subscribe
to fire then, you might want to have a flag that you can use to simply skip the processing of the subscribe
handler. Something like:
function ViewModel() {
var self = this;
self.selectedID = ko.observable();
self.selectedID(10); // this won't fire the event because we haven't subscribed yet
var _skipNotification = false; // this tells us whether or not we should process subscribe
// putting this logic in a function makes it easier if you have multiple places
// where you need to programmatically set the id.
function setSelectedID(value) {
_skipNotification = true;
self.selectedID(value);
_skipNotification = false;
}
self.selectedID.subscribe(function(value) {
if (!_skipNotification) {
alert("value changed by user");
}
});
self.changeProgrammatically = function() {
setSelectedID(1);
};
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="number" data-bind="value: selectedID" />
<input type="button" data-bind="click: changeProgrammatically" value="change programmatically" />
Here's your fiddle fixed to use the technique above. A local variable _skipNotification
is defined in the view model and checked in the subscribe event. Then the importData
function that is called from the mouse click looks like this:
this.importData = function () {
skipNotification = true;
self.selectedGroup(ko.utils.arrayFirst(self.availableGroups(), function (val) {
//debugger;
return val.GroupId == 8;
}));
skipNotification = false;
console.log("Lets see if it hits me first");
};
This will set the selectedGroup
without causing the body of the selectedGroup.subscribe
to execute. Note that as a result the selectedGroupId
doesn't get set so your one span will still say You have chosen Nothing
despite the fact that something is selected in the drop-down. I'm not sure if that was what you were actually going for, but it seems pretty misleading. Especially since the only way to now get it to correctly read You have chosen Football Team
is to select something else first and then reselect Football Team
.
Upvotes: 1