Gershon Papi
Gershon Papi

Reputation: 5126

angular's $scope not updating?

I'm trying to create a basic weather app based on the user's location, which I take using javascript geolocation service. Everything regarding the location and weather works as expected.
My problem is when the user reject the location request, what I want to do is hide the weather data (which I can't get) and show an appropriate message.
HTML:

<body ng-app="weatherApp">
  <div class="container text-center" style="margin-top: 15vh" ng-controller="weatherCtrl">
    <h1>Local Weather App</h1>
    <h3>{{error}}</h3>
    <div class="row" ng-hide="showError">
      <div id="loc-col" class="col-xs-3 col-xs-offset-1">
        <h3>{{data.name}}</br>
        <small>{{data.sys.country}}</small></h3>
      </div>
      <div id="temp-col" class="col-xs-4">
        <h3>{{data.main.temp}} {{degree}}&deg;</h3>
      </div>
      <div id="weather-col" class="col-xs-3">
        <h3>{{data.weather[0].main}} </br><small>{{data.weather[0].description}}</small> </h3>
      </div>
      <div id="icon-col" class="col-xs-6 col-xs-offset-3">
        <img id="icon" class="img-responsive" ng-src="{{icon}}">
      </div>
    </div>
  </div>
</body>

The error message should be in the <h3> below the h1.

JS:

'use strict';
var app = angular.module('weatherApp', []);

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

  weather.getWeather = function(lat, lon){
    return $http.jsonp("http://api.openweathermap.org/data/2.5/weather?lat="+lat+"&lon="+lon+"&units=metric&callback=JSON_CALLBACK");
  };
  return weather;
}]);

app.controller('weatherCtrl', ['$scope', 'weatherFactory', '$http', function($scope, weatherFactory, $http){
  $scope.degree = "C";

  $scope.error = "";
  $scope.showError = false;

  var icons = { };

  function getWeatherFromPos(position){
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    weatherFactory.getWeather(lat,lon).success(
            function(data){
              $scope.data = data;
              $scope.icon = icons[data.weather[0].icon];
            }
          ).error(function(error){
            setError(error);
          });
  }

  function setError(error){
    $scope.showError = true;
    $scope.error = error;
  }

  //THIS IS THE RELEVANT CODE:
  if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        function(position) {
          getWeatherFromPos(position);
        }, 
        function() {
          //EXECUTED UPON REJECTION
          setError("Geolocation service failed.");
        }
      );
    }
    else {
      setError("Your browser doesn't support geolocation.");
    }
}]);

When I open up the consoler and I execute the following:

angular.element($(".row")).scope().error
"Geolocation service failed."

So somehow the variable do get updated, but the error message is not shown and the weather data is not hidden.

Upvotes: 0

Views: 93

Answers (2)

Dmitriy
Dmitriy

Reputation: 3765

Your setError function execute out of $digest cycle of angular. You can do follow:

  function setError(error){
    $scope.showError = true;
    $scope.error = error;
    $scope.$apply();
  }

or

function setError(error){
    $scope.$apply(function () {
       $scope.showError = true;
       $scope.error = error;
   }
}

P.S.: It is concerned about setError("Geolocation service failed."); and setError("Your browser doesn't support geolocation.");.

But for setError(error) it is not ok to use $apply because it is already inside $digest loop (there is no need to call $apply method). Remember you need to call $apply only after you made some changes outside of angular digest loop. See more about it https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply

Upvotes: 1

alexey
alexey

Reputation: 1411

I think thank you missed ng-bind:

<h3 ng-bind="error">{{error}}</h3>

Upvotes: 0

Related Questions