Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs: TypeError: Cannot call method 'insertBefore' of null

Please find the fiddle here http://jsfiddle.net/UxYLa/6/

This is a simplified form of what I am trying to do. There are two directive, and the nested one, subDirective, which dynamically creates html form based on the selection(random). If you click repeatedly on the button, it throws below error

TypeError: Cannot call method 'insertBefore' of null
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:138:283
    at q (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:7:332)
    at q.after (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:138:258)
    at Object.O.(anonymous function) [as after] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:139:414)
    at Object.enter (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:141:226)
    at Object.move (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:141:360)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:185:282
    at Object.fn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js:99:371)

I found a reference about this https://groups.google.com/forum/#!msg/angular/dNra_7P2hwU/09-UBn1XxyUJ https://github.com/angular/angular.js/issues/2151 but I am using the latest stable version.

What is the cause of this error.

Full code below:

script:

var myApp = angular.module('myApp', [])
    .controller('TestController', ['$scope', function ($scope) {
        $scope.data = [{ type: "a", values: [{name:"aa"}, {name: "bb"}]},
          { type: "b", values: [{name:"aa"}, {name: "bb"}]}]
}]);   
myApp.directive('directive', function () {
    return {
        scope: {
            data: "=",
        },
        restrict: 'E',
        controller: function ($scope, $element, $attrs) {
            $scope.random = function(){
                $scope.model = $scope.data[Math.floor(Math.random()*$scope.data.length)];
                console.log($scope.model)
            };
        },
         template: '<div><button ng-click="random()">Random</button><sub-directive data="model"></sub-directive></div>'
    };
});


myApp.directive('subDirective', function ($templateCache, $compile) {
    return {    
         scope: {
            data: "=",
        },
        restrict: 'E', 
        link: function (scope, element, attrs) {
             scope.$watch('data', function (newVal, oldVal) {
                if (newVal) {
                     element.html($templateCache.get(newVal.type + '.html'));
                     $compile(element.contents())(scope);
                 }
             });
        }
    };
});

html

  <script type="text/ng-template" id="a.html">
     a.html
  </script>


<script type="text/ng-template" id="b.html">
      <div ng-repeat="itm in data">
          <span ng-if='"string" == itm.type'>
              <input name='{{itm.Name}}'id='{{itm.Name}}' ng-model='model[itm.Name]' type='text'></input>
          </span>
      </div>
  </script>

<div ng-controller="TestController">
    <directive data="data"></directive>
</div>
like image 474
bsr Avatar asked Jan 28 '14 23:01

bsr


3 Answers

I had the same error message. I could fix this by referencing JQuery before Angular in my html script tags.

like image 145
Hinrich Avatar answered Oct 08 '22 10:10

Hinrich


It has something to do with the compilation and how data is bound. I made a working version here: http://jsfiddle.net/UxYLa/9/

The main differences are in b.html

  <div ng-if="data.values">
      <div ng-repeat="itm in data.values">
          <input name='{{itm.name}}' id='{{itm.name}}' ng-model="itm.name" type='text'></input>
      </div>
  </div>

Have to interate over arrays and refer to itm instead of model since it's in the scope.

Edit: after some digging here are some more clues as to why the error happens, but not when you wrap it in a div. It is calling this: parent.insertBefore(node, index.nextSibling); where parent is element.parent of your ng-repeat. If you don't have the wrapper, the parent is null.

This means the error occurs whenever the html you are compiling has a watch that is on the outside of the template when directly changing the element.

I also made a solution that doesn't attempt to change element directly, but rather appends the compiled element to it. So that everything, when it's checked in the digest cycle will have a proper structure. http://jsfiddle.net/UxYLa/12/

Hope this helped.

like image 23
hassassin Avatar answered Oct 08 '22 10:10

hassassin


I had the same issue, but I found I was adding class="md-sticky" on a <md-subheader> tag, and it meant to say class="md-no-sticky"

As soon as I changed this class, that sorted the problem for me, but I also had the same issue with using an ng-repeat not within it's own parent tag, but I had! It was just I used ng-show="condition" on that parent tag, and if that parent tag didn't show it would cause this issue, so I changed it to ng-if="condition" and that sorted that problem.

like image 43
Pete Garland Avatar answered Oct 08 '22 11:10

Pete Garland