Cannot Read Property 'then' of Undefined Angularjs

The other day at InVision, we launched some code that worked fine locally, fine in QA, fine in Staging, and fine in Production - except for a small set up of users. For simply a few people, the page was completely breaking with the AngularJS-initiated JavaScript fault, "TypeError: Cannot Read Property 'childNodes' Of Undefined." After the customer back up team 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 merely i of a number of Google Chrome plugins that tin can [potentially] disrupt the AngularJS compile and linking lifecycle.

I've tried to follow the AngularJS compile and linking code to effigy out exactly what is going wrong. But, to exist honest, the lawmaking is a bit as well complicated for me to trace effectively. I sympathise, at a high level, what is going incorrect; only, I cannot make up one's mind the depression-level landscape of details. Ultimately, the mistake has to practice with the fact that the DOM (Certificate Object Model) is being altered indirectly, past a Controller, during the compile and linking phase. The alteration of the DOM throws the internal tree-walker out of whack and we end up referencing an undefined node.

In our particular case, the problem relates to a breakdown in the separation of concerns betwixt module types. In AngularJS, the Controller is not supposed to know anything about the DOM. And, to that extend, it probably shouldn't load whatever services that mutate the DOM. But, that's exactly what we were doing - we were loading a service that was injecting a 3rd-party Script element every bit part of its initialization.

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

On its ain, this may non have been a problem - or rather, the problem may never have go symptomatic. But, for users that had certain Google Chrome plugins installed, the page would break because the plugins themselves were injecting Script tags into the HTML chemical element of the page. The tertiary-party script tags would and so getting injected before the plugin-injected tags, and that's what was breaking everything.

To get a sense of what I'm talking most, here is an isolated use-case:

                  <!doctype html> <html ng-app="Demo" ng-controller="AppController"> <head> 	<meta charset="utf-viii" />  	<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 order for this to demo to break, we need to have a few things in play:  			i. Nosotros need the AppController to be on the HTML element.  			2. We need the AppController to trigger the loading of a third-party script 			that gets injected into document.  			iii. Nosotros demand the body to have a directive (it doesn't matter which one) that 			is nested inside another chemical element (ie, it cannot be a direct child of the 			trunk tag).  			4. We need the user to have some sort of Chrome plugin like "CookieOK" or 			"Google Analytics Opt-out Improver" that injects a Script into the folio. 		--> 		<div ng-manner="{}"> 			Woot, at that place it is. 		</div>  	</div>   	<!-- Load scripts. --> 	<script type="text/javascript" src="./angular-one.4.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", 			role( $scope, thirdPartyScript ) {  				// Trigger the loading of a script, which volition exist injected into the DOM. 				thirdPartyScript.load();  			} 		);   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I provide the ability to load and so collaborate with a 3rd-party script. 		angular.module( "Demo" ).mill( 			"thirdPartyScript", 			function() {  				// Return the public API. 				return({ 					load: load 				});   				// --- 				// PUBLIC METHODS. 				// ---   				// I load the third-political party script tag. 				function load() {  					// Inject script earlier first script in page. 					// -- 					// NOTE: Code like this is often copy-pasted out of some read-me 					// on the third-party vendor documentation.  					var script = certificate.createElement( "script" ); 					script.src = "//cdn.some-3rd-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 Addition" Google Chrome plugins installed and I attempt to run the above page, I become the post-obit output:

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

NOTE: This will non error if the controller is in a different place; or, if we don't accept a nested directive in the body tag. At that place is something about this combination of elements that causes the internal tree-walker to go confused. But, like I said higher up, I can't pinpoint the actual problem in the AngularJS source lawmaking.

To gear up this, we need to pull the DOM-mutation out of the Controller lifecycle. And, the easiest way to do that is simply to wrap the DOM-mutation inside of $timeout() phone call:

                  <!doctype html> <html ng-app="Demo" ng-controller="AppController"> <head> 	<meta charset="utf-8" />  	<championship> 		TypeError: Cannot Read Holding "childNodes" Of Undefined In AngularJS 	</championship> </head> <body>  	<h1> 		TypeError: Cannot Read Property "childNodes" Of Undefined In AngularJS 	</h1>  	<div>  		<div ng-style="{}"> 			Woot, there it is. 		</div>  	</div>   	<!-- Load scripts. --> 	<script blazon="text/javascript" src="./athwart-one.4.iii.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( $scope, thirdPartyScript ) {  				// Trigger the loading of a script, which will be injected into the DOM. 				thirdPartyScript.load();  			} 		);   		// --------------------------------------------------------------------------- // 		// --------------------------------------------------------------------------- //   		// I provide the ability to load and and then collaborate with a 3rd-political party script. 		athwart.module( "Demo" ).mill( 			"thirdPartyScript", 			function( $timeout ) {  				// Return the public API. 				render({ 					load: load 				});   				// --- 				// PUBLIC METHODS. 				// ---   				// I load the 3rd-political party script tag. 				function load() {  					// Utilize the script inject in the side by side tick of the effect loop. This 					// will give AngularJS time to safely finish its compile and linking. 					$timeout( loadSync, 0, simulated );  				}   				// --- 				// Individual METHODS. 				// ---   				// I load the 3rd-political party script tag. 				function loadSync() {  					// Inject script before commencement 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-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.

There's probably a amend way to organize this lawmaking. But, I oasis't personally dealt with loading many tertiary-party script tags; and then, I don't have a adept instinct for this nevertheless. Mostly, I just wanted to get this out there in example others were running into the aforementioned, seemingly unreproducible JavaScript error.

Black Lives Matter

Ad for InVision App, Inc prototying platform.


frazerrenat1978.blogspot.com

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

0 Response to "Cannot Read Property 'then' of Undefined Angularjs"

Enregistrer un commentaire

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel