Search code examples
javascriptangularjsng-map

How to set watcher in AngularJS component?


I am using NgMap to display google map and I need the ability to change center position from varios parts of site. I have markerService for that:

 angular.module('markerService')
        .factory('MarkerService', MarkerService);
    MarkerService.$inject = [];
    function MarkerService(){
        var coords = [
            56.936,
            23.12
        ]
        var markers = [];
        return {
            setCoords: setCoords,
            getCoords: getCoords,
            setMarkers: setMarkers,
            getMarkers: getMarkers,
        };

        function setCoords(a){
            coords = a;
        }
        function getCoords{
            return coords;
        }
        function setMarkers(a){
            markers= a;
        }
        function getMarkers(){
            return markers;
        }
   }

Then I have component map, that uses NgMap:

    angular.module('map')
        .component('mapComponent', {
            templateUrl: 'app/mapComponent/map.html',
            controller: mapController
        });
    mapController.$inject = ['NgMap', 'MarkerService'];
    function mapController(NgMap, MarkerService){
        var ctrl = this;
        ctrl.markers = MarkerService.getMarkers();
        ctrl.center = MarkerService.getCoords();
    }
}

and template:

<div class="map_wrapper">
    <ng-map default-style="false" 
            center="{{$ctrl.center}}"
            zoom="10"
            >
        <marker ng-repeat="m in $ctrl.markers" position="{{m.lat}},{{m.lng}}" on-click="$ctrl.openModal()"></marker>
    </ng-map>
</div>

If I change markers array using MarkerService.setMarkers([...]) the markers on map are updated because ng-repeat sets watcher but changing coords with MarkerService.setCords([...]) does not change center of map because there is no watcher.

I tried using ng-bind center="ng-bind='$ctrl.center'" but logically it did not work. I am sure that I have to set watcher from components controller, but I fail to do that whatever I try.

UPDATE:

Did some serious investigation and bumped into some weird behavior.

MarkerService.getCoords() does not return an instance of coords but value. If I make changes to coords using MarkerService.setCoords(//some value) it is not reflected in variable that previously was declared var ctrl.center=MarkerService.getCoords(); but if I call getter again, I get updated value.

It is strange because I have been using this getter and setter approach a lot before and always rely on fact that getter would return an instance of variable.


Solution

  • If you want to set a watcher you have to use $scope.

    To do that, you need to inject it in your controller:

    MarkerService.$inject = ['$scope'];
    

    And then add your watcher:

    function MarkerService($scope){
        $scope.$watch([...]);
    }
    

    But the problem you have doesn't seem to come from here, I think you are setting the coordinates on the wrong object, that is why your map is not updated.

    Do you do it like this ?:

    MarkerService.setCoords(coords)
    ctrl.center = MarkerService.getCoords();