My chat app had a bug where, if I typed very fast, the letter from the next message would be sent along in the previous message. It would look like "yesterdaym/y laptop..." instead of "yesterday/my laptop...".

My initial thought was that it was because I was using Template-driven forms instead of Reactive forms. I remember reading over here that Reactive forms were synchronous whereas Template-driven forms are asynchronous. This forces tests to be written differently. Mainly for Template-driven forms you have to wait for a tick after simulating typing. Sounds awfully similar to my bug.

So I went over to the DartAngular docs on Forms, only to find out that the tutorial only teaches how to use Template-driven forms. A quick search then led me to an example on how to use Reactive forms (API doc).

But after switching to it, the problem persisted!

So I pointed my attention on this line:

<material-input (keyup.enter)="send()"...

I switched to using ngSubmit by replacing my parent div by a form like so:

<form (ngSubmit)="send()">

and removing the listener to keyup.enter.

And voilà, it works! With both Template-driven and Reactive forms. So the conclusion is, prefer ngSubmit over capturing keyboard events manually.

Along the way, I stumbled upon a few issues:

  • According to this GitHub ticket, you can't use type="submit" on a material button. I don't seem to have this issue?...
  • If I forget to add formDirectives to my Component's directives, when I press Enter, the browser navigates to domain/?...! It looks like the default browser behavior for forms to reload the page with ?query params in the URL.