Search code examples
angularjsdomangular-ng-if

AngularJS - bring back element to DOM after ng-if


I have got into problem when the code tried to reach an element in the DOM which was taken off before by ng-if

Code for that view looks like:

<div class="col-md-9" id="map-container" ng-if="searchCount<=5000">
    <div class="col-md-12" id="map_canvas" >
    </div>
</div>
<div class="cener-btn-container"  ng-if="searchCount>5000"></div>

and a controller part which effect that looks like

    $scope.searchCount = $scope.searchList.length;
    $log.debug("Ready to load map");
    $scope.loadMap();       

     $scope.loadMap=function(){
        var latlng = new google.maps.LatLng(39.774769, -101.414795)
        $scope.customList=[];
        var map_options = {
            center: latlng,
            zoom: 6,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            disableDefaultUI: true,
            zoomControl: true
        };

        google_map = new google.maps.Map(document.getElementById("map_canvas"), map_options);
        ...
        $log.debug("Map lodaded");

    }

After reaching searchCount more then 5000 results and refining search query to lower amount it throws an error

TypeError: Cannot read property 'firstChild' of null
    at Object._.ug (js?sensor=false:85)
    at new zg (js?sensor=false:87)
    at r.$scope.loadMap (controller.js:208)
    at controller.js:151
    at angular-resource.js:643
    at angular.js:14792
    at r.$eval (angular.js:16052)
    at r.$digest (angular.js:15870)
    at r.$apply (angular.js:16160)
    at g (angular.js:10589)

and line 208 is

google_map = new google.maps.Map(document.getElementById("map_canvas"), map_options);

when map_canvas was taken by ng-if from the DOM before as there were more than 5000 results.

My question is how I can get map_canvas back before loadMap() is executed?


Solution

  • Problem was that there is no way to know if angular is done with the digest loop, ensuring that all elements have been rendered.

    To solve this issue, there were two options

    1. Wrap a callback function in a directive. include that directive in ng-if. and make that expression true only when u want your callback to be executed. Something like

      <div ng-if="sectionActivated"> <div ng-init="callBack()"></div> </div>

    2. Call a callback function inside, setTimeOut(function(){ ... }, 0); as browsers by default keep all events in a queue, therefore, when digest loop is running, your callback function will enter the queue and get executed as soon digest loop is over.

    In my case preferred solution was with setTimeout, allowing me to do things that are not a part of the map on a page or restricted to being inside the ng-if.