fix(ivy): Ensure ngProjectAs marker name appears at even attribute index (#34617)

The `getProjectAsAttrValue` in `node_selector_matcher` finds the
ProjectAs marker and then additionally checks that the marker appears in
an even index of the node attributes because "attribute names are stored
at even indexes". This is true for "regular" attribute bindings but
classes, styles, bindings, templates, and i18n do not necessarily follow
this rule because there can be an uneven number of them, causing the
next "special" attribute "name" to appear at an odd index. To address
this issue, ensure ngProjectAs is placed right after "regular"
attributes.

PR Close #34617
This commit is contained in:
Andrew Scott
2020-01-02 09:49:18 -08:00
committed by Alex Rickabaugh
parent a53f510c63
commit 4f3215d281
3 changed files with 72 additions and 48 deletions

View File

@ -955,6 +955,50 @@ describe('projection', () => {
expect(fixture.nativeElement).toHaveText('hello');
});
it('should support ngProjectAs with a various number of other bindings and attributes', () => {
@Directive({selector: '[color],[margin]'})
class ElDecorator {
@Input() color?: string;
@Input() margin?: number;
}
@Component({
selector: 'card',
template: `
<ng-content select="[card-title]"></ng-content>
---
<ng-content select="[card-subtitle]"></ng-content>
---
<ng-content select="[card-content]"></ng-content>
---
<ng-content select="[card-footer]"></ng-content>
`
})
class Card {
}
@Component({
selector: 'card-with-title',
template: `
<card>
<h1 [color]="'red'" [margin]="10" ngProjectAs="[card-title]">Title</h1>
<h2 xlink:href="google.com" ngProjectAs="[card-subtitle]">Subtitle</h2>
<div style="font-color: blue;" ngProjectAs="[card-content]">content</div>
<div [color]="'blue'" ngProjectAs="[card-footer]">footer</div>
</card>
`
})
class CardWithTitle {
}
TestBed.configureTestingModule({declarations: [Card, CardWithTitle, ElDecorator]});
const fixture = TestBed.createComponent(CardWithTitle);
fixture.detectChanges();
// Compare the text output, because Ivy and ViewEngine produce slightly different HTML.
expect(fixture.nativeElement.textContent)
.toContain('Title --- Subtitle --- content --- footer');
});
it('should support ngProjectAs on elements (including <ng-content>)', () => {
@Component({
selector: 'card',