Automating AJAX Forms
Tags: autofill, automation, javascript
Published: 2023-03-24 06:35:25

While [Autofill](https://www.tohodo.com/autofill/) can autofill the majority of forms on the internet, there are more and more forms these days that it has a hard time with. These modern forms either use non-standard HTML form tags (e.g., `<div>` instead of `<select>`) or render forms dynamically via [AJAX](https://www.w3schools.com/whatis/whatis_ajax.asp). Today, we're going to go over how to automate filling out a multi-page form that is powered by AJAX.

Since Autofill is typically triggered on page load, when a form uses the magic of AJAX to "load" the next page without actually loading the web page, Autofill is never triggered again. This is the reason why you might see Autofill working only on the first page and not subsequent pages. In order to properly autofill AJAX forms, we need to use Autofill's powerful JavaScript rules. For this tutorial, we will use [Fundrise](https://fundrise.com/questionnaire/personal-info) as a case study.

First, go to the Fundrise link above and enter any email address and password to create a dummy account. The multi-page form should start at the page below, and this is where we'll begin our automation:

[![Form page 1 screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nib6y4zx9syy3qxild3u.png)](https://fundrise.com/questionnaire/survey)

For the purpose of this tutorial, let's create a new profile called "Fundrise":

![Manage Profiles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqbq9mrqs7780qap2s1p.png)

In this new profile, create a JavaScript rule (select Type = "JavaScript") and enter this into the Value field:

```javascript
const fields = [
  { name: '[data-test="Family or Friend"]' },
  { name: '[data-test="TAXABLE"]' },
  { name: '[data-test="Income"]' },
  { name: '[data-test="$10K - $25K"]' },
  { name: '[data-test="3-5 years"]' },
  { name: '[data-test="I am more hands-on"]' },
  { name: '[data-test="first-name"]', value: 'First' },
  { name: '[data-test="last-name"]', value: 'Last' },
  { name: '[data-test="agreements"]' },
  { name: '[data-test="address-form-address1"]', value: '321 Test Dr' },
  { name: '[data-test="address-form-city"]', value: 'Beverly Hills' },
  { name: '[data-test="address-form-state"]', value: 'CA' },
  { name: '[data-test="address-form-zip"]', value: '90210' },
  { name: '[data-test="phone-number"]', value: '(310) 555-1212' },
  { name: '[data-test="date-input"]', value: '04/01/1984' },
  { name: '[data-test="amount-input"]', value: '10' },
  { name: '[data-test="other-amount-input"]', value: '10' },
  { name: '[data-test="manually-enter-account"]' },
  { name: '[data-test="new-bank-name"]', value: 'Big Bank' },
  { name: '[data-test="new-bank-routing"]', value: '123456789' },
  { name: '[data-test="new-bank-acct-1"]', value: '1234567890' },
  { name: '[data-test="new-bank-acct-2"]', value: '1234567890' },
  { name: '[data-test="acknowledgment-0"]' },
  { name: '[data-test="acknowledgment-1"]' },
  { name: '[data-test="acknowledgment-2"]' },
  { name: '[data-test="acknowledgment-3"]' },
  { name: '[data-test="acknowledgment-4"]' },
  { name: '[data-test="acknowledgment-5"]' },
  { name: '[data-test="acknowledgment-6"]' },
];

setInterval(() => {
  for (let i = 0, field; i < fields.length; ++i) {
    field = document.querySelector(fields[i].name);
    if (field) {
      if (fields[i].value) {
        field.value = fields[i].value;
        field.dispatchEvent(new Event('input'));
        field.dispatchEvent(new Event('change'));
      } else if (!field.checked) {
        field.click();
      }
    }
  }
}, 500);
```

Whoa, that's quite a handful! Don't worry, I'm going to break it down for you. It's not so intimidating once you break it down into smaller chunks. Let's dive in...

```javascript
const fields = [ ... ];
```

Here we are defining all of the form fields that we want to automate. The `[ ... ]` contains a list of items, with each item having one or both of these properties:

- `name` - the [CSS selector](https://www.w3schools.com/cssref/css_selectors.php) that we will use to identify the fields.
- `value` - the text that will be entered in input boxes.

As you'll soon see below, we will assume items that only contain the `name` property to be checkbox/radio elements that should be clicked on, and items that also contain the `value` property are input boxes that should be autofilled.

**NOTE:** Throughout this tutorial I will use the terms "field" and "element" to refer to the same thing — the form's `<input>` tag.

```javascript
setInterval(() => { ... }, 500);
```

We are going to execute everything inside `{ ... }` every 500 milliseconds (half a second). Since the page never reloads as you move through the steps, what we are essentially doing is polling the page to detect when the form elements we want to fill out or click are added to the page. As with most things in JavaScript, there are other ways of doing this, such as using [Mutation Observers](https://developer.mozilla.org/docs/Web/API/MutationObserver), but for our needs good ol' `setInterval()` works fine.

```javascript
for (let i = 0, field; i < fields.length; ++i) { ... }
```

This loops through each item in the `fields` list.

```javascript
field = document.querySelector(fields[i].name);
```

Here we are querying the document for the form element we want to automate by using the CSS selector stored in the `name` property, and saving the first matching element to a variable called `field` for easier reference in the future.

```javascript
if (field) { ... }
```

Only proceed if the element actually exists in the document at the time of the polling. If not, then continue to the next item in the `fields` list.

```javascript
if (fields[i].value) { ... }
```

If the form element does exist, and the `fields` list item contains the `value` property, then assume the element is an input box that should be autofilled.

```javascript
field.value = fields[i].value;
```

Autofill the input box with the text stored in the `value` property.

```javascript
field.dispatchEvent(new Event('input'));
field.dispatchEvent(new Event('change'));
```

This is required on some forms to simulate a human manually entering the text into the input box. Not having these two lines can make the code break or result in unexpected behaviors.

```javascript
else if (!field.checked) { ... }
```

If the `fields` list item does not contain the `value` property, then we'll assume it's either a checkbox or radio element that needs to be auto-clicked. The `!field.checked` condition means we only click it if it's not already checked/ticked; if we leave out this condition, then Autofill would repeatedly click on this element every half second — not good.

```javascript
field.click();
```

Click on the checkbox or radio element.

That's pretty much it. I hope it was straight-forward enough. If you wanted even more automation, then there's nothing stopping you from adding a few lines of code to make it also automatically click the Continue button for you. I left that out because there were some sensitive fields that should not be automated by Autofill, such as the Social Security number field.

One thing that may not be obvious is how we came up with the CSS selectors for the form fields. To do this, right-click on a field and select "Inspect"; then look for the `<input>` tag closest to the highlighted code. Below I have inspected the "Family or Friend" radio element from our example:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bb8kyu6za92woymxw966.png)

For this part you'll have to look at all of the form elements you want to automate and see which attributes are common among them. In our case, the `data-test` attribute was one of the attributes found in all of the fields.

As you proceed through the Fundrise form, it should be autofilled for you even though each page was rendered dynamically via AJAX. Autofill + JavaScript rules can be used like this to open up a world of automation that can significantly reduce your menial workload. Happy autofilling! ⚡