Skip to content

Commit

Permalink
Add ajaxifyForm
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante committed Nov 23, 2020
1 parent 74a852d commit 5f8d1ea
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 20 deletions.
48 changes: 47 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,55 @@ async function pushForm(
return (pushForm.fetch ?? fetch)(url.toString(), init);
}

// Silently allow the user to override the fetch globally
interface Options {
request?: RequestInit;
onSuccess?: (r: Response) => void | Promise<void>;
onError?: (r: unknown) => void | Promise<void>;
}

function onErrorDefault(error: unknown): void {
alert('The form couldn’t be submitted');
throw error;
}

function onSuccessDefault(): void {
alert('Thanks for your submission');
}

function ajaxifyForm(
form: HTMLFormElement,
{
onSuccess = onSuccessDefault,
onError = onErrorDefault,
request = {}
}: Options = {}
): () => void {
const submitHandler = async (event: Event) => {
event.preventDefault();
form.disable = true;
try {
const response = await pushForm(form, request);
if (!response.ok) {
throw new Error(response.statusText);
}

void onSuccess(response);
} catch (error: unknown) {
void onError(error);
}
};

form.addEventListener('submit', submitHandler);

return () => {
form.removeEventListener('submit', submitHandler);
};
}

// Allow the user to override the fetch globally
namespace pushForm {
export let fetch: typeof window.fetch;
}

export default pushForm;
export {ajaxifyForm};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"browser"
],
"rules": {
"import/no-mutable-exports": "off"
"import/no-mutable-exports": "off",
"no-alert": "off"
}
},
"devDependencies": {
Expand Down
67 changes: 49 additions & 18 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,47 +41,78 @@ Given a regular form element:
</form>
```

You can ajaxify it with this simple code:
You can post it via `fetch` with:

```js
import pushForm from 'push-form';

const form = document.querySelector('form');
form.addEventListener('submit', async event => {
if (form.checkValidity()) {
event.preventDefault();

// The response is what `fetch` returns
const response = await pushForm(form);
if (response.ok) {
form.reset();
form.append('Form submitted!');
} else {
form.append('Aomething wrong happened');
}
}
await pushForm(form);
```

Or you can handle the submissing with:

```js
import {ajaxifyForm} from 'push-form';

const form = document.querySelector('form');
ajaxifyForm(form, {
onSuccess: () => {/**/},
onError: () => {/**/},
});
```

## API

### pushForm(formElement, fetchInit)
### pushForm(formElement, requestInit)

Returns a `Promise` that resolves with a `Reponse` exactly as `fetch` does.
Returns a `Promise` that resolves with a `Response` exactly as `fetch` does.

#### formElement

Type: `HTMLFormElement`

The form to submit. Its `action` and `method` attributes will be used to create the HTTP request.

#### fetchInit
#### requestInit

Type: `FetchInit` <br>
Type: `object` <br>
Example: `{headers: {Accept: 'application/json'}}`

This matches the second parameter of [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch), however the `body` and `method` will be overridden with what the `form` element specifies in its attributes.

### ajaxifyForm(formElement, options)

Stops the `submit` event of a form and uses `pushForm` instead. This returns a `function` that you can call to remove the `submit` handler.

#### formElement

Same as the one in `pushForm`

#### options

Type: `object`

Optional submission/error handlers and configuration for the `fetch`.

##### onSuccess

Type: `function`<br>
Example: `(fetchResponse) => {alert('The form was submitted!')}`

It will be called when `fetch` makes the request and the server returns a successful response (`response.ok`)

##### onError

Type: `function`<br>
Example: `(error) => {alert('Something happened:' + error.message)}`

It will be called when `fetch` fails the request or if the server returns an error response (`response.ok === false`)

##### requestInit

Same as the one in `pushForm`.

## Related

- [select-dom](https://github.com/fregante/select-dom) - Lightweight `querySelector`/`All` wrapper that outputs an Array.
Expand Down

0 comments on commit 5f8d1ea

Please # to comment.