-
Notifications
You must be signed in to change notification settings - Fork 25.9k
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
feat(ivy): add support for the ngProjectAs attribute #22498
feat(ivy): add support for the ngProjectAs attribute #22498
Conversation
@@ -539,8 +539,10 @@ function setUpAttributes(native: RElement, attrs: string[]): void { | |||
|
|||
const isProc = isProceduralRenderer(renderer); | |||
for (let i = 0; i < attrs.length; i += 2) { | |||
isProc ? (renderer as ProceduralRenderer3).setAttribute(native, attrs[i], attrs[i | 1]) : | |||
native.setAttribute(attrs[i], attrs[i | 1]); | |||
if (attrs[i] !== NG_PROJECT_AS_ATTR_NAME) { |
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.
what about
const attrName = a[i];
const attrValue = a[i+1];
// ... use attrName & attrValue
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.
👍 done
@@ -1262,7 +1266,7 @@ export function projectionDef(index: number, selectors?: CssSelector[]): void { | |||
// - there are selectors defined | |||
// - a node has a tag name / attributes that can be matched | |||
if (selectors && componentChild.tNode) { | |||
const matchedIdx = matchingSelectorIndex(componentChild.tNode, selectors !); | |||
const matchedIdx = matchingSelectorIndex(componentChild.tNode, selectors !, rawSelectors !); |
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.
You should be able to remove the ! from selectors !
(b/c if (selectors)
)
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.
👍 done
@@ -115,13 +115,30 @@ export function isNodeMatchingSelector(tNode: TNode, selector: CssSelector): boo | |||
return false; | |||
} | |||
|
|||
function isNodeMatchingProjectAs(tNode: TNode, rawSelector: string): boolean { |
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.
comment ?
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.
This function went away with the recent code changes.
const nodeAttrs = tNode.attrs; | ||
if (nodeAttrs != null) { | ||
const ngProjectAsAttrIdx = nodeAttrs.indexOf(NG_PROJECT_AS_ATTR_NAME); | ||
if (ngProjectAsAttrIdx > -1) { |
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.
if (ngProjectAsAttrIdx & 1 === 0)
-> add a test
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.
Should NG_PROJECT_AS_ATTR_NAME
always come first and then we don't have to iterate ?
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.
Should
NG_PROJECT_AS_ATTR_NAME
always come first and then we don't have to iterate ?
It would be a possible runtime optimisation at the expense of more work in the compiler. I will let @chuckjaz to decide.
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.
if (ngProjectAsAttrIdx & 1 === 0) -> add a test
This function went away with the recent code changes.
for (let i = 0; i < selectors.length; i++) { | ||
if (isNodeMatchingSelector(tNode, selectors[i])) { | ||
if (isNodeMatchingProjectAs(tNode, rawSelectors[i]) || |
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.
Is this logic right ?
I think that when a node is ngProjectedAs we should not isNodeMatchingSelector
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.
Oh, good catch! You are right, we should probably not match selectors if ngProjectAs
is not matching. Changed the logic and added a test. Thnx!
@@ -1245,9 +1247,11 @@ export function directiveRefresh<T>(directiveIndex: number, elementIndex: number | |||
* each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is | |||
* backed by a selector). | |||
* | |||
* @param selectors | |||
* @param selectors A collection of parsed CSS selectors | |||
* @param rawSelectors A collection of CSS selectors in the raw, un-parsed form |
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 think rawSelectors
needs more documentation. Why is it needed, What is the format., how to use it. Also why do we have two different formats? Can it be unified?
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.
maybe textSelectors
?
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.
Renamed to textSelectors
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.
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.
The changes to the compiler spec look good.
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.
See inline comments
5a57866
to
81f375c
Compare
const nodeAttrs = tNode.attrs; | ||
if (nodeAttrs != null) { | ||
const ngProjectAsAttrIdx = nodeAttrs.indexOf(NG_PROJECT_AS_ATTR_NAME); | ||
if (ngProjectAsAttrIdx > -1) { |
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.
this is still wrong see my previous comment.
Also please create a github issue to move the ngProjectAs attr first.
// if a node has the ngProjectAs attribute match it against unparsed selector | ||
// match a node against a parsed selector only if ngProjectAs attribute is not present | ||
if (ngProjectAsAttrVal === textSelectors[i] || | ||
ngProjectAsAttrVal === null && isNodeMatchingSelector(tNode, selectors[i])) { |
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.
nit: Wouldn't ngProjectAsAttrVal && ngProjectAsAttrVal === textSelectors[i] || isNodeMatchingSelector(tNode, selectors[i])
make more sense ? (with the same behavior)
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.
that's actually wrong !
current impl is fine.
@@ -183,4 +184,26 @@ describe('css selector matching', () => { | |||
}); | |||
}); | |||
|
|||
describe('getProjectAsAttrValue', function() { |
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.
nit describe('reading the ngProjectAs attribute value' => ...
b/c function names change.
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.
1 nit on the test name
Would it be possible to let the template compiler recognize the ngProjectAs attribute and have it perform the CSS compilation that is then stored on |
@JoostK it would be certainly possible but would have drawbacks:
I'm sure that there are ways of improving solution from this PR but I've considered what you are suggesting and decided against it for the reasons outlined above. But definitively, feel free to send follow-up PR(s) when this one lands, if you've got ideas for a better solution! |
6cd602f
to
6f5e7a5
Compare
6f5e7a5
to
2194b45
Compare
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. |
This PR adds support for the
ngProjectAs
attribute.The implementation in this PR requires us to store a CSS selector (from the
<ng-content>
'sselect
attribute) in both parsed and raw (un-parsed) form. The raw form is needed so we can easily compare it with a value of thengProjectAs
attribute.@chuckjaz this PR changes the compiler's canonical spec for content projection, so the compiler's implementation will have to be updated accordingly.