Search code examples
angularjsangular-ng-if

ng-if only works when referencing var direct from service, instead of var in controller scope


I am trying to understand why my ng-if statement doesn't work when I reference a local variable in my controller that is assigned to a value from a service, but it works properly if assigned directly to the value from that service.

For example, this works:

<div class="map" ng-if="interactiveMap.mapService.esriLoaded">
    <esri-map id="map1" 
    map-options="interactiveMap.mapOptions" 
    load="interactiveMap.load"
    register-as="interactiveMap">
    </esri-map>
</div>

with the following controller:

angular.module('tamcApp')
  .controller('InteractivemapCtrl', function (map, config) {

    var self = this;
    self.map = {};

    self.mapService = map;

    self.mapOptions =  {
                    basemap: 'mcgiStreet',
                    extent: config.globals.initialExtent,
                    sliderStyle: 'small'
            };

     self.load = function(){
       map.getMap('interactiveMap').then(function(thisMap) {
         console.log(thisMap);
         self.map = thisMap;
       });

     };
  });

But if I were to assign the "esriLoaded" var to a local var in the scope, like this:

<div class="map" ng-if="interactiveMap.esriLoaded">
    <esri-map id="map1" 
    map-options="interactiveMap.mapOptions" 
    load="interactiveMap.load"
    register-as="interactiveMap">
    </esri-map>
</div>

Controller here:

angular.module('tamcApp')
  .controller('InteractivemapCtrl', function (map, config) {

    var self = this;
    self.map = {};

    self.esriLoaded = map.esriLoaded;

    self.mapOptions =  {
                    basemap: 'mcgiStreet',
                    extent: config.globals.initialExtent,
                    sliderStyle: 'small'
            };

     self.load = function(){
       map.getMap('interactiveMap').then(function(thisMap) {
         console.log(thisMap);
         self.map = thisMap;
       });

     };
  });

Then it doesn't work. The value for "esriLoaded" is always false (which is the default value for esriLoaded). It's like it isn't updating the value of self.ersiLoaded when the value gets updated in the "map" service. Here is the code for the "map" service, just in case folks need it to answer this question.

angular.module('tamcApp')
  .service('map', function (config, esriLoader, esriRegistry, esriMapUtils) {
    // AngularJS will instantiate a singleton by calling "new" on this function

    var self = this;


    self.esriLoaded = false;


    self.lazyload = function() {
      // Make a call to load Esri JSAPI resources.
      // A promise is provided for when the resources have finished loading.
      esriLoader.bootstrap({
            url: config.globals.esriJS
            }).then(function() {

                    // Set Loaded to be true
                    self.esriLoaded = true;

                    // DEFINE CUSTOM BASEMAP USED BY ALL MAPS
                    esriMapUtils.addCustomBasemap('mcgiStreet', {
                        urls: ['http://myhost.com/arcgis/rest/services/BaseMap/StreetMap/MapServer'],
                        title: 'MCGI Street Map',
                        thumbnailurl: ''
                    });


            });
    };

    if (!self.esriLoaded) {
            self.lazyload();
    }


    self.getMap = function(id){
      return esriRegistry.get(id);
    };

  });

Solution

  • That is actually not because of angular, but because of JavaScript. map.esriLoaded is a boolean value, a primitive and thus not an object, which leads to your local self.esriLoaded not becoming a reference (as only objects can be referenced), but just a plain copy of the boolean value contained in map.esriLoaded.

    A short example to make it more clear:

    //Primitive
    var a = 5; //primitive
    var b = a; //b just copies the value of a
    
    a = 6; //This will change a, but not b
    
    conosle.log(b); //will print 5
    
    //Object
    var a = { someValue: 5 }; //a is now a reference to that object
    var b = a; //b also becomes a reference to the object above
    
    a.someValue = 1337; //will change the object a is referencing, thus also
                        //changing the object b is referencing, as its the same object
    
    console.log(b.someValue); //will print 1337