AngularJS - Multiple Directive Instances making XH

2019-05-06 20:34发布

问题:

I have an Angularjs directive 'ExampleDirective' which has the controller 'ExampleController'. The controller defines two Promise objects where each Promise object makes an Http GET request and returns the response.

In the directive, we get the response data from the promise objects and process them to render the directive.

ExampleDirective gets instantiated twice within the same view and each instance makes it's own Http GET requests. This causes performance issues on the front end due to two requests sent at the same time to make expensive database calls and read from the same table as well.

Controller:

angular.module('exampleModule')
  .constant("EXAMPLE_URL", "{% url 'example:get_example' %}")
  .controller('exampleCtrl', ['$scope', '$http', 'EXAMPLE_URL', exampleCtrl]);

function exampleCtrl($scope, $http, EXAMPLE_URL) {
  $scope.examplePromise = $http.get(EXAMPLE_URL).then(function(response) {
    return response.data;
  });
}

Directive:

angular.module('exampleModule')
.directive('exampleDirective', ['exampleFactory', 'STATIC_URL',      '$http', '$window', exampleDirective]);

function exampleDirective(exampleFactory, STATIC_URL, $http, $window) {
  return {
    scope: {
      title:'@?',
      loadingImage:'@?',
    },
    restrict: 'AE',
    templateUrl: STATIC_URL + 'example/example-template.html',
    controller: "exampleCtrl",

    link: function (scope, element, attrs) {

     //add default options:
    if (!scope.title) {
      scope.title = 'Example Title';
    }
    if (!scope.loadingImage) {
      scope.loadingImage = '';
    }

    scope.examplePromise.then(function(data) {
      scope.exampleData = data;
      // do something
    });
  }
 };
}

Is there a way to instantiate a directive multiple times but not have to make the Http GET requests in the controller twice?

UPDATE This is what I did, I added a service as suggested in the answer.

Service:

angular.module('chRatingsModule')
.factory('chExampleFactory', ['$http', 'EXAMPLE_URL', chExampleFactory]);

function chExampleFactory($http, EXAMPLE_URL) {
  var api = {}
  var promise = null;
  api.examplePromise = examplePromise; 

  function examplePromise() {
    if (promise == null) {
      promise = $http.get(EXAMPLE_URL).then(function(response) {
        return response.data;
      });
    }
    return promise;
  }

  return api;
}

Updated Directive:

angular.module('exampleModule')
.directive('exampleDirective', ['exampleFactory', 'STATIC_URL',      '$http', '$window', exampleDirective]);

function exampleDirective(exampleFactory, STATIC_URL, $http, $window) {
  return {
    scope: {
      title:'@?',
      loadingImage:'@?',
    },
    restrict: 'AE',
    templateUrl: STATIC_URL + 'example/example-template.html',

    link: function (scope, element, attrs) {

    exampleFactory.examplePromise.then(function(data) {
      scope.exampleData = data;
      // do something
    });
  }
 };
}

回答1:

First solution, probably the best one: don't make the call from the directive, which should just be a graphical element. Do the call from the controller, and pass the data as argument to both directives.

Second solution, use a service in the directive, and always return the same promise:

myModule.factory('myService', function($http) {
    var promise = null;
    var getData = function() {
        if (promise == null) {
            promise = $http.get(...).then(...);
        }
        return promise;
    };

    return {
        getData: getData
    };
});


回答2:

The controller defines two Promise objects where each Promise object makes an Http GET request and returns the response.

Change to:

The SERVICE defines two Promise objects where each Promise object makes an Http GET request and returns the response.

The service then can remember that it has already done the GET(s) and just return their result every subsequent time it is asked for them.