-
Notifications
You must be signed in to change notification settings - Fork 27k
Description
Which @angular/* package(s) are relevant/related to the feature request?
compiler-cli
Description
Just today I tried to write:
<div>The count is: {{count}}</div>
<button (click)="increment">Increment</button>Clicking this button has no effect. No error or warning is emitted, nothing happens.
What I actually wanted to do was:
<div>The count is: {{count}}</div>
<button (click)="increment()">Increment</button>Note the parenthesis added to increment().
This is confusing because it is very easy to think that Angular will call the function in the event binding, when it is really executing the expression, and increment is a no-op expression.
Proposed solution
Angular should emit an extended diagnostic which it sees an event binding bound to an expression with a callable signature. This would flag the mistake and clearly denote that the developer's intention was to invoke the function with ().
Alternatives considered
A slight variation would be to emit a diagnostic only when the expression is a callable identifier, as opposed to any expression. The main difference is whether or not Angular should warn in scenarios where the expression is not an identifier, but we know it's a function such as:
<button (click)="counter.increment">Increment</button>I think it's reasonable to emit in this situation. A related issue is where a function returns which the developer doesn't care about such as:
@Component({
selector: 'my-component',
template: `
<div>The count is: {{count()}}</div>
<button (click)="incrementAndLaterDecrement()">Increment</button>
`,
})
export class MyComponent {
protected readonly count = signal(0);
protected incrementAndLaterDecrement(): () -> void {
this.count.update((c) => c + 1);
return () => {
this.count.update((c) => c - 1);
};
}
}In this case, incrementAndLaterDecrement does return a function. Should it emit the diagnostic in this scenario?
I think it should, as the developer is likely misusing incrementAndLaterDecrement, but there may be instances where they don't care about the returned function. In those cases I'm thinking they should drop the return value with void or maybe just add a semicolon?
<button (click)="void incrementAndLaterDecrement()">Increment</button>
<button (click)="incrementAndLaterDecrement();">Increment</button>Neither of those are super clear to future readers why they are necessary. I kinda like void as I tend to see as a mechanism to "swallow this value so the caller does not consume it", which seems to fit the intention of "ignore the curried function". But void isn't super commonly used so I can understand it being unintuitive to others. Also I have no idea if our template syntax supports void, I wouldn't be surprised if it didn't.
Basically, we can consider whether we want to restrict this to purely callable identifiers or any callable expression. I'm inclined to go with the later, but worth discussing for sure.