0

I am newbie in angularJs. I am trying to re-run init() function inside link when 'localid' has been changed, but it said

  var elm = angular.element(element[0].getSVGDocument().getElementsByTagName("path"));

is null even it works at the first time on page load.

TypeError: Cannot read property 'getElementsByTagName' of null

I googled it a lot for more than 5 hours but i couldn't find the reason. What do I missing ?

(function() {
'use strict';

angular
.module('neuroSeoulFinance')
.directive('seoulmap', seoulMap);

/** @ngInject */
function seoulMap($log) {
var directive = {
    restrict: 'E',
    template: '<object id="seoulmap" class="localMap" data="../assets/images/seoul.svg" type="image/svg+xml" width="80%"></object>',
    replace: true,
    scope: {
        localid : "="
    },
    link: function(scope, element, attrs) {

        var init = function() {
            var elm = angular.element(element[0].getSVGDocument().getElementsByTagName("path"));
            $log.log(elm);
            for(var i=0; i<elm.length; i++) {

                if(elm[i].id == scope.localid.id) {

                    elm[i].style.fill = attrs.highlight;
                }
                else {
                    elm[i].style.fill = "#e1e3e4";                        
                }
            }
        };

        scope.$watch('localid', function(newValue, oldValue) {
            if (newValue){
                init();  // <-- it doesn't work. 
            // var ealm = angular.element(element[0].getSVGDocument().getElementsByTagName("path")); 
            // ^ it also return null..

            $log.log("I see a data change!");
            }
        }, true);

        if(element[0].getSVGDocument()) {
            $log.log("init");
            init();
        } else {
            $log.log("load");
            element.on("load",init);  
        }
    }
};

return directive;
}})();
David Hong
  • 39
  • 2

2 Answers2

2

See How to check if an embedded SVG document is loaded in an html page?

If getSVGDocument returns null that means the element is not loaded yet, so as said in the link use a timeout, and since you use angular, use a $timeout.

Community
  • 1
  • 1
Walfrat
  • 5,363
  • 1
  • 16
  • 35
  • it only returns Null when Init() is called inside of $watch, whereas when a page loaded it works due to 'element.on("load",init);'. my question is why it isn't in $watch. – David Hong Feb 05 '16 at 12:47
  • My guess is since you're watching a data binded to a parent scope, the binding occurs before the dom is fully loaded and then the $watch happen before the getSVGElement is usable. Just protect your init method by a (if getSVGElement() == null) return; – Walfrat Feb 05 '16 at 12:56
  • Thanks for your comment. the thing is, user changes localid by manual after all the pages are fully loaded. (when the svg files already exists. and It needs to run init() function every time user selected different localid. – David Hong Feb 05 '16 at 13:07
  • I didn't say the opposite, i just say that when angular load your directive before rendering them, it bind the value between your directive and the controller of the current view. So the $watch is triggered with a newValue. This is why it happens. Just protect your init method as i said. You may try if(newValue && oldValue) in the $watch but i'm not sure and you'll have trouble if the value localid can be null – Walfrat Feb 05 '16 at 13:11
0

I changed the $watch code after the element.on("load") is done. thanks for the helpful comments.

        if(element[0].getSVGDocument()) {
            init();
        } else {
            element.on("load",function(){   
                scope.$watch('localid', function(newValue, oldValue) {
                if (newValue){
                    init();
                }
                });
            });
        }
David Hong
  • 39
  • 2