Efficient techniques for developing lazy-loading ajax services

What are some efficient ways to create lazy ajax services in angular-js? For instance, I need a resource that returns a promise such as:

angular.module('MyModule',[])
  .factory('myService', function() {
    return {
      getData: function() {
          return $http.get('http://host/api/data');
      }
    }
  });

I want to ensure that this data is loaded only once. What would be the best approach to achieve this? The current solution I have seems quite inelegant:

angular.module('MyModule', [])
.factory('myService', function($q) {
    var dataResponse = null;
    return {
        getData: function() {
            if (dataResponse) {
                var def = $q.defer();
                def.resolve(dataResponse);
                return def.promise;
            }
            return $http.get('http://host/api/data');
        },
        setDataResponse: function(response) {
            dataResponse = response;
        }
    }
})
.controller('MyCtrl', function($scope, myService) {
    myService.getData().then(function(response) {
        myService.setDataResponse(response);
        $scope.data = response.data
    })
});

This part doesn't sit well with me:

var def = $q.defer();
def.resolve(dataResponse);
return def.promise;

Additionally, having to set the response every time I call for it is not ideal. Are there better ways to improve this code?

Answer №1

You could improve the efficiency of your memoization logic.

angular.module('MyModule', [])
.factory('myService', function($q) {
    var dataResponse = null;
    return {
        getData: function() {
            if (dataResponse) {
                return $q.when(dataResponse); // or $q.resolve for angular 1.4+
            }
            return $http.get('http://host/api/data').then(function(data) {
              dataResponse = data;
              return data;
            });
        },
    }
})
.controller('MyCtrl', function($scope, myService) {
    // utilize as normal without needing to write back
    myService.getData().then(function(response) {
        $scope.data = response.data
    })
});

Answer №2

Since you dislike this section:

var def = $q.defer();
def.resolve(dataResponse);
return def.promise;

You can rephrase it as:

return $q.resolve(dataResponse);

Note that in AngularJS < 1.4, the resolve method is referred to as when().

To improve the remaining code, consider caching the results internally within the service's 'getData' method before resolving. This task should not fall on the caller. Therefore:

return {
    getData: function() {
        if (dataResponse !== null) {
            return $q.resolve(dataResponse);
        }

        return $http.get('http://host/api/data').then(onSuccess);

        function onSuccess(data){
            dataResponse = data;
            return data;
        }
    }
}

Answer №3

Utilizing $resource is recommended, as it provides a simple data caching option and facilitates binding to a RESTful API.

If you prefer, you can implement your own data caching like this:

angular.module('MyApp', [])
.factory('DataService', function($q) {
    var cachedData;
    return {
        getData: function() {
            return $q(function(resolve, reject) {
                if (angular.isDefined(cachedData)) {
                    resolve(cachedData);
                } else {
                    $http
                        .get('http://host/api/data')
                        .then(function(response) {
                            cachedData = response;
                            resolve(cachedData);    
                        });
                }
            });
            if (cachedData) {
                var deferred = $q.defer();
                deferred.resolve(cachedData);
                return deferred.promise;
            }
            return $http.get('http://host/api/data');
        },
        setCachedData: function(response) {
            cachedData = response;
        }
    }
})
.controller('DataController', function($scope, DataService) {
    DataService
        .getData()
        .then(function(response) {
            var vm = this;
            vm.data = response.data
        })
});

Remember that I linked the data to the controller (vm for ViewModel), so adjust your template accordingly:

<ul ng-controller="DataController as dc">
    <li ng-repeat="item in dc.data">
        {{ item.name }}: {{ item.price }}
    </li>
</ul>

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

Troubleshooting head.js and jQuery problems in Chrome/Firefox 5

After rendering the page, it looks something like this: <!DOCTYPE html> <html> <head> <script> head.js("js/jquery.js", "js/jquery.autocomplete.js"); </script> </head> <body> ... content ...

JavaScript implementations of basic Prolog predicates

Are there any proven methods for defining simple prolog predicates and asserting facts in javascript client code? I came across which seems to rely on a server-side "toy" interpreter. ...

Aurelia: Understanding the Integration of a View/ViewModel from an npm Package

We've decided to implement Aurelia for the frontend of our application. With multiple projects in the pipeline, we are looking to streamline the process by packaging our custom code into npm packages that can be easily integrated by developers. This w ...

How to best handle dispatching two async thunk actions in Redux Toolkit when using TypeScript?

A recent challenge arose when attempting to utilize two different versions of an API. The approach involved checking for a 404 error with version v2, and if found, falling back to version v1. The plan was to create separate async thunk actions for each ver ...

What is the best way to ensure that the radius of the circle adjusts according to the canvas element in

I've successfully drawn a circle on a canvas element, but now I need to make it responsive. How can I achieve this? I want the radius of the circle to change by a certain amount when the browser width or height changes. How do I calculate this changi ...

Performing multiple AJAX requests in Laravel

Hey! I'm having an issue with my code where only one query, "sad", gets submitted to the database when I actually expect multiple queries to be sent. I've tried using $request->has('happy') but it doesn't seem to work a ...

iOS Ionic Camera Plugin

I've encountered a common issue that I haven't been able to solve despite trying many solutions. While running my Ionic app on my IOS device, the camera plugin coding is returning undefined values and getting stuck before reaching the options va ...

Is it possible to override values set in the constructor(props) in React? If not, what is the best way to set defaults that can be overwritten later?

I'm confident I know the solution to this problem because my setState({}) seems to have no effect. This is the constructor code that I currently have: constructor(props) { super(props); this.state = { percentiles: { incN ...

Jquery Ajax not triggering the code behind method in ASP.NET

Here is the JQuery code snippet: <script type="text/javascript> $(document).ready(function () { $("#frmReg").on('submit', function (e) { var emailAddr = $("#inputEmail").val(); var userName = $("#userName").val(); v ...

Enhancing 2D video viewing with Threejs interactivity

I want to create an interactive 2D video using three.js and maintain the aspect ratio of the video when resizing the browser window. Here is the code I am currently using: var camera, scene, renderer; var texture_placeholder, distance = 500; init() ...

Execute an AJAX post request to the identical PHP page (utilizing the Jquery Form Plugin)

I am in the process of developing a new web interface using JavaTMP, an AJAX-based admin template. After spending time understanding its functionality, I have created a page with a form to allow users to create projects within my software. Typically, creat ...

Adjusting the width of a select box to match the size of its child table using CSS

Within my Vue application, I've implemented a select box that contains a table component. When the select box is clicked, the table becomes visible in a container. However, I'm facing an issue where I can't dynamically adjust the width of th ...

Encountering issue: LineChart is not recognized as a constructor, resulting in failure to display chart on webpage

I am struggling with displaying a chart in my HTML file that should show the details of a specific process from the past few minutes. Whenever I try to initialize the chart using google.charts.load('current', {'packages':['line&apo ...

I can't figure out why my code is only returning the else statement and an undefined value instead of the totalBasketballScore

I was confident that my code was correct, but I am encountering an issue when trying to calculate basketball scores based on free throws, 2 pointers, and 3 pointers. Whenever I console.log the totalBasketballScore, the output is 'All entries must be n ...

Can you explain Node.js and its applications as well as how it is commonly used?

A while back, during my time at IBM when I was immersed in learning, I came across something known as BlueMix, a cloud product. Within BlueMix, there was a rather primitive component called Node.js. Since that moment, I've been filled with curiosity a ...

Using JSON to parse data and applying specific formatting

I have a function that uses the following AJAX code: $.ajax({ type: 'POST', url: 'demopost.php', data: { ... }, dataType: 'json', success: function(data) { console.log(data); } ...

Encountering an error while attempting to run bcrypt on Meteor and Nodejs - "Undefined property '_handle'."

Having trouble integrating the bcryptjs package into my Meteor app. Successfully installed bcrypt using meteor npm install --save bcrypt. Trying to implement bcrypt functions with import bcrypt from 'bcrypt';. Encountering an error in the cons ...

Sending Unique Identifier to AJAX Script

As I delve into my inaugural AJAX script, coupled with PHP pages, the intricacies of AJAX are slowly revealing themselves to me. Being relatively new to Javascript, I have managed to successfully implement the script. The task at hand involves enhancing a ...

What's the best way to ensure that the theme state remains persistent when navigating, refreshing, or revisiting a page in the browser?

Is there a way to ensure that my light/dark theme settings remain persistent when users reload the page, navigate to a new page, or use the browser's back button? The current behavior is unreliable and changes unexpectedly. This is the index.js file ...

Tips for inserting a value into a specific location within an array using JavaScript

I am working with an array of objects that looks like this: const array = [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]; My task is to add a new entry to this array, but it needs to be inserted at a specific position. For instance, when adding { ...