Search code examples
angularjsangularjs-watch

Angular $watch just parent object instead of its multiple children


I have a div, listing properties of the object POI = {"address":"Martinsicuro (TE), Italy", "phone":"+39 333 45657", "website':'http://mysite.it"}. The object POI si owned by a Service. The directive's controller has the function getPoi() that gets the POI from the service, and returns it to the directive.

My current HTML is something like this:

<table ng-controller="Controller as ctrl">
    <tr> <!-- address -->
        <td>{{ctrl.getPoi().address}}</td>
    </tr>
    <tr> <!-- phone -->                   
        <td>{{ctrl.getPoi().phone}}</td>
    </tr>
    <tr> <!-- website -->
        <td>
            <a ng-href="{{ctrl.getPoi().website}}"> 
                {{ctrl.getPoi().website}}
            </a>
        </td>   
    </tr>
</table>

The controller

.controller('Controller', function(CurrentPoiService)
{

  this.getPoi = function()
    { return CurrentPoiService.POI; }
}

The service

.service('CurrentPoiService', function()
{

  this.POI = {"address":"Martinsicuro (TE), Italy", "phone":"+39 333 45657", "website':'http://mysite.it"}
}

In this way I am adding 3 watchers. Is there a way to add just 1 watcher, since it's the same parent object? Here it is a JSFiddle Thank you

[UPDATE 1] This is the (still not working) JSFiddle using the solution proposed by @Charlie

[UPDATE 2] This is the working JSFiddle


Solution

  • As Claies has mentioned in a comment, you should never call your data from the view through a function this way.

    In this scenario you can create a watch for the POI object with the objectEquality argument true to watch the properties of the object in a single $watch. Then find your elements inside the listener and change the value in the way you want.

    $scope.$watch('POI', function(){
    
        //Assume that $scope.propertyIndex is the current property to display
    
        angular.element($document[0].querySelector("#myTd" + $scope.propertyIndex)).html(POI.address);
        angular.element($document[0].querySelector("#myTd" + $scope.propertyIndex)).html(POI.phone);
        //etc...
    
    }, true);
    

    You have a better control this way. But please keep in mind that this method is not suitable if POI is a complex object.

    UPDATE:

    Here is a working example of showing a random number every second using a watch and a factory. You should be able to learn from this and apply it to your project.

                myApp.controller('myController', function($scope, dataSource) {
    
                     $scope.poi = {rand: 0};    
    
                     $scope.$watch('poi', function() {
                        $('#rand').html($scope.poi.rand);
                     }, true);
    
                    dataSource.open($scope);               
    
                });
    
                myApp.factory('dataSource', function($interval) {                
    
                    return {                       
                                open: function(scope){
                                    $interval(function() {
                                        scope.poi.rand = Math.random();
                                    }, 1000);
                                }
                    }    
                });