I have 2 big issues with an Angular app, I'm completely stuck and hoping someone out there can help me.
- My method of sharing data from a web-service out to multiple controllers is flawed and I don't know how to fix it.
- 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.