Skip to content
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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/core/src/render3/assert.ts
Expand Up @@ -40,6 +40,12 @@ export function assertLessThan<T>(actual: T, expected: T, msg: string) {
}
}

export function assertGreaterThan<T>(actual: T, expected: T, msg: string) {
Copy link
Contributor

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?

Copy link
Contributor

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.

if (actual <= expected) {
throwError(msg);
}
}

export function assertNull<T>(actual: T, msg: string) {
if (actual != null) {
throwError(msg);
Expand Down
43 changes: 31 additions & 12 deletions packages/core/src/render3/di.ts
Expand Up @@ -18,7 +18,7 @@ import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_co
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Type} from '../type';

import {assertLessThan, assertNotNull} from './assert';
import {assertGreaterThan, assertLessThan, assertNotNull} from './assert';
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
Expand Down Expand Up @@ -608,26 +608,31 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
this.remove(0);
}
}

get(index: number): viewEngine_ViewRef|null { return this._viewRefs[index] || null; }

get length(): number {
const lContainer = this._lContainerNode.data;
return lContainer.views.length;
}

createEmbeddedView<C>(templateRef: viewEngine_TemplateRef<C>, context?: C, index?: number):
viewEngine_EmbeddedViewRef<C> {
const viewRef = templateRef.createEmbeddedView(context || <any>{});
this.insert(viewRef, index);
return viewRef;
}

createComponent<C>(
componentFactory: viewEngine_ComponentFactory<C>, index?: number|undefined,
injector?: Injector|undefined, projectableNodes?: any[][]|undefined,
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<C> {
throw notImplemented();
}

insert(viewRef: viewEngine_ViewRef, index?: number): viewEngine_ViewRef {
const lViewNode = (viewRef as EmbeddedViewRef<any>)._lViewNode;
const adjustedIdx = this._adjustAndAssertIndex(index);
const adjustedIdx = this._adjustIndex(index);

insertView(this._lContainerNode, lViewNode, adjustedIdx);
// invalidate cache of next sibling RNode (we do similar operation in the containerRefreshEnd
Expand All @@ -653,23 +658,37 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
}
return viewRef;
}
move(viewRef: viewEngine_ViewRef, currentIndex: number): viewEngine_ViewRef {
throw notImplemented();

move(viewRef: viewEngine_ViewRef, newIndex: number): viewEngine_ViewRef {
const index = this.indexOf(viewRef);
this.detach(index);
this.insert(viewRef, this._adjustIndex(newIndex));
return viewRef;
}
indexOf(viewRef: viewEngine_ViewRef): number { throw notImplemented(); }

indexOf(viewRef: viewEngine_ViewRef): number { return this._viewRefs.indexOf(viewRef); }

remove(index?: number): void {
const adjustedIdx = this._adjustAndAssertIndex(index);
this.detach(index);
// TODO(ml): proper destroy of the ViewRef, i.e. recursively destroy the LviewNode and its
// children, delete DOM nodes and QueryList, trigger hooks (onDestroy), destroy the renderer,
// detach projected nodes
}

detach(index?: number): viewEngine_ViewRef|null {
const adjustedIdx = this._adjustIndex(index, -1);
removeView(this._lContainerNode, adjustedIdx);
this._viewRefs.splice(adjustedIdx, 1);
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
}
detach(index?: number|undefined): viewEngine_ViewRef|null { throw notImplemented(); }

private _adjustAndAssertIndex(index?: number|undefined) {
private _adjustIndex(index?: number, shift: number = 0) {
if (index == null) {
index = this._lContainerNode.data.views.length;
} else {
return this._lContainerNode.data.views.length + shift;
}
if (ngDevMode) {
assertGreaterThan(index, -1, 'index must be positive');
// +1 because it's legal to insert at the end.
ngDevMode && assertLessThan(index, this._lContainerNode.data.views.length + 1, 'index');
assertLessThan(index, this._lContainerNode.data.views.length + 1 + shift, 'index');
}
return index;
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/render3/node_manipulation.ts
Expand Up @@ -311,6 +311,7 @@ export function removeView(container: LContainerNode, removeIndex: number): LVie
setViewNext(views[removeIndex - 1], viewNode.next);
}
views.splice(removeIndex, 1);
viewNode.next = null;
destroyViewTree(viewNode.data);
addRemoveViewFromContainer(container, viewNode, false);
// Notify query that view has been removed
Expand Down
13 changes: 9 additions & 4 deletions packages/core/test/render3/render_util.ts
Expand Up @@ -48,22 +48,27 @@ function noop() {}
*/
export class TemplateFixture extends BaseFixture {
hostNode: LElementNode;
private _directiveDefs: DirectiveDefList|null;
private _pipeDefs: PipeDefList|null;
/**
*
* @param createBlock Instructions which go into the creation block:
* `if (creationMode) { __here__ }`.
* @param updateBlock Optional instructions which go after the creation block:
* `if (creationMode) { ... } __here__`.
*/
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() {};
this._directiveDefs = toDefs(directives, extractDirectiveDef);
this._pipeDefs = toDefs(pipes, extractPipeDef);
this.hostNode = renderTemplate(this.hostElement, (ctx: any, cm: boolean) => {
if (cm) {
this.createBlock();
}
this.updateBlock();
}, null !, domRendererFactory3, null);
}, null !, domRendererFactory3, null, this._directiveDefs, this._pipeDefs);
}

/**
Expand All @@ -74,7 +79,7 @@ export class TemplateFixture extends BaseFixture {
update(updateBlock?: () => void): void {
renderTemplate(
this.hostNode.native, updateBlock || this.updateBlock, null !, domRendererFactory3,
this.hostNode);
this.hostNode, this._directiveDefs, this._pipeDefs);
}
}

Expand Down