Search code examples
angularjsangularjs-scopeangularjs-service

view not updated when using $http in service


I have an angularJS application with 2 controllers and one service to exchange data between controllers.

  1. Controller 1 "controls" an angluarjs-map an provides the map-metadata for the view.

  2. A service, that provides the data sharedProperty, that should be displayed in the map, related to the current location of the user

  3. Controller 2, that watches the changes of the user an if a change happens, update the sharedProperty in order to update the map/view

The original controller are to complex, so I like to post some "pseudo"/example code.

MyCtrl.controller('ctrl1', 
    function($scope, myService) {
        $scope.map = {
        center:[..],
        zoom: [..],
        markers: myService.getSharedProperty(),
    };
});

MyCtrl.service('myService', function ($http) {
    if (property === undefined)
    {
        //Default Marker
        var property = [];
    }

    return {
        getSharedProperty: function () {
            return property;
        },
        setSharedProperty: function(location) {
            $http.jsonp('[..myURL...]')
                .success(function(value){
                    property = [];
                    angular.forEach(value.data, function(val,key){
                        property.push({
                               prop:val;
                        });
                      }); 
                });
        }
    };
});


MyCtrl.controller('ctrl2',
    function($scope,myService) {

        $scope.watchMyPositionChangesID = 
            navigator.geolocation
                      .watchPosition(
                          function(data) {
                              myService.setSharedProperty(data);
                          },
            [...]
            );
        }
});

This kind of constructs works in different situation, as long as the service does not use an http request. Probably the callback is the reason, why angularJS does not notice the change of the sharedProperty.

So the Question: how can I trigger the view to update by using the new value?

The service works, if I rip the destination map-scope and apply the new property "by hand", like:

               mapScope=angular.element(document.getElementById('id_map'))
                            .scope();
               mapScope.map.circles = property;  

(this code should be added in the success callback of $http)

But I think. this is a kind of dirty? Because, if I change the ID of the HTML element on view side, I have to crawl all my source-code to change the ID from old to new.

I know, there are some SO questions related to "view not updated", like this one: The view is not updated in AngularJS

But I was unable to get the right solution for me. Most of them results in: use $scope.$apply(), but $scope is not available at the service.


Solution

  • The controller gets the property once, when it's instantiated:

    markers: myService.getSharedProperty()
    

    So it gets an empty array.

    But the service changes the property in its http callback:

    .success(function(value){
        property = [];
    

    So, the service's property variable now references a new, empty array, but the controller's property variable still references the old, initial, empty array.

    If you want the controller to see the changes in the array, you should'nt assign a new array to the property. You should clear it, and fill it with new values:

    .success(function(value){
        property.splice(0, property.length);
    

    The alternative is to always get the property from the service in the view. In the controller:

    $scope.getProperty = myService.getSharedProperty
    

    In the view:

    {{ getProperty() }}