Search code examples
javascriptangularjsajaxtypeerrorfactories

AngularJS web app gives "TypeError: domNode is null" when navigating from /pull/:pull_id to /pulls using a "Go Back" link


As stated in the title, I'm getting a rather poorly described error in my Angular scanner/checkout application.

When I load the /pulls page directly it's fine, no console errors. I can then select a pull and click "view" to load the /pull/:pull_id page.. Again, it's all good there. But the problem shows up when I then click a link to "Go Back" to the /pulls list of pulls.

See code samples below, and the console log (including my lovely debug comments) below the samples..

I have a factory named "pullsSvc" in my services.js file..

app.factory("pullsSvc", ["$http","$q","$window","$routeParams", function ($http, $q, $window, $routeParams) {

var pulls;
var pull;
console.log('pullSvc Factory started');
function get_pulls() {
    console.log('pullSvc Factory get_pulls() started');
    var deferred = $q.defer();
    console.log('pullSvc Factory get_pulls() deferred');
    $http({
        method: 'post',
        url: 'ajax.php',
        data: $.param({
            'event' : 'get_pulls'
        }),
        headers: {'Content-Type' : 'application/x-www-form-urlencoded'}
    }).
    success(function(data) {
        if(data.success == true){
            console.log('pullSvc Factory get_pulls() success');
            pulls = data.pulls;
            deferred.resolve(pulls);
        }else{
            console.log('pullSvc Factory get_pulls() error 1');
            deferred.reject('Could not get pulls.');
        }
    }).
    error(function(data) {
        console.log('pullSvc Factory get_pulls() error 2');
        deferred.reject(error);
    });

    return deferred.promise;
}

function get_pull(pull_id) {
    .....
}
return {
    get_pulls: get_pulls,
    get_pull: get_pull,
};
}]);

Then in my controllers.js I have

app.controller("ViewPullsCtrl", ["$rootScope", "$scope", "$http", "$q", "$route", "$routeParams", "$location", "$window", "$timeout", "$sessionStorage", "authenticationSvc", "auth", "pullsSvc", "pulls",
function ($rootScope, $scope, $http, $q, $route, $routeParams, $location, $window, $timeout, $sessionStorage, authenticationSvc, auth, pullsSvc, pulls) {
    console.log('This 1');
    $scope.userInfo = auth;
    $scope.pulls    = pulls;
    console.log('This 2');
    // FUNCTIONS
        $scope.logout = function () {
            authenticationSvc.logout()
                .then(function (result) {
                    $sessionStorage.$reset();
                    $location.path("/login");
                }, function (error) {
                     if(debug) if(debug) console.log(error);
                });
        };
        $scope.alert = function(message){
            if(message){
                console.log(message);
            }
        }
        $scope.consolelog = function(value){
            console.log(value);
        }
        $scope.setSelected = function(idSelected) {
            $scope.idSelected = idSelected;
        }
}
]);

And in my app.js routing (ngRoute) the relevant bit is

    }).when("/pulls", {
    templateUrl: "views/pulls.html",
    controller: "ViewPullsCtrl",
    activetab: "pulls",
    url: "/pulls",
    resolve: {
        auth: function ($q, authenticationSvc) {
            var userInfo = authenticationSvc.getUserInfo();
            if (userInfo) {
                console.log('authSvc success');
                return $q.when(userInfo);
            } else {
                console.log('authSvc failure');
                return $q.reject({ authenticated: false });
            }
        },
        pulls: function ($q, pullsSvc) {
            var pulls = pullsSvc.get_pulls();
            if(pulls) {
                if(debug) console.log('pullsSvc success');
                return $q.when(pulls);
            } else {
                if(debug) console.log('pullsSvc failure');
                return $q.reject({ pulls: false });
            }
        }
    }

Console logs

Route Change Start:
app.js (line 179)
Route Change Success:
app.js (line 187)
Object { name="$routeChangeSuccess",  targetScope=Scope,  defaultPrevented=false,  more...}
app.js (line 188)
Route Change Start:
app.js (line 179)
authSvc success
app.js (line 71)
pullSvc Factory get_pulls() started
services.js (line 189)
pullSvc Factory get_pulls() deferred
services.js (line 193)
pullsSvc success
app.js (line 81)
POST http://portal_dev.mycompany.com:8888/custom_scripts/mobile_scanner/ajax.php

200 OK
        1.24s   
angular.js (line 12011)
TypeError: domNode is null


return domNode.offsetWidth + 1;


angular.js (line 10490, col 7)
pullSvc Factory get_pulls() success
services.js (line 205)
Route Change Success:
app.js (line 187)
Object { name="$routeChangeSuccess",  targetScope=Scope,  defaultPrevented=false,  more...}
app.js (line 188)
This 1
controllers.js (line 142)
This 2

Updates: changing <a href...> to <a ng-href...> did not make a difference.

line 12011 of angular.js is xhr.send(isUndefined(post) ? null : post); (v1.5.6)

Chrome's error log slightly more helpful.. angular.js:10490 Uncaught TypeError: Cannot read property 'offsetWidth' of null


Solution

  • It turns out this was an issue somehow stemming from ngAnimate, which was included in my app dependencies but I wasn't making use of (intended to, but reversed changes, and never removed from app dependencies).

    I still don't know how or why it caused the issue. But it's resolved by removing it from dependencies.

    Other research suggests the error happens when trying to access part of the DOM before it loads. I don't know what it was trying to animate since I didn't do anything with it in my controller.. but whatever's clever.

    I've chosen to leave the question and post my "resolution" because topics on this error that are NOT related to google maps api's are non existent.

    If you can answer WHY it is happening or HOW to resolve it without removing ngAnimate, I would love to get some clarification and will mark any in depth answers as a resolution.