Skip to content

Commit

Permalink
Disable submit button after click to stop multiple submissions (#636)
Browse files Browse the repository at this point in the history
* submit button fix

* add javascript to disable and style on click

* remove log line

* added tests

* remove .only from test

* refactored

* changed readme

* change readme

* revert refactor

* remove button loading from feeback

* pr comments and changes to examples

* removed test functionality covered by another test
  • Loading branch information
rmccar authored and boxadesign committed Oct 15, 2019
1 parent d1a3abf commit 3fbea5e
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/components/button/_macro.njk
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
{% else %}
type="{{ params.type if params.type else ('button' if params.print else 'submit') }}"
{% endif %}
class="btn{% if params.classes %} {{ params.classes }}{% endif %}{% if params.url %} btn--link{% endif %}{% if params.disabled %} btn--disabled{% endif %}{% if params.print %} btn--print u-d-no js-print-btn{% endif %}"
class="btn{% if params.classes %} {{ params.classes }}{% endif %}{% if params.url %} btn--link{% endif %}{% if params.disabled %} btn--disabled{% endif %}{% if params.print %} btn--print u-d-no js-print-btn{% endif %}{% if params.type == 'submit' %} btn--loader js-button{% endif %}"
{% if params.id %}id="{{ params.id }}"{% endif %}
{% if params.value %}value="{{ params.value }}"{% endif %}
{% if params.name %}name="{{ params.name }}"{% endif %}
{% if params.disabled %} disabled="disabled" aria-disabled="true"{% endif %}
{% if params.disabled %} disabled{% endif %}
{% if params.url and params.newWindow %}target="_blank"{% endif %}
{% if params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
>
Expand Down
14 changes: 14 additions & 0 deletions src/components/button/button.dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import domready from 'js/domready';

async function submitButton() {
const buttons = [...document.querySelectorAll('.js-button')];

if (buttons.length) {
const SubmitButton = (await import('./button')).default;
buttons.forEach(button => {
new SubmitButton(button);
});
}
}

domready(submitButton);
11 changes: 11 additions & 0 deletions src/components/button/button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default class SubmitButton {
constructor(component) {
this.button = component;
this.button.addEventListener('click', this.loadingButton.bind(this));
}

loadingButton() {
this.button.classList.add('is-loading');
this.button.setAttribute('disabled', true);
}
}
5 changes: 2 additions & 3 deletions src/components/button/examples/button-loader/index.njk
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Start',
"classes": 'btn--loader is-loading'
"type": 'submit',
"text": 'Submit'
})
}}
3 changes: 1 addition & 2 deletions src/components/button/examples/button/index.njk
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Submit'
"text": 'Save and continue'
})
}}
2 changes: 1 addition & 1 deletion src/components/button/index.njk
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Use `btn--disabled` with the `disabled=true` element attribute for buttons that
}}

### Loader
The `btn--loader` class can be added to a button when there is a need to indicate to the user that the action taken place is waiting for a response i.e. uploading a file. This helps prevent user’s from clicking buttons multiple times when they are unsure if the action they have carried out has worked.
The `btn--loader` class will be added to a button if the type is explicitly declared as `submit` then when the button is clicked the `is-loading` class is added to start the animation and the button is disabled. This is used when there is a need to indicate to the user that the action taken place is waiting for a response i.e. uploading a file. This helps prevent user’s from clicking buttons multiple times when they are unsure if the action they have carried out has worked.
{{
patternlibExample({"path": "components/button/examples/button-loader/index.njk"})
}}
Expand Down
2 changes: 1 addition & 1 deletion src/components/feedback/_macro.njk
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
{{
onsButton({
"text": params.button.send.text,
"classes": "js-feedback-send btn--loader",
"classes": "js-feedback-send",
"attributes": params.button.send.attributes
})
}}
Expand Down
2 changes: 0 additions & 2 deletions src/components/feedback/feedback.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,5 @@ export default class Feedback {
element.disabled = !enabled;
}
});

this.button.classList[enabled ? 'remove' : 'add']('is-loading');
}
}
1 change: 1 addition & 0 deletions src/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ import 'components/checkboxes/checkboxes.dom';
import 'components/radios/radios.dom';
import 'components/typeahead/typeahead.dom';
import 'components/cookies-banner/cookies-banner.dom';
import 'components/button/button.dom';
4 changes: 0 additions & 4 deletions src/tests/spec/feedback/feedback.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ describe('Component: Feedback', function() {
expect(this.submit.disabled).to.be.true;
});

it('the submit button should be set to loader mode', function() {
expect(this.submit.classList.contains('is-loading')).to.be.true;
});

it('the form should be posted', function() {
expect(this.mockedFetch).to.have.been.called();
});
Expand Down
66 changes: 66 additions & 0 deletions src/tests/spec/submit-button/submit-button.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { awaitPolyfills } from 'js/polyfills/await-polyfills';
import template from 'components/button/_test-template.njk';
import SubmitButton from 'components/button/button';

const params = {
id: 'button',
type: 'submit',
text: 'Submit',
};

describe('Function: Submit Button ', function() {
let wrapper, buttonElement;

before(() => awaitPolyfills);

beforeEach(() => {
const html = template.render({ params });

wrapper = document.createElement('div');
wrapper.innerHTML = html;
document.body.appendChild(wrapper);

buttonElement = document.getElementById(params.id);
});

afterEach(() => {
if (wrapper) {
wrapper.remove();
}
});

describe('Before the button is initialised', () => {
it('Button should have relevant classes', () => {
expect(buttonElement.classList.contains('btn--loader')).to.be.true;
expect(buttonElement.classList.contains('js-button')).to.be.true;
});

it('Button should be type submit', () => {
expect(buttonElement.getAttribute('type')).to.equal('submit');
});
});

describe('Once the button is initialised', () => {
beforeEach(() => {
new SubmitButton(buttonElement);
});

it('Button disabled attribute should not be set', () => {
expect(buttonElement.getAttribute('disabled')).to.not.exist;
});

describe('and the button is clicked', () => {
beforeEach(() => {
buttonElement.click();
});

it('Button should have loading style applied', () => {
expect(buttonElement.classList.contains('is-loading')).to.be.true;
});

it('Button should be disabled', () => {
expect(buttonElement.getAttribute('disabled')).to.equal('true');
});
});
});
});

0 comments on commit 3fbea5e

Please sign in to comment.