fix(core): trigger host animations for elements that are removed. (#15251)

Fixes #14813
Fixes #15193
This commit is contained in:
Tobias Bosch 2017-03-17 11:04:30 -07:00 committed by Miško Hevery
parent 28ce68a13d
commit 0d3e314df0
5 changed files with 33 additions and 14 deletions

View File

@ -1030,9 +1030,9 @@ function elementBindingDef(inputAst: BoundElementPropertyAst, dirAst: DirectiveA
o.literal(inputAst.securityContext) o.literal(inputAst.securityContext)
]); ]);
case PropertyBindingType.Animation: case PropertyBindingType.Animation:
const bindingType = dirAst && dirAst.directive.isComponent ? const bindingType = BindingFlags.TypeProperty |
BindingFlags.TypeProperty | BindingFlags.SyntheticComponentHostProperty : (dirAst && dirAst.directive.isComponent ? BindingFlags.SyntheticHostProperty :
BindingFlags.TypeProperty; BindingFlags.SyntheticProperty);
return o.literalArr([ return o.literalArr([
o.literal(bindingType), o.literal('@' + inputAst.name), o.literal(inputAst.securityContext) o.literal(bindingType), o.literal('@' + inputAst.name), o.literal(inputAst.securityContext)
]); ]);

View File

@ -238,8 +238,10 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
setElementStyle(view, binding, renderNode, name, value); setElementStyle(view, binding, renderNode, name, value);
break; break;
case BindingFlags.TypeProperty: case BindingFlags.TypeProperty:
const bindView = const bindView = (def.flags & NodeFlags.ComponentView &&
binding.flags & BindingFlags.SyntheticComponentHostProperty ? elData.componentView : view; binding.flags & BindingFlags.SyntheticHostProperty) ?
elData.componentView :
view;
setElementProperty(bindView, binding, renderNode, name, value); setElementProperty(bindView, binding, renderNode, name, value);
break; break;
} }

View File

@ -195,7 +195,9 @@ export const enum BindingFlags {
TypeElementClass = 1 << 1, TypeElementClass = 1 << 1,
TypeElementStyle = 1 << 2, TypeElementStyle = 1 << 2,
TypeProperty = 1 << 3, TypeProperty = 1 << 3,
SyntheticComponentHostProperty = 1 << 4, SyntheticProperty = 1 << 4,
SyntheticHostProperty = 1 << 5,
CatSyntheticProperty = SyntheticProperty | SyntheticHostProperty,
// mutually exclusive values... // mutually exclusive values...
Types = TypeElementAttribute | TypeElementClass | TypeElementStyle | TypeProperty Types = TypeElementAttribute | TypeElementClass | TypeElementStyle | TypeProperty

View File

@ -230,12 +230,7 @@ export function rootRenderNodes(view: ViewData): any[] {
return renderNodes; return renderNodes;
} }
export enum RenderNodeAction { export const enum RenderNodeAction {Collect, AppendChild, InsertBefore, RemoveChild}
Collect,
AppendChild,
InsertBefore,
RemoveChild
}
export function visitRootRenderNodes( export function visitRootRenderNodes(
view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) { view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) {
@ -298,7 +293,19 @@ function visitRenderNode(
view, nodeDef.ngContent.index, action, parentNode, nextSibling, target); view, nodeDef.ngContent.index, action, parentNode, nextSibling, target);
} else { } else {
const rn = renderNode(view, nodeDef); const rn = renderNode(view, nodeDef);
execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); if (action === RenderNodeAction.RemoveChild && (nodeDef.flags & NodeFlags.ComponentView) &&
(nodeDef.bindingFlags & BindingFlags.CatSyntheticProperty)) {
// Note: we might need to do both actions.
if (nodeDef.bindingFlags & (BindingFlags.SyntheticProperty)) {
execRenderNodeAction(view, rn, action, parentNode, nextSibling, target);
}
if (nodeDef.bindingFlags & (BindingFlags.SyntheticHostProperty)) {
const compView = asElementData(view, nodeDef.index).componentView;
execRenderNodeAction(compView, rn, action, parentNode, nextSibling, target);
}
} else {
execRenderNodeAction(view, rn, action, parentNode, nextSibling, target);
}
if (nodeDef.flags & NodeFlags.EmbeddedViews) { if (nodeDef.flags & NodeFlags.EmbeddedViews) {
const embeddedViews = asElementData(view, nodeDef.index).viewContainer._embeddedViews; const embeddedViews = asElementData(view, nodeDef.index).viewContainer._embeddedViews;
for (let k = 0; k < embeddedViews.length; k++) { for (let k = 0; k < embeddedViews.length; k++) {

View File

@ -90,7 +90,15 @@ export class AnimationRenderer implements Renderer2 {
} }
removeChild(parent: any, oldChild: any): void { removeChild(parent: any, oldChild: any): void {
this._engine.onRemove(oldChild, () => this.delegate.removeChild(parent, oldChild)); this._engine.onRemove(oldChild, () => {
// Note: if an component element has a leave animation, and the component
// a host leave animation, the view engine will call `removeChild` for the parent
// component renderer as well as for the child component renderer.
// Therefore, we need to check if we already removed the element.
if (this.delegate.parentNode(oldChild)) {
this.delegate.removeChild(parent, oldChild);
}
});
this._queueFlush(); this._queueFlush();
} }