I have an Angular app communicating with an external API. I'm able to generate the initial view from an Angular $resource call. My problem is that I have a form that runs a function on ng-click. That function then queries the API again and is supposed to update that same scoped variable but I'm not able to get the results of the second $resource call to update the scoped variable.
In my controller, this is the initial call that gets the data that shows up in the view initially:
// Initial weather and geolocation data
var Weather = $resource('http://example.com/:method');
Weather.get({method: 'current'}).$promise.then(function(weather) {
// Success
$scope.weather = weather.weather;
$scope.geolocation = weather.location;
}, function(error) {
// Failure
$scope.weather = error;
});
So far so good, the view updates and I can show the JSON that the API sends back with {{ weather.currently.temp }}
as well as all the data in the {{ geolocation }} variable.
However, I have a form (it is properly set up to talk to the controller) that upon submission should make another request to the same API and return new data:
// Search functionality
$scope.weatherLookup = function(query) {
$http.get('http://example.com/location/' + query).then(function (value) {
$scope.weather = value;
});
};
At this point, in the view, the {{ weather }} variable does not update anywhere. At all. If I throw a console.log
function inside the weatherLookup
function I get undefined
when trying to get the value of $scope.weather
but I do get a valid JSON object when I ask for value
in that same console.log()
statement instead.
How can I get that value
variable assigned to the $scope.weather
inside $scope.weatherLookup
so that it can update that value and have it bubble up to the view?
This is the solution I found - I welcome alternative/better ways to do this.
Apparently $scope.weather
references multiple values. That is to say, because the $resource and $http methods return promises and the nature of those promises, $scope.weather
can actually reference two separate objects as far as the view and controller are concerned. The way I solved the problem was by using $rootScope
to make sure the same weather
object was always overwritten.
Here's the new code:
'use strict';
angular.module('myApp')
.controller('WeatherCtrl', function ($scope, Restangular, $rootScope) {
// Get initial weather data (NOW WITH $rootScope)
Restangular.one('current').get().then(function(weather) {
$rootScope.weather = weather.weather;
$scope.geolocation = weather.location;
});
// Search functionality
$scope.weatherLookup = function(query) {
Restangular.one('location/' + query).get().then(function(newWeather) {
$rootScope.weather = newWeather;
console.log($rootScope.weather);
});
console.log($rootScope.weather);
};
});
I switched from using Angular's own $resource
and $http
services to the wonderful Restangular library. Despite this change, the original problem persisted until I used $rootScope
. I tested this theory using $resource
and $http
and it still worked so I know that the issue was that $scope.weather
was somehow splitting off and referencing two separate objects under the hood because of the way $scope
and promises work in Angular.