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): implement some of the ViewContainerRef API #23189
Conversation
|
packages/core/src/render3/di.ts
Outdated
@@ -628,22 +628,29 @@ class ViewContainerRef implements viewEngine_ViewContainerRef { | |||
return viewRef; | |||
} | |||
move(viewRef: viewEngine_ViewRef, currentIndex: number): viewEngine_ViewRef { |
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 know that you are not changing this part but the currentIndex
is probably not the best arg name here. How about newIndex
?
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.
currentIndex
is the name of the arg in the ViewContainerRef
abstract class. It makes some sense to keep it here, but it could be changed.
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.
Changed it btw
packages/core/src/render3/di.ts
Outdated
this.detach(index); | ||
// TODO(ml): proper destroy of the ViewRef | ||
} | ||
detach(index?: number|undefined): viewEngine_ViewRef|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.
it is enough to have index?: number
(.?
adds 'undefined')
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
directiveInstance !.vcref.createEmbeddedView(directiveInstance !.tplRef, {name: s}, index); | ||
} | ||
|
||
function createTemplate() { |
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.
Could you please add code for a template in a comment of this function? It makes it easier to understand what is going on.
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
elementEnd(); | ||
} | ||
|
||
function updateTemplate() { |
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: isn't it too fragile as an utility function with the indexes hard-coded? Maybe you should pass container / element index as arguments to this 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.
Not needed yet, let's keep it simple until it is.
} | ||
|
||
describe('createEmbeddedView (incl. insert)', () => { | ||
it('should work on elements', () => { |
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.
How is this test different as compared to the existing one here:
it('should add embedded view into a view container on elements', () => { |
Seems like both tests are trying to assert the same thing? Maybe we should merge it into one instead of having 2 similar ones?
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've removed the old ones as the new ones are testing more cases with more concise code (except remove and clear, but it will be done later in another PR).
expect(() => { createView('Z', 5); }).toThrow(); | ||
}); | ||
|
||
it('should work on containers', () => { |
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.
As above we've got a similar test already:
it('should add embedded view into a view container on ng-template', () => { |
Moreover I believe that we can't have a LContainerNode
that is both:
- created from a JS block
- having a directive on it
as it would require sth like:
% if (exp) { //how to add a directive here???
...
% }
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 my comment above about refactoring.
About this test, it is true that this precise set of instructions cannot be generated with the current syntax. But it is a unit test which ensures that the embedded views are properly created after the container. So it is valid IMO.
}); | ||
|
||
describe('move', () => { | ||
it('should work', () => { |
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.
could you think of a more descriptive name for this 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.
Done
}); | ||
|
||
describe('get and indexOf', () => { | ||
it('should work', () => { |
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.
could you think of a more descriptive name for this 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.
Done
createView('B'); | ||
createView('C'); | ||
fixture.update(); | ||
fixture.hostElement.childNodes[1].nodeValue = '**A**'; |
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.
Could we have, somewhere in a comment, how the template for this test looks like? I find it hard to see what this tests is asserting and if things are working correctly...
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 also add a comment explaining why we are doing DOM manipulation here?
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.
Added a comment and more expect
to show all the steps of the test.
@marclaval I did the first pass on this PR, see my comments in the code. Looks good, generally speaking, IMO tests need more work (let's make sure that we are not duplicating those, add more comments etc.). Also you will have to run Since we are both touching the same area it would be great to have your opinion on #23193 |
All comments addressed, thanks for the review |
packages/core/src/render3/di.ts
Outdated
remove(index?: number): void { | ||
const adjustedIdx = this._adjustAndAssertIndex(index); | ||
this.detach(index); | ||
// TODO(ml): proper destroy of the ViewRef |
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.
could you add to your comments what steps are missing from here. Otherwise this TODO becomes confusing in the future.
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
packages/core/src/render3/di.ts
Outdated
} | ||
indexOf(viewRef: viewEngine_ViewRef): number { throw notImplemented(); } | ||
indexOf(viewRef: viewEngine_ViewRef): number { return this._viewRefs.indexOf(viewRef); } |
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: Can you leave empty line between methods.
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
|
||
describe('ViewContainerRef', () => { | ||
class TestDirective { | ||
constructor(public viewContainer: ViewContainerRef, public template: TemplateRef<any>, ) {} | ||
describe('API', () => { |
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 is the value of this additional describe
?
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 goal is to group pure API tests, before adding more describe
in future PRs, like projection, query, lifecycle hooks
Please add merge label once you take care of the nits |
packages/core/src/render3/di.ts
Outdated
|
||
private _adjustAndAssertIndex(index?: number|undefined) { | ||
private _adjustAndAssertIndex(index?: number|undefined, shift: number = 0) { |
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 assert be in the name (it's a debug thing) ?
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.
Agreed
Hi @marclaval! This PR has merge conflicts due to recent upstream merges. |
packages/core/src/render3/di.ts
Outdated
// +1 because it's legal to insert at the end. | ||
ngDevMode && assertLessThan(index, this._lContainerNode.data.views.length + 1, 'index'); | ||
ngDevMode && | ||
assertLessThan(index, this._lContainerNode.data.views.length + 1 + shift, 'index'); |
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.
refactor to have
if (ngDevMode && index !==null) {
// asserts
return index;
}
return this._lContainerNode.data.views.length + shift;
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 wouldn't work when ngDevMode is false
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.
Well yep there is an error in my extract but the point here is
- multiple
ngDevMode &&
does not help with readability, - especially when the else branch is empty in non dev mode
So maybe
if (index === null) return ...
if (ngDevMode) {
// assert
}
return ...;
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
constructor(private createBlock: () => void, private updateBlock: () => void = noop) { | ||
constructor( | ||
private createBlock: () => void, private updateBlock: () => void = noop, | ||
directives?: DirectiveTypesOrFactory|null, pipes?: PipeTypesOrFactory|null) { | ||
super(); | ||
this.updateBlock = updateBlock || 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.
needed ? (defalut is noop
)
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 can preview 157a25e at https://pr23189-157a25e.ngbuilds.io/. |
You can preview 944452f at https://pr23189-944452f.ngbuilds.io/. |
Nits integrated and PR rebased. One job is failing in Travis because of a bundle size issue, but the same is happening on master. |
@@ -40,6 +40,12 @@ export function assertLessThan<T>(actual: T, expected: T, msg: string) { | |||
} | |||
} | |||
|
|||
export function assertGreaterThan<T>(actual: T, expected: T, msg: string) { |
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.
Generic really needed? Any possibility other than number
for <=
operator?
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.
@trotyl Could be used for simple alphabetical sorting too, couldn't it? All the other assert
functions are implemented the same way, so I suppose this is for consistency above all else.
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
5299f3c
to
a8619b3
Compare
You can preview a8619b3 at https://pr23189-a8619b3.ngbuilds.io/. |
@vicb I did the change you requested, the PR should be good to go |
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 implements some of the API of the
ViewContainerRef
and adds more tests.In scope:
Out of scope: