POST request on form submit Ember.JS

I am totally green in Ember.JS. I’ve made simple adoption shelter application with Ember tutorials as I am using ember on front end, and Strapi (Node.JS) as an Headless CMS. I have all the endpoints and my ember front is successfully fetching data with GET method via JavaScript’s fetch. However, I want to allow users to create POST requests based on form submit, I can’t find any good example or tutorial how to properly make an post request on form submit in ember.js, could you please help me with figuring out how to do this?

Hi @yakan, welcome to Ember! That’s a really big question because there are a LOT of different ways you could go with it, with varying levels of sophistication. I’ll try to give a bird’s eye view of some of the decisions you could make and then give you a very simple form component example.

You could make a lot of decisions about how you want your forms to work:

  • do you back your form with Ember Data or just with raw GET/POST/PUT requests? Or something like Apollo or Redux? Many possibilities.
  • do you need any fancy state management features or just the basic HTTP requests?
  • do you want to build out a bunch of forms? if so it’s worth having a good suite of form control components like select, etc
  • how much do you care about loading/error states and presenting them appropriately? Something a little bit more ergonomic like ember-concurrency might be warranted

Anyway, the most basic version of a form component might look something like a form tag, some labeled inputs, and a submit button that submits the form. The backing class could have an action that collects the inputs and fires off a POST request. Then it’s up to you to decide what to do after that request is completed. I’ll sketch out some code:

// my-form-component.hbs
<form {{on "submit" this.onSubmit}}>
 <div>New User Form</div>
 <label>
    <span>First Name</span>
    <Input @value={{this.firstName}} />
  </label>
 <label>
    <span>Last Name</span>
    <Input @value={{this.lastName}} />
  </label>
  <button type="submit" disabled={{this.disableSubmit}}>Create</button>
</form>

// my-form-component.js
import Component from '@glimmer/component';
import { action } from '@ember/object';

export default class MyFormComponet extends Component {
  @tracked firstName = '';
  @tracked lastName = '';

  get disableSubmit() {
    // if either value is empty we don't want to allow submitting the form
    return !this.firstName.length || !this.lastName.length;
  }

  @action async onSubmit(event) {
    event.preventDefault(); // to prevent event propagation
    const data = {
      firstName: this.firstName,
      lastName: this.lastName
    }
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data);
    });
    if (response.ok) {
      // handle success
    } else {
      // handle error
    }
  }
}

What’s happening here? We’re using the Ember <Input /> component to bind this.firstName and this.lastName to two DOM <input> elements, we’re capturing the form submit event and triggering an Ember @action with it (the action decorator is just binding to the right this context), and we’re making sure the button won’t allow submit if both inputs don’t have a value. The action makes a fetch request to the server with the input data, and… well that’s it.

Now you could use Ember Data instead of fetch here, you could use ember-concurrency for nice generator-based tasks instead of async/await actions, you could introduce more sophisticated validation or changesets (ember-changeset and ember-changeset-validation, for example). You could come up with a robust set of UI form components… the list goes on. But I think something along these lines is the most basic implementation for you to experiment with. Definitely feel free to ask any follow-up questions here or in the Discord server!

In this example the event.preventDefault(); in onSubmit is missing

Yes good catch! will edit. Thanks!