1

In angularJS, With one call, when get the service response need access that json value in multiple controllers but in same page

I have two controller js file and both controllers are called in the same page when I called the service "this.getNavigationMenuDetails" in the first controller.js and as well as called in the controller2.js file as well. without timeout function, I want to access that same response which I get it from the "this.getNavigationMenuDetails" service in controller2.js. But it happened that service call twice in the page. I don't want to call the same service twice in a page. When js are loading that time both controllers are called in the same layer then getting the response from the service so on the second controller2.js file code is not execute after the response. How can I solve this issue so that only one call i can get the response and access this response in controller2.js also.

controler1.js

var app = angular.module("navApp", []);

app.controller("navCtrl", ['$scope', 'topNavService', '$window', function ($scope, $timeout, topNavService, $window) {

    $scope.menuItemInfo = {};

    /*Navigation Menu new Code */
    $scope.getNavigationDetails = function () {
        topNavService.getNavigationMenuDetails().then(function (result) {
            $scope.menuItemInfo = result;
            angular.forEach($scope.menuItemInfo.items, function (val, key) {
                if (val.menuTitle === 
                        $window.sessionStorage.getItem('selectedNavMenu')) {
                    if ($scope.menuItemInfo.items[key].isEnabled) {
                        $scope.menuItemInfo.items[key].isActive = 'highlighted';
                    } else {
                        $window.sessionStorage.removeItem('selectedNavMenu');
                    }
                }
                if (val.menuTitle === 'Find a Fair' && !val.hasSubMenu) {
                    $scope.menuItemInfo.items[key].redirectTo = appConfig.findafairpageurl;
                }
            });
        });
    };
    $scope.init = function () {
        if ($window.location.pathname.indexOf('all-my-fairs.html') > 0) {
            if (angular.isDefined($cookies.get('cpt_bookfair'))) {
                $cookies.remove('cpt_bookfair', {
                    path: '/'
                });
            }
        }
        $scope.getNavigationDetails();
        $scope.callOnLoad();
    };

    $scope.init();
}]);
app.service('topNavService', ['$http', '$timeout', '$q'function ($http, $timeout, $q) {

    var menuInfo;
    this.getNavigationMenuDetails = function () {
        if (!menuInfo) {
            // If menu is undefined or null populate it from the backend
            return $http.get("/etc/designs/scholastic/bookfairs/jcr:content/page/header-ipar/header/c-bar.getMenuDetails.html?id=" + Math.random()).then(function (response) {
                menuInfo = response.data;
                return menuInfo;
            });
        } else {
            // Otherwise return the cached version
            return $q.when(menuInfo);
        }
    }
}]);

Controller2.js

var app = angular.module('bookResourcePage', []);

app.controller('bookResourceCtrl', ['topNavService', '$scope', function (topNavService, $scope) {
    $scope.topInfo = '';

    topNavService.getNavigationMenuDetails.then(function success() {
        $scope.productId = $scope.topInfo.isLoggedin;
        $scope.linkParam = '?productId=' + $scope.productId;
    }, function failure() {
        console.error("something bad happened");
    });
}]);
Community
  • 1
  • 1
Priya
  • 11
  • 1
  • I strongly recommend that if you and a peer of some sort are posting about the same website or homework, that you refrain from doing so. https://stackoverflow.com/questions/56731270/how-to-avoid-an-ajax-request-before-getting-response-for-previous-call –  Jun 24 '19 at 11:00

2 Answers2

0

The service would work better if it cached the HTTP promise instead of the value:

app.service('topNavService', function ($http) {

    var menuInfoPromise;
    this.getNavigationMenuDetails = function () {
        if (!menuInfoPromise) {
            // If menu is undefined or null populate it from the backend
            menuInfoPromise =  $http.get(url);
        };
        return menuInfoPromise;
    };

});

The erroneous approach of caching the value introduces a race condition. If the second controller calls before the data arrives from the server, a service sends a second XHR for the data.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
0

You can do this with following approach.

Service.js

app.service('topNavService', function($http) {

  var menuInfoPromise;
  var observerList = [];
  var inProgress = false;

  this.addObserver(callback) {
    if (callback) observerList.push(callback);
  }

  this.notifyObserver() {
    observerList.forEach(callback) {
      callback();
    }
  }

  this.getNavigationMenuDetails = function() {
    if (!menuInfoPromise && !inProgress) {
      inProgress = true;
      // If menu is undefined or null populate it from the backend
      menuInfoPromise = $http.get(url);
      this.notifyObserver();
    };
    return menuInfoPromise;
  };
});

You have to make a function in service to add your controller's function on list. then each controller will register their get function on service and call service method to get data. first call will make service variable inProgress to true. so it will prevent for multiple server request. then when data available to service then it will call its notifyObserver function to message for all controller by calling their function.

Controller 1

app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
  service.addObserver('getData1'); //name of your controller function

  $scope.getData1() {
    service.getNavigationMenuDetails.then(function success() {
      $scope.productId = $scope.topInfo.isLoggedin;
      $scope.linkParam = '?productId=' + $scope.productId;
    }, function failure() {
      console.error("something bad happened");
    });
  }
  $scope.getData1()
}]);

Controller 2

app.controller('ctrl1', ['service', '$scope', function(service, $scope) {
  service.addObserver('getData2'); //name of your controller function

  $scope.getData2() {
    service.getNavigationMenuDetails.then(function success() {
      $scope.productId = $scope.topInfo.isLoggedin;
      $scope.linkParam = '?productId=' + $scope.productId;
    }, function failure() {
      console.error("something bad happened");
    });
  }

  $scope.getData2()
}]);

with this approach you can real time update data to different controllers without have multiple same request to server.

Manish Balodia
  • 1,863
  • 2
  • 23
  • 37