Question

I am sure I am missing something obvious but I can't seem to make heads or tails of this problem. I have a web page that is being driven by javascript. The bindings are being provided by Knockout.js, the data is coming down from the server using Breeze.js, I am using modules tied together with Require.js. My goal is to load the html, load the info from Breeze.js, and then apply the bindings to show the data to the user. All of these things appear to be happening correctly, just not in the correct order which is leading to weird binding errors. Now on to the code.

I have a function that gets called after the page loads

function applyViewModel() {
        var vm = viewModel();
        vm.activate()
            .then(
                applyBindings(vm)
            );
    }

This should call activate, wait for activate to finish, then apply bindings....but it appears to be calling activate, not waiting for it to finish and then runs applybindings.

activate -

function activate() {
            logger.log('Frames Admin View Activated', null, 'frames', false);

            return datacontext.getAllManufacturers(manufacturers)
                .then(function () {
                    manufacturer(manufacturers()[0]);
                }).then(function () {
                    datacontext.getModelsWithSizes(modelsWithSizes, manufacturers()[0].manufacturerID())
                        .then(datacontext.getTypes(types));
                });
        }

datacontext.getAllManufacturers -

var getAllManufacturers = function (manufacturerObservable) {
        var query = entityQuery.from('Manufacturers')
            .orderBy('name');

        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            if (manufacturerObservable) {
                manufacturerObservable(data.results);
            }
            log('Retrieved [All Manufacturer] from remote data source',
                data, true);
        }
    };

datacontext.getModelsWithSizes -

var getModelsWithSizes = function (modelsObservable, manufacturerId) {
        var query = entityQuery.from('Models').where('manufactuerID', '==', manufacturerId)
            .orderBy('name');

        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            if (modelsObservable) {
                for (var i = 0; i < data.results.length; i++) {
                    datacontext.getSizes(data.results[i].sizes, data.results[i].modelID());

                    // add new size function
                    data.results[i].addNewSize = function () {
                        var newValue = createNewSize(this.modelID());
                        this.sizes.valueHasMutated();
                        return newValue;
                    };
                }
                modelsObservable(data.results);

            }
            log('Retrieved [Models With Sizes] from remote data source',
                data, false);
        }
    };

Any help on why this promise isn't working would be appreciated, as would any process to figure it out so I can help myself the next time I run into this.

Was it helpful?

Solution

A common mistake when working with promises is instead of specifying a callback, you specify the value returned from a callback:

function applyViewModel() {
    var vm = viewModel();
    vm.activate()
        .then( applyBindings(vm) );
}

Note that when the callback returns a regular truthy value (number, object, string), this should cause an exception. However, if the callback doesn't return anything or it returns a function, this can be tricky to locate.

To correct code should look like this:

function applyViewModel() {
    var vm = viewModel();
    vm.activate()
        .then(function() {
            applyBindings(vm);
        });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top