Sergey Kudryashov
Sergey Kudryashov

Reputation: 723

ANgularJS sync server data with local data on request

There is one thing I can't understand in Angular - how better to sync API data with local data.

My structure object is very big, I just give you simple example.

I have 4 api links.

api_links: {
  allCars: '/cars/',
     cabrio: '/cars/cabrio',
     sedan: '/cars/sedan',
        mercedes: 'cars/sedan/mercedes'
}

And this is my local object to keep data locally

$rootScope.apiData = {
  cars{
    cabrio:{},
    sedan: {}
  }
}

In my single page app I want to reduce count of requests. So on common page I'm recieving all Cars and put data to $rootScope.apiData

When I go to sedans page, I check if there any data in $rootScope.apiData.cars.sedan. If it's exist, I don't send request.

But if I start from sedans page, I recieve only sedans. Then when I go to common page - HOW can I check am I need to load more categories.

It's quick abstract example. But I try to find any good solutions or plugins for this and cannot.

Please help me!

UPDATE:

Here is my factory:

var api = angular.module('app.api', []);
api.factory('GetData', ['$http', '$q', '$rootScope', '$location'
    function($http, $q, $rootScope, $location) {


        var apiUrl = '/api/js/';
        var apiMixes = {
            dashBoard: 'api/dashboard',
            accounts: 'api/accounts',
            top: 'top',
            logout: 'client/logout',
            ...
        }

        var methods = {};

        methods.getApi = function(u, params) {

            var url = apiMixes[u] + '?' + $.param( params );

            var deferred = $q.defer();



            // Here I need to check if I have cached data
            cachedData(data) = ___TODO___;

            if( cachedData(data) ){

                deferred.resolve(cachedData(data));

                // Turn watching on
                $rootScope.$emit("receivedApiUpdate", cachedData(data));

                return deferred.promise;

            }


            // If no - get gata from server and put to cache
            $http.get(url, {cache: true}).success(function (res, status, headers, config) {

                if(res && res.data){

                    // Turn watching on
                    $rootScope.$emit("receivedApiUpdate", res.data);

                    //LocalData.put(res.data);
                    deferred.resolve(res.data);

                }else{

                    deferred.reject(status);

                }



            }).error(function (res, status, headers, config) {

                (status==401) && $location.path('login/lock');

                deferred.reject(status);
            });

            return deferred.promise;



        };



        methods.sendData = function(u, data, o) {

            data = data || {};
            o = o || {};

            var deferred = $q.defer();

            var url = '/api/js/'+ apiMixes[u];


            $http.post(url, JSON.stringify(data)).success(function(res, status) {


                if(res.success && res.data){


                    // Here I need to update my cache with some new value
                    o.localUpdate && ___PUT_TO_CACHE_TODO___;

                    deferred.resolve(res.data);


                }


            });

            return deferred.promise;
        };


        return methods;


}]);

Here is my Controller

app.controller('MyAccountsCtrl', ["$rootScope", "$scope", 
    function ($rootScope, $scope) {


    // Watcher for api updates
    $rootScope.$on('receivedApiUpdate',function(event, response){

        if(!response || !response.accounts) return;
        renderData(response.accounts);

    });


    function renderData(accounts){

        // This renders to template
        $scope.accountList = accounts;

    }


}]);

Here is mainCtrl, whick make common request, after it I need to update data in several templates.

app.controller('AppCtrl', ['$rootScope', '$scope', 'GetData',
function ($rootScope, $scope, GetData) {

    // Here I fire different request for each page, I keep requests in router.
    GetData.getApi( 'accounts' ).then(function(data){

        // Show content when page is loaded
        $('.main-content').removeClass('hidden');

    },function(res){
        log('GET DATA FAIL', res);

    });


}]);

Upvotes: 2

Views: 382

Answers (1)

Itamar L.
Itamar L.

Reputation: 519

You need to create a service/factory for this, not use the $rootScope. Also, unless you need the data to be constantly updated, you can use the cache: true option inside your $http call.

angular
    .module('app')
        .factory('carFactory', carFactory);

function carFactory() {
    var factory = {
        getData: getData
    }

    return factory;

    function getData(callback) {
        $http({
            method: 'GET',
            url: '/cars',
            cache: true
        }).success(callback);
    }
}

And then inside your controller/directives just inject the carFactory and use carFactory.getData(function(cars) { ... }) when you need the data. If the data doesn't exist, it will $http call for it and afterwards execute the callback function. If it does exist, it will return the data directly to the callback, without an $http call.

Upvotes: 1

Related Questions