Angular Cannot Read Property 'url' of Undefiend
The other twenty-four hour period at InVision, we launched some code that worked fine locally, fine in QA, fine in Staging, and fine in Production - except for a small gear up of users. For just a few people, the page was completely breaking with the AngularJS-initiated JavaScript error, "TypeError: Cannot Read Belongings 'childNodes' Of Undefined." After the customer support squad dug into the tickets, they noticed a trend that almost of the users were in Europe; and, that most of the users had the "CookiesOK" Google Chrome plugin installed. Information technology turns out, this was just one of a number of Google Chrome plugins that tin [potentially] disrupt the AngularJS compile and linking lifecycle.
I've tried to follow the AngularJS compile and linking code to figure out exactly what is going wrong. Just, to be honest, the code is a bit also complicated for me to trace finer. I sympathize, at a high level, what is going wrong; but, I cannot make up one's mind the depression-level mural of details. Ultimately, the mistake has to practise with the fact that the DOM (Document Object Model) is existence altered indirectly, by a Controller, during the compile and linking stage. The alteration of the DOM throws the internal tree-walker out of whack and we terminate up referencing an undefined node.
In our particular instance, the problem relates to a breakup in the separation of concerns betwixt module types. In AngularJS, the Controller is non supposed to know anything nigh the DOM. And, to that extend, it probably shouldn't load any services that mutate the DOM. Merely, that's exactly what nosotros were doing - nosotros were loading a service that was injecting a tertiary-party Script chemical element as function of its initialization.
The Controller was [indirectly] mutating the DOM, which is a big no-no in AngularJS.
On its ain, this may not have been a problem - or rather, the problem may never have become symptomatic. But, for users that had certain Google Chrome plugins installed, the folio would break because the plugins themselves were injecting Script tags into the HTML element of the folio. The 3rd-party script tags would then getting injected before the plugin-injected tags, and that's what was breaking everything.
To get a sense of what I'm talking about, here is an isolated use-case:
<!doctype html> <html ng-app="Demo" ng-controller="AppController"> <caput> <meta charset="utf-eight" /> <title> TypeError: Cannot Read Belongings "childNodes" Of Undefined In AngularJS </championship> </caput> <torso> <h1> TypeError: Cannot Read Holding "childNodes" Of Undefined In AngularJS </h1> <div> <!-- In order for this to demo to suspension, nosotros need to have a few things in play: i. Nosotros need the AppController to be on the HTML chemical element. 2. We need the AppController to trigger the loading of a 3rd-party script that gets injected into document. 3. Nosotros demand the body to take a directive (it doesn't affair which one) that is nested inside another element (ie, it cannot be a straight child of the body tag). four. We need the user to have some sort of Chrome plugin similar "CookieOK" or "Google Analytics Opt-out Add-on" that injects a Script into the page. --> <div ng-mode="{}"> Woot, in that location it is. </div> </div> <!-- Load scripts. --> <script type="text/javascript" src="./angular-one.iv.3.js"></script> <script blazon="text/javascript"> // Create an awarding module for our demo. var app = angular.module( "Demo", [] ); // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // // I control the root of the application. angular.module( "Demo" ).controller( "AppController", function( $telescopic, thirdPartyScript ) { // Trigger the loading of a script, which volition exist injected into the DOM. thirdPartyScript.load(); } ); // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // // I provide the ability to load and then interact with a tertiary-political party script. angular.module( "Demo" ).factory( "thirdPartyScript", part() { // Return the public API. return({ load: load }); // --- // PUBLIC METHODS. // --- // I load the 3rd-party script tag. function load() { // Inject script before commencement script in page. // -- // Note: Code similar this is frequently re-create-pasted out of some read-me // on the third-party vendor documentation. var script = certificate.createElement( "script" ); script.src = "//cdn.some-third-party-vendor.com/js/script.js"; var firstScript = document.getElementsByTagName( "script" )[ 0 ]; firstScript .parentNode .insertBefore( script, firstScript ) ; } } ); </script> </body> </html>
If I have the "CookiesOK" or the "Google Analytics Opt-out Add-on" Google Chrome plugins installed and I try to run the above page, I get the following output:
Annotation: This will non mistake if the controller is in a different place; or, if we don't have a nested directive in the body tag. In that location is something about this combination of elements that causes the internal tree-walker to get confused. Only, like I said above, I can't pinpoint the actual problem in the AngularJS source code.
To set up this, we need to pull the DOM-mutation out of the Controller lifecycle. And, the easiest fashion to do that is simply to wrap the DOM-mutation inside of $timeout() call:
<!doctype html> <html ng-app="Demo" ng-controller="AppController"> <head> <meta charset="utf-viii" /> <championship> TypeError: Cannot Read Belongings "childNodes" Of Undefined In AngularJS </title> </head> <body> <h1> TypeError: Cannot Read Belongings "childNodes" Of Undefined In AngularJS </h1> <div> <div ng-style="{}"> Woot, there information technology is. </div> </div> <!-- Load scripts. --> <script type="text/javascript" src="./angular-ane.4.three.js"></script> <script type="text/javascript"> // Create an awarding module for our demo. var app = athwart.module( "Demo", [] ); // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // // I control the root of the application. angular.module( "Demo" ).controller( "AppController", function( $scope, thirdPartyScript ) { // Trigger the loading of a script, which will exist injected into the DOM. thirdPartyScript.load(); } ); // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // // I provide the ability to load and then collaborate with a 3rd-political party script. angular.module( "Demo" ).mill( "thirdPartyScript", function( $timeout ) { // Render the public API. render({ load: load }); // --- // PUBLIC METHODS. // --- // I load the 3rd-party script tag. function load() { // Apply the script inject in the next tick of the event loop. This // will give AngularJS time to safely terminate its compile and linking. $timeout( loadSync, 0, fake ); } // --- // Individual METHODS. // --- // I load the third-party script tag. office loadSync() { // Inject script earlier first script in page. // -- // NOTE: Lawmaking like this is ofttimes re-create-pasted out of some read-me // on the 3rd-party vendor documentation. var script = document.createElement( "script" ); script.src = "//cdn.some-tertiary-political party-vendor.com/js/script.js"; var firstScript = document.getElementsByTagName( "script" )[ 0 ]; firstScript .parentNode .insertBefore( script, firstScript ) ; } } ); </script> </torso> </html>
With this slight modification, the folio runs fine, no "childNodes" error.
At that place's probably a amend way to organize this code. Merely, I oasis't personally dealt with loading many 3rd-political party script tags; and then, I don't have a expert instinct for this all the same. More often than not, I just wanted to become this out in that location in case others were running into the same, seemingly unreproducible JavaScript error.
Source: https://www.bennadel.com/blog/2892-typeerror-cannot-read-property-childnodes-of-undefined-in-angularjs.htm
Postar um comentário for "Angular Cannot Read Property 'url' of Undefiend"