Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unmount angular by using the proper rootScope #24

Merged
merged 4 commits into from
Sep 6, 2016

Conversation

blittle
Copy link
Contributor

@blittle blittle commented Sep 6, 2016

It looks as though the way we were getting the rootScope is incorrect.

The following is true:

angular.injector(['ng']).get('$rootScope') !== angular.injector(['ng']).get('$rootScope')

In other words, the rootScope is not the same each time it is queried with this method. Whereas this is true:

angular.element(getContainerEl().childNodes[0]).scope() === angular.element(getContainerEl().childNodes[0]).scope()

The problem was noticed when calling angular.injector(['ng']).get('$rootScope').$destroy() no children components .$on('$destroy') events were getting fired. More importantly, the $onInit of components wasn't getting fired on remount. When switching to the new way of querying the $rootScope and calling $destroy() all events properly fire.

It looks as though the way we were getting the rootScope is incorrect.

The following is true:

```js
angular.injector(['ng']).get('$rootScope') !== angular.injector(['ng']).get('$rootScope')
```

In other words, the rootScope is not the same each time it is queried with this method. Whereas this is true:

```js
angular.element(getContainerEl().childNodes[0]).scope() === angular.element(getContainerEl().childNodes[0]).scope()
```

The problem was noticed when calling `angular.injector(['ng']).get('$rootScope').$destroy()` no children components `.$on('$destroy')` events were getting fired. More importantly, the `$onInit` of components wasn't getting fired on remount. When switching to the new way of querying the `$rootScope` and calling `$destroy()` all events properly fire.
@@ -68,7 +68,9 @@ function mount() {

function unmount() {
return new Promise((resolve, reject) => {
let rootScope = angular.injector(['ng']).get('$rootScope');
let rootElement = angular.element(getContainerEl().childNodes[0]);
Copy link
Contributor Author

@blittle blittle Sep 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is querying the first element that angular mounted which should have the $rootScope.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only concern is for this to throw an uncaught error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that the first childNode is the correct one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do something like getContainerEl().querySelector('[ng-scope]')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if so, does angular put that ng-scope attribute on both in debug mode and production mode??

Copy link
Contributor Author

@blittle blittle Sep 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joeldenning There is no ng-scope attribute :( Maybe because I am debugging in prod!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kentmclean if it does throw an error, what should the outcome be? My thoughts are if there is an error, it is a catastrophic error. Is it something we could ignore? Maybe if we mount the app and unmount it super fast (before the dom has been built) then the [0] could be undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joeldenning there is a className present with ng-scope

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blittle - an error here would be unexpected for sure, probably due to a timing issue or an unintended re-unloading of an app. For our customers I'd want the error eaten as gracefully as possible. Then for our own purposes (and I assume this is already happening) we want to have the error alerted on through Sentry with relevant autoTrace stack.

@@ -68,7 +72,9 @@ function mount() {

function unmount() {
return new Promise((resolve, reject) => {
let rootScope = angular.injector(['ng']).get('$rootScope');
let rootElement = angular.element(getContainerEl().querySelector(`#${SINGLE_SPA_ELEMENT_ID}`));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not using getElementById because it isn't available at a node level and I don't want to use document.getElementById because there might be more than one instance of this element.

@joeldenning
Copy link
Member

Lgtm nice work finding this!

@joeldenning
Copy link
Member

🚶

@kentmclean
Copy link

👍

@blittle blittle merged commit 5df3b39 into master Sep 6, 2016
@blittle blittle deleted the bugfix/properlyUnMountAngular branch December 13, 2016 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants