Managing the invocation of a promise multiple times in AngularJS, and handling some specific exceptions

After previously asking a question on handling promises multiple times in AngularJS (AngularJS handle calling promise multiple times), I am facing a new challenge. This time, I need to retrieve a list of cities, but encounter an exception.

Similar to how countries were handled in my previous question, cities can also be called multiple times. However, this time around, I must implement a caching mechanism to prevent redundant calls for the same city data. While the solution from my old question blocked multiple calls altogether, I now need to allow certain calls - specifically when requesting cities for a new country.

My current dilemma is as follows: How can I effectively cache cities data to avoid making repeated calls for the same information? Essentially, my function needs to differentiate between requests for cities of a new country versus those already cached.

Below is the snippet of my service:

var cityCache = {};
vm.getCities = function (countryCode) {

    if (countryCode!=undefined && !cityCache[countryCode]) {

        vm.cityPromise = $http({
            method: 'POST',
            cache: true,
            url: API + '/api/Global/CountryCities',
            data: {
                "CountryCode": countryCode
            }
        }).then(function successCallback(response,countryCode) {
            if (errorHandler(response.data)) {
                console.log("cities come from ajax")
                cityCache[response.config.data.CountryCode] = response.data;
                console.log(cityCache)
                return response.data
            }
        });
    } else {
        vm.cityPromise = $timeout(function () {//I use this to get promise object
            return cityCache[countryCode]
        }, 0)
        console.log("cities comes from cache");
    }

    return vm.cityPromise;
}

To illustrate further, let's consider the following scenario: If the getCities function is called three times simultaneously with the following arguments - requesting cities in Germany, Ireland, and Germany once more - ideally, there should only be two network calls made. One for Germany and one for Ireland, effectively reducing redundancy.

Answer №1

Instead of reiterating the same response as your previous inquiry, I suggest implementing a mapping to the country code within the promise object. Additionally, it is crucial to address potential error scenarios, as previously mentioned.

let app = this;

app.countriesPromises = {};

function getCitiesByCountry(countryCode) {
    if (!app.countriesPromises[countryCode]) {
        app.countriesPromises[countryCode] = $http({
            method: 'POST',
            cache: true,
            url: API + '/api/Global/Countries',
        }).then(function successCallback(response) {
            if (errorHandler(response.data)) {
                console.log("ajax")
                return response.data;
            }
        });
    } else {
        console.log("cache")
    }
    return app.countriesPromises[countryCode];
}

Answer №2

Feel free to customize your promise creation process using your own method. Just make sure to include the $q service for injection.

var cityCache = {};

vm.getCities = function (countryCode) {

    var deferred = $q.defer();
    if (countryCode!=undefined && !cityCache[countryCode]) {
        vm.cityPromise = $http({
            method: 'POST',
            cache: true,
            url: API + '/api/Global/CountryCities',
            data: {
                "CountryCode": countryCode
            }
        }).then(function successCallback(response,countryCode) {
            if (errorHandler(response.data)) {
                cityCache[response.config.data.CountryCode] = response.data;
                deferred.resolve(response.data);
            }
            else{
                deferred.reject();
            }
        });
    } 
    else {
         vm.cityPromise = $timeout(function () {//Utilizing this approach to obtain the promise object
             deferred.resolve(cityCache[countryCode]);
        }, 0);
    }

    return deferred.promise;
}

Answer №3

Consider implementing the $q service provided by Angular:

Updated code to avoid making multiple calls for the same city:

Check out the FIDDLE here

Here's a snippet of the service in action:

.service("cityService", function($http, $q, $httpParamSerializerJQLike){
    var cityCache = {};
    return {
        getCities: function(countryCode){

            var promise = $q.defer();

            if (countryCode != undefined && !cityCache[countryCode]) {
                console.log("New city request");
                var data = $httpParamSerializerJQLike({
                    json: JSON.stringify({
                        name: countryCode + Math.random().toString(36).substring(7)
                    })
                });
                $http({
                    method: 'POST',
                    url:"/echo/json/",
                    data: data
                }).then(function(response) {
                    console.log("Service log", response.data);
                    cityCache[countryCode] = response.data;
                    var object = angular.extend({cache: false}, response.data);
                    promise.resolve(object);
                });
            } else {
                setTimeout(function(){
                    var object = angular.extend({cache: true}, cityCache[countryCode]);
                    promise.resolve(object);
                }, 1000)
            }
            return promise.promise;
        }
    }  
});

Answer №4

After encountering an issue, I managed to resolve it by implementing a promise object. Big thanks to @Luke Harper for his assistance in the past and present :) While his solution was on the right track, I needed to tweak it slightly to fit my application's requirements.

If you spot any flaws in my code, please feel free to reach out so I can make necessary adjustments.

Here is how I tackled the problem:

vm.cityPromise = {};
vm.getCities = function (countryCode) {
    vm.cityPromise["cityCache"] = countryCode;
    if (!vm.cityPromise[countryCode]) {
        if (countryCode != undefined && !cityCache[countryCode]) {
            vm.cityPromise[countryCode] = $http({
                method: 'POST',
                cache: true,
                url: API + '/api/Global/CountryCities',
                data: {
                    "CountryCode": countryCode
                }
            }).then(function successCallback(response, countryCode) {
                if (errorHandler(response.data)) {
                    cityCache[response.config.data.CountryCode] = response.data;
                    console.log("cities ajax, cityCache", cityCache)
                    return response.data
                }
            },function error (response){
                console.log ("error:",response)
            });
        } else {
            vm.cityPromise[countryCode] = $timeout(function () {
                return cityCache[countryCode]
            }, 0)
            console.log("getCities cache");
        }
    }
    return vm.cityPromise[countryCode];
}

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

Repeating the setTimeout function in a loop

I've been delving into JavaScript and trying to understand it better. What I'm aiming for is to have text displayed on the screen followed by a countdown sequence, like this: "Test" [1 second pause] "1" [1 second pause] "2" [1 second pause ...

The resolveMX function in Google Cloud Functions is encountering issues when trying to process a list of domains

Here is the task at hand. I have a large list of domains, over 100,000 in total, and I need to iterate through them using a foreach loop to resolve MX records for each domain. Once resolved, I then save the MX records into another database. Below is the c ...

Error message: Laravel Ajax function encountered an undefined variable

I am facing an issue with my ajax submission to the database. When I click the submit button, I get an "undefined" value in the return response. The problem seems to be in the controller, specifically with the 'fname' variable. I'm unsure ab ...

Error: The method `push` within the `useHistory` function is causing an issue and is currently undefined

Whenever the home button is clicked, I need it to redirect to the homepage '/ '. However, I keep encountering this error. Any suggestions on what steps I should take to resolve this? : import { Route, useHistory } from 'react-router-dom/cjs/ ...

Anticipating the resolution of promises and observables in Angular 2

Within my accountService module, there is a dialog prompt that requests the user's username and password, returning a promise. If the user clicks on close instead of dismissing the dialog box and the validators require the input data before allowing t ...

Uncaught TypeError: Cannot read property 'e' of undefined in vue.js

Feeling a bit frustrated now :( This is my first time trying to use vue.js, which comes after jQuery as the second JS framework I'm diving into on this planet. Here's the HTML code I have: var main = new Vue({ el: ".main-content", data: { ...

Gridsome server-side rendering encounters issues with Auth0 authentication when the window object is not defined

After successfully following the Auth0 Vuejs tutorial with Gridsome during development, I encountered a problem when trying to build using gridsome build. The build failed because window was undefined in a server context. I discovered some issues in the A ...

What are some ways I can optimize my Bootstrap CSS code to enhance responsiveness across different page widths?

After creating this fiddle, I noticed that my webpage layout with two texts stacked on top of each other looks great on wide screens. However, when the screen size is reduced or viewed on a mobile device, the layout gets all messed up. Take a look at this ...

Exploring the Functionality of POST in AJAX Requests

I'm facing an issue where the data is not displaying on my page even though I am using a Github URL and Ajax POST. Can anyone help me identify what needs to be fixed in the code below? <div id="content"> </div> window.onload = ...

Tips for testing "defineAsyncComponent" in Vue 3:

Suppose I need to unit test this utility function. I am utilizing Vue 3, however, this code resides in a "regular" JavaScript file rather than an SFC. How can I go about doing that? function getDynamicComponent() { if (...) { return defineAsyncComp ...

Utilizing numerous instances of setInterval

I've created a jsFiddle which can be found here: http://jsfiddle.net/dztGA/22/ Main Objective: My aim is to have two independent timers on the same page that can be stopped and restarted either by hovering or manually. The Issue: The problem illustr ...

Oops! You forgot to include the necessary getStaticPaths function for dynamic SSG pages on '/blogs/[post]'

Whenever I attempt to execute npm run build, an error occurs. The following build error occurred: Error: getStaticPaths is required for dynamic SSG pages and is missing for '/blogs/[post]'. This is the code snippet causing the issue: function ...

What is the process for generating an HTTP response that results in a pipe error being thrown

In my NestJS application, I have created a custom pipe that validates if a given value is a valid URL. If the URL is invalid, an error is thrown. This pipe is utilized in a controller to save an item into the database. Recently, I discovered that the pipe ...

Ways to set the initial value of an input[range] in Angular2 when the value exceeds 100

After encountering a similar issue with AngularJS, I posted a question on StackOverflow titled How to initialize the value of an input[range] using AngularJS when value is over 100. As I dive into learning Angular2, I am curious if it handles initializatio ...

Retrieve the URL of an image located within an <li> tag within a jQuery selector item array

I am currently using a jQuery slider plugin to display images, and I am attempting to retrieve the URL of the current image when a button is clicked. The slider functions by showcasing all the image slides as list items in a continuous horizontal row. It ...

Enhancing functionality by integrating Jquery/JS with input fields and labels

I am currently facing a challenge in applying CSS to the label element when the corresponding input is selected. After attempting and failing to use input:checked + label due to limitations in the HTML structure that cannot be altered, I seek alternative ...

Easily Update Your Div Content by Simply Clicking a Single Link/Button

I am in need of assistance here. My goal is to display dynamic content within a div. Below you will find the code I currently have: <script type="text/javascript"><!-- function AlterContentInContainer(id, content) { var container = documen ...

Analyzing Varied Date Formats

I'm looking to create a function in AngularJS that checks if a given date is after today: $scope.isAfterToday= function(inputDate){ if(inputDate > Date.now().toString()){ return true; } else { return false; } } The iss ...

Nodejs registration and user verification process for accessing account features

I am facing a decision on how to handle two types of users - vendors and buyers. Should I develop separate APIs for registering and authenticating each user type, or should I create a single API to manage both? When designing my database model, should I h ...

PHP/AJAX user action history manager

Is there a library available that offers undo/redo functionality with a complete history for a web application? One possible solution could be a system using php/javascript/ajax where you can record the opposite action and variable state for each user acti ...