From 6462abdf0bbd32e063bc74e2dd19634891300bee Mon Sep 17 00:00:00 2001 From: Dario-DC <105294544+Dario-DC@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:03:49 +0100 Subject: [PATCH] feat(curriculum): add form validation lab to FSD cert (#57211) Co-authored-by: Zaira <33151350+zairahira@users.noreply.github.com> --- client/i18n/locales/english/intro.json | 7 +- .../lab-customer-complaint-form/index.md | 9 + .../lab-customer-complaint-form/meta.json | 11 + .../67279fe50237291f80eed8b8.md | 857 ++++++++++++++++++ .../superblock-structure/full-stack.json | 1 + 5 files changed, 884 insertions(+), 1 deletion(-) create mode 100644 client/src/pages/learn/full-stack-developer/lab-customer-complaint-form/index.md create mode 100644 curriculum/challenges/_meta/lab-customer-complaint-form/meta.json create mode 100644 curriculum/challenges/english/25-front-end-development/lab-customer-complaint-form/67279fe50237291f80eed8b8.md diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 1b947300be9..0a6cb23a122 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -3042,7 +3042,12 @@ "You'll also practice basic regular expressions, template literals, the addEventListener() method, and more." ] }, - "egkv": { "title": "213", "intro": [] }, + "lab-customer-complaint-form": { + "title": "Build a Customer Complaint Form", + "intro": [ + "For this lab, you will use JavaScript to validate a customer complaint form." + ] + }, "review-form-validation-with-javascript": { "title": "Form Validation with JavaScript Review", "intro": [ diff --git a/client/src/pages/learn/full-stack-developer/lab-customer-complaint-form/index.md b/client/src/pages/learn/full-stack-developer/lab-customer-complaint-form/index.md new file mode 100644 index 00000000000..77bde14d11f --- /dev/null +++ b/client/src/pages/learn/full-stack-developer/lab-customer-complaint-form/index.md @@ -0,0 +1,9 @@ +--- +title: Introduction to the Build a Customer Complaint Form +block: lab-customer-complaint-form +superBlock: full-stack-developer +--- + +## Introduction to the Build a Customer Complaint Form + +For this lab, you will use JavaScript to validate a customer complaint form. diff --git a/curriculum/challenges/_meta/lab-customer-complaint-form/meta.json b/curriculum/challenges/_meta/lab-customer-complaint-form/meta.json new file mode 100644 index 00000000000..13ee027c19a --- /dev/null +++ b/curriculum/challenges/_meta/lab-customer-complaint-form/meta.json @@ -0,0 +1,11 @@ +{ + "name": "Build a Customer Complaint Form", + "isUpcomingChange": true, + "usesMultifileEditor": true, + "blockType": "lab", + "blockLayout": "link", + "dashedName": "lab-customer-complaint-form", + "superBlock": "full-stack-developer", + "challengeOrder": [{ "id": "67279fe50237291f80eed8b8", "title": "Build a Customer Complaint Form" }], + "helpCategory": "JavaScript" +} diff --git a/curriculum/challenges/english/25-front-end-development/lab-customer-complaint-form/67279fe50237291f80eed8b8.md b/curriculum/challenges/english/25-front-end-development/lab-customer-complaint-form/67279fe50237291f80eed8b8.md new file mode 100644 index 00000000000..78f13743ed4 --- /dev/null +++ b/curriculum/challenges/english/25-front-end-development/lab-customer-complaint-form/67279fe50237291f80eed8b8.md @@ -0,0 +1,857 @@ +--- +id: 67279fe50237291f80eed8b8 +title: Build a Customer Complaint Form +challengeType: 25 +dashedName: build-a-customer-complaint-form +demoType: onClick +--- + +# --description-- + +For this lab, you have been provided with all the HTML and CSS. You will use JavaScript to validate the complaint form. + +**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab. + +**User Stories:** + +1. When the form is submitted, you should ensure that: + - `#full-name` is not empty. + - `#email` is a valid email address format. + - `#order-no` is a sequence of ten numbers starting with `2024`. + - `#product-code` follows the pattern `XX##-X###-XX#`, where `X` represents either a lowercase letter or an uppercase letter and `#` represents a number. + - `#quantity` is a positive integer. + - at least one checkbox from `#complaints-group` is checked. + - `#complaint-description` contains at least twenty characters if the `Other` checkbox is checked. + - a radio button from `#solutions-group` is selected. + - `#solution-description` contains at least twenty characters if the `Other` radio button is selected. +1. You should have a function named `validateForm` that returns an object containing the following keys: `full-name`, `email`, `order-no`, `product-code`, `quantity`, `complaints-group`, `complaint-description`, `solutions-group`, and `solution-description`. The value of each key should be `true` if the corresponding form field is correctly filled and `false` otherwise. +1. You should have a function named `isValid` that takes the object returned by `validateForm` as argument and returns `true` if every form field is correctly filled and `false` otherwise. +1. If a change event is triggered on a form field and it has a valid value, you should set its border color to `green`. In case of checkbox and radio button groups, you should set the border color of the parent `fieldset`. +1. If a change event is triggered on a form field and it has an invalid value, you should set its border color to `red`. In case of checkbox and radio button groups, you should set the border color of the parent `fieldset`. +1. When you try to submit the form you should call `isValid` to validate the form. +1. When you try to submit the form, if the form has any invalid field, each invalid field should be highlighted by setting the border color of each invalid input, textarea or fieldset (in case of checkbox and radio button groups) to `red`. + +# --hints-- + +You should have a function named `validateForm`. + +```js +assert.isFunction(validateForm); +``` + +`validateForm` should return an object. + +```js +assert.isObject(validateForm()); +``` + +`validateForm()["full-name"]` should be `false` when `#full-name` is empty, and `true` otherwise. + +```js +const field = document.getElementById("full-name"); +field.value = ""; +assert.isFalse(validateForm()["full-name"]); +field.value = "testing"; +assert.isTrue(validateForm()["full-name"]); +``` + +When a `change` event is triggered on `#full-name`, you should set its border color to `green` if it contains a valid value, and `red` otherwise. + +```js +const field = document.getElementById("full-name"); +field.value = "testing" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +field.value = "" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +`validateForm()["email"]` should be `true` when `#email` contains a valid email address, and `false` otherwise. + +```js +const field = document.getElementById("email"); +field.value = "example@domain.com" +assert.isTrue(validateForm()["email"]); +field.value = "testing" +assert.isFalse(validateForm()["email"]); +``` + +When a `change` event is triggered on `#email`, you should set its border color to `green` if it contains a valid email address, and `red` otherwise. + +```js +const field = document.getElementById("email"); +field.value = "example@domain.com" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +field.value = "" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +`validateForm()["order-no"]` should be `true` when `#order-no` contains a valid value, and `false` otherwise. + +```js +const field = document.getElementById("order-no"); +field.value = "2024001122" +assert.isTrue(validateForm()["order-no"]); +field.value = "testing" +assert.isFalse(validateForm()["order-no"]); +``` + +When a `change` event is triggered on `#order-no`, you should set its border color to `green` if it contains a valid value, and `red` otherwise. + +```js +const field = document.getElementById("order-no"); +field.value = "2024001122" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +field.value = "20240011" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +`validateForm()["product-code"]` should be `true` when `#product-code` contains a valid value, and `false` otherwise. + +```js +const field = document.getElementById("product-code"); +field.value = "Xa22-X123-Xb4"; +assert.isTrue(validateForm()["product-code"]); +field.value = "testing" +assert.isFalse(validateForm()["product-code"]); +``` + +When a `change` event is triggered on `#product-code`, you should set its border color to `green` if it contains a valid value, and `red` otherwise. + +```js +const field = document.getElementById("product-code"); +field.value = "Xa22-X123-Xb4" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +field.value = "Xa22-123-Xb4" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +`validateForm()["quantity"]` should be `true` when `#quantity` contains a valid value, and `false` otherwise. + +```js +const field = document.getElementById("quantity"); +field.value = "5"; +assert.isTrue(validateForm()["quantity"]); +field.value = "0"; +assert.isFalse(validateForm()["quantity"]); +``` + +When a `change` event is triggered on `#quantity`, you should set its border color to `green` if it contains a valid value, and `red` otherwise. + +```js +const field = document.getElementById("quantity"); +field.value = "2" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +field.value = "0" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +When at least one checkbox from `#complaints-group` is checked, `validateForm()["complaints-group"]` should be `true`. + +```js +document.getElementById("damaged-product").checked = true +assert.isTrue(validateForm()["complaints-group"]); +``` + +When none of the checkboxes from `#complaints-group` is checked, `validateForm()["complaints-group"]` should be `false`. + +```js +document.getElementById("damaged-product").checked = false; +document.getElementById("nonconforming-product").checked = false; +document.getElementById("delayed-dispatch").checked = false; +document.getElementById("other-complaint").checked = false; +assert.isFalse(validateForm()["complaints-group"]); +``` + +Once one checkbox from `#complaints-group` is checked, you should set `#complaints-group`'s border color to `green`. + +```js +document.getElementById("damaged-product").checked = true; +document.getElementById("nonconforming-product").checked = false; +document.getElementById("delayed-dispatch").checked = false; +document.getElementById("other-complaint").checked = false; +const fieldset = document.getElementById("complaints-group"); +fieldset.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(fieldset.style.borderColor, "green"); +``` + +When all of the checkboxes from `#complaints-group` are changed to the unchecked state, you should set `#complaints-group`'s border color to `red`. + +```js +document.getElementById("damaged-product").checked = false; +document.getElementById("nonconforming-product").checked = false; +document.getElementById("delayed-dispatch").checked = false; +document.getElementById("other-complaint").checked = false; +const fieldset = document.getElementById("complaints-group"); +fieldset.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(fieldset.style.borderColor, "red"); +``` + +When `#other-complaint` is checked and `#complaint-description` contains at least twenty characters, `validateForm()["complaint-description"]` should be `true`. + +```js +document.getElementById("other-complaint").checked = true +document.getElementById("complaint-description").value = "A sentence with at least twenty characters"; +assert.isTrue(validateForm()["complaint-description"]); +``` + +When `#other-complaint` is checked and `#complaint-description` contains less than twenty characters, `validateForm()["complaint-description"]` should be `false`. + +```js +document.getElementById("other-complaint").checked = true +document.getElementById("complaint-description").value = "Less than 20 chars"; +assert.isFalse(validateForm()["complaint-description"]); +``` + +Once the value of `#complaint-description` is changed to a valid value, you should set its border color to `green`. + +```js +const field = document.getElementById("complaint-description"); +field.value = "A sentence with at least twenty characters" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +``` + +Once the value of `#complaint-description` is changed to an invalid value, you should set its border color to `red`. + +```js +const field = document.getElementById("complaint-description"); +field.value = "Not enough chars" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +When a radio button from `#solutions-group` is checked, `validateForm()["solutions-group"]` should be `true`. + +```js +document.getElementById("refund").checked = true +assert.isTrue(validateForm()["solutions-group"]); +``` + +When none of the radio buttons from `#solutions-group` is checked, `validateForm()["solutions-group"]` should be `false`. + +```js +document.getElementById("refund").checked = false; +document.getElementById("exchange").checked = false; +document.getElementById("other-solution").checked = false; +assert.isFalse(validateForm()["solutions-group"]); +``` + +Once a radio button from `#solutions-group` is checked, you should set `#solutions-group`'s border color to `green`. + +```js +document.getElementById("refund").checked = true; +document.getElementById("exchange").checked = false; +document.getElementById("other-solution").checked = false; +const fieldset = document.getElementById("solutions-group"); +fieldset.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(fieldset.style.borderColor, "green"); +``` + +When all of the checkboxes from `#complaints-group` are changed to the unchecked state, you should set `#complaints-group`'s border color to `red`. + +```js +document.getElementById("refund").checked = false; +document.getElementById("exchange").checked = false; +document.getElementById("other-solution").checked = false; +const fieldset = document.getElementById("solutions-group"); +fieldset.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(fieldset.style.borderColor, "red"); +``` + +When `#other-solution` is checked and `#solution-description` contains at least twenty characters, `validateForm()["solution-description"]` should be `true`. + +```js +document.getElementById("other-solution").checked = true +document.getElementById("solution-description").value = "A sentence with at least twenty characters"; +assert.isTrue(validateForm()["solution-description"]); +``` + +When `#other-solution` is checked and `#solution-description` contains less than twenty characters, `validateForm()["solution-description"]` should be `false`. + +```js +document.getElementById("other-solution").checked = true +document.getElementById("solution-description").value = "Less than 20 chars"; +assert.isFalse(validateForm()["solution-description"]); +``` + +Once the value of `#solution-description` is changed to a valid value, you should set its border color to `green`. + +```js +const field = document.getElementById("solution-description"); +field.value = "A sentence with at least twenty characters" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "green"); +``` + +Once the value of `#solution-description` is changed to an invalid value, you should set its border color to `red`. + +```js +const field = document.getElementById("solution-description"); +field.value = "Not enough chars" +field.dispatchEvent(new Event("change", { bubbles: true })); +assert.equal(field.style.borderColor, "red"); +``` + +You should have a function named `isValid`. + +```js +assert.isFunction(isValid); +``` + +Your `isValid` function should take the `validateForm()` as its argument and return `true` when all the form fields have been filled correctly. + +```js +document.getElementById("full-name").value = "testing" +document.getElementById("email").value = "example@domain.com" +document.getElementById("order-no").value = "2024001122" +document.getElementById("product-code").value = "Xa22-X123-Xb4" +document.getElementById("quantity").value = "5" +document.getElementById("damaged-product").checked = true +document.getElementById("other-complaint").checked = false +document.getElementById("refund").checked = true +document.getElementById("other-solution").checked = false +assert.isTrue(isValid(validateForm())); + +document.getElementById("other-complaint").checked = true +document.getElementById("complaint-description").value = "A sentence with at least twenty characters"; +document.getElementById("other-solution").checked = true +document.getElementById("solution-description").value = "A sentence with at least twenty characters"; +assert.isTrue(isValid(validateForm())); +``` + +Your `isValid` function should take the `validateForm()` as its argument and return `false` when not all the form fields have been filled correctly. + +```js +const name = document.getElementById("full-name"); +const email = document.getElementById("email"); +const orderNo = document.getElementById("order-no"); +const prCode = document.getElementById("product-code"); +const quantity = document.getElementById("quantity"); +const damaged = document.getElementById("damaged-product"); +const nonConforming = document.getElementById("nonconforming-product"); +const delayed = document.getElementById("delayed-dispatch"); +const otherC = document.getElementById("other-complaint"); +const complaintDescr = document.getElementById("complaint-description"); +const refund = document.getElementById("refund"); +const exchange = document.getElementById("exchange"); +const otherS = document.getElementById("other-solution"); +const solutionDescr = document.getElementById("solution-description"); + +// invalid full-name +name.value = ""; +email.value = "example@domain.com"; +orderNo.value = "2024001122"; +prCode.value = "Xa22-X123-Xb4"; +quantity.value = "5"; +damaged.checked = true; +refund.checked = true; +assert.isFalse(isValid(validateForm())); + +// invalid email +name.value = "testing"; +email.value = ""; +assert.isFalse(isValid(validateForm())); + +// invalid order-no +email.value = "example@domain.com"; +orderNo.value = "202400"; +assert.isFalse(isValid(validateForm())); + +// invalid product-code +orderNo.value = "2024001122"; +prCode.value = "1a22-Xa23-Xb4"; +assert.isFalse(isValid(validateForm())); + +// invalid quantity +prCode.value = "Xa22-X123-Xb4"; +quantity.value = 0; +assert.isFalse(isValid(validateForm())); + +// invalid complaints-group +quantity.value = 5; +damaged.checked = false; +nonConforming.checked = false; +delayed.checked = false; +otherC.checked = false; +assert.isFalse(isValid(validateForm())); + +// invalid complaint-description +otherC.checked = true; +complaintDescr.value = "not enough chars"; +assert.isFalse(isValid(validateForm())); + + +// invalid solutions-group +complaintDescr.value = "A sentence with at least twenty characters"; +refund.checked = false; +exchange.checked = false; +otherS.checked = false; +assert.isFalse(isValid(validateForm())); + +// invalid solutions-description +otherS.checked = true; +solutionDescr.value = "not enough chars"; +assert.isFalse(isValid(validateForm())); +``` + +You should call `isValid` when you try to submit the form. + +```js +let flag = false; +const temp = isValid; +try { + isValid = (obj) => {flag = true}; + document.getElementById("form").dispatchEvent(new Event("submit")); + assert.isTrue(flag); +} finally { + isValid = temp; +} +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + Customer Complaint Form + + + + + + +

Complaint Form

+
+
+
+ + +
+ +
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ Complaint Reason: +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ Description of Complaint Reason + +
+ +
+ Desired Solution + + + + + + + + +
+ +
+ Description of Desired Solution + +
+
+ + +
+ +
+ + + + + +``` + +```css +* { + box-sizing: border-box; +} + +h1 { + text-align: center; +} + +#form { + max-width: 70%; + margin: auto; + border-radius: 10px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + padding: 10px; +} + +input { + border-color: rgb(118, 118, 118); +} + +#personal-info input, #product-info input { + width: 100%; + margin-bottom: 10px; +} + + +fieldset { + margin-bottom: 10px; + border-radius: 5px; + border-color: rgb(118, 118, 118); +} + +textarea { + width: 100%; + border-color: rgb(118, 118, 118); +} + +#btn-container { + display: flex; + justify-content: space-between; + align-items: center; +} + +#submit-btn, #clear-btn { + margin: 10px 15px 0; +} +``` + +```js + +``` + +## --solutions-- + +```html + + + + + Customer Complaint Form + + + + + + +

Complaint Form

+
+
+
+ + +
+ +
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ Complaint Reason: +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ Description of Complaint Reason + +
+ +
+ Desired Solution + + + + + + + + +
+ +
+ Description of Desired Solution + +
+
+ + + +
+ +
+ + + + + +``` + +```css +* { + box-sizing: border-box; +} + +h1 { + text-align: center; +} + +#form { + max-width: 70%; + margin: auto; + border-radius: 10px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + padding: 10px; +} + +input { + border-color: rgb(118, 118, 118); +} + +#personal-info input, #product-info input { + width: 100%; + margin-bottom: 10px; +} + + +fieldset { + margin-bottom: 10px; + border-radius: 5px; + border-color: rgb(118, 118, 118); +} + +textarea { + width: 100%; + border-color: rgb(118, 118, 118); +} + +#btn-container { + display: flex; + justify-content: space-between; + align-items: center; +} + +#submit-btn, #clear-btn { + margin: 10px 15px 0; +} +``` + +```js +const form = document.getElementById("form"); +const fullName = document.getElementById("full-name"); +const emailAddress = document.getElementById("email"); +const orderNo = document.getElementById("order-no"); +const productCode = document.getElementById("product-code"); +const quantity = document.getElementById("quantity"); +const complaints = document.querySelectorAll('input[name="complaint"]'); +const complaintDescription = document.getElementById("complaint-description"); +const complaintTextAreaDiv = document.getElementById("complaint-description-container"); +const solutions = document.querySelectorAll('input[name="solutions"]'); +const solutionDescription = document.getElementById("solution-description"); +const solutionTextAreaDiv = document.getElementById("solution-description-container"); +const submitBtn = document.getElementById("submit-btn"); +const messageBox = document.getElementById("message-box"); +const clearBtn = document.getElementById("clear-btn"); + +const hideTextareas = () => { + complaintTextAreaDiv.style.display = "none"; + solutionTextAreaDiv.style.display = "none"; +} + +hideTextareas(); + +const formFields = { + "full-name": fullName, + "email": emailAddress, + "order-no": orderNo, + "product-code": productCode, + "quantity": quantity, + "complaints-group": Array.from(complaints), + "complaint-description": complaintDescription, + "solutions-group": Array.from(solutions), + "solution-description": solutionDescription +} + +const clearForm = () => { + Object.entries(formFields).forEach(entry => { + const [key, val] = entry; + if (Array.isArray(val)) { + val.forEach(i => i.checked = false); + } else { + val.value = ""; + } + hideTextareas(); + messageBox.innerText = ""; + document.getElementById(key).style.borderColor = "rgb(118, 118, 118)"; + }) +} + +const validateForm = () => { + const complaintsArr = Array.from(complaints).map(i => i.checked); + const solutionsArr = Array.from(solutions).map(i => i.checked); + const validationObject = { + "full-name": Boolean(fullName.value.trim()), + "email": /^\S+@\S+\.\S+$/.test(emailAddress.value.trim()), + "order-no": /^2024\d{6}$/.test(orderNo.value.trim()), + "product-code": /[A-Z]{2}\d{2}-[A-Z]\d{3}-[A-Z]{2}\d/i.test(productCode.value.trim()), + "quantity": Number(quantity.value.trim()) > 0, + "complaints-group": complaintsArr.some(i => i), + "complaint-description": null, + "solutions-group": solutionsArr.some(i => i), + "solution-description": null + } + + if (complaintsArr[3]) { + complaintTextAreaDiv.style.display = "block"; + const complaintsDescriptionVal = complaintDescription.value.trim(); + if (complaintsDescriptionVal.length < 20) { + validationObject["complaint-description"] = false; + } else { + validationObject["complaint-description"] = true; + } + } else { + complaintTextAreaDiv.style.display = "none"; + } + if (solutionsArr[2]) { + solutionTextAreaDiv.style.display = "block"; + const solutionDescriptionVal = solutionDescription.value.trim(); + if (solutionDescriptionVal.length < 20) { + validationObject["solution-description"] = false; + } else { + validationObject["solution-description"] = true; + } + } else { + solutionTextAreaDiv.style.display = "none"; + } + if (validationObject["complaint-description"] === null) delete validationObject["complaint-description"]; + if (validationObject["solution-description"] === null) delete validationObject["solution-description"]; + + return validationObject; +} + +clearBtn.addEventListener("click", clearForm); + +Object.keys(formFields).forEach(key => { + document.getElementById(key).addEventListener("change", (e) => { + const validationObject = validateForm(); + if (Object.values(validationObject).every(val => val)) messageBox.innerText = ""; + if (!validationObject[key]) { + document.getElementById(key).style.borderColor = "red"; + } else { + document.getElementById(key).style.borderColor = "green"; + } + }); +}); + +const isValid = (validationObj) => Object.values(validationObj).every(i => i); + +form.addEventListener("submit", (e) => { + e.preventDefault(); + const validationObject = validateForm(); + if (!isValid(validationObject)) { + messageBox.innerText = "Please, fill out the required fields correctly before submitting."; + Object.keys(validationObject).forEach(key => { + if (!validationObject[key]) { + document.getElementById(key).style.borderColor = "red"; + } else { + document.getElementById(key).style.borderColor = "green"; + } + }); + } else { + messageBox.innerText = ""; + alert("Form successfully submitted."); + clearForm(); + } +}); +``` diff --git a/curriculum/superblock-structure/full-stack.json b/curriculum/superblock-structure/full-stack.json index ede684855bb..cb6f74ec50d 100644 --- a/curriculum/superblock-structure/full-stack.json +++ b/curriculum/superblock-structure/full-stack.json @@ -445,6 +445,7 @@ "blocks": [ { "dashedName": "lecture-understanding-form-validation" }, { "dashedName": "workshop-calorie-counter" }, + { "dashedName": "lab-customer-complaint-form" }, { "dashedName": "review-form-validation-with-javascript" }, { "dashedName": "quiz-form-validation-with-javascript" } ]