Jquery Cannot Read Property 'childnodes' of Null

The other twenty-four hours at InVision, we launched some code that worked fine locally, fine in QA, fine in Staging, and fine in Production - except for a small-scale prepare of users. For merely a few people, the page was completely breaking with the AngularJS-initiated JavaScript error, "TypeError: Cannot Read Property 'childNodes' Of Undefined." After the customer support squad dug into the tickets, they noticed a trend that most of the users were in Europe; and, that most of the users had the "CookiesOK" Google Chrome plugin installed. It turns out, this was only one of a number of Google Chrome plugins that can [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 exist honest, the code is a bit also complicated for me to trace finer. I empathize, at a high level, what is going wrong; simply, I cannot determine the low-level landscape of details. Ultimately, the error has to do with the fact that the DOM (Document Object Model) is being contradistinct indirectly, by a Controller, during the compile and linking phase. The alteration of the DOM throws the internal tree-walker out of whack and we stop upwardly referencing an undefined node.

In our particular case, the problem relates to a breakup in the separation of concerns between module types. In AngularJS, the Controller is not supposed to know anything well-nigh the DOM. And, to that extend, it probably shouldn't load any services that mutate the DOM. Just, that's exactly what we were doing - we were loading a service that was injecting a 3rd-party Script element as part of its initialization.

The Controller was [indirectly] mutating the DOM, which is a big no-no in AngularJS.

On its own, this may not take been a problem - or rather, the trouble may never accept become symptomatic. Just, for users that had certain Google Chrome plugins installed, the page would intermission because the plugins themselves were injecting Script tags into the HTML element of the page. The 3rd-party script tags would then getting injected earlier the plugin-injected tags, and that'southward what was breaking everything.

To become a sense of what I'm talking about, here is an isolated utilize-case:

                  <!doctype html> <html ng-app="Demo" ng-controller="AppController"> <head> 	<meta charset="utf-eight" />  	<championship> 		TypeError: Cannot Read Property "childNodes" Of Undefined In AngularJS 	</championship> </head> <body>  	<h1> 		TypeError: Cannot Read Property "childNodes" Of Undefined In AngularJS 	</h1>  	<div>  		<!-- 			In club for this to demo to break, nosotros need to have a few things in play:  			ane. Nosotros need the AppController to be on the HTML element.  			2. We need the AppController to trigger the loading of a 3rd-party script 			that gets injected into document.  			three. We demand the body to have a directive (it doesn't thing which i) that 			is nested inside another element (ie, it cannot be a direct child of the 			trunk tag).  			four. We need the user to have some sort of Chrome plugin similar "CookieOK" or 			"Google Analytics Opt-out Improver" that injects a Script into the folio. 		--> 		<div ng-style="{}"> 			Woot, in that location it is. 		</div>  	</div>   	<!-- Load scripts. --> 	<script type="text/javascript" src="./athwart-1.iv.3.js"></script> 	<script type="text/javascript">  		// Create an application module for our demo. 		var app = angular.module( "Demo", [] );   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I control the root of the application. 		angular.module( "Demo" ).controller( 			"AppController", 			part( $scope, thirdPartyScript ) {  				// Trigger the loading of a script, which will be injected into the DOM. 				thirdPartyScript.load();  			} 		);   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I provide the ability to load and so interact with a 3rd-party script. 		athwart.module( "Demo" ).manufactory( 			"thirdPartyScript", 			function() {  				// Return the public API. 				return({ 					load: load 				});   				// --- 				// PUBLIC METHODS. 				// ---   				// I load the 3rd-political party script tag. 				role load() {  					// Inject script before first script in page. 					// -- 					// NOTE: Code like this is often copy-pasted out of some read-me 					// on the 3rd-party vendor documentation.  					var script = document.createElement( "script" ); 					script.src = "//cdn.some-3rd-party-vendor.com/js/script.js";  					var firstScript = certificate.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 attempt to run the above folio, I go the following output:

TypeError: Cannot read property childNodes of undefined in AngularJS application.

Notation: This will non fault if the controller is in a different place; or, if we don't have a nested directive in the body tag. There is something nigh this combination of elements that causes the internal tree-walker to get confused. But, like I said above, I can't pinpoint the actual trouble in the AngularJS source code.

To fix this, we need to pull the DOM-mutation out of the Controller lifecycle. And, the easiest manner to practise 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-8" />  	<title> 		TypeError: Cannot Read Belongings "childNodes" Of Undefined In AngularJS 	</championship> </caput> <torso>  	<h1> 		TypeError: Cannot Read Property "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.3.js"></script> 	<script type="text/javascript">  		// Create an awarding module for our demo. 		var app = angular.module( "Demo", [] );   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I command the root of the awarding. 		athwart.module( "Demo" ).controller( 			"AppController", 			office( $scope, thirdPartyScript ) {  				// Trigger the loading of a script, which will be injected into the DOM. 				thirdPartyScript.load();  			} 		);   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I provide the power to load and and so interact with a 3rd-party script. 		angular.module( "Demo" ).manufacturing plant( 			"thirdPartyScript", 			function( $timeout ) {  				// Return the public API. 				return({ 					load: load 				});   				// --- 				// PUBLIC METHODS. 				// ---   				// I load the tertiary-party script tag. 				function load() {  					// Apply the script inject in the adjacent tick of the event loop. This 					// will give AngularJS time to safely finish its compile and linking. 					$timeout( loadSync, 0, false );  				}   				// --- 				// PRIVATE METHODS. 				// ---   				// I load the 3rd-party script tag. 				function loadSync() {  					// Inject script before showtime script in page. 					// -- 					// Annotation: Code similar this is often copy-pasted out of some read-me 					// on the 3rd-party vendor documentation.  					var script = document.createElement( "script" ); 					script.src = "//cdn.some-3rd-party-vendor.com/js/script.js";  					var firstScript = certificate.getElementsByTagName( "script" )[ 0 ];  					firstScript 						.parentNode 							.insertBefore( script, firstScript ) 					;  				}  			} 		);  	</script>  </body> </html>                                  

With this slight modification, the page runs fine, no "childNodes" error.

At that place'south probably a improve fashion to organize this lawmaking. But, I haven't personally dealt with loading many 3rd-party script tags; so, I don't have a good instinct for this all the same. Mostly, I just wanted to get this out there in example others were running into the same, seemingly unreproducible JavaScript error.

Black Lives Matter

Ad for InVision App, Inc prototying platform.


hauserdideenable.blogspot.com

Source: https://www.bennadel.com/blog/2892-typeerror-cannot-read-property-childnodes-of-undefined-in-angularjs.htm

0 Response to "Jquery Cannot Read Property 'childnodes' of Null"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel