0

I asked this question before (AngularJS handle calling promise multiple times) and now I have different obstacle. Now I have to get cities list but there is an exception.

Cities can be called multiple times like countries (in my old question) and I have to cache data to prevent multiple calls for same data(cities). Old question's solution can block multiple calls but now I have to let some calls (for new country's cities).

So my question is: How can I cache cities data to prevent call for same data? (My function have to catch if call is for new country's cities list or not. if yes: call service and get cities, if not: return cities from cache)

Here is 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;
}

Example: Let's say I am calling getCities function 3 times in the same time. I am watching my network traffic via chrome. I see 3 ajax calls. It's normal. But sometimes, I call for same city. I need to edit my function that can understand if city data is already called before (kind of cache).
For example: If i ask function 3 times with this arguments:

1-Give me the cities in Germany,
2-Give me the cities in Ireland,
3-Give me the cities in Germany (again),

It's calling 3 times. But I want 1 call for Germany, 1 call for Ireland. Just 2 calls.

2
  • Question is unclear. What exactly is it you want to do? And what exactly is it that doesnt work in your code? Commented Jul 11, 2016 at 14:16
  • Thank you, I edited the question. Commented Jul 11, 2016 at 14:32

4 Answers 4

1

Same answer as your other question, just map to country code to the promise. Also same as before, consider the error case.

var vm = this;

vm.cityPromises = {};

function getCities(countryCode) {
    if (!vm.cityPromises[countryCode]) {
        vm.cityPromises[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 vm.cityPromises[countryCode];
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer, I wrote my function like yours before you answered and it worked! :) I wrote my solution as an aswer here. Thank you again!
0

You can use your own promise here. Don't forget injecting the $q service.

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 () {//I use this to get promise object
             deferred.resolve(cityCache[countryCode]);
        }, 0);
    }

    return deferred.promise;
}

1 Comment

Please check my old question stackoverflow.com/questions/38303136/… I am having the same problem with your example too.
0

Try to use the $q service from angular:

updated to prevent multiple call of same city:

FIDDLE

the service:

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

            //if(callCache[countryCode] === undefined){
                  var promise = $q.defer();
           //     callCache[countryCode] = promise;
            //}else{
            //      console.log("return cached promise!!", callCache[countryCode]);
            //      return callCache[countryCode].promise;
            //}

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

3 Comments

Please check my old question stackoverflow.com/questions/38303136/…. I am having the same problem with your example too.
where is the problem?
Let's say I am calling getCities function 15 times in the same time. I am watching my network traffic via chrome. I see 15 ajax calls. It's normal. But sometimes, I call for same city. I need to edit my function that can understand if city data is already called before (kind of cache). For example: If i ask function 3 times with this arguments: Give me the cities in Germany + Give me the cities in Ireland +Give me the cities in Germany (again), It's calling 3 times. But I want 1 call for Germany, 1 call for Ireland. Just 2 calls.
0

I solved my problem by creating an object for the promise and many thanks to @Luke Harper for helping me before and now :) His answer is also correct but I must add a bit more code for my app.

If you see any problem in my code, please write to me so that I would edit the answer

So here is my solution:

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];
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.