fix(ivy): ensure element removal triggers host removal animations (#28162)

Prior to this fix Ivy would not execute any animation triggers
that exist as host bindings on an element if it is removed by
the parent template.

PR Close #28162
This commit is contained in:
Matias Niemelä
2019-01-14 15:36:08 -08:00
committed by Alex Rickabaugh
parent e172e97e13
commit 5a582a8afd
10 changed files with 127 additions and 124 deletions

View File

@ -267,8 +267,10 @@ export abstract class Renderer2 {
* Implement this callback to remove a child node from the host element's DOM.
* @param parent The parent node.
* @param oldChild The child node to remove.
* @param isHostElement Optionally signal to the renderer whether this element is a host element
* or not
*/
abstract removeChild(parent: any, oldChild: any): void;
abstract removeChild(parent: any, oldChild: any, isHostElement?: boolean): void;
/**
* Implement this callback to prepare an element to be bootstrapped
* as a root element, and return the element instance.

View File

@ -74,7 +74,7 @@ export interface ProceduralRenderer3 {
destroyNode?: ((node: RNode) => void)|null;
appendChild(parent: RElement, newChild: RNode): void;
insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void;
removeChild(parent: RElement, oldChild: RNode): void;
removeChild(parent: RElement, oldChild: RNode, isHostElement?: boolean): void;
selectRootElement(selectorOrNode: string|any): RElement;
parentNode(node: RNode): RElement|null;

View File

@ -14,7 +14,7 @@ import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
import {CLEANUP, CONTAINER_INDEX, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
import {assertNodeType} from './node_assert';
import {findComponentView, getNativeByTNode, isLContainer, isRootView, readElementValue, renderStringify} from './util';
import {findComponentView, getNativeByTNode, isComponent, isLContainer, isRootView, readElementValue, renderStringify} from './util';
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
@ -84,15 +84,16 @@ function walkTNodeTree(
let nextTNode: TNode|null = null;
if (tNode.type === TNodeType.Element) {
executeNodeAction(
action, renderer, renderParent, getNativeByTNode(tNode, currentView), beforeNode);
action, renderer, renderParent, getNativeByTNode(tNode, currentView), tNode, beforeNode);
const nodeOrContainer = currentView[tNode.index];
if (isLContainer(nodeOrContainer)) {
// This element has an LContainer, and its comment needs to be handled
executeNodeAction(action, renderer, renderParent, nodeOrContainer[NATIVE], beforeNode);
executeNodeAction(
action, renderer, renderParent, nodeOrContainer[NATIVE], tNode, beforeNode);
}
} else if (tNode.type === TNodeType.Container) {
const lContainer = currentView ![tNode.index] as LContainer;
executeNodeAction(action, renderer, renderParent, lContainer[NATIVE], beforeNode);
executeNodeAction(action, renderer, renderParent, lContainer[NATIVE], tNode, beforeNode);
if (lContainer[VIEWS].length) {
currentView = lContainer[VIEWS][0];
@ -166,11 +167,11 @@ function walkTNodeTree(
*/
function executeNodeAction(
action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement | null,
node: RComment | RElement | RText, beforeNode?: RNode | null) {
node: RComment | RElement | RText, tNode: TNode, beforeNode?: RNode | null) {
if (action === WalkTNodeTreeAction.Insert) {
nativeInsertBefore(renderer, parent !, node, beforeNode || null);
} else if (action === WalkTNodeTreeAction.Detach) {
nativeRemoveChild(renderer, parent !, node);
nativeRemoveChild(renderer, parent !, node, isComponent(tNode));
} else if (action === WalkTNodeTreeAction.Destroy) {
ngDevMode && ngDevMode.rendererDestroyNode++;
(renderer as ProceduralRenderer3).destroyNode !(node);
@ -550,8 +551,9 @@ export function nativeInsertBefore(
/**
* Removes a native child node from a given native parent node.
*/
export function nativeRemoveChild(renderer: Renderer3, parent: RElement, child: RNode): void {
isProceduralRenderer(renderer) ? renderer.removeChild(parent as RElement, child) :
export function nativeRemoveChild(
renderer: Renderer3, parent: RElement, child: RNode, isHostElement?: boolean): void {
isProceduralRenderer(renderer) ? renderer.removeChild(parent as RElement, child, isHostElement) :
parent.removeChild(child);
}