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
Project root node of @if and @for blocks #52414
Conversation
*/ | ||
block: boolean; | ||
functionNameSuffix: string|null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super attached to the name so I'm open to suggestions. The main goal was to stop using the tag name for the function name generation.
13d885e
to
8bc2e23
Compare
8bc2e23
to
1ba5951
Compare
01ed981
to
ad069fc
Compare
I've pushed some changes to avoid future issues if we start capturing comments by default and to rebase. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall but I would like to revisit this assumption:
If
preserveWhitespaces
is enabled, it's very likely that indentation will break this
- workaround, because it'll include an additional text node as the first child. We can work
- around it here, but in a discussion it was decided not to, because the user explicitly opted
- into preserving the whitespace and we would have to drop it from the generated code.
- The diagnostic mentioned point transpiler: show line numbers that have errors #1 will flag such cases to users.
I would say that we should have just one rule: we opt out of the root node capturing if there is more than one root node. This will be more common case with preserveWhitespaces
but still there is one consistent rule here.
ad069fc
to
c8abae0
Compare
Feedback has been addressed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thnx!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Makes perfect sense to me, and thank you for also updating the template pipeline. A lot of the use of tag
for control flow and conditionals was marginal to begin with -- it was more designed for elements and containers.
state, compatibility); | ||
} | ||
const repeaterToken = | ||
op.tag === null ? '' : '_' + prefixWithNamespace(op.tag, op.namespace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of preferred having this prefixing logic in the naming phase as opposed to ingest, where you've now folded it into the new suffix field -- it seems like it's logically part of naming. It's a weak preference though. I don't think we could conceivably need to use the raw suffix for anything else, so it's probably fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it would've felt more appropriate to have the naming logic there, but the rules we have for the function naming are a bit too different for the template nodes vs control flow that I couldn't find a better place than this one. I think that once we remove the definition builder, we can revisit the naming scheme.
With the directive-based control flow users were able to conditionally project content using the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are copied to the template via the template creation instruction. With `@if` and `@for` that is not the case, because the conditional is placed *around* elements, rather than *on* them. The result is that content projection won't work in the same way if a user converts from `*ngIf` to `@if`. These changes aim to cover the most common case by doing the same copying when a control flow node has *one and only one* root element or template node. This approach comes with some caveats: 1. As soon as any other node is added to the root, the copying behavior won't work anymore. A diagnostic will be added to flag cases like this and to explain how to work around it. 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this workaround, because it'll include an additional text node as the first child. We can work around it here, but in a discussion it was decided not to, because the user explicitly opted into preserving the whitespace and we would have to drop it from the generated code. The diagnostic mentioned point angular#1 will flag such cases to users. Fixes angular#52277.
…template pipeline Recreates the fix for content projection in control flow in the new template pipeline. I also had to make the following adjustments to the pipeline: 1. The `TemplateOp.tag` property was being used to generate the name of the template function, rather than the actual tag name being passed into `ɵɵtemplate`. Since the content projection fix requires the tag name to be passed in, I've introduced a new `functionNameSuffix` property instead. 2. `TemplateOp.block` was being used to determine whether to pass `TemplateOp.tag` into the `ɵɵtemplate` instruction. Now that we're always passing in the tag name after the refactor in point 1, we no longer need this flag. In addition to the refactors above, I also made some minor cleanups where I saw the opportunity to do so.
c8abae0
to
d0b7cc3
Compare
Caretaker note: the |
This PR was merged into the repository by commit c7b730e. |
…52414) With the directive-based control flow users were able to conditionally project content using the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are copied to the template via the template creation instruction. With `@if` and `@for` that is not the case, because the conditional is placed *around* elements, rather than *on* them. The result is that content projection won't work in the same way if a user converts from `*ngIf` to `@if`. These changes aim to cover the most common case by doing the same copying when a control flow node has *one and only one* root element or template node. This approach comes with some caveats: 1. As soon as any other node is added to the root, the copying behavior won't work anymore. A diagnostic will be added to flag cases like this and to explain how to work around it. 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this workaround, because it'll include an additional text node as the first child. We can work around it here, but in a discussion it was decided not to, because the user explicitly opted into preserving the whitespace and we would have to drop it from the generated code. The diagnostic mentioned point #1 will flag such cases to users. Fixes #52277. PR Close #52414
…rol flow (#52515) Discovered this while validating #52414 against Angular Material. We were projecting `<ng-template>` nodes at the root of `@if` and `@for` with the `ng-template` tag name which enables directive matching and applies the directive to the control flow node. These changes fix the issue by never passing along the `ng-template` tag name. PR Close #52515
…rol flow (#52515) Discovered this while validating #52414 against Angular Material. We were projecting `<ng-template>` nodes at the root of `@if` and `@for` with the `ng-template` tag name which enables directive matching and applies the directive to the control flow node. These changes fix the issue by never passing along the `ng-template` tag name. PR Close #52515
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot.
…ent projection (angular#53190) This is a follow-up to the fix from angular#52414. It adds a diagnostic that will tell users when a control flow is preventing its direct descendants from being projected into a specific component slot. PR Close angular#53190
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
…ngular#52414) With the directive-based control flow users were able to conditionally project content using the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are copied to the template via the template creation instruction. With `@if` and `@for` that is not the case, because the conditional is placed *around* elements, rather than *on* them. The result is that content projection won't work in the same way if a user converts from `*ngIf` to `@if`. These changes aim to cover the most common case by doing the same copying when a control flow node has *one and only one* root element or template node. This approach comes with some caveats: 1. As soon as any other node is added to the root, the copying behavior won't work anymore. A diagnostic will be added to flag cases like this and to explain how to work around it. 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this workaround, because it'll include an additional text node as the first child. We can work around it here, but in a discussion it was decided not to, because the user explicitly opted into preserving the whitespace and we would have to drop it from the generated code. The diagnostic mentioned point angular#1 will flag such cases to users. Fixes angular#52277. PR Close angular#52414
…template pipeline (angular#52414) Recreates the fix for content projection in control flow in the new template pipeline. I also had to make the following adjustments to the pipeline: 1. The `TemplateOp.tag` property was being used to generate the name of the template function, rather than the actual tag name being passed into `ɵɵtemplate`. Since the content projection fix requires the tag name to be passed in, I've introduced a new `functionNameSuffix` property instead. 2. `TemplateOp.block` was being used to determine whether to pass `TemplateOp.tag` into the `ɵɵtemplate` instruction. Now that we're always passing in the tag name after the refactor in point 1, we no longer need this flag. In addition to the refactors above, I also made some minor cleanups where I saw the opportunity to do so. PR Close angular#52414
…ngular#52414) With the directive-based control flow users were able to conditionally project content using the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are copied to the template via the template creation instruction. With `@if` and `@for` that is not the case, because the conditional is placed *around* elements, rather than *on* them. The result is that content projection won't work in the same way if a user converts from `*ngIf` to `@if`. These changes aim to cover the most common case by doing the same copying when a control flow node has *one and only one* root element or template node. This approach comes with some caveats: 1. As soon as any other node is added to the root, the copying behavior won't work anymore. A diagnostic will be added to flag cases like this and to explain how to work around it. 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this workaround, because it'll include an additional text node as the first child. We can work around it here, but in a discussion it was decided not to, because the user explicitly opted into preserving the whitespace and we would have to drop it from the generated code. The diagnostic mentioned point angular#1 will flag such cases to users. Fixes angular#52277. PR Close angular#52414
…template pipeline (angular#52414) Recreates the fix for content projection in control flow in the new template pipeline. I also had to make the following adjustments to the pipeline: 1. The `TemplateOp.tag` property was being used to generate the name of the template function, rather than the actual tag name being passed into `ɵɵtemplate`. Since the content projection fix requires the tag name to be passed in, I've introduced a new `functionNameSuffix` property instead. 2. `TemplateOp.block` was being used to determine whether to pass `TemplateOp.tag` into the `ɵɵtemplate` instruction. Now that we're always passing in the tag name after the refactor in point 1, we no longer need this flag. In addition to the refactors above, I also made some minor cleanups where I saw the opportunity to do so. PR Close angular#52414
A couple of fixes to get the content projection behavior of
@if
and@for
blocks closer to*ngIf
and*ngFor
. Includes the following commits:fix(compiler): project control flow root elements into correct slot
With the directive-based control flow users were able to conditionally project content using the
*
syntax. E.g.<div *ngIf="expr" projectMe></div>
will be projected into<ng-content select="[projectMe]"/>
, because the attributes and tag name from thediv
are copied to the template via the template creation instruction. With@if
and@for
that is not the case, because the conditional is placed around elements, rather than on them. The result is that content projection won't work in the same way if a user converts from*ngIf
to@if
.These changes aim to cover the most common case by doing the same copying when a control flow node has one and only one root element or template node.
This approach comes with some caveats:
preserveWhitespaces
is enabled, it's very likely that indentation will break this workaround, because it'll include an additional text node as the first child. We can work around it here, but in a discussion it was decided not to, because the user explicitly opted into preserving the whitespace and we would have to drop it from the generated code. The diagnostic mentioned point 1 will flag such cases to users.refactor(compiler): implement control flow content projection fix in template pipeline
Recreates the fix for content projection in control flow in the new template pipeline. I also had to make the following adjustments to the pipeline:
TemplateOp.tag
property was being used to generate the name of the template function, rather than the actual tag name being passed intoɵɵtemplate
. Since the content projection fix requires the tag name to be passed in, I've introduced a newfunctionNameSuffix
property instead.TemplateOp.block
was being used to determine whether to passTemplateOp.tag
into theɵɵtemplate
instruction. Now that we're always passing in the tag name after the refactor in point 1, we no longer need this flag.In addition to the refactors above, I also made some minor cleanups where I saw the opportunity to do so.
Fixes #52277.