Simon
Simon

Reputation: 205

Binding selectand preventing a user selection certain options

<select data-bind="options: vm.BusinessStatus, optionsText: 'vcrStatus', optionsValue: 'intStatusID', value: CurrentStatus ">

vm.CurrentStatus.subscribe(function (newValue) {
    alert("the new value is " + newValue);
});

   self.BusinessStatus = ko.observableArray([{ "intStatusID": "2", "vcrStatus": "Provis" }, { "intStatusID": "1", "vcrStatus": "Active" }, { "intStatusID": "3", "vcrStatus": "Negative" }, { "intStatusID": "4", "vcrStatus": "Active (Verified)" }])

When the page loads and the select is being populated the event the alert will fire for each option untile it finally binds to the value. I wish to fire off an event if the user changes the current status to another status, and also restrict the user from selecting a status on the ui but not stop the dropdown from binding to this status if thats what is in the database. I have added the options as a Data will eventually come from a database but is currently as is in the example.

Upvotes: 0

Views: 46

Answers (1)

Ilya Luzyanin
Ilya Luzyanin

Reputation: 8110

I think you should use beforeChange option of KO subscription logic (see documentation).

Suppose your view model looks something like this:

function ViewModel() {
    var self = this;
    self.availableStatuses = ko.observableArray(["New", "In progress", "Fixed", "Verified"]);
    self.currentStatus = ko.observable("New");
    self.oldStatus = self.currentStatus();
    self.currentStatus.subscribe(function(oldValue) {
        self.oldStatus = oldValue ;
    }, null, 'beforeChange');
    self.currentStatus.subscribe(function(newValue) {
        if (newValue != "New" && newValue != "In progress") {
            alert("Value " + newValue + " is not allowed!");
            self.currentStatus(self.oldStatus);
        }
    });
}

Where availableStatuses contains array of your available statuses from the database, currentStatus is an observable with currently selected status. You also can see 2 subscriptions here, first one is fired before currentStatus is changed to remember its value and the second one fires after the change, makes validations and sets the value accordingly.

Markup looks like this:

<select data-bind="options: availableStatuses, value: currentStatus"></select>

Here is working demo.

Edit:

To postpone subscriptions until the moment the data is loaded you can do something like this:

ViewModel.prototype.init = function() {
    var self = this;
    // Let's assume that we made an ajax call to server to get data and in success callback
    // we populate the data and adding subscriptions.
    self.availableStatuses(["New", "In progress", "Fixed", "Verified"]);
    self.currentStatus(self.availableStatuses()[0]);
    // make subscriptions
    self.currentStatus.subscribe(function(oldValue) {
        self.oldStatus = oldValue ;
    }, null, 'beforeChange');
    self.currentStatus.subscribe(function(newValue) {
        if (newValue != "New" && newValue != "In progress") {
            alert("Value " + newValue + " is not allowed!");
            self.currentStatus(self.oldStatus);
        }
    });
}

See updated demo. You also may find useful the dispose() method (see Explicitly subscribing to observables) that can be applied to subscription (for example, when you need to reload your available statuses, you can dispose currentStatus subscriptions and add new ones after loading is complete.

Upvotes: 1

Related Questions