Make sure to wait for the current operation to finish before moving onto the next one

In the primeData function within the datacontext, four queries are made to a back-end Web API service:

function primeData(forceRefresh) {
    return (getLookups(forceRefresh) // this needs to complete before moving on
              .then(success))
              .then(model.initialize(datacontext)) // depends on getLookups
              .then(getDatasetOne()) // depends on model.initialize
              .then(getDataSetTwo()) // depends on model.initialize
              .then(getNonDependantDataset); // doesn't depend on previous calls

    function success(data) {

       if (!initialized) {
         datacontext.lookups = data.results[0];
         initialized = true;
       } else {
         datacontext.lookups = {
           teams: getLocal('Teams', 'id'),
           // other lookup values here                       
          };
       }
       // should I call model.initialize(datacontext) here??
    }
}

The second and third queries (getDatasetOne() and getDatasetTwo()) rely on model.initialize, which in turn relies on the results of the first query (getLookups()). How can we ensure that model.initialize is not executed until getLookups has successfully completed, and also make sure that getDatasetOne/Two are only called after the model has been initialized. The code has been simplified for clarity, but there seems to be confusion related to Q library usage. Any guidance on this issue would be appreciated.

CONTROLLER:

'use strict';

app.controller('HomeController',
    ['$scope', 'breeze', 'datacontext', 'logger', 
    function HomeController($scope, breeze, datacontext, logger) {

        function initialize(forceRefresh) {
            datacontext.initialize(forceRefresh)
                .then(getSucceeded)
                .fail(queryFailed)
                .fin(refreshView);
        }

        initialize();

        $scope.refresh = refresh;

        function refresh() {
            initialize(true);
        }

        function getSucceeded() {
            $scope.lookups = datacontext.lookups;
            $scope.datasetOne = datacontext.datasetOne;
            $scope.datasetTwo = datacontext.datasetTwo;
        }

        function refreshView() {
            $scope.$apply();
        }

        function queryFailed(error) {
            logger.error(error);
        }       
    }]);

DATACONTEXT:

app.factory('datacontext',
    ['breeze', 'Q', 'logger', 'model',
    function (breeze, q, logger, model) {

        var initialized;

        var manager = configureBreezeManager();

        var datacontext = {
            initialize: initialize,
            metadataStore: manager.metadataStore,
            saveEntity: saveEntity
        };

        return datacontext;

        //#region private members

        function initialize(forceRefresh) {
            if (!initialized || forceRefresh) {
                return primeData(forceRefresh).then(function () {
                    logger.log("Running Initialize");
                });
            } else {
                logger.log("Already Initialized");
                return q();
            }
        }

        function primeData(forceRefresh) {

            return (getLookups(forceRefresh)
                .then(success))
                .then(model.initialize(datacontext))
                .then(getDatasetOne())
                .then(getDataSetTwo())
                .then(getNonDependantDataset);

            function success(data) {

                if (!initialized) {
                    datacontext.lookups = data.results[0];
                    initialized = true;
                } else {
                    datacontext.lookups = {
                        teams: getLocal('Teams', 'id'),
                        // other lookup values here                       
                    };
                }
                // should I call model.initialize(datacontext) here??
            }
        }

        function getLookups(forceRefresh) {
            var query = breeze.EntityQuery
                .from('Lookups');

            if (initialized && !forceRefresh) {
                return true;
            }
            return manager.executeQuery(query);
        }

        function getDatasetOne() {
            var query = breeze.EntityQuery
                .from("EntityNameOne");
            return manager.executeQuery(query).then(getSucceeded);

            function getSucceeded(data) {
                datacontext.datasetOne = model.process(data.results)
                return q();
            }
        }

        function getDatasetTwo() {
            var query = breeze.EntityQuery
                .from("EntityNameTwo");
            return manager.executeQuery(query).then(getSucceeded);

            function getSucceeded(data) {
                datacontext.datasetTwo = model.process(data.results);
                return q();
            }
        }

        function getNonDependentDataset() {
            var query = breeze.EntityQuery
                .from('EntityNameThree');

            return manager.executeQuery(query).then(success);

            function success(data) {
                datacontext.nonNependentDataset = data.results;
            }
        }

        function saveEntity(masterEntity, message) {
            // standard implementation
        }

        function getLocal(resource, ordering) {
            var query = breeze.EntityQuery.from(resource)
                .orderBy(ordering);
            return manager.executeQueryLocally(query);
        }

        function configureBreezeManager() {
            // standard implementation
        }
    }]);

MODEL:

app.factory('model', ['logger', function (logger) {

    var datacontext;
    extendDatasetOne();
    extendDatasetTwo();

    var model = {
        initialize: initialize,
        getDatasetOne: getDatasetOne,
        getDatasetTwo: getDatasetTwo
    };

    return model;

    function initialize(context) {
        datacontext = context;        
    }

    function getDatasetOne(input) {
        var ret = [];
        for (var i = 0; i < input.length; i++) {
            var item = new TypeOne(input[i]);
            ret.push(item);
        }
        return ret;
    }

    function getDatasetTwo(input) {
        var ret = [];
        for (var i = 0; i < input.length; i++) {
            var item = new TypeTwo(input[i]);
            ret.push(item);
        }
        return ret;
    }

    function TypeOne(item) {
        var self = this;

        for (var prop in item) {
            if (item.hasOwnProperty(prop)) {
                self[prop] = item[prop];
            }
        }

        self.name = getNameForId(item.id);
    }

    function TypeTwo(item) {
        var self = this;

        for (var prop in item) {
            if (item.hasOwnProperty(prop)) {
                self[prop] = item[prop];
            }
        }

        self.name = getNameForId(item.id);
    }

    function extendDatasetOne() {
        // add properties to prototype
    }

    function extendDatasetOne() {
        // add properties to prototype
    }

    function getNameForId(id) {
        var set = datacontext.lookups.items;
        for (var i = 0; i < set.length; i++) {
            if (id == set[i].id) {
                return set[i].name;
            }
        }
        return null;
    }



}]);

Answer №1

Creating a function that returns a promise is a simple task:

function example() {
    var def = Q.def();
    
    serverCall(function (req) {
        if (req.status === 200) {
            def.resolve(req.responseText);
        } else {
            def.reject(new Error("Error: Status code " + req.status));
        }
    });
    
    return def.promise;
}

You can then use it with the .then() method.

Here's an illustration of how the primeData function could operate:

function primeData(forceRefresh) {
    function succeed(data) {
       if (!initialized) {
         datacontext.lookups = data.results[0];
         initialized = true;
       } else {
         datacontext.lookups = {
           teams: getLocal('Teams', 'id'),
           // other lookup values                       
          };
       }
    }

    var lookupsPromise = getLookups(forceRefresh);

    var successPromise = lookupsPromise.then(succeed); 

    var initializePromise = lookupsPromise.then(function () {
        model.initialize(datacontext); 
    });

    var datasetOnePromise = initializePromise.then(getDatasetOne);
    var datasetTwoPromise = initializePromise.then(getDatasetTwo);

    var dependentPromise = getNonDependantDataset();

    return q.all([lookupsPromise, successPromise, initializePromise, 
        datasetOnePromise, datasetTwoPromise, dependentPromise]);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The ng-model does not reflect changes when using the JQuery datepicker

Currently, I have set up two textboxes for users to choose a date. I am utilizing JqQuery's datepicker UI to showcase a small calendar pop-up whenever the user clicks on the textbox. However, an issue arises when I select a date in the calendar popup ...

Determine the daily volume of emails sent from the "no-reply email" address using the Nodemailer library

Our company currently utilizes Nodemailer for internal email communication. Lately, we have been encountering issues with exceeding our daily SMTP relays, resulting in some emails failing to send. To investigate further, I have been tasked with monitoring ...

Determining the minimum and maximum values of a grid using props in a React component

I have created a code for a customizable grid screen that is functioning perfectly. However, I am facing an issue where I want the minimum and maximum size of the grid to be 16 x 100. Currently, when a button is clicked, a prompt window appears asking for ...

The function of AJAX is to send and receive data asynchronously without

Recently, I was experimenting with AJAX. When I use echo "hello" in my PHP file, everything works perfectly. However, if I try something like echo "<script language=Javascript> alert('hi');</script>"; in the PHP file, the alert ...

Changes in query parameters on NextJS navigation within the same page do not activate hooks

When utilizing NextJS without SSR, I encountered an issue with basic navigation using different query parameters. Upon the initial arrival on the page/component, everything seems fine as the component gets mounted and URL params change accordingly. However ...

What is the best way to invoke a method within the $http body in AngularJS

When I try to call the editopenComponentModal method in another method, I encounter the following error: angular.js:13920 TypeError: Cannot read property 'editopenComponentModal' of undefined EditCurrentJob(job) { this.$http.put(pr ...

Retrieve the latest array from the Angular JS factory

Within the factory, I have declared an array called "voci". The controller then updates this array using a function named "CalcolaTotaleEuroPagine". My goal is to access the updated "voci" array and display it in the view, but I am facing issues with this. ...

Creating a new Express JS application

I've encountered an issue with my express application. When I run the server and navigate to localhost in my browser, the index page loads but without the image that should be displayed. The browser console shows a 404 error for the image URL. GET ht ...

VueJS does not update values instantly as they change

I have implemented a JS class with the following code: class Field { public Value = null; public Items = []; public UniqueKey = null; public getItems() { let items = [...this.Items]; items = items.filter((item) => { ...

Tips on retaining the value of $index in ng-repeat and storing it within the array

I currently have a cart for shopping. The code for the "add to cart" function looks something like this (shortened): "add" : function(code) { codes.push({ "id" : code.id, "order" : "N/A", ...

I'm looking to automate a system response whenever a user inputs something - how can I achieve this using NodeJS and Socket

I'm looking to create a feature where, if a user enters a specific command, the socket.io will respond with a predefined message. For example: Input: !hi Output: hello! If anyone knows how to achieve this, I'd appreciate some guidance, tha ...

Access the array value in AngularJS based on a different property array

Here are my Arrays: var FirstArr=[ { "id":"123", "aboutUS":"Demo About Us" }, { "id":"234", "tutorial":"Demo Tutorial" } ...

How can I remove a dynamically added <tr> element using jQuery?

I insert the <tr> into the <tbody> for (var i = 0 ;i < 12 ;i++){ $(`<tr><td>test</td></tr>`).appendTo('#songsTbody'); } within this HTML structure. <tbody id="songsTbody"> </tbody> ...

Capitalizing a specific letter in a string at a designated index

Looking for an efficient way to convert a specific letter in a string to uppercase? Let's explore different methods: Suppose we have the string: let str = "Dwightschrute"; One way to achieve this is by slicing the string and then updating the desir ...

Error: The function registerUser from require(...) is not defined

I am facing an issue where I am trying to import the registerUser function inside router.post within the same file that houses its exported function (registerUser). However, when attempting to use it outside of this module, I receive the following error: ...

The resend email feature isn't functioning properly on the production environment with next js, however, it works seamlessly in the development environment

import { EmailTemplate } from "@/components/email-template"; import { Resend } from "resend"; const resend = new Resend("myApiKey"); // this works only in dev // const resend = new Resend(process.env.NEXT_PUBLIC_RESEND_API_KE ...

Utilize the Twitter Bootstrap modal feature to play autoplaying Youtube videos that automatically pause when

Similar Question: How do I halt a video using Javascript on Youtube? I am curious about how I can utilize the modal feature in Twitter Bootstrap to automatically play a Youtube video, and when a user clicks the "close" button, it will cease the video ...

What are the steps for creating an animated visualization of the peak chart?

As a newcomer to CSS and Javascript, I am currently struggling with animating a peak (bar) chart that I came across on codepen. If anyone can provide assistance or guidance, it would be greatly appreciated! The chart can be found here: http://codepen.io/An ...

Tips for customizing the appearance of popup windows

I want to enhance the appearance of my popup window by applying a different format for opening it. How can I style it so that it looks visually appealing when the popup window opens? You can find below the source code I am working with: HTML: <div onM ...

Guide on how to retrieve a value using image.onload on the client side

I have encountered an issue with exporting a png image from an svg element using Blob. The problem arises when clicking the anchor tag to export the image, as the content is not rendered due to the asynchronous method (image.onload()) being called after th ...