Skip to content

Commit c90651a

Browse files
committed
feat(core form-data-event): New core pattern to allow passing form data via events.
1 parent a4ff273 commit c90651a

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

src/core/form-data-event.js

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import Base from "./base";
2+
import Parser from "./parser";
3+
import logging from "./logging";
4+
5+
const log = logging.getLogger("form-data-event");
6+
7+
export const parser = new Parser("form-data-event");
8+
parser.attribute = "data-form-data-event"; // do not require ``data-pat-``
9+
parser.addArgument("event-name-submit");
10+
parser.addArgument("event-name-init");
11+
parser.addArgument("prevent-submit", true);
12+
parser.addArgument("close-modal", true);
13+
14+
export default Base.extend({
15+
name: "form-data-event",
16+
trigger: ".form-data-event", // note: no .pat- trigger!
17+
18+
init() {
19+
this.options = parser.parse(this.el, this.options);
20+
if (this.el.tagName !== "FORM") {
21+
log.warn("pattern must be initialized on a form element.");
22+
return;
23+
}
24+
if (this.options.event["name-submit"]) {
25+
this.el.addEventListener("submit", this.handle_submit.bind(this));
26+
}
27+
if (this.options.event["name-init"]) {
28+
document.addEventListener(
29+
this.options.event["name-init"],
30+
this.handle_init.bind(this),
31+
{ once: true }
32+
);
33+
}
34+
},
35+
36+
handle_submit(e) {
37+
if (this.options.preventSubmit) {
38+
e.preventDefault();
39+
}
40+
// Note: line breaks might change from /n to /r
41+
const form_data = new FormData(this.el);
42+
if (e.submitter?.name) {
43+
form_data.append("action", e.submitter.name);
44+
}
45+
const ev = new CustomEvent(this.options.event["name-submit"], {
46+
detail: { form_data: form_data },
47+
});
48+
document.dispatchEvent(ev);
49+
if (this.options.closeModal) {
50+
const modal = this.el.closest(".pat-modal");
51+
if (modal) {
52+
modal["pattern-modal"].destroy();
53+
}
54+
}
55+
if (this.options.event["name-init"]) {
56+
document.removeEventListener(
57+
this.options.event["name-init"],
58+
this.handle_init
59+
);
60+
}
61+
},
62+
63+
handle_init(e) {
64+
const form_data = e?.detail?.form_data;
65+
for (const [key, value] of form_data.entries()) {
66+
const _el = this.el.querySelector(`[name=${key}]`);
67+
if (_el) {
68+
if (_el.type === "checkbox") {
69+
// TODO:
70+
// should set checked=true if value exists and set the checkbox value to the form_data value?
71+
// then we need some logic to unset the checkbox if value is omitted.
72+
_el.checked = value === "true" || value === "on"; // default value for checked checkboxes is "on"
73+
} else {
74+
_el.value = value;
75+
}
76+
}
77+
}
78+
},
79+
});

src/core/form-data-event.test.js

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import "./form-data-event";
2+
import registry from "./registry";
3+
import utils from "./utils";
4+
5+
describe("form-data-event: Pass form data via events.", () => {
6+
afterEach(() => {
7+
document.body.innerHTML = "";
8+
});
9+
10+
it("Initializes a form with data when receiving an initialization event, but only once", async () => {
11+
document.body.innerHTML = `
12+
<form
13+
class="form-data-event"
14+
data-form-data-event="
15+
event-name-init: init-event
16+
">
17+
<input type="text" name="inp1" />
18+
<input type="text" name="inp2" />
19+
<input type="checkbox" name="inp3" />
20+
<textarea name="inp4"></textarea>
21+
</form>
22+
`;
23+
24+
registry.scan(document.body);
25+
26+
const longer_text = `HalloGallo
27+
Sonderangebot
28+
Weissensee
29+
Jahresüberblick
30+
Im Glück
31+
Negativland
32+
Lieber Honig`;
33+
34+
const form_data = new FormData();
35+
form_data.append("inp1", "Neu!");
36+
form_data.append("inp2", "1972");
37+
form_data.append("inp3", true);
38+
form_data.append("inp4", longer_text);
39+
40+
const init_event = new CustomEvent("init-event", {
41+
detail: { form_data: form_data },
42+
});
43+
document.dispatchEvent(init_event);
44+
45+
await utils.timeout(1);
46+
47+
const form = document.querySelector("form");
48+
expect(form.querySelector("[name=inp1]").value).toBe("Neu!");
49+
expect(form.querySelector("[name=inp2]").value).toBe("1972");
50+
expect(form.querySelector("[name=inp3]").checked).toBe(true);
51+
expect(form.querySelector("[name=inp4]").value).toBe(longer_text);
52+
53+
// Another initialization Event won't change the form again
54+
// The reason for the once-registration of the event is to prevent
55+
// unused event handlers to be hanging around.
56+
57+
const form_data_2 = new FormData();
58+
form_data_2.append("inp1", "Kraftwerk");
59+
form_data_2.append("inp2", "Autobahn");
60+
form_data_2.append("inp3", false);
61+
form_data_2.append("inp4", "");
62+
63+
const init_event_2 = new CustomEvent("init-event", {
64+
detail: { form_data: form_data_2 },
65+
});
66+
document.dispatchEvent(init_event_2);
67+
68+
await utils.timeout(1);
69+
70+
expect(form.querySelector("[name=inp1]").value).toBe("Neu!");
71+
expect(form.querySelector("[name=inp2]").value).toBe("1972");
72+
expect(form.querySelector("[name=inp3]").checked).toBe(true);
73+
expect(form.querySelector("[name=inp4]").value).toBe(longer_text);
74+
});
75+
76+
it("Passes form data via an submit event", async () => {
77+
// Note: line breaks might change from /n to /r
78+
// Testing without line breaks for now.
79+
const longer_text = `Autobahn, Kometenmelodie 1, Kometenmelodie 2, Mitternacht, Morgenspaziergang`;
80+
81+
document.body.innerHTML = `
82+
<form
83+
class="form-data-event"
84+
data-form-data-event="
85+
event-name-submit: submit-event
86+
">
87+
<input type="text" name="inp1" value="Kraftwerk" />
88+
<input type="text" name="inp2" value="Autobahn" />
89+
<input type="checkbox" name="inp3" value="on" checked />
90+
<textarea name="inp4">${longer_text}</textarea>
91+
</form>
92+
`;
93+
94+
registry.scan(document.body);
95+
96+
let form_data;
97+
document.addEventListener("submit-event", (e) => {
98+
form_data = e.detail.form_data;
99+
});
100+
101+
const form = document.querySelector("form");
102+
103+
form.dispatchEvent(new Event("submit"));
104+
105+
await utils.timeout(1);
106+
107+
expect(form_data instanceof FormData).toBeTruthy();
108+
expect(form_data.get("inp1")).toBe("Kraftwerk");
109+
expect(form_data.get("inp2")).toBe("Autobahn");
110+
expect(form_data.get("inp3")).toBe("on");
111+
expect(form_data.get("inp4")).toBe(longer_text);
112+
});
113+
});

0 commit comments

Comments
 (0)