Skip to content

Commit

Permalink
fix(form): fix fast selection in checkboxes
Browse files Browse the repository at this point in the history
This fixes an issue where the value of a checkbox question was not
properly updated to the answer model and therefore the backend. This
happened because the save task uses a timeout to debounce value saving.
As the update function of the component always used the value from the
user model this caused a race condition if the user clicked the options
too fast.
  • Loading branch information
anehx authored and czosel committed Sep 20, 2023
1 parent 93ee2ac commit bd9bb3f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
8 changes: 6 additions & 2 deletions packages/form/addon/components/cf-field/input/checkbox.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { action } from "@ember/object";
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";

/**
* Input component for the checkbox question type
Expand All @@ -8,6 +9,8 @@ import Component from "@glimmer/component";
* @argument {Field} field The field for this input type
*/
export default class CfFieldInputCheckboxComponent extends Component {
@tracked selected = this.args.field.value;

/**
* Update the value of the field with the slugs of the currently checked
* boxes.
Expand All @@ -16,14 +19,15 @@ export default class CfFieldInputCheckboxComponent extends Component {
*/
@action
update({ target: { value, checked } }) {
const valueSet = new Set(this.args.field.value);
const valueSet = new Set(this.selected);

if (checked) {
valueSet.add(value);
} else {
valueSet.delete(value);
}

this.args.onSave([...valueSet]);
this.selected = [...valueSet];
this.args.onSave(this.selected);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { render, click, settled } from "@ember/test-helpers";
import { tracked } from "@glimmer/tracking";
import { hbs } from "ember-cli-htmlbars";
import { timeout } from "ember-concurrency";
import { setupIntl } from "ember-intl/test-support";
import { module, test } from "qunit";

Expand Down Expand Up @@ -154,4 +155,32 @@ module("Integration | Component | cf-field/input/checkbox", function (hooks) {
assert.dom("label input[type=checkbox]").isDisabled();
assert.dom("label del.uk-text-muted").doesNotExist();
});

test("it handles fast selections correctly", async function (assert) {
assert.expect(1);

this.field = new (class {
@tracked value = [];
options = [
{ slug: "option-1", label: "Option 1" },
{ slug: "option-2", label: "Option 2" },
];
})();

this.save = async (value) => {
await timeout(50);
this.field.value = value;
await settled();
};

await render(
hbs`<CfField::Input::Checkbox @onSave={{this.save}} @field={{this.field}} />`,
);

// explicitly don't await the first click to trigger two concurrently
// running save tasks
click("label:nth-of-type(1) input");
await click("label:nth-of-type(2) input");
assert.deepEqual(this.field.value, ["option-1", "option-2"]);
});
});

0 comments on commit bd9bb3f

Please sign in to comment.