Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

App freezes when using a directive that transcludes ng-message #14183

Closed
robianmcd opened this issue Mar 4, 2016 · 7 comments
Closed

App freezes when using a directive that transcludes ng-message #14183

robianmcd opened this issue Mar 4, 2016 · 7 comments

Comments

@robianmcd
Copy link

I'm trying to create a directive that contains some common css classes and hide/show logic that I use for all my ng-messages. it looks like this

var StandardMessagesComponent = function() {

}

angular.module('myApp').component('standardMessages', {
    controller: StandardMessagesComponent,
    controllerAs: 'ctrl',
    templateUrl: 'standardMessages.html',
    transclude: true,
    bindings: {
        form: '<',
        field: '@'
    }
});
<ng-messages for="ctrl.form[ctrl.field].$error" role="alert" class="standard-messages"
             ng-if="ctrl.form[ctrl.field].$error && (ctrl.form.$submitted || ctrl.form[ctrl.field].$touched)"
>
    <ng-transclude></ng-transclude>
</ng-messages>

It is causing my app to freeze when the following is true:
-there is a validation error causing one of the ng-messages to be shown
-there are multiple ng-message elements
-The user navigates to another page

The following plunkr reproduces the issue: https://plnkr.co/edit/Qi2JQ4RioAOxZG98uCou?p=preview
To crash the app click the input and then click the "other page" link.

I'm using Angular 1.5, angular-messages 1.5, and ui-router 0.2.18. This issue exists in Chrome and Firefox but works fine in IE11 (although it freezes for a second)

@gkalpak
Copy link
Member

gkalpak commented Mar 5, 2016

FWIW, this is not related to uiRouter. It happens with any structural directive (example with ngIf).

Without looking too much into it, there seems to be an infinite loop because the ngMessage is removed, which causes a reRender() which somehow re-inserts the ngMessage element (not sure why this only happens in the presence of ngTransclude inside standardMessages).
It also happens only if the first ngMessage is currently shown.
BTW, it was introduced in 1.4.0-beta.5 (i.e. it works fine until 1.4.0-beta.4).

Ugly, temp, hackish work-around: PRepend a dummy ngMessage (that will never be shown) :(

@gkalpak
Copy link
Member

gkalpak commented Mar 5, 2016

So, since this broke in v1.4.0-beta.5 and since it's related to [email protected], it must be c9a4421.

@robianmcd
Copy link
Author

@gkalpak thanks, good to know there is a temporary workaround

@Narretz Narretz self-assigned this Mar 15, 2016
Narretz added a commit to Narretz/angular.js that referenced this issue Mar 15, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that only messages with an index lower than the starting message are considered
previous elements.

Fixes angular#14183
Narretz added a commit to Narretz/angular.js that referenced this issue Mar 15, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that only messages with an index lower than the starting message are considered
previous elements.

Fixes angular#14183
Narretz added a commit to Narretz/angular.js that referenced this issue Mar 15, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that only messages with an index lower than the starting message are considered
previous elements.

Fixes angular#14183
@gkalpak gkalpak modified the milestones: 1.5.1, 1.5.2 Mar 16, 2016
Narretz added a commit to Narretz/angular.js that referenced this issue Mar 18, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that only messages with an index lower than the starting message are considered
previous elements.

Fixes angular#14183
@matsko matsko modified the milestones: 1.5.2, 1.5.3 Mar 18, 2016
gkalpak pushed a commit to gkalpak/angular.js that referenced this issue Mar 20, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that only messages with an index lower than the starting message are considered
previous elements.

Fixes angular#14183
Narretz added a commit to Narretz/angular.js that referenced this issue Mar 23, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that when searching for previous messages, ngMessage walks the DOM in a way so
that messages that come after the current message are never identified as previous messages.

This commit also detaches and destroys all child ngMessage elements when the ngMessages element is
destroyed, which should improve performance slightly.

Fixes angular#14183
Closes angular#14242
Narretz added a commit that referenced this issue Mar 23, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that when searching for previous messages, ngMessage walks the DOM in a way so
that messages that come after the current message are never identified as previous messages.

This commit also detaches and destroys all child ngMessage elements when the ngMessages element is
destroyed, which should improve performance slightly.

Fixes #14183
Closes #14242
Narretz added a commit that referenced this issue Mar 23, 2016
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that when searching for previous messages, ngMessage walks the DOM in a way so
that messages that come after the current message are never identified as previous messages.

This commit also detaches and destroys all child ngMessage elements when the ngMessages element is
destroyed, which should improve performance slightly.

Fixes #14183
Closes #14242
@robianmcd
Copy link
Author

Tested in 1.5.3 and this is working now. Thanks!

@baktun14
Copy link

baktun14 commented Apr 6, 2016

I tried with 1.5.3 and I still get a crash with ng-messages-include but not with ng-message.

@Narretz
Copy link
Contributor

Narretz commented Apr 6, 2016

@mbeauchamp7 Without a runnable demo / code we cannot do anything about this.

@Narretz
Copy link
Contributor

Narretz commented Apr 8, 2016

@mbeauchamp7 Please open a new issue with a minimal demo if you have on. Thanks!
I'm going to lock this issue as discussions in closed issues are not fruitful.

@angular angular locked and limited conversation to collaborators Apr 8, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.