-
-
Notifications
You must be signed in to change notification settings - Fork 595
Expand file tree
/
Copy pathconfirmation_controller.js
More file actions
117 lines (103 loc) · 3.95 KB
/
Copy pathconfirmation_controller.js
File metadata and controls
117 lines (103 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { Controller } from "@hotwired/stimulus"
/**
* Connects to data-controller="confirmation"
* Displays a confirmation modal with the details of the form that user just submitted.
* Launched when the user clicks Save from the form.
* First runs a "pre-check" on the form data to a validation endpoint,
* which is specified in the controller's `preCheckPathValue` property.
* If the pre-check passes, it shows the modal. Because the confirmation modal should only be shown
* when the form data can pass initial validation.
* If the pre-check fails, it submits the form to the server for full validation and render with the errors.
*
* The pre-check validation endpoint also returns the html body to display in the modal if validation passes.
* If the user clicks the "Yes..." button from the modal, it submits the form.
* If the user clicks the "No..." button from the modal, it closes and user remains on the same url.
*
* The button that opened the modal is remembered and passed back into requestSubmit, so that any other
* Stimulus controller composed onto the same form (e.g. duplicate-items) still sees it as `event.submitter`
* when the form is eventually (re)submitted.
*/
export default class extends Controller {
static targets = [
"modal",
"form"
]
static values = {
preCheckPath: String
}
openModal(event) {
event.preventDefault();
this.submitter = event.currentTarget;
const formData = new FormData(this.formTarget);
const formObject = this.buildNestedObject(formData);
fetch(this.preCheckPathValue, {
method: "POST",
headers: {
"X-CSRF-Token": this.getMetaToken(),
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(formObject),
credentials: "same-origin"
})
.then((response) => response.json())
.then((data) => {
if (data.valid) {
this.modalTarget.innerHTML = data.body;
$(this.modalTarget).modal("show");
} else {
this.formTarget.requestSubmit(this.submitter);
}
})
.catch((error) => {
// Something went wrong in communication to server validation endpoint
// In this case, just submit the form as if the user had clicked Save.
// NICE TO HAVE: Send to bugsnag but need to install/configure https://www.npmjs.com/package/@bugsnag/js
console.log(`=== ConfirmationController ERROR ${error}`);
this.formTarget.requestSubmit(this.submitter);
});
}
getMetaToken() {
const metaTokenElement = document.querySelector("meta[name='csrf-token']");
return metaTokenElement
? metaTokenElement.content
: "default_test_csrf_token";
}
// Prepare the form data for submission as expected by Rails, excluding
// the form level authenticity token because that is specific to creation.
// This controller needs to submit a validation only request.
buildNestedObject(formData) {
let formObject = {};
for (let [key, value] of formData.entries()) {
if (key === "authenticity_token") {
continue;
}
const keys = key.split(/[\[\]]+/).filter((k) => k);
keys.reduce((obj, k, i) => {
if (i === keys.length - 1) {
obj[k] = value;
} else {
obj[k] = obj[k] || {};
}
return obj[k];
}, formObject);
}
return formObject;
}
debugFormData() {
const formData = new FormData(this.formTarget);
let formDataString = "=== ConfirmationController FormData:\n";
for (const [key, value] of formData.entries()) {
formDataString += `${key}: ${value}\n`;
}
console.log(formDataString);
}
submitForm() {
$(this.modalTarget).find('#modalClose').prop('disabled', true);
$(this.modalTarget).find('#modalYes').prop('disabled', true);
$(this.modalTarget).find('#modalNo').prop('disabled', true);
$(this.modalTarget).modal("hide");
this.formTarget.requestSubmit(this.submitter);
}
}