-1

I have 2 big issues with an Angular app, I'm completely stuck and hoping someone out there can help me.

  1. My method of sharing data from a web-service out to multiple controllers is flawed and I don't know how to fix it.
  2. My directives sporadically don't have access to data in the controller scope (probably because of issue 1) and log as undefined, I think the route change happens before the scope data is resolved.

So, details, I have an Angular app which provides a form where people register their hotel with our website, people can save their details and come back later to edit.

My app is setup as follows.

I have controllers and routes for:

  • Hotel info (name, location, costs etc)
  • Rooms
  • Facilities (swimming pool, sauna, steam room etc)
  • Proprietor Details (name, email, bank details)
  • Availability
  • Photos

I have a factory called "HotelService" which calls a web-service to retrieve/store data about the Hotel.

I want to share data between controllers so I've been storing the data retrieved on the web-service in the $rootScope, I've seen that people, generally, do not deem this to be "the angular way" but I haven't been able to find any other way to achieve the same thing. It also makes it difficult to test my controllers using this technique. So I'm open to another solution.

The important part is that I don't want to make more than one initial "GET" request to the web-service. Once I have the data, I want all of my controllers to be able to access/update that data, users can save all the data at any time from any controller.

Some code:

Here's my app config:

app.config(['$routeProvider', function($routeProvider)
{
  $routeProvider
    .when('/', {
      templateUrl: '/views/info.html',
      controller:  'InfoController'
    })
    .when('/rooms', {
      templateUrl: '/views/rooms.html',
      controller:  'RoomsController'
    })
    .when('/facilities', {
      templateUrl: '/views/facilities.html',
      controller:  'FacilitiesController'
    })
    .when('/proprietor', {
      templateUrl: '/views/proprietor.html',
      controller:  'ProprietorController'
    })
    .when('/available', {
      templateUrl: '/views/available.html',
      controller:  'AvailableController'
    })
    .when('/photos', {
      templateUrl: '/views/photos.html',
      controller:  'PhotosController'
    });
}]);

Here's my app.run where I set the data on $rootScope:

app.run(
['$rootScope', '$window', 'HotelService',
function($rootScope, $window, HotelService)
{
    HotelService.get($window.hotelId).then(function(hotel) {
        $rootScope.data = hotel;
    });
  }
]);

Here's my HotelService code:

app.factory('HotelService', ['$http', '$rootScope', function ($http, $rootScope) {
  var hotel = {};
  return {
    get: function(hotelId) {
      premId = (angular.isUndefined(hotelId)) ? 0 : premId;
      return $http.jsonp('/webservice', {
        method: 'GET',
        params: { 'id': hotelId, 'callback': 'JSON_CALLBACK' },
        responseType: 'json'
        })
        .then(function(response) {
            hotel = response.hotel;
            $rootScope.$broadcast('handleSharedHotel', hotel);
            return hotel;
      });
    },
    save: function(data) {
      $rootScope.$broadcast('handleBeforeSaveHotel');
      return $http.jsonp('/webservice?callback=JSON_CALLBACK', {
        method: 'POST',
        data: data,
        responseType: 'json'
      }).then(function(response) {
        hotel = response.data.hotel;
        $rootScope.$broadcast('handleSharedHotel', hotel);
        $rootScope.$broadcast('handleAfterSaveHotel', response);
        return hotel;
      });
    }
  };
}]);

Here's my Hotel Info Controller:

controllers.InfoController = [
  '$scope', '$window', '$rootScope', '$timeout', 'HotelService',
  function($scope, $window, $rootScope, $timeout, HotelService)
  {
    $scope.data = $rootScope.data;

    this.save = function() {
        HotelService.save($scope.data);
    };

    $scope.$on('handleSharedHotel', function(events, hotel) {
        $scope.data = hotel;
    });

    return $scope.InfoController = this;
}

];

One very strange (strange because I don't fully understand scopes in Angular yet) issue I've been having is, my directives are not getting data in time when a route changes, so scope values are coming back undefined. It only happens sometimes when I load the page directly from the address bar or a link but seems to happen every time I refresh the page.

Any ideas would be greatly appreciated.

Herbage Onion
  • 181
  • 4
  • 15

1 Answers1

0

I would suggest to cache the returned promises inside HotelService and then inject the service in every controller where you need returned data.

That would mean that the request will be made only first time when this portion of code will be called inside one of your controllers:

HotelService.get($window.hotelId).then(function(hotel) {
        $rootScope.data = hotel;
});

On all subsequent calls the cached promise for passed in hotelId will be returned.

[EDIT]

There is simplified example (just get method) of HotelService implementation with cache (although I haven't tested it). You will have to introduce few changes to your code base but the idea is there:

app.factory('HotelService', ['$http', function ($http) {
    var service = {};

    var hotelPromisesCache = {};

    service.get = function (hotelId) {
        var hotelPromise = hotelPromisesCache[hotelId];

        if (hotelPromise == undefined) {
            hotelPromise = $http.jsonp('/webservice', {
                method: 'GET',
                params: { 'id': hotelId, 'callback': 'JSON_CALLBACK' },
                responseType: 'json'
            });

            hotelPromisesCache[hotelId] = hotelPromise;
        }

        return hotelPromise;
    };

    return service;
}]);

Don't forget to remove the promise from the cache after the hotel data are changed or you will get back cached, not modified version.

PrimosK
  • 13,848
  • 10
  • 60
  • 78
  • Hi, wont that implementation remove all changes on the model each time the route changes? How can I remove the promise from the cache each time the hotel data changes? – Herbage Onion Sep 03 '13 at 14:21