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

Any suggestions for solving the issue of breaking the line at the end of a <td> within a <table> element using jQuery or JavaScript?

Here is a table format that I have: $(document).ready(function() { var enteredText = document.getElementById("textArea").value; var numberOfLineBreaks = (enteredText.match(/\n/g)||[]).length; var characterCount = enteredText.length + numberOfLineB ...

Revolutionizing business applications with AngularJS 2.0

We're currently assessing the technology for a new application and have some questions: - Is Angular JS 2.0 stable enough for production use? - Will older directives like Google Map and Multi-lingual be compatible with Angular JS 2.0? We currently don ...

Manipulating an SVG file with JavaScript

Within the HTML code, there is a photo already added as an SVG file. I am interested in learning how to enable the user to select between two options - either a cross or a zero. Upon clicking on the designated area, the chosen figure should appear (resembl ...

Ways to extract information from a text

I have a massive string, divided into two parts that follow this pattern: {\"Query\":\"blabla"\",\"Subject\":\"gagaga"}", {\"Query\":\"lalala"\",\"Subject\":\"rarara&bso ...

Retrieve the corresponding value from an object received from express and display it on a jade template

I'm currently working on a solution to display the correct user information on a page when users navigate to "/users/:name". For example, I want to show "welcome user2" if user2 is logged in. My approach involves passing along the parameter from "/use ...

What causes errors in my AJAX request based on the particular file extension?

Utilizing JavaScript and jQuery, I have a function that loads data using $.get(url, function(response){ /* ... */});. The data is retrieved from a text file and handled within the response function of the JavaScript. Recently, I encountered an issue on my ...

What is the best way to verify and eliminate unnecessary attributes from a JSON request payload in a node.js application?

My goal is to verify the data in the request payload and eliminate any unknown attributes. Example of a request payload: { "firstname":"john", "lastname":"clinton", "age": 32 } Required attributes: firstname and lastname Optional a ...

"Is there a way to transmit a Firebase error message from a service to a controller

In my development work, I utilize Angular js and firebase. Specifically, for handling login and register forms, I have created a controller named "userController" which calls functions in my userProvider service. One challenge I faced was how to display f ...

Generate - Create 2 different versions of the web application

Currently, I am in the process of learning Grunt and exploring ways to generate 2 variations of an application with different configuration settings. My goal is to have one version where a boolean in a specific .js file is set to false, and another versio ...

What are the ways to activate an element in vue js?

Is there a way to modify the code so that the function triggers with just one click instead of two? export default { methods: { remove(){ $('.remove-me button').click( function() { removeItem(this); }); ...

What is the best way to add the current date to a database?

code: <?php session_start(); if(isset($_POST['enq'])) { extract($_POST); $query = mysqli_query($link, "SELECT * FROM enquires2 WHERE email = '".$email. "'"); if(mysqli_num_rows($query) > 0) { echo '<script&g ...

React maintains the state of just a single element within an array at a time

I'm faced with a roadblock while developing my covid19 application. The app should display a list of countries on the left side of the screen, allowing users to add any number of countries to the right side for more detailed covid data. I'm still ...

Issues with functionality of JavaScript calculator in HTML forms

Currently, I am working on creating a basic perimeter calculator specifically designed for a projector screen. This code is intended to take the response from a radio button input and the diagonal length in order to accurately calculate the perimeter base ...

Allow foreign characters with regex while excluding special symbols

While browsing, I came across this thread: Is there a regular expression to match non-English characters?. It provides a regex to remove foreign characters using the code snippet str = str.replace(/[^\x00-\x7F]+/g, "");. My goal is slightly diff ...

What steps can I take to ensure that my React child components will render successfully, even if a prop is absent

TLDR; Seeking solution to render child components in React even if a property of this.props is missing. My React app utilizes Yahoo's Fluxible and fetches data from a Wordpress site using WP REST API. Sometimes, the API may return incomplete data cau ...

What are the steps for implementing oncopy in Angular?

If I attempt the following: <div oncopy="myfunc('{{angularvar}}')">Copy me</div> Then an error message is displayed: Interpolations for HTML DOM event attributes are not permitted. It is recommended to use the ng- versions (such ...

Problem encountered when running "npm install" following the configuration of an AngularJS project using Yeoman

Encountering an issue during or after the creation of an Angular project using the command: yo angular While installing devDependencies from the package.json ("npm install" which is triggered by yo angular), I noticed certain modules were missing in the ...

Exclude React Native module and import web module in Webpack

Currently, I am facing a challenge in my project where I need to alias a different package specifically for a webpack configuration. The issue revolves around the VictoryJS library (link: https://formidable.com/open-source/victory/). In my React Native app ...

What is the best way to split an array into four columns and allocate 10 <li> items from the array to each column?

If I have a dynamic array with 40 elements that changes on every render, how can I loop through the array and return 4 groups of elements, each containing 10 items without any repetition? I want to style these objects in the array using a parent flex con ...

Leveraging react-markdown alongside Material-UI's table component

Currently, I am attempting to parse a markdown table using the react-markdown library and then displaying the resulting tags with the help of the Material-UI table component. Below is the code snippet for my renderer: import withStyles from '@material ...