How to Work With Forms In JavaScript

Forms also referred as web forms are a very important part of front end web application development for sake of interaction with users. Most commonly, forms are used to collect the data from users or provide a provision for user to control the user interface. Forms are great potential assets if correctly used in building an interactive web application. We would be touch basing some of the essential aspects of them like HTML structure, styling form controls, events, data validation and submitting data to server.Understanding forms in detail needs expertise in other areas than just HTML like styling form controls (CSS), scripting to validate or create custom controls (JavaScript).We would be referring or using libraries like Jquery (for document traversal, manipulation etc) and parsley (form validation library) to build better forms.A typical form’s HTML is made of HTML elements called as form controls like single or multiline text fields, dropdowns, checkboxes, button etc mostly created using <input> element with specific type being set on Type attribute. These form controls can be programmed to add some validations to support specific values based on constraints set on them. These controls can be enriched to support accessibility for enabling the interaction for less privileged users.Let’s create a simple html page to build a form.<!DOCTYPE html> <html lang="en-US">   <head>     <meta charset="utf-8">     <title>Learning Forms</title>   </head>   <body>   </body> </html>All forms have to start with <form> element which is container having the form fields user would interact with. All attributes of <form> element are optional but for programming forms to capture data we need at least ‘action’ and ‘method’ attributes.action – is basically the URL where the form fields data would be sent to.method – corresponds to the HTTP method to submit the form data. Possible HTTP method names which can be set as values are post and get. And another value dialog is set when form is imbedded inside a <dialog>.Note: Both formaction and formmethod can be overridden by button, input with type submit elements which we will learn as we go forward.Refer to this link to know more about form attributes.Let’s add a form element to our body with action (“”) and method(“get”). This implies that form will send a GET request to the current URL. If it is post then it would be a POST request to the URL in action.<form action="" method="get"> </form>Add few fields to form say name, email and a submit button using <input> with type being specified as text, email and submit respectively.Note: The <input> tag is an empty element, meaning that it doesn't need a closing tag. Value attribute can be populated to set the default value.<form action="" method="get">    <div>      <label for="name">Enter your name: </label>      <input type="text" name="name" id="name">    </div>    <div>      <label for="email">Enter your email: </label>      <input type="email" name="email" id="email">    </div>    <div>      <input type="submit" value="Click me!">   </div> </form>Save and open the html in chrome or your preferred browser. Clicking on ‘Click me!’ should send a http get call with empty name and email.Note: We can use <button> instead of <input> with type as submit. The difference is that button can contain HTML content allowing to create a complex button whereas input allows only plain text.Let’s understand the Sending of form data.If we observer all the form fields again, we have added an attribute called ‘name’. This property is important to inform that which data is associated with which form field i.e. name/value pairs. Try adding some data to our fields rendering in html (say myName and first.last@email.com) and click submit button. You should see the data being sent as query parameters in the browser URL.?name=myName&email=first.last@email.com.Change the Form method value to POST instead of GET and send the submitted data by clicking the ‘Click me!’ button. You should be seeing Form Data being sent but the browser URL will not get update.name: myName email: first.last@email.comAll this while, we have our action method being set as empty. Replace this with another URL on server side say ‘/captureFormData’. Now on clicking submit button the data should be received by the script at ‘/captureFormData’ with key/value items contained in the HTTP request object.Note that each server-side language like Node.js, C# etc have their own way of handling the submitted form data. And this blog would not cover those topics and it is beyond the scope.Let’s refine our basic form structure with help of other HTML elements like <fieldset>, <legend>, <label> etc. Though we used few of them in basic example. Let’s go little deep on them.Note: Nesting of form inside another form is unacceptable as it might result in unpredictable behavior.<fieldset> is a convenient way of grouping for sake of styling and semantic purpose. This control can be associated with <legend> so that some assistive technologies can read this legend and associate it with the controls inside the <fieldset>. Let’s understand this will an example:<fieldset>         <legend>Interested programming language</legend>         <p>           <input type="radio" name="size" id="js" value="JavaScript">           <label for="js">JavaScript</label>         </p>         <p>           <input type="radio" name="size" id="csharp" value="CSharp">           <label for="csharp">CSharp</label>         </p>         <p>           <input type="radio" name="size" id="java" value="Java">           <label for="java">Java</label>         </p>       </fieldset>When reading the above form by any screen readers, it will read as “Interested programming language JavaScript” for the first radio, “Interested programming language CSharp” and “Interested programming language Java” for second and third radio.Imagine if you have a long form with multiple fields. It would help to improve the usability if we can categorize/section them with the help of <fieldset>. It would even help to improve the accessibility of forms.Talking about accessibility, with the <label> associated correctly with the <input> via its for attribute (which contains the <input> element's id attribute), a screenreader will read out something like "name, edit text" for below one.<label for="name">Enter your name: </label> <input type="text" name="name" id="name">Another advantage of having label associated with input of type text, radio etc is they are clickable too.  If you click on a label then the associated input control will get the focus. If the input control is of type checkbox or radio, clicking on label will select the check box and radio. This will be useful as clickable area of checkbox or radio is small and having label gives provision to select it easily.Note: We can always associate multiple labels to a single input control but it is not a good idea as it will impact the accessibility and assistive technologies.<section> along with <fieldset> can be used to separate the functionality in a form and group the same purpose elements like radio buttons.Here is an example of the same.<form action="" method="POST">       <section>         <h2>Contact information</h2>         <fieldset>           <legend>Title</legend>           <ul>               <li>                 <label for="title_1">                   <input type="radio" id="title_1" name="title" value="mr" >                   Mr                 </label>               </li>               <li>                 <label for="title_2">                   <input type="radio" id="title_2" name="title" value="mrs">                   Mrs                 </label>               </li>           </ul>         </fieldset>         <p>           <label for="name">             <span>Name: </span>           </label>           <input type="text" id="name" name="username">         </p>         <p>           <label for="mail">             <span>E-mail: </span>           </label>           <input type="email" id="mail" name="usermail">         </p>         <p>           <label for="pwd">             <span>Password: </span>           </label>           <input type="password" id="pwd" name="password">         </p>       </section>       <section>         <h2>Additional information</h2>         <p>           <label for="socialId">             <span>Social type:</span>           </label>           <select id="socialId" name="socialType">             <option value="linkedIn">LinkedIn</option>             <option value="twitter">Twitter</option>             <option value="instagram">Instagram</option>           </select>         </p>         <p>           <label for="number">             <span>Phone number:</span>           </label>           <input type="tel" id="number" name="phonenumber">         </p>       </section>       <section>         <p>           <button type="submit">Submit</button>         </p>       </section>     </form>Every time you like to create an HTML form you need to start using <form> element and  nesting all the content controls inside it. Most of the assistive technologies and browser plugins can help to discover <form> elements and implement special hooks to make them easier to use.We have already some of the form elements like <form>, <fieldset>, <legend>, <label>, <button>, and <input>. Other common input types are button, checkbox, file, hidden, image, password, radio, reset, submit, and text.Input types.Attributes of Input.Few attributes on <input> element help in validating the data like required, max, maxlength, min, minlength, multiple, pattern, step etc based on their respective type.Also other attributes on <input> of type submit/image like formaction, formmethod, formnovalidate, formenctype etc helps in overriding the form level methods.ValidationBefore submitting the data to the server, it is important to perform some client side validation to avoid unwanted round trips. Client-side validation is needed but it is not a replacement to the server side validation. Advantage of having client side validation is to capture the invalid data and fix it immediately.Some of the important and popular checks which are most commonly used on client areField requiredSpecific data formatEnter valid email addressPassword and more…Let’s build a form with the above validation checks.<form>       <p>         <fieldset>           <legend>Do you have experience in programming ?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>           <!-- While only one radio button in a same-named group can be selected at a time, and therefore only one radio button in a same-named group having the "required" attribute suffices in making a selection a requirement -->           <input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>           <input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</label>         </fieldset>       </p>       <p>         <label for="n1">How many years of experience you have ?</label>         <!-- The pattern attribute can act as a fallback for browsers which              don't implement the number input type but support the pattern attribute. Please note that browsers that support the pattern attribute will make it fail silently when used with a number field. Its usage here acts only as a fallback -->         <input type="number" min="1" max="40" step="1" id="n1" name="experience" pattern="\d+">       </p>       <p>         <label for="t1">What's your programming language?<abbr title="This field is mandatory" aria-label="required">*</abbr></label>         <input type="text" id="t1" name="fruit" list="l1" required                pattern="[Ru]by|[Ja]va|[Ty]peScript|[CS]harp|[Go]|[Sw]ift">         <datalist id="l1">           <option>TypeScript</option>           <option>Java</option>           <option>CSharp</option>           <option>Ruby</option>           <option>Go</option>           <option>Swift</option>         </datalist>       </p>       <p>         <label for="t2">What's your company e-mail address?</label>         <input type="email" id="t2" name="email">       </p>       <p>         <label for="t3">Cover letter</label>         <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>       </p>       <p>         <button>Submit</button>       </p> </form>Say, if we enter an value which is more than 40 in experience field. We should see an inbuilt error as shown below:All these validations and notifications are coming out of the box. Thanks to inbuilt functionality in <input> control. Let’s see how we can perform validation of forms using JavaScript and take control of look and feel of error message.Most browsers support constraint validation API by providing few validation properties on HTML elements like <input>, <select>, <textarea>, <button> etc.validationMessage: we can customize this message if the control value failed validation otherwise it will return an empty string. It is dependent on other constraint i.e. willValidate and isValid.willValidate: If element is validated then it will be true otherwise false.validity: is the validity state of the element and it is dependent on other properties likepatternMatch for specified pattern attribute,tooLong and tooShort are for string fields based on maxLength and minLengthrangeOverflow and rangeUnderflow for numeric fields based on max and min attributestypeMatch for fields which are based on email or url.valid if all the validation constraints are metvalueMissing if the field is set as required.Along with properties, we do also have methods to perform validation like checkValidity() which returns true or false and setCustomValidity(message) is to set the message if the element is considered invalid. Also if the element is invalid then checkValidity will raise an event called invalid Event.Let’s create a simple form and customize the validation message.<form>       <label for="mail">Please enter an email address:</label>       <input type="email" id="mail" name="mail">       <button>Submit</button>     </form>Add a script tag and customize the message as shown below:<script>     const email = document.getElementById("mail");     email.addEventListener("input", function (event) {       if (email.validity.typeMismatch) {         email.setCustomValidity("I am expecting an e-mail address!");       } else {         email.setCustomValidity("");       }     });   </script>Here we are listening to the input event on email field and checking if the validity on the control is valid or not and based on that we are setting the custom message.Here are we relying on inbuilt validation method. Let’s disable the validation at form level by with the help of ‘novalidate’ and take control over validation. This would mean the browser will not perform auto check on validation before sending the data. But still we have access to constraint validation API to perform validation ourself.Refine the above form to add few addition validation like required and minLength etc.<form novalidate>       <label for="mail">         <span>Please enter an email address:</span>         <input type="email" id="mail" name="mail" required minlength="8">         <span class="error" aria-live="polite"></span>       </label>       <div><button>Submit</button></div>     </form>Let’s update the script to handle the validation<script>     const form  = document.getElementsByTagName('form')[0];     const email = document.getElementById('mail');     const emailError = document.querySelector('#mail + span.error');     email.addEventListener('input', function (event) {       // Each time the user types something, we check if the form fields are valid.       if (email.validity.valid) {         // In case there is an error message visible, if the field is valid, we remove the error message.         emailError.textContent = ''; // Reset the content of the message         emailError.className = 'error'; // Reset the visual state of the message       } else {         // If there is still an error, show the correct error         showError();       }     });     form.addEventListener('submit', function (event) {       // if the email field is valid, we let the form submit       if(!email.validity.valid) {         // If it isn't, we display an appropriate error message         showError();         // Then we prevent the form from being sent by cancelling the event         event.preventDefault();       }     });     function showError() {       if(email.validity.valueMissing) {         // If the field is empty display the following error message.         emailError.textContent = 'You need to enter an e-mail address.';       } else if(email.validity.typeMismatch) {         // If the field doesn't contain an email address display the following error message.         emailError.textContent = 'Invalid value is entered, expected an e-mail address.';       } else if(email.validity.tooShort) {         // If the data is too short display the following error message.         emailError.textContent = Email should be at least ${ email.minLength } characters; you entered${ email.value.length }.;       }       // Set the styling appropriately       emailError.className = 'error active';     } </script>Reload the HTML and try entering an invalid email address, the corresponding error message should be displayed.Note: In the current scope of this blog, we are not working on styling.Is it possible to validate forms without built in APIs ? Let’s see with the same example.We would consider the same form again but have lot of functionality in <script><form>       <p>         <label for="mail">             <span>Please enter an email address:</span>             <input type="text" id="mail" name="mail">             <span class="error" aria-live="polite"></span>         </label>       </p>       <button type="submit">Submit</button>     </form>   <script>     const form  = document.getElementsByTagName('form')[0];     const email = document.getElementById('mail');     let error = email.nextElementSibling;     const emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;     function addEvent(element, event, callback) {       let previousEventCallBack = element["on"+event];       element["on"+event] = function (e) {         const output = callback(e);         // A callback that returns false stops the callback chain and interrupts the execution of the event callback.         if (output === false) return false;         if (typeof previousEventCallBack === 'function') {           output = previousEventCallBack(e);           if(output === false) return false;         }       }     };     // Now we can rebuild our validation constraint. Because we do not rely on CSS pseudo-class, we have to explicitly set the valid/invalid class on our email field     addEvent(window, "load", function () {       // Here, we test if the field is empty (remember, the field is not required)       // If it is not, we check if its content is a well-formed e-mail address.       const test = email.value.length === 0 || emailRegExp.test(email.value);       email.className = test ? "valid" : "invalid";     });     // This defines what happens when the user types in the fiel     addEvent(email, "input", function () {       const test = email.value.length === 0 || emailRegExp.test(email.value);       if (test) {         email.className = "valid";         error.textContent = "";         error.className = "error";       } else {         email.className = "invalid";       }     });     // This defines what happens when the user tries to submit the data     addEvent(form, "submit", function () {       const test = email.value.length === 0 || emailRegExp.test(email.value);       if (!test) {         email.className = "invalid";         error.textContent = "Expecting an e-mail";         error.className = "error active";         return false;       } else {         email.className = "valid";         error.textContent = "";         error.className = "error";       }     });   </script>On refreshing the page, the output with invalid email address should be displayed as shown below.In real time applications, we can rely on existing libraries like Parsley along with JQuery which would ease our life by taking away lot of complexity.Overview of Parsley:Parsley is a front-end javascript validation library which helps to give proper feedback to user on submission of form. As mentioned earlier, it is not a replacement of server side validation. Parsley library helps us to define our own validation.Parsley uses a DOM API namely ‘data-parsley-’ prefix on the existing properties. For example if we want to add this on a property say ‘sample’ then we would add as [data-parsley-sample=’value’]. This will allow us to configure pretty much everything without any configuration or custom function.There is no specific installation process but adding the corresponding script tags will enable the validation. Parsley is relied on Jquery so it has to be included as well.<script src="jquery.js"></script>     <script src="parsley.min.js"></script>     <form data-parsley-validate>     ...     </form>      <script>       $('#form').parsley(); </script>Assumption is that we have downloaded the Jquery and Parsley minified librarie and added it to our working directory. Otherwise we can refer to CDN location as shown below.<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/parsley.js/2.9.2/parsley.min.js"></script>Adding attribute ‘data-parsley-validate’ to each form will allow us to validate. And “$(‘#form’).parsley()” will manually bind Parsley to your forms.Let’s understand further by configuring the attributes via JavaScript. For which, lets add two input fields inside the form element.<form data-parsley-validate>       <input id="first" data-parsley-maxlength="42" value="hello"/>       <input id="second" value="world"/>     </form>Also let’s update the <script> content to perform some pre-defined validation based on attributes.<script>       var instance = $('#first').parsley(); console.log(instance.isValid()); // maxlength is 42, so field is valid$('#first').attr('data-parsley-maxlength', 4);       console.log(instance.isValid()); // No longer valid, as maxlength is 4       // You can access and override options in javascript too:       instance.options.maxlength++;       console.log(instance.isValid()); // Back to being valid, as maxlength is 5       // Alternatively, the options can be specified as:       var otherInstance = $('#second').parsley({ maxlength: 10 }); console.log(otherInstance.options); </script>In the console.log, we should see thistrue false true {maxlength: 10}Options are inherited from the global level to form level and further to field. So if we set the options at global level then the same can be observed at field level.<form data-parsley-validate> <input/> </form> Parsley.options.maxlength = 42; // maxlength of 42 is declared at global level var formInstance =$('form').parsley(); var field = $('input').parsley(); console.log(field.options.maxlength); // Shows that maxlength is 42 inherited from global Parsley.options.maxlength = 30; console.log(field.options.maxlength); // Shows that maxlength is automatically 30 formInstance.options.maxlength++; console.log(field.options.maxlength); // Shows that maxlength is automatically 31We can also add our own custom validations. Let understand this with an example.<form data-parsley-validate> <input type="text" data-parsley-multiple-of="3" /> </form> <script> window.Parsley.addValidator('multipleOf', { requirementType: 'integer', validateNumber: function(value, requirement) { return 0 === value % requirement; }, messages: { en: 'This value should be a multiple of %s', } }); </script>Here we are adding a new attribute namely ‘data-parsley-multiple-of’ which takes only numeric values which are multiples of 3.In window.Parsley, we added a new validator with name ‘multiple-of’ with an object containing few important properties like ‘requirementType’, ‘validateNumber’ and ‘messages’ to be shown. This properties helps the library to check if the input value is valid or not.Similar to validateNumber, other properties are also there for different types like validateString, validateDate and validateMultiple.Also for requirementType, we have different options like string, number, date, regexp, boolean etc.Messages by default has English format, to support multiple locales we need to add the specific localization and also add specific locale.Events: Parsley triggers events that allows ParsleyUI to work and for performance reasons they don’t rely on JQuery events but the usage is similar to JQuery i.e. parsley events will also bubble up like JQuery events. For example, if a field is validated then the event ‘field:validate’ will be triggred on the field instance then on to form instance and finally to the window.Parsley.$('#some-input').parsley().on('field:success', function() {         // In here, this is the parlsey instance of #some-input       });       window.Parsley.on('field:error', function() {         // This global callback will be called for any field that fails validation.         console.log('Validation failed for: ', this.$element); });Many times, we need some validation based on the response from server. Parsley provides an attributes i.e. data-parsley-remote and data-parsley-remote-validator to perform the same.Let’s consider this HTML<input name="q" type="text" data-parsley-remote data-parsley-remote-validator='customValidator' value="test" />Let’s add the async validator on the window.Parsley object.window.Parsley.addAsyncValidator('customValidator', function (xhr) { console.log(this.$element); // jQuery Object[ input[name="q"] ]           return 404 === xhr.status;         }, 'customURL');Parsley is a very useful and powerful JavaScript form frontend validation library.Note: For developers building react based web applications, they can rely on FORMIK which is most popular library for building forms in React and React Native.ConclusionForms are important in HTML and it was needed and still needed now. <form> is an html tag that allow us to perform HTTP methods like GET/POST operation without writing any code in JavaScript. Form defines an boundary to identify all set of the form field elements to be submitted to the server. For example, if we perform an enter key or clicking on submit button , the agent triggers form submission data based on each form field value to the server based on the action URL on the form.Before HTML5, all the elements are expected to be part of the <form> to send the data to server. In HTML5, they maintained the backward compatibility and also enhanced the capabilities who may want to use AJAX and don’t want to rely on default behaviours i.e. they have enabled designers who expect more flexibility in having their form elements outside the form and still maintain the connections with the form.

How to Work With Forms In JavaScript

2K

Forms also referred as web forms are a very important part of front end web application development for sake of interaction with users. Most commonly, forms are used to collect the data from users or provide a provision for user to control the user interface. Forms are great potential assets if correctly used in building an interactive web application. We would be touch basing some of the essential aspects of them like HTML structure, styling form controls, events, data validation and submitting data to server.

Understanding forms in detail needs expertise in other areas than just HTML like styling form controls (CSS), scripting to validate or create custom controls (JavaScript).

We would be referring or using libraries like Jquery (for document traversal, manipulation etc) and parsley (form validation library) to build better forms.

A typical form’s HTML is made of HTML elements called as form controls like single or multiline text fields, dropdowns, checkboxes, button etc mostly created using <input> element with specific type being set on Type attribute. These form controls can be programmed to add some validations to support specific values based on constraints set on them. These controls can be enriched to support accessibility for enabling the interaction for less privileged users.

Let’s create a simple html page to build a form.

<!DOCTYPE html>
<html lang="en-US">
<meta charset="utf-8">
<title>Learning Forms</title>
<body>
</body>
</html>

All forms have to start with <form> element which is container having the form fields user would interact with. All attributes of <form> element are optional but for programming forms to capture data we need at least ‘action’ and ‘method’ attributes.

action – is basically the URL where the form fields data would be sent to.

method – corresponds to the HTTP method to submit the form data. Possible HTTP method names which can be set as values are post and get. And another value dialog is set when form is imbedded inside a <dialog>.

Note: Both formaction and formmethod can be overridden by button, input with type submit elements which we will learn as we go forward.

Let’s add a form element to our body with action (“”) and method(“get”). This implies that form will send a GET request to the current URL. If it is post then it would be a POST request to the URL in action.

<form action="" method="get">
</form>

Add few fields to form say name, email and a submit button using <input> with type being specified as text, email and submit respectively.

Note: The <input> tag is an empty element, meaning that it doesn't need a closing tag. Value attribute can be populated to set the default value.

<form action="" method="get">
<div>
<input type="text" name="name" id="name">
</div>
<div>
<input type="email" name="email" id="email">
</div>
<div>
<input type="submit" value="Click me!">
</div>
</form>

Save and open the html in chrome or your preferred browser. Clicking on ‘Click me!’ should send a http get call with empty name and email.

Note: We can use <button> instead of <input> with type as submit. The difference is that button can contain HTML content allowing to create a complex button whereas input allows only plain text.

Let’s understand the Sending of form data.

If we observer all the form fields again, we have added an attribute called ‘name’. This property is important to inform that which data is associated with which form field i.e. name/value pairs. Try adding some data to our fields rendering in html (say myName and first.last@email.com) and click submit button. You should see the data being sent as query parameters in the browser URL.

?name=myName&email=first.last@email.com.

Change the Form method value to POST instead of GET and send the submitted data by clicking the ‘Click me!’ button. You should be seeing Form Data being sent but the browser URL will not get update.

name: myName
email: first.last@email.com

All this while, we have our action method being set as empty. Replace this with another URL on server side say ‘/captureFormData’. Now on clicking submit button the data should be received by the script at ‘/captureFormData’ with key/value items contained in the HTTP request object.

Note that each server-side language like Node.js, C# etc have their own way of handling the submitted form data. And this blog would not cover those topics and it is beyond the scope.

Let’s refine our basic form structure with help of other HTML elements like <fieldset>, <legend>, <label> etc. Though we used few of them in basic example. Let’s go little deep on them.

Note: Nesting of form inside another form is unacceptable as it might result in unpredictable behavior.

<fieldset> is a convenient way of grouping for sake of styling and semantic purpose. This control can be associated with <legend> so that some assistive technologies can read this legend and associate it with the controls inside the <fieldset>. Let’s understand this will an example:

<fieldset>
<legend>Interested programming language</legend>
<p>
<label for="js">JavaScript</label>
</p>
<p>
<label for="csharp">CSharp</label>
</p>
<p>
<label for="java">Java</label>
</p>
</fieldset>

When reading the above form by any screen readers, it will read as “Interested programming language JavaScript” for the first radio, “Interested programming language CSharp” and “Interested programming language Java” for second and third radio.

Imagine if you have a long form with multiple fields. It would help to improve the usability if we can categorize/section them with the help of <fieldset>. It would even help to improve the accessibility of forms.

Talking about accessibility, with the <label> associated correctly with the <input> via its for attribute (which contains the <input> element's id attribute), a screenreader will read out something like "name, edit text" for below one.

<label for="name">Enter your name: </label>
<input type="text" name="name" id="name">

Another advantage of having label associated with input of type text, radio etc is they are clickable too.  If you click on a label then the associated input control will get the focus. If the input control is of type checkbox or radio, clicking on label will select the check box and radio. This will be useful as clickable area of checkbox or radio is small and having label gives provision to select it easily.

Note: We can always associate multiple labels to a single input control but it is not a good idea as it will impact the accessibility and assistive technologies.

<section> along with <fieldset> can be used to separate the functionality in a form and group the same purpose elements like radio buttons.

Here is an example of the same.

<form action="" method="POST">
<section>
<h2>Contact information</h2>
<fieldset>
<legend>Title</legend>
<ul>
<li>
<label for="title_1">
<input type="radio" id="title_1" name="title" value="mr" >
Mr
</label>
</li>
<li>
<label for="title_2">
Mrs
</label>
</li>
</ul>
</fieldset>
<p>
<label for="name">
<span>Name: </span>
</label>
</p>
<p>
<label for="mail">
<span>E-mail: </span>
</label>
<input type="email" id="mail" name="usermail">
</p>
<p>
<label for="pwd">
</label>
</p>
</section>
<section>
<p>
<label for="socialId">
<span>Social type:</span>
</label>
<select id="socialId" name="socialType">
<option value="instagram">Instagram</option>
</select>
</p>
<p>
<label for="number">
<span>Phone number:</span>
</label>
<input type="tel" id="number" name="phonenumber">
</p>
</section>
<section>
<p>
<button type="submit">Submit</button>
</p>
</section>
</form>

Every time you like to create an HTML form you need to start using <form> element and  nesting all the content controls inside it. Most of the assistive technologies and browser plugins can help to discover <form> elements and implement special hooks to make them easier to use.

We have already some of the form elements like <form>, <fieldset>, <legend>, <label>, <button>, and <input>. Other common input types are button, checkbox, file, hidden, image, password, radio, reset, submit, and text.

Few attributes on <input> element help in validating the data like required, max, maxlength, min, minlength, multiple, pattern, step etc based on their respective type.

Also other attributes on <input> of type submit/image like formaction, formmethod, formnovalidate, formenctype etc helps in overriding the form level methods.

Validation

Before submitting the data to the server, it is important to perform some client side validation to avoid unwanted round trips. Client-side validation is needed but it is not a replacement to the server side validation. Advantage of having client side validation is to capture the invalid data and fix it immediately.

Some of the important and popular checks which are most commonly used on client are

• Field required
• Specific data format

Let’s build a form with the above validation checks.

<form>
<p>
<fieldset>
<legend>Do you have experience in programming ?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>
<!-- While only one radio button in a same-named group can be selected at a time, and therefore only one radio button in a same-named group having the "required" attribute suffices in making a selection a requirement -->
<input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>
<input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</label>
</fieldset>
</p>
<p>
<label for="n1">How many years of experience you have ?</label>
<!-- The pattern attribute can act as a fallback for browsers which
don't implement the number input type but support the pattern attribute. Please note that browsers that support the pattern attribute will make it fail silently when used with a number field. Its usage here acts only as a fallback -->
<input type="number" min="1" max="40" step="1" id="n1" name="experience" pattern="\d+">
</p>
<p>
<label for="t1">What's your programming language?<abbr title="This field is mandatory" aria-label="required">*</abbr></label>
<input type="text" id="t1" name="fruit" list="l1" required
pattern="[Ru]by|[Ja]va|[Ty]peScript|[CS]harp|[Go]|[Sw]ift">
<datalist id="l1">
<option>TypeScript</option>
<option>Java</option>
<option>CSharp</option>
<option>Ruby</option>
<option>Go</option>
<option>Swift</option>
</datalist>
</p>
<p>
<input type="email" id="t2" name="email">
</p>
<p>
<label for="t3">Cover letter</label>
<textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
</p>
<p>
<button>Submit</button>
</p>
</form>

Say, if we enter an value which is more than 40 in experience field. We should see an inbuilt error as shown below:

All these validations and notifications are coming out of the box. Thanks to inbuilt functionality in <input> control. Let’s see how we can perform validation of forms using JavaScript and take control of look and feel of error message.

Most browsers support constraint validation API by providing few validation properties on HTML elements like <input>, <select>, <textarea>, <button> etc.

• validationMessage: we can customize this message if the control value failed validation otherwise it will return an empty string. It is dependent on other constraint i.e. willValidate and isValid.
• willValidate: If element is validated then it will be true otherwise false.
• validity: is the validity state of the element and it is dependent on other properties like
• patternMatch for specified pattern attribute,
• tooLong and tooShort are for string fields based on maxLength and minLength
• rangeOverflow and rangeUnderflow for numeric fields based on max and min attributes
• typeMatch for fields which are based on email or url.
• valid if all the validation constraints are met
• valueMissing if the field is set as required.

Along with properties, we do also have methods to perform validation like checkValidity() which returns true or false and setCustomValidity(message) is to set the message if the element is considered invalid. Also if the element is invalid then checkValidity will raise an event called invalid Event.

Let’s create a simple form and customize the validation message.

<form>
<input type="email" id="mail" name="mail">
<button>Submit</button>
</form>

Add a script tag and customize the message as shown below:

<script>
const email = document.getElementById("mail");
if (email.validity.typeMismatch) {
email.setCustomValidity("I am expecting an e-mail address!");
} else {
email.setCustomValidity("");
}
});
</script>

Here we are listening to the input event on email field and checking if the validity on the control is valid or not and based on that we are setting the custom message.

Here are we relying on inbuilt validation method. Let’s disable the validation at form level by with the help of ‘novalidate’ and take control over validation. This would mean the browser will not perform auto check on validation before sending the data. But still we have access to constraint validation API to perform validation ourself.

Refine the above form to add few addition validation like required and minLength etc.

<form novalidate>
<label for="mail">
<input type="email" id="mail" name="mail" required minlength="8">
<span class="error" aria-live="polite"></span>
</label>
<div><button>Submit</button></div>
</form>

Let’s update the script to handle the validation

<script>
const form  = document.getElementsByTagName('form')[0];
const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.error');
// Each time the user types something, we check if the form fields are valid.
if (email.validity.valid) {
// In case there is an error message visible, if the field is valid, we remove the error message.
emailError.textContent = ''; // Reset the content of the message
emailError.className = 'error'; // Reset the visual state of the message
} else {
// If there is still an error, show the correct error
showError();
}
});
// if the email field is valid, we let the form submit
if(!email.validity.valid) {
// If it isn't, we display an appropriate error message
showError();
// Then we prevent the form from being sent by cancelling the event
event.preventDefault();
}
});
function showError() {
if(email.validity.valueMissing) {
// If the field is empty display the following error message.
emailError.textContent = 'You need to enter an e-mail address.';
} else if(email.validity.typeMismatch) {
// If the field doesn't contain an email address display the following error message.
emailError.textContent = 'Invalid value is entered, expected an e-mail address.';
} else if(email.validity.tooShort) {
// If the data is too short display the following error message.
emailError.textContent = Email should be at least ${ email.minLength } characters; you entered${ email.value.length }.;
}
// Set the styling appropriately
emailError.className = 'error active';
}
</script>

Reload the HTML and try entering an invalid email address, the corresponding error message should be displayed.

Note: In the current scope of this blog, we are not working on styling.

Is it possible to validate forms without built in APIs ? Let’s see with the same example.

We would consider the same form again but have lot of functionality in <script>

<form>
<p>
<label for="mail">
<input type="text" id="mail" name="mail">
<span class="error" aria-live="polite"></span>
</label>
</p>
<button type="submit">Submit</button>
</form>
<script>
const form  = document.getElementsByTagName('form')[0];
const email = document.getElementById('mail');
let error = email.nextElementSibling;
const emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
let previousEventCallBack = element["on"+event];
element["on"+event] = function (e) {
const output = callback(e);
// A callback that returns false stops the callback chain and interrupts the execution of the event callback.
if (output === false) return false;
if (typeof previousEventCallBack === 'function') {
output = previousEventCallBack(e);
if(output === false) return false;
}
}
};
// Now we can rebuild our validation constraint. Because we do not rely on CSS pseudo-class, we have to explicitly set the valid/invalid class on our email field
// Here, we test if the field is empty (remember, the field is not required)
// If it is not, we check if its content is a well-formed e-mail address.
const test = email.value.length === 0 || emailRegExp.test(email.value);
email.className = test ? "valid" : "invalid";
});
// This defines what happens when the user types in the fiel
const test = email.value.length === 0 || emailRegExp.test(email.value);
if (test) {
email.className = "valid";
error.textContent = "";
error.className = "error";
} else {
email.className = "invalid";
}
});
// This defines what happens when the user tries to submit the data
const test = email.value.length === 0 || emailRegExp.test(email.value);
if (!test) {
email.className = "invalid";
error.textContent = "Expecting an e-mail";
error.className = "error active";
return false;
} else {
email.className = "valid";
error.textContent = "";
error.className = "error";
}
});
</script>

On refreshing the page, the output with invalid email address should be displayed as shown below.

In real time applications, we can rely on existing libraries like Parsley along with JQuery which would ease our life by taking away lot of complexity.

Overview of Parsley:

Parsley is a front-end javascript validation library which helps to give proper feedback to user on submission of form. As mentioned earlier, it is not a replacement of server side validation. Parsley library helps us to define our own validation.

Parsley uses a DOM API namely ‘data-parsley-’ prefix on the existing properties. For example if we want to add this on a property say ‘sample’ then we would add as [data-parsley-sample=’value’]. This will allow us to configure pretty much everything without any configuration or custom function.

There is no specific installation process but adding the corresponding script tags will enable the validation. Parsley is relied on Jquery so it has to be included as well.

<script src="jquery.js"></script>
<script src="parsley.min.js"></script>
<form data-parsley-validate>
...
</form>
<script>
$('#form').parsley(); </script> Assumption is that we have downloaded the Jquery and Parsley minified librarie and added it to our working directory. Otherwise we can refer to CDN location as shown below. <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/parsley.js/2.9.2/parsley.min.js"></script> Adding attribute ‘data-parsley-validate’ to each form will allow us to validate. And “$(‘#form’).parsley()” will manually bind Parsley to your forms.

Let’s understand further by configuring the attributes via JavaScript. For which, lets add two input fields inside the form element.

<form data-parsley-validate>
<input id="first" data-parsley-maxlength="42" value="hello"/>
<input id="second" value="world"/>
</form>

Also let’s update the <script> content to perform some pre-defined validation based on attributes.

<script>
var instance = $('#first').parsley(); console.log(instance.isValid()); // maxlength is 42, so field is valid$('#first').attr('data-parsley-maxlength', 4);
console.log(instance.isValid()); // No longer valid, as maxlength is 4
// You can access and override options in javascript too:
instance.options.maxlength++;
console.log(instance.isValid()); // Back to being valid, as maxlength is 5
// Alternatively, the options can be specified as:
var otherInstance = $('#second').parsley({ maxlength: 10 }); console.log(otherInstance.options); </script> In the console.log, we should see this true false true {maxlength: 10} Options are inherited from the global level to form level and further to field. So if we set the options at global level then the same can be observed at field level. <form data-parsley-validate> <input/> </form> Parsley.options.maxlength = 42; // maxlength of 42 is declared at global level var formInstance =$('form').parsley();
var field = $('input').parsley(); console.log(field.options.maxlength); // Shows that maxlength is 42 inherited from global Parsley.options.maxlength = 30; console.log(field.options.maxlength); // Shows that maxlength is automatically 30 formInstance.options.maxlength++; console.log(field.options.maxlength); // Shows that maxlength is automatically 31 We can also add our own custom validations. Let understand this with an example. <form data-parsley-validate> <input type="text" data-parsley-multiple-of="3" /> </form> <script> window.Parsley.addValidator('multipleOf', { requirementType: 'integer', validateNumber: function(value, requirement) { return 0 === value % requirement; }, messages: { en: 'This value should be a multiple of %s', } }); </script> Here we are adding a new attribute namely ‘data-parsley-multiple-of’ which takes only numeric values which are multiples of 3. In window.Parsley, we added a new validator with name ‘multiple-of’ with an object containing few important properties like ‘requirementType’, ‘validateNumber’ and ‘messages’ to be shown. This properties helps the library to check if the input value is valid or not. Similar to validateNumber, other properties are also there for different types like validateString, validateDate and validateMultiple. Also for requirementType, we have different options like string, number, date, regexp, boolean etc. Messages by default has English format, to support multiple locales we need to add the specific localization and also add specific locale. Events: Parsley triggers events that allows ParsleyUI to work and for performance reasons they don’t rely on JQuery events but the usage is similar to JQuery i.e. parsley events will also bubble up like JQuery events. For example, if a field is validated then the event ‘field:validate’ will be triggred on the field instance then on to form instance and finally to the window.Parsley. $('#some-input').parsley().on('field:success', function() {
// In here, this is the parlsey instance of #some-input
});
window.Parsley.on('field:error', function() {
// This global callback will be called for any field that fails validation.
console.log('Validation failed for: ', this.$element); }); Many times, we need some validation based on the response from server. Parsley provides an attributes i.e. data-parsley-remote and data-parsley-remote-validator to perform the same. Let’s consider this HTML <input name="q" type="text" data-parsley-remote data-parsley-remote-validator='customValidator' value="test" /> Let’s add the async validator on the window.Parsley object. window.Parsley.addAsyncValidator('customValidator', function (xhr) { console.log(this.$element); // jQuery Object[ input[name="q"] ]
return 404 === xhr.status;
}, 'customURL');

Parsley is a very useful and powerful JavaScript form frontend validation library.

Note: For developers building react based web applications, they can rely on FORMIK which is most popular library for building forms in React and React Native.

Conclusion

Forms are important in HTML and it was needed and still needed now. <form> is an html tag that allow us to perform HTTP methods like GET/POST operation without writing any code in JavaScript.

Form defines an boundary to identify all set of the form field elements to be submitted to the server. For example, if we perform an enter key or clicking on submit button , the agent triggers form submission data based on each form field value to the server based on the action URL on the form.

Before HTML5, all the elements are expected to be part of the <form> to send the data to server. In HTML5, they maintained the backward compatibility and also enhanced the capabilities who may want to use AJAX and don’t want to rely on default behaviours i.e. they have enabled designers who expect more flexibility in having their form elements outside the form and still maintain the connections with the form.

KnowledgeHut

Author

KnowledgeHut is an outcome-focused global ed-tech company. We help organizations and professionals unlock excellence through skills development. We offer training solutions under the people and process, data science, full-stack development, cybersecurity, future technologies and digital transformation verticals.
Website : https://www.knowledgehut.com

Handling React Events - A Detailed Guide

5355
Handling React Events - A Detailed Guide

Event handling essentially allows the user to inte... Read More

MongoDB Query Document Using Find() With Example

MongoDB's find() method selects documents from a collection or view and returns a cursor to those documents. There are two parameters in this formula: query and projection.Query – This is an optional parameter that specifies the criteria for selection. In simple terms, a query is what you want to search for within a collection.Projection – This is an optional parameter that specifies what should be returned if the query criteria are satisfied. In simple terms, it is a type of decision-making that is based on a set of criteria.MongoDB's Flexible SchemaA NoSQL database, which stands for "not only SQL," is a way of storing and retrieving data that is different from relational databases' traditional table structures (RDBMS).When storing large amounts of unstructured data with changing schemas, NoSQL databases are indeed a better option than RDBMS. Horizontal scaling properties of NoSQL databases allow them to store and process large amounts of data.These are intended for storing, retrieving, and managing document-oriented data, which is frequently stored in JSON format (JavaScript Object Notation). Document databases, unlike RDBMSs, have a flexible schema that is defined by the contents of the documents.MongoDB is one of the most widely used open-source NoSQL document databases. MongoDB is known as a 'schemaless' database because it does not impose a specific structure on documents in a collection.MongoDB is compatible with a number of popular programming languages. It also offers a high level of operational flexibility because it scales well horizontally, allowing data to be spread or 'sharded' across multiple commodity servers with the ability to add more servers as needed. MongoDB can be run on a variety of platforms, including developer laptops, private clouds, and public clouds.Querying documents using find()MongoDB queries are used to retrieve or fetch data from a MongoDB database. When running a query, you can use criteria or conditions to retrieve specific data from the database.The function db.collection is provided by MongoDB. find() is a function that retrieves documents from a MongoDB database.In MongoDB, the find method is used to retrieve a specific document from the MongoDB collection. In Mongo DB, there are a total of six methods for retrieving specific records.find()findAndModify()findOne()findOneAndDelete()findOneAndReplace()findOneAndUpdate()Syntax:find(query, projection)We can fetch a specific record using the Find method, which has two parameters. If these two parameters are omitted, the find method will return all of the documents in the MongoDB collection.Example:Consider an example of employees with the database of employee_id and employee_name and we will fetch the documents using find() method.First, create a database with the name “employees” with the following code:use employeesNow, create a collection “employee” with:db.createCollection("employee")In the next step we will insert the documents in the database:db.employee.insert([{employee_id: 101, employee_name: "Ishan"}, {employee_id: 102, employee_name: "Bhavesh"}, {employee_id: 103, employee_name: "Madan"}])Find all Documents:To get all the records in a collection, we need to use the find method with an empty parameter. In other words, when we need all the records, we will not use any parameters.db.employee.find()Output in Mongo ShellThe pretty() method can be used to display the results in a formatted manner.Syntax:db.COLLECTION_NAME.find().pretty()Let’s check our documents with pretty() method:Query FiltersWe will see examples of query operations using the db.collection.find() method in mongosh.We will use the employee collection in the employees database.db.employee.insert([{employee_id: 101, employee_name: "Ishan", age: 21, email_id: "ishanjain@gmail.com"}, {employee_id: 102, employee_name: "Bhavesh", age: 22, email_id: "bhaveshg@gmail.com"}, {employee_id: 103, employee_name: "Madan", age: 23, email_id: "madan@gmail.com"}])As we have seen earlier that to select all the documents in the database we pass an empty document as the query filter parameter to the find method.db.employee.find().pretty()Find the first document in a collection:db.employee.findOne()Find a document by ID:db.employee.findOne({_id : ObjectId("61d1ae0b56b92c20b423a5a7")})Find Documents that Match Query Criteriadb.employee.find({“age”: “22”})db.employee.find({"employee_name": "Madan"}).pretty()Sort Results by a Field:db.employee.find().sort({age: 1}).pretty()order by age, in ascending orderdb.employee.find().sort({age: -1}).pretty()order by age, in descending orderAND Conditions:A compound query can specify conditions for multiple fields in the documents in a collection. A logical AND conjunction connects the clauses of a compound query indirectly, allowing the query to select all documents in the collection that meet the specified conditions.In the following example, we will consider all the documents in the employee collection where employee_id equals 101 and age equals 21.db.employee.find({"employee_id": 101, "age": "21" }).pretty()Querying nested fieldsThe embedded or nested document feature in MongoDB is a useful feature. Embedded documents, also known as nested documents, are documents that contain other documents.You can simply embed a document inside another document in MongoDB. Documents are defined in the mongo shell using curly braces (), and field-value pairs are contained within these curly braces.Using curly braces, we can now embed or set another document inside these fields, which can include field-value pairs or another sub-document.Syntax:{ field: { field1: value1, field2: value2 } }Example:We have a database “nested” and in this database we have collection “nesteddoc”.The following documents will insert into the nesteddoc collection.db.nesteddoc.insertMany([ { "_id" : 1, "dept" : "A", "item" : { "sku" : "101", "color" : "red" }, "sizes" : [ "S", "M" ] }, { "_id" : 2, "dept" : "A", "item" : { "sku" : "102", "color" : "blue" }, "sizes" : [ "M", "L" ] }, { "_id" : 3, "dept" : "B", "item" : { "sku" : "103", "color" : "blue" }, "sizes" : "S" }, { "_id" : 4, "dept" : "A", "item" : { "sku" : "104", "color" : "black" }, "sizes" : [ "S" ] } ])Place the documents in the collection now. Also, take a look at the results:As a result, the nesteddoc collection contains four documents, each of which contains nested documents. The find() method can be used to access the collection's documents.db.nesteddoc.find()Specify Equality Condition:In this example, we will select the document from the nesteddoc query where dept equals “A”.db.nesteddoc.find({dept: "A"})Querying ArraysUse the query document {: } to specify an equality condition on an array, where is the exact array to match, including the order of the elements.The following query looks for all documents where the field tags value is an array with exactly two elements, "S" and "M," in the order specified:db.nesteddoc.find( { sizes: ["S", "M"] } )Use the $all operator to find an array that contains both the elements "S" and "M," regardless of order or other elements in the array:db.nested.find( { sizes: {$all: ["S", "M"] } } )Query an Array for an Element:The following example queries for all documents where size is an array that contains the string “S” as one of its elements:db.nesteddoc.find( { sizes: "S" } )Filter conditionsTo discuss the filter conditions, we will consider a situation that elaborates this. We will start by creating a collection with the name “products” and then add the documents to it.db.products.insertMany([ { _id: 1, item: { name: "ab", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }, { _id: 2, item: { name: "cd", code: "123" }, qty: 20, tags: [ "B" ] }, { _id: 3, item: { name: "ij", code: "456" }, qty: 25, tags: [ "A", "B" ] }, { _id: 4, item: { name: "xy", code: "456" }, qty: 30, tags: [ "B", "A" ] }, { _id: 5, item: { name: "mn", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }])To check the documents, use db.products.find():$gt$gt selects documents with a field value greater than (or equal to) the specified value.db.products.find( { qty: { $gt: “20” } } )$gte:$gte finds documents in which a field's value is greater than or equal to (i.e. >=) a specified value (e.g. value.)db.products.find( { qty: {$gte: 20 } } )$lt:$lt selects documents whose field value is less than (or equal to) the specified value.db.products.find( { qty: { $lt: 25 } } )$lte:$lte selects documents in which the field's value is less than or equal to (i.e. =) the specified value.db.products.find( { qty: {$lte: 20 } } )Query an Array by Array Length:To find arrays with a specific number of elements, use the $size operator. For example, the following selects documents with two elements in the array.db.products.find( { "tags": {$size: 2} } )ProjectionIn MongoDB, projection refers to selecting only the data that is required rather than the entire document's data. If a document has five fields and you only want to show three of them, select only three of them.The find() method in MongoDB accepts a second optional parameter, which is a list of fields to retrieve, as explained in MongoDB Query Document. When you use the find() method in MongoDB, it displays all of a document's fields. To prevent this, create a list of fields with the values 1 or 0. The value 1 indicates that the field should be visible, while 0 indicates that it should be hidden.Syntax:db.COLLECTION_NAME.find({},{KEY:1})Example:We will consider the previous example of products collection. Run the below command on mongoshell to learn how projection works:db.products.find({},{"tags":1, _id:0})Keep in mind that the _id field is always displayed while executing the find() method; if you do not want this field to be displayed, set it to 0.Optimized FindingsTo retrieve a document from a MongoDB collection, use the Find method.Using the Find method, we can retrieve specific documents as well as the fields that we require. Other find methods can also be used to retrieve specific documents based on our needs.By inserting array elements into the query, we can retrieve specific elements or documents. To retrieve data for array elements from the collection in MongoDB, we can use multiple query operators.
6495
MongoDB Query Document Using Find() With Example

MongoDB's find() method selects documents from a c... Read More

Implementing MongoDb Map Reduce using Aggregation

Algorithms and applications in today's data-driven market collect data about people, processes, systems, and organisations 24 hours a day, seven days a week, resulting in massive amounts of data. The problem is figuring out how to process this massive amount of data efficiently without sacrificing valuable insights.What is Map Reduce? The MapReduce programming model comes to the rescue here. MapReduce, which was first used by Google to analyse its search results, has grown in popularity due to its ability to split and process terabytes of data in parallel, generating results faster. A (Key,value) pair is the basic unit of information in MapReduce. Before feeding the data to the MapReduce model, all types of structured and unstructured data must be translated to this basic unit. The MapReduce model, as the name implies, consists of two distinct routines: the Map-function and the Reduce-function.  MapReduce is a framework for handling parallelizable problems across huge files using a huge number of devices (nodes), which are collectively referred to as a cluster (if all nodes are on the same local network and use similar hardware) or a grid (if the nodes are shared across geographically and administratively distributed systems, and use more heterogeneous hardware).  When data stored in a filesystem (unstructured) or a database(structured) is processed, MapReduce can take advantage of data's locality, processing it close to where it's stored to reduce communication costs. Typically, a MapReduce framework (or system) consists of three operations: Map: Each worker node applies the map function to local data and saves the result to a temporary storage. Only one copy of the redundant input data is processed by a master node. Shuffle: worker nodes redistribute data based on output keys (produced by the map function), ensuring that all data associated with a single key is stored on the same worker node. Reduce: each group of output data is now processed in parallel by worker nodes, per key. This article will walk you through the Map-Reduce model's functionality step by step. Map Reduce in MongoDB The map-reduce operation has been deprecated since MongoDB 5.0. An aggregation pipeline outperforms a map-reduce operation in terms of performance and usability. Aggregation pipeline operators like $group,$merge, and others can be used to rewrite map-reduce operations. Starting with version 4.4, MongoDB provides the $accumulator and$function aggregation operators for map-reduce operations that require custom functionality. In JavaScript, use these operators to create custom aggregation expressions. The map and reduce functions are the two main functions here. As a result, the data is independently mapped and reduced in different spaces before being combined in the function and saved to the specified new collection. This mapReduce() function was designed to work with large data sets only. You can perform aggregation operations like max and avg on data using Map Reduce, which is similar to groupBy in SQL. It works independently and in parallel on data. Implementing Map Reduce with Mongosh (MongoDB Shell)  The db.collection.mapReduce() method in mongosh is a wrapper for the mapReduce command. The examples that follow make use of the db.collection.mapReduce(). Example: Create a collection ‘orders’ with these documents: db.orders.insertMany([     { _id: 1, cust_id: "Ishan Jain", ord_date: new Date("2021-11-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" },     { _id: 2, cust_id: "Ishan Jain", ord_date: new Date("2021-11-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" },     { _id: 3, cust_id: "Bhavesh Galav", ord_date: new Date("2021-11-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" },     { _id: 4, cust_id: "Bhavesh Galav", ord_date: new Date("2021-11-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },     { _id: 5, cust_id: "Bhavesh Galav", ord_date: new Date("2021-11-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"},     { _id: 6, cust_id: "Madan Parmar", ord_date: new Date("2021-11-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },     { _id: 7, cust_id: "Madan Parmar", ord_date: new Date("2021-11-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },     { _id: 8, cust_id: "Abhresh", ord_date: new Date("2021-11-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },     { _id: 9, cust_id: "Abhresh", ord_date: new Date("2021-11-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },     { _id: 10, cust_id: "Abhresh", ord_date: new Date("2021-11-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }  ]) Apply a map-reduce operation to the orders collection to group them by cust_id, then add the prices for each cust_id: To process each input document, define the map function: this refers the document that the map-reduce operation is processing in the function. For each document, the function maps the price to the cust_id and outputs the cust_id and price. var mapFunction1 = function() {emit(this.cust_id, this.price);}; With the two arguments keyCustId and valuesPrices, define the corresponding reduce function: The elements of the valuesPrices array are the price values emitted by the map function, grouped by keyCustId. The valuesPrice array is reduced to the sum of its elements by this function. var reduceFunction1 = function(keyCustId, valuesPrices) {return Array.sum(valuesPrices);};Apply the mapFunction1 map function and the reduceFunction1 reduce function to all documents in the orders collection: db.orders.mapReduce(mapFunction1,reduceFunction1,{ out: "map_reduce_example" }) The results of this operation are saved in the map_reduce_example collection. If the map_reduce_example collection already exists, the operation will overwrite its contents with the map-reduce operation's results. Check the map_reduce_example collection to verify: db.map_reduce_example.find().sort( { _id: 1 } ) Aggregation Alternative:You can rewrite the map-reduce operation without defining custom functions by using the available aggregation pipeline operators: db.orders.aggregate([{$group: { _id:"$cust_id",value:{$sum: "$price" } } },{ \$out: "agg_alternative_1" }]) Check the agg_alternative_1 collection to verify: db.agg_alternative_1.find().sort( { _id: 1 } )Implementing Map Reduce with Java Consider the collection car and insert the following documents in it. db.car.insert( [ {car_id:"c1",name:"Audi",color:"Black",cno:"H110",mfdcountry:"Germany",speed:72,price:11.25}, {car_id:"c2",name:"Polo",color:"White",cno:"H111",mfdcountry:"Japan",speed:65,price:8.5}, {car_id:"c3",name:"Alto",color:"Silver",cno:"H112",mfdcountry:"India",speed:53,price:4.5}, {car_id:"c4",name:"Santro",color:"Grey",cno:"H113",mfdcountry:"Sweden",speed:89,price:3.5} , {car_id:"c5",name:"Zen",color:"Blue",cno:"H114",mfdcountry:"Denmark",speed:94,price:6.5} ] ) You will get an output like this:  Let's now write the map reduce function on a collection of cars, grouping them by speed and classifying them as overspeed cars.  var speedmap = function (){  var criteria;  if ( this.speed > 70 ) {criteria = 'overspeed';emit(criteria,this.speed);}}; Based on the speed, this function classifies the vehicle as an overspeed vehicle. The term "this" refers to the current document that requires map reduction. var avgspeed_reducemap = function(key, speed) {       var total =0;       for (var i = 0; i
7344
Implementing MongoDb Map Reduce using Aggregation

Algorithms and applications in today's data-driven... Read More