How do I force a Knockout subscribe to fire when the value doesn't change?
Asked Answered
D

1

11

I have a set of cascading dropdown lists which are used to select a house address. We break apart the address in this order:

  1. Street Name (e.g. 10th, 11th, Main)
  2. Street Suffix (e.g. St, Ave)
  3. Street Direction
  4. Street Number (house number)

I am using knockout to generate the values in the dropdowns which are pulled from the database via REST queries. I have this working well, except for a single edge case.

First let me tell you a bit about addresses (when they are broken apart like this). There is always a street name and there is always a street number. Suffix and direction aren't always used. So I might have a 100 Savanna South (Savanna South being the street name), or 101 Main St. I have these scenarios working assuming that the suffix and direction change.

The problem is that when I switch from say 10th to 11th. They both only have a suffix of "Street" and both have only one direction of "West". When I make the change, suffix and direction don't change which does not trigger the appropriate subscribes to pull the next set of data. So if I change from 10th to 11th, the house numbers don't update.

function AddViewModel() {
/* Address */
self.StreetName = ko.observable('');
self.StreetNames = ko.observableArray([""]);
self.StreetName.subscribe(function (val) {
    if ((val !== undefined && val !== null && val !== '') && val !== viewModel.StreetType()) {
        getStreetTypes(val);
    }
});

self.StreetType = ko.observable('');
self.StreetTypes = ko.observableArray([]);
self.StreetType.subscribe(function (val) {
    if (val !== undefined && val !== null && val !== '') {
        alert("I changed to " + val);
        getStreetDirections(self.StreetName, val);
    }
});

self.StreetDirection = ko.observable('');
self.StreetDirections = ko.observableArray([]);
self.StreetDirection.subscribe(function (val) {
    if (val !== undefined && val !== null && val !== '') {
        getStreetNumbers(self.StreetName, self.StreetType, val);
    }
});

self.StreetNumber = ko.observable('');
self.StreetNumbers = ko.observableArray([]);
self.StreetNumber.subscribe(function (val, e) {
    if (val !== undefined && val !== null && val !== '') {
            $.get('/api/gis/addressview/getaddress',
                { streetName: $('#StreetName').val(), streetType: $('#StreetType').val(), streetDirection: $('#StreetDirection').val(), streetNumber: val },
                function (result) {
                    loadAddresses(result);
                }, 'json');
    }
});
}

// Get the street types
function getStreetTypes(streetName) {
    $.get('/api/gis/cascadingaddress/getstreettypes', { streetName: streetName }, function (result) {
        viewModel.StreetTypes(result);

        // If there is only one street type, load it.
        if (result.length === 1) {
            if (result[0] !== "" && result[0] !== " ") {
                viewModel.StreetType(result[0]);
                viewModel.StreetType.notifySubscribers();
            } else {
                getStreetDirections(streetName, result[0]);
                viewModel.StreetType.notifySubscribers();
            }
        }
    }, 'json');
}

function getStreetDirections(streetName, streetType) {
    $.get('/api/gis/cascadingaddress/getstreetdirections', { streetName: streetName, streetType: streetType }, function (result) {
        viewModel.StreetDirections(result);

        // If there is only one street direction, load it
        if (result.length === 1) {
            if (result[0] !== "" && result[0] !== " ") {
                viewModel.StreetDirection(result[0]);
                viewModel.StreetDirection.valueHasMutated();
            } else {
                getStreetNumbers(streetName, streetType, result[0]);
                viewModel.StreetDirection.valueHasMutated();
            }
        }
    }, 'json');
}

function getStreetNumbers(streetName, streetType, streetDirection) {
    $.get('/api/gis/cascadingaddress/getstreetnumbers', { streetName: streetName, streetType: streetType, streetDirection: streetDirection }, function (result) {
        viewModel.StreetNumbers(result);
    }, 'json');
}

I have been trying several things from doing a jQuery $.trigger('change') on the field to what you see above with adding .valueHasMutated(). I could write elaborate code to check if the street name has changed, but the suffix and direction hasn't, then reload the street numbers, but I am trying to keep within the subscribe framework if possible.

Can anyone point me in the right direction to either trigger the .subscribe() function or how to take another approach?

NOTE: I really can't do a JSFiddle given that the REST endpoints are in a private network and are not publicly available. Otherwise I would provide one.

Debbi answered 15/8, 2014 at 16:50 Comment(4)
Since you've already tried .valueHasMutated(), how about declaring the observables as ko.observable('').extend({notify: 'always'});? From here.Fecit
I am not familiar with that. I'll take a look.Debbi
Also see here for more info on extending observables.Fecit
Make that an answer, and I'll mark it as so.Debbi
F
17

Since you've already tried .valueHasMutated(), how about declaring the observables as ko.observable('').extend({notify: 'always'});? From here, and see here for more info on extending observables.

Fecit answered 15/8, 2014 at 19:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.