diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts
index 60e6f4e482..d74e15d715 100644
--- a/packages/core/src/render3/instructions.ts
+++ b/packages/core/src/render3/instructions.ts
@@ -1202,7 +1202,6 @@ export function hostElement(
return node;
}
-
/**
* Adds an event listener to the current node.
*
@@ -1215,29 +1214,35 @@ export function hostElement(
*/
export function listener(
eventName: string, listenerFn: (e?: any) => any, useCapture = false): void {
- ngDevMode && assertPreviousIsParent();
- ngDevMode && assertNodeOfPossibleTypes(previousOrParentNode, TNodeType.Element);
+ ngDevMode &&
+ assertNodeOfPossibleTypes(
+ previousOrParentNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer);
const node = previousOrParentNode;
- const native = node.native as RElement;
- ngDevMode && ngDevMode.rendererAddEventListener++;
- // In order to match current behavior, native DOM event listeners must be added for all
- // events (including outputs).
- if (isProceduralRenderer(renderer)) {
- const wrappedListener = wrapListenerWithDirtyLogic(viewData, listenerFn);
- const cleanupFn = renderer.listen(native, eventName, wrappedListener);
- storeCleanupFn(viewData, cleanupFn);
- } else {
- const wrappedListener = wrapListenerWithDirtyAndDefault(viewData, listenerFn);
- native.addEventListener(eventName, wrappedListener, useCapture);
- const cleanupInstances = getCleanup(viewData);
- cleanupInstances.push(wrappedListener);
- if (firstTemplatePass) {
- getTViewCleanup(viewData).push(
- eventName, node.tNode.index, cleanupInstances !.length - 1, useCapture);
+ // add native event listener - applicable to elements only
+ if (previousOrParentNode.tNode.type === TNodeType.Element) {
+ const native = node.native as RElement;
+ ngDevMode && ngDevMode.rendererAddEventListener++;
+
+ // In order to match current behavior, native DOM event listeners must be added for all
+ // events (including outputs).
+ if (isProceduralRenderer(renderer)) {
+ const wrappedListener = wrapListenerWithDirtyLogic(viewData, listenerFn);
+ const cleanupFn = renderer.listen(native, eventName, wrappedListener);
+ storeCleanupFn(viewData, cleanupFn);
+ } else {
+ const wrappedListener = wrapListenerWithDirtyAndDefault(viewData, listenerFn);
+ native.addEventListener(eventName, wrappedListener, useCapture);
+ const cleanupInstances = getCleanup(viewData);
+ cleanupInstances.push(wrappedListener);
+ if (firstTemplatePass) {
+ getTViewCleanup(viewData).push(
+ eventName, node.tNode.index, cleanupInstances !.length - 1, useCapture);
+ }
}
}
+ // subscribe to directive outputs
let tNode: TNode|null = node.tNode;
if (tNode.outputs === undefined) {
// if we create TNode here, inputs must be undefined so we know they still need to be
diff --git a/packages/core/test/render3/directive_spec.ts b/packages/core/test/render3/directive_spec.ts
index 3d7ee5deab..cf9076d20d 100644
--- a/packages/core/test/render3/directive_spec.ts
+++ b/packages/core/test/render3/directive_spec.ts
@@ -8,10 +8,11 @@
import {EventEmitter} from '@angular/core';
-import {AttributeMarker, defineDirective} from '../../src/render3/index';
-import {bind, element, elementEnd, elementProperty, elementStart, listener, loadDirective} from '../../src/render3/instructions';
+import {AttributeMarker, RenderFlags, defineDirective} from '../../src/render3/index';
-import {TemplateFixture} from './render_util';
+import {bind, element, elementEnd, elementProperty, elementStart, listener, template, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
+
+import {ComponentFixture, TemplateFixture, createComponent} from './render_util';
describe('directive', () => {
@@ -149,6 +150,67 @@ describe('directive', () => {
expect(fixture.html).toEqual('');
expect(directiveInstance !).not.toBeUndefined();
});
+ });
+
+ describe('outputs', () => {
+
+ let directiveInstance: Directive;
+
+ class Directive {
+ static ngDirectiveDef = defineDirective({
+ type: Directive,
+ selectors: [['', 'out', '']],
+ factory: () => directiveInstance = new Directive,
+ outputs: {out: 'out'}
+ });
+
+ out = new EventEmitter();
+ }
+
+ it('should allow outputs of directive on ng-template', () => {
+ /**
+ *