Skip to content

fix(animations): allow enter animation of every inserted element#44243

Closed
dario-piotrowicz wants to merge 1 commit into
angular:masterfrom
dario-piotrowicz:query-enter-change
Closed

fix(animations): allow enter animation of every inserted element#44243
dario-piotrowicz wants to merge 1 commit into
angular:masterfrom
dario-piotrowicz:query-enter-change

Conversation

@dario-piotrowicz
Copy link
Copy Markdown
Contributor

currently in the animations package not all newly inserted elements
are treated as entering ones, thus querying them via ':enter' does not
always work as expeted, change such behavior so that all newly inserted
elements are considered entering ones

solves: #30477

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix (sort of)
  • Feature (sort of)
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: #30477

In the angular package querying "entering" elements not always work, this has caused confusion amongst developers as some of their animations were not being applied as they expected to

(for more details see the issue thread and PR #44216)

What is the new behavior?

All elements added to the DOM are not treated as "moving" ones as such they can be queried with ":enter" as one would expect to

Does this PR introduce a breaking change?

  • Yes
  • No
  • Likely

Other information

  • I think that the changes here are debatable, the behaviour of not treating all new elements as "entering"/"move" ones seems to have been put in place purposely, I believe that the logic being was to only allow ":enter" queries to work on elements that enter by their own accord and not those that enter because of their parents, if an element enters because of its parent then the parent's transition can be ":enter" and the query will be specific for the child itself.
    Thus I am not 100% sure if these changes are actually providing a real benefit, or if we should just change the documentation to make clear when child elements can be queried or not based on the existing implementation (meaning, is it really important to be able to do transition(":enter", [ query(":enter", ...? does that provide a clear better developer experience? are there instances this implementation doesn't provide the functionality needed?)

  • some aio docs animations don't work properly because of this issue (or the lack of clarity around it)

Comment on lines 2522 to 2524
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The comment should be self explanatory, but yeah, it seems like i18n insertions were done via insertBefore so they needed not to be treated as entering, since now everything is treated as entering the i18n insertions are no difference, I guess this should be ok 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did you intend to say "threated"? Or did you mean threaded?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or "treated"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

"treated" 😅

honestly I just wanted to remove this test and not x-it, I just put the comment in the code to start a discussion
(seems like a succeeded, even though this is not the sort of discussion I was expecting 😆)

Copy link
Copy Markdown
Contributor Author

@dario-piotrowicz dario-piotrowicz Nov 21, 2021

Choose a reason for hiding this comment

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

my changes are only fixing the :enter issue, the :leave one can be treated separately (of if you want I can look into it and add it to this PR)

Comment on lines 2576 to 2577
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

my changes are only fixing the :enter issue, the :leave one can be treated separately (of if you want I can look into it and add it to this PR)

currently in the animations package not all newly inserted elements
are treated as entering ones, thus querying them via ':enter' does not
always work as expeted, change such behavior so that all newly inserted
elements are considered entering ones

solves: angular#30477
@jessicajaniuk jessicajaniuk added the area: animations legacy animations package only. Otherwise use area: core. label Nov 22, 2021
@ngbot ngbot Bot added this to the Backlog milestone Nov 22, 2021
Copy link
Copy Markdown
Contributor

@jessicajaniuk jessicajaniuk left a comment

Choose a reason for hiding this comment

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

LGTM 🍪

Other than that one spelling error this looks good.

Comment on lines 2522 to 2524
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did you intend to say "threated"? Or did you mean threaded?

Copy link
Copy Markdown
Member

@JoostK JoostK left a comment

Choose a reason for hiding this comment

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

Drive-by-comment about one change in particular; I have not attempted to understand the problem nor the approach taken by this PR (and that would likely require significant time as the animations logic is 🤯)

}
}

function addClassRecursively(element: any, className: string) {
Copy link
Copy Markdown
Member

@JoostK JoostK Nov 22, 2021

Choose a reason for hiding this comment

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

I am concerned about this approach for perf reasons; adding and removing classes is not free. Would it be possible to tweak query selectors from .${class} to something like .${class}, .${class} * to select all descendants? I am not sure about the perf characteristics of such query, though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I understand what you mean....

I don't think that tweaking the selector should be too much of an issue

For context the code that does the querying is this one:

invokeQuery(
selector: string, originalSelector: string, limit: number, includeSelf: boolean,
optional: boolean, errors: any[]): any[] {
let results: any[] = [];
if (includeSelf) {
results.push(this.element);
}
if (selector.length > 0) { // only if :self is used then the selector can be empty
selector = selector.replace(ENTER_TOKEN_REGEX, '.' + this._enterClassName);
selector = selector.replace(LEAVE_TOKEN_REGEX, '.' + this._leaveClassName);
const multi = limit != 1;
let elements = this._driver.query(this.element, selector, multi);
if (limit !== 0) {
elements = limit < 0 ? elements.slice(elements.length + limit, elements.length) :
elements.slice(0, limit);
}
results.push(...elements);
}
if (!optional && results.length == 0) {
errors.push(`\`query("${originalSelector}")\` returned zero elements. (Use \`query("${
originalSelector}", { optional: true })\` if you wish to allow this.)`);
}
return results;
}
}

I think that before selector = selector.replace(ENTER_TOKEN_REGEX, '.' + this._enterClassName); we could have a check and if the element doing the querying is entering then we just substitute the assignment to: selector = selector.replace(ENTER_TOKEN_REGEX, '*');
(ps: there is not info about the parent element entering so we would need to add that somehow too)

this seems like a pretty inexpensive change

Then what actually actually does the querying (called by the driver._query above) is a simple querySelector/querySelectorAll:

_query = (element: any, selector: string, multi: boolean): any[] => {
let results: any[] = [];
if (multi) {
// DO NOT REFACTOR TO USE SPREAD SYNTAX.
// For element queries that return sufficiently large NodeList objects,
// using spread syntax to populate the results array causes a RangeError
// due to the call stack limit being reached. `Array.from` can not be used
// as well, since NodeList is not iterable in IE 11, see
// https://developer.mozilla.org/en-US/docs/Web/API/NodeList
// More info is available in #38551.
const elems = element.querySelectorAll(selector);
for (let i = 0; i < elems.length; i++) {
results.push(elems[i]);
}
} else {
const elm = element.querySelector(selector);
if (elm) {
results.push(elm);
}
}
return results;
};
}

this again doesn't seem like a too expensive change since we use the browser's native api... I think?! 🤷

what do you think? does this sound like a good thing to try out? shall I give it a shot?

@dario-piotrowicz
Copy link
Copy Markdown
Contributor Author

Thanks so very much for the reviewing all 🙂

In the issue's thread (#30477) we've agreed that the current behavior is correct and that instead of changing it, it'd be better to keep it as is and instead clarify/improve the docs, so that we can avoid future misunderstandings/confusion like the one that lead to the issue being opened

@angular-automatic-lock-bot
Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Dec 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area: animations legacy animations package only. Otherwise use area: core. cla: yes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants