uninvokedFunctionInEventBinding (NG8111) does not check host metadata listeners · Issue #70718 · angular/angular · GitHub
Skip to content

uninvokedFunctionInEventBinding (NG8111) does not check host metadata listeners #70718

Description

@xia-chao

Which @angular/* package(s) are the source of the bug?

compiler-cli

Is this a regression?

No

Description

If I forget to call a function in a template event binding, Angular warns me (NG8111). If I make the exact same mistake in the component's host metadata, I get no warning at all.

@Component({
  selector: 'app-repro',
  standalone: true,
  template: 'x',
  host: { '(click)': 'myFn' },   // same mistake: myFn is never called
})
export class Repro {
  myFn(): void {}
}

Clicking does nothing, and the compiler says nothing either. The NG8111 check's own doc says it exists to catch this:

"Ensures that function in event bindings are called. For example, <button (click)="myFunc"></button> will not call myFunc when the button is clicked. Instead, it should be <button (click)="myFunc()"></button>."

Comparison — same class, only the place where I write the binding differs:

# How the listener is written What I get
A <button (click)="myFn">x</button> NG8111 reported ✅
B host: { '(click)': 'myFn' } nothing at all
C host: { '(click)': 'myFn()' } nothing (correct — the function is called)

Case B is the problem. And unlike some other similar reports, TypeScript doesn't catch it either — I checked with a plain tsc run (exit 0, no errors) — so the user gets total silence.

Evidence

I debugged the compiler (@angular/compiler-cli@22.1.3) and took two screenshots at the same breakpoint in the same source file — the only difference is which component is being checked.

1. Entry A (template). Inside extended_template_checker.ts, getDiagnosticsForComponent: template = ["button"]. The template contains the element with (click)="myFn", so the check sees it and reports NG8111.

entry A: template contains the button with the click binding

2. Entry B (host). Same breakpoint, same line, but this is the component with host: { '(click)': 'myFn' }: template = ["Text"]. The host listener isn't in there at all, so the check has nothing to look at.

entry B: the host listener is absent from the template nodes

Why it can't be caught today

getDiagnosticsForComponent() only ever hands the check the template:

const template = this.partialCtx.templateTypeChecker.getTemplate(component);
...
diagnostics.push(...check.run(ctx, component, template));

getTemplate() returns TmplAstNode[] | null — template AST only. Host listener metadata lives on the decorator, so it never enters that tree. On top of that, the check starts with if (!(node instanceof TmplAstBoundEvent)) return [];.

Not the same as #70680

That one was about a signal without () in @defer (when ...), where an extra TypeScript error ("This condition will always return true since this function is always defined…") already reached the user, so adding NG8109 there was redundant. Here there is no TypeScript fallback for case B — the user sees nothing.

Question

Is host: metadata meant to be out of scope for extended diagnostics? I couldn't find this stated either way in the NG8111 docs or the extended-diagnostics overview. If it's intentional, feel free to close this. If not, I'd like to help — but I'd rather ask first than send a patch in the wrong direction.

Please provide a link to a minimal reproduction of the bug

The two screenshots above are the reproduction. Minimal source:

import { Component } from '@angular/core';

@Component({
  selector: 'app-repro',
  standalone: true,
  template: 'x',
  host: { '(click)': 'myFn' },          // nothing reported
})
export class Repro {
  myFn(): void {}
}

@Component({
  selector: 'app-control',
  standalone: true,
  template: `<button (click)="myFn">x</button>`,   // NG8111 reported
})
export class Control {
  myFn(): void {}
}

Compile both with ngc (strictTemplates: true, compilationMode: "full"): Control reports NG8111, Repro stays silent.

Please tell us about your environment

  • Angular version: @angular/compiler-cli@22.1.3 (the check is unchanged on main as of writing)
  • Node version: v26.8.1
  • Package Manager: npm
  • OS: macOS (darwin arm64)
  • Language: TypeScript 6.0.2

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions