You think it'd be cool to create a form that users can submit without pressing a button? Yeah, that would be cool.

Well, sometimes anyway.

Truth be told, a form that auto-submits can be user-hostile. That's because the form might submit before the user is completed filling it out completely.

Or if the user makes a mistake and wants to go back and correct it, the form might submit before that's possible.

So use this approach judiciously. Nine times out of ten, you're best bet is probably to go "old school" and stick with the standard Save button.

Nevertheless, if you really want to go this route, I'll show you how to do it.

Value & Validity

As the title suggests, you're going to skin this cat with the aid of a property called valueChanges.

That property, by the way, belongs to the AbstractControl class. That's the base class for the FormControl and FormGroup objects.

But what does valueChanges do? It returns an Observable.

That means it does exactly what it should do. It follows the publisher/subscriber pattern. Your code will need to subscribe to that Observable to "listen" for changes.

In this case, the code will listen for changes that happen anywhere on the whole form. 

That means if even one letter in one form field changes, it will detect that change and emit it.

So what does that have to do with submitting a form without a button?

Here's what it has to do with that: your code will listen for changes to the form. Then, when a change occurs, it will check the form to make sure it's valid.

If the form is valid, then the code will automagically submit it. If not, then it does nothing.

That's it. That's the whole task here.

Implementation & Integration

Let's say you're developing a CRM app that allows sales reps to create activities for contacts. For whatever reason, you decide you want the form to auto-submit once it's valid.

Here's what that code would look like:

this.activityFormGroup.valueChanges.pipe(
  debounceTime(500),
  distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
).subscribe(() => {
  if (this.activityFormGroup.valid) {
    this.saveActivity();
  }
});

The FormGroup object here is named activityFormGroup. The code above grabs the valueChanges property from that object so it can listen for changes.

As I mentioned above, that valueChanges property returns an Observable

The code also uses the pipe() operator to do some work on with that Observable and make the source a little more readable.

The first function inside pipe() is debounceTime(). It's set to 500 (for 500 milliseconds) because you don't want to emit a value every time the user presses a key in a free-text field.

That's inefficient and unnecessary.

Instead, the code waits for at least half a second between emissions. Of course, it will wait even longer if the user doesn't press anything.

That distinctUntilChanged() function won't emit anything if the last value of the form is exactly the same as the current value. It uses JSON.stringify() to convert the entire form into a JSON string. Then it compares the current string with the previous string. If there's no difference, then it won't emit a value.

Keep in mind: an Observable doesn't do anything until somebody subscribes to it. So the code above also subscribes to the Observable.

And when a new value is emitted (meaning there's been a change to any field in the form), the code checks to see if the form is valid.

If it's valid, then it saves the form by turning over execution to the saveActivity() method.

And that's it. Do something like that with your form and you'll get an auto-submit with no button.

Assuming that's you want, of course.

Wrapping It Up

Now you know how to auto-submit a form.

Again, though, I caution you to think about user-friendliness before going this route. But if you've thought about that and determined it's what you want to do, go for it.

Just remember to have fun!

Photo by Qazi Ikram Ul Haq from Pexels