Mike Sav
Mike Sav

Reputation: 15291

Multiple AngularJS $http requests via directive are blocking other JavaScript methods

I've inherited a project from a colleague and I need to troubleshoot some issues. The project uses the Angular UI-Bootstrap module and its directives/services. My colleague has written a custom directive that uses $http to get some data then depending on the returned results populates a template and injects this into the view. This seems fine but I have noticed that when this directive is running (sometimes 20 instances on a view) it blocks other functionality for example Modal Windows provided by UI Bootstrap. When the page loads and the custom directive is loading/waiting for the $http results the click functionality of launching a modal window (or any thing else) seems to have to wait till the majority of the custom directives have executed. The custom directive looks like so (see below), and I have set a priority to 1 but this does nothing... do I need to clone/remove attributes, can anyone see a way I can improve the code I have been given? Should the compile be used rather than the link function? Have can I prevent the blocking nature of this directive?

I also think he has imported / injected some items that are not required (like $q).

in the HTML view

<div data-get-partner-availability data-partner-id="1234"></div>

and the JavaScript / directive:

.directive('getPartnerAvailability', function ($http, $q) {
        return {
            restrict: 'AE',
            priority: 1,
            scope: {
                partnerId: '@partnerId'
            },
            template: '<div class="partner-availability"><img src="../../../img/ajax-loader.gif" /></div>',
            controller: function () {
                return {
                    getAvailability: function (partnerId) {
                        return $http({
                            method: 'GET',
                            url: '/api/partner/:partnerId/getAvailability',
                            params: {
                                'partnerId': partnerId
                            }
                        });
                    }
                };
            },
            link: function (scope, element, attrs, controller) {

                controller.getAvailability(scope.partnerId).then(function (result) {

                    var html = '',
                        container = [];

                    if (typeof result.data !== 'undefined' && typeof result.data.times !== 'undefined' && result.data.times.length > 0) {
                        var isFirst = true;
                        for (var i in result.data.times) {
                            var itemHtml = '';

                            // some nested conditions that create a string called itemHTML

                            html += itemHtml;
                        }
                    } else {
                        html += 'Some message';
                    }

                    element.html(html);
                });
            }
        }
    }

Thanks in advance.

Upvotes: 0

Views: 1108

Answers (1)

Zerot
Zerot

Reputation: 196

Most browsers have a limit of the amount of concurrent requests that are allowed per page. You are creating a lot of requests, so the later requests will wait in queue until earlier requests are finished. This will cause the modal to not appear until the earlier requests are finished because the modal $http request will be at the bottom of the queue.

To clean this up, I would first move all data retrieval logic to a service and have the directives call that service. Then in that service you could either maintain a queue of requests and make sure that they aren't all sent at the same time, OR you might want to add a batch functionality to the server api so you can get more than 1 partner availability in 1 go.

Upvotes: 2

Related Questions