Jeremy Troy Suchanski
Web Frontend Development II
Gary James
May 4, 2022
L06 Readings Notes
Ch8: Forms (Notes)
-
Forms: a very common method of interacting with a web page. Traditionally,
when a form was submitted, it would be sent to a server where the
information would be processed using a 'back end' language
such as PHP or Ruby.
It’s becoming more and more common, to process the
information in a form on the 'front end' before it is sent
to the server using JavaScript.
-
Forms UX: has to do with form usability and accessibility considerations,
like using correct and semantic markup, making forms keyboard
accessible and using WAI-AIRA labels. For more info: Designing UX: Forms by Jessica Enders.
-
search.html: a form that contains one input field, and a button to submit a
search query. This form has a name attribute of search. The input
field’s name attribute of searchInput is used to access the
information inside it. The action attribute is the URL the form will
be submitted to so it can be processed on the server side.
Example Code:
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>Search</title>
</head>
<body>
<form name='search' action='/search'>
<input name='searchInput'>
<button type='submit'>Search</button>
</form>
<script src='main.js'></script>
</body>
</html>
Accessing Form Elements:
-
document.forms: returns an HTML collection of all the forms in the document in the
order they appear in the markup. (i.e. const form = document.forms[0];) Instead of using a numerical index, we can use the name
attribute to identify a form. (i.e. const form = document.forms.search;) If the form had the same name as any properties or methods of the
document.forms object, such as 'submit', for example, that
property or method would be referenced instead of the <form>
element.
To avoid this, square bracket notation can be used (this is also
required if the form’s name attribute contains any invalid
characters, such as spaces or dashes) (ie const form = document.forms['search'];)
-
elements method: returns an HTML collection of all the elements contained in the
form. (i.e. const [input,button] = form.elements;) You can
access the form controls using their 'name' attributes. (i.e const input = form.searchInput;) The square bracket notation can also be used instead (again, this
is useful if there are any naming clashes with existing property and
method names, or if the name is an invalid variable name). (i.e. const input = form['searchInput'];)
-
form.elements: will return an HTML collection of all elements contained within a
form.
Form Properties and Methods
-
form.submit() method: submits the form automatically. This can be done through a button
or input element with a type attribute of submit
-
form.reset() method: resets all the form controls back to their initial values in HTML.
This can be accomplished through a button with a type attribute of
reset.
-
form.action property: used to set the action attribute of a form, so it’s sent to a
different URL to be processed on the server. (i.e. form.action = '/an/other.url';)
Form Events
-
focus event: occurs when an element is focused on.
-
blur event: the user moves the focus away from the form element.
-
change event: occurs when the user moves the focus away from the form element
after changing it.
-
submit event: occurs when the form is submitted. Likely the most important form
event.
Submitting a Form
-
Submission to Server: Usually submit will send the content of the form to the server to
be processed.
-
Submission to JavaScript: By adding a submit event listener to intercept the form
before it’s sent JavaScript can be used to process the
submission.
-
preventDefault() method: will stop the form from being submitted to that URL.
Code Example:
const form = document.forms['search'];
form.addEventListener ('submit', search, false);
function search() {
alert(' Form Submitted');
event.preventDefault(); }
Retrieving and Changing Values From a Form
-
value property: Property of text input element objects used to retrieve
text inside a field. This can be used to report back what the user
has searched for. Code Example:
function search(event) {
alert(`You Searched for: ${input.value}`);
event.preventDefault();
}
-
input.value: to set the value using JavaScript and then
using the focus and blur event handlers
the default text will disappear when the user clicks inside the
input field (the focus event) and reappear if the user leaves the
field blank and clicks away from it (the blur event).
Code Example:
input.addEventListener('focus', function(){
if (input.value==='Search Here') {
input.value = '' }
}, false);
input.addEventListener('blur', function(){
if(input.value === '') {
input.value = 'Search Here';
} }, false);
-
placeholder attribute: produces similar functionality to above code, the difference is
the placeholder text is not actually a value of the input field, so
it won’t be submitted as the field’s value if the user
fails to fill it in. Code Example:
<input type='text' name='search-box' placeholder='Search Here'>
-
Form Controls: can help to make web pages more interactive. The following are
common types of form controls:
<input>: fields, including text, passwords, check boxes, radio buttons, and
file uploads
<select>: menus for drop-down lists of options
<textarea>: elements for longer text entry
<button>: elements for submitting and resetting forms
-
New Attributes in HTML5: autofocus, placeholder, maxlength & Article of others.
Code Example: Once the object is created, normally it would be returned by
the function & then used elsewhere in the rest of the program.
Instead, since this is just a demo, we convert the object into a JSON
string using JSON.stringify() method & then display it in an alert
dialog.
function makeHero(event) {
event.preventDefault(); // prevent the form from being submitted
const hero = {}; // create an empty object
hero.name = form.heroName.value; // create a name property based on the input field's value
alert(JSON.stringify(hero)); // convert object to JSON string and display in alert dialog
return hero; }
-
Input Field Categories: the most common types of form control is input, but there are
several categories of input field.
-
Text Input Fields (type='text'): the attribute
isn’t required (because text is the default), but it is
advisable to use it as it makes the intended purpose of the field
explicit, helping with maintenance, readability and
future-proofing.
value attribute: can set
the initial value of this field
in HTML. Code Example:
<label for='donation-amount'>Enter amount to donate:
<input type='text' id ='donation-amount' name='donationAmount' value='10'>
</label>
-
Password Input Fields (input type='password'): used to enter passwords or secret information. The characters are
concealed as they are entered so they’re unable to be read on
the screen. Code Example:
<label for='realName'>Real Name:
<input type='password' name='realName' id='realName'></label>
JavaScript File:
hero.realName = form.realName.value;
-
Checkbox Input Fields (type='checkbox'): used to select different options that can be checked (true) or
left unchecked (false). The user can select more than one checkbox
from a list.
checked property: a property of checkbox objects
that tells us if it has been checked or not with values of true or
false.
value property: used to set the name of the value of the checkbox choice if
checked.
Code Example:
<p>Super Powers:</p>
<label for='flight'>Flight:
<input type='checkbox' id='flight' value='Flight' name='powers'>
</label>
<label for='strength'>Super Strength:
<input type='checkbox' id='strength' value='Strength' name='powers'>
</label>
<label for='speed'>Super Speed:
<input type='checkbox' id='speed' value='Super Speed' name='powers'>
</label>
<label for='energy'>Energy Blasts:
<input type='checkbox' id='energy' value='Energy Blasts' name='powers'>
</label>
<label for='telekinesis'>Telekinesis:
<input type='checkbox' id='telekinesis' value='Telekinesis' name='powers'>
</label>
(above all the checkbox elements have the same 'name'
property of 'powers', so form.powers; will access them as an
HTML collection)
for loop: can be used to iterate over the collection to see if each checkbox
was checked. Code Example:
hero.powers = [];
for (let i=0; i < form.powers.length; i++) {
if (form.powers[i].checked) {
hero.powers.push(form.powers[i].value); } }
spread operator (. . .): turn the node list into an array.
filter() method: returns an array containing only the check boxes that were
checked.
map() method: replaces each checkbox in the array with its 'value'
property.
variable: stores the array. Code Example:
hero.powers = [...form.powers].filter(box => box.checked).map(box => box.value);
'checked' property: can set a checkbox to true using JavaScript.
Code Example:
document.forms.hero.powers[0].checked = true;
'checked' attribute: in the HTML can initially set checkboxes as checked.
Code Example:
<input type='checkbox' value='Flight' name='powers' checked>
-
Radio Button Input Fields (type='radio'): they allow users to check an option as true, but only one option
can be selected. Code Example:
'name' attribute of 'category': reused to group radio buttons together ― only one can be checked in a
group with the same name attribute. Code Example:
<p>What type of hero are you?</p>
<label for='hero'>Hero:
<input type='radio' name='category' value='Hero' id='hero'>
</label>
<label for='villain'>Villain:
<input type='radio' name='category' value='Villain' id='villain'>
</label>
<label for='anti-hero'>Anti-Hero:
<input type='radio' name='category' value='Antihero' id='anti-hero'>
</label>
name property: can access an HTML collection of all the radio buttons.
Code Example:
form.category
form.category.value: Where value of the radio button that was selected is stored and can
be used to assign a category property to an object.
Code Example:
hero.category = form.category.value;
'checked' property: returns the boolean values true if selected or false if not.
JavaScript changing checked property: (others change to false) Code Example:
form.type[2].checked = true;
'checked' attribute: in the HTML
can initially set radio button as checked.
Code Example:
<input type='radio' name='type' value='Villain' checked>
-
Hidden Input Fields (type='hidden'): are not displayed by the browser, but have a 'value'
attribute that can contain information that is submitted with the
form. They are often used to send information such as settings or
information that the user has already provided. Note that the
information in these fields is in no way secret, as it’s visible
in the HTML, so shouldn’t be used for sensitive data. The value
of a hidden input field can be changed using JavaScript in the same
was as any other input field.
-
File Input Fields (type='file'): used to upload files, most browsers will provide a browse button or
similar that lets users select a file from their file system.
-
Other Input Types (type='number', type='tel',
type='color', type='date',
type='email'): There are lots of new input types included in HTML5. As browsers
start to support these, they will implement different user-interface
elements & validate automatically.
If the new input type isn’t supported the browser will just
display a normal text input field. New form elements link.
-
Number input fields (type='number'): have optional
'min' and 'max' attributes that
can be used to limit the input given. The
'step' attribute is used to specify how
much the value changes by each click.
-
Select Drop-Down List: used to select one or more options from a list of values.
'multiple' attribute: required if more than one option is to be selected.
Code Example:
<label for='City'>Base of Operations:
<select name='city' id='city'>
<option value='' selected>Choose a City</option>
<option value='Metropolis'>Metropolis</option>
<option value='Gotham City'>Gotham City</option>
<option value='Keystone City'>Keystone City</option>
<option value='Coast City'>Coast City</option>
<option value='Star City'>Star City</option>
</select>
</label>
'selected' attribute: used to set the initial value in the HTML. If only one item was
selected, this will return a reference to that selection; otherwise a
collection will be returned containing each selection.
Code Example:
form.city;
value property: equal to the 'value' attribute of the
<option> tag that was selected.
Code Example:
hero.city = form.city.value;
selectedIndex property: finds the index of the option that has been selected. This can then
be used with index notation to access the actual text
of the selected option. Code Example:
form.city.options[form.city.selectedIndex].text
-
Text Areas (<textarea> element): used to enter long pieces of text over multiple lines such as a
comment or blog post.
<label for='origin'>Origin Story:
<textarea id='origin' name='origin' rows='20' cols='60'></textarea>
</label>
'name' attribute: used to access the text area.
value property: used to see what text was entered.
object property: can be added from text area through JavaScript.
Code Example:
hero.origin = form.origin.value;
JavaScript changing
text area value in the form: Code Example:
form.origin.value = 'Born as Kal-El on the planet Krypton...';
text area initial value: set in the HTML by placing the text between the opening and closing
tags. Code Example:
<textarea name='origin' rows='20' cols='60'>Born as Kal-El on the planet Krypton...</textarea>
-
Buttons: there are different types of buttons. The default is
type='submit'.
-
type='reset': will reset all the form fields to their initial settings.
This is not recommended good practice for usability
reasons!
-
type='button': This doesn’t need to be inside a form element and has no
default behavior. It creates a clickable button that can have an
event listener attached to it.
-
type='menu': can be combined with
<menu>, <menuitem> and <li> tags
to create a dropdown menu when it’s clicked on. support is
fairly patchy at present.
-
Form Validation: the process of checking whether a user has entered the information
into a form correctly. (i.e., #1 A required field is completed #2 An
email address is valid #3 A number is entered when numerical data is
required #4 A password is at least a minimum number of
characters)
Validation can occur on the client side using
JavaScript, and on the server side. It is
advisable to use both. (JavaScript should not be relied upon to
validate any data before it’s saved to a database. This is
because it’s possible for a user to modify the JavaScript code
and bypass the validation rules. It's also very easy to bypass
the front-end completely and send arbitrary data to the
application's backend.)
validation API: is an optional part of HTML5. (lacks the full support from all
browsers at the moment)
It
works by simply adding relevant attributes to the form
fields. Link
required attribute: As you click in another field, the blank name field is highlighted
because it’s a required field. Code Example:
<input type='text' id='heroName' name='heroName' autofocus placeholder='Your Super Hero Name' maxlength=32 required>
custom form validation: you can create your own custom validation using JavaScript.
Code Example:
form.addEventListener('submit',validate,false);
function validate(event) {
const firstLetter = form.heroName.value[0];
if (firstLetter.toUpperCase() === 'X') {
event.preventDefault();
alert('Your name is not allowed to start with X!'); } }
instant feedback: improves the usability of the form. by adding the
event listener directly to the input field
that will fire when the user presses a key (using the
keyup event). The feedback can then be inserted inside
the label element of the input field, along with a
class of error for more direct feedback.
Code Example:
const label = form.querySelector('label');
const error = document.createElement('div');
error.classList.add('error');
error.textContent = '! Your name is not allowed to start with X.';
label.append(error);
function validateInline() {
const heroName = this.value.toUpperCase();
if(heroName.startsWith('X')){
error.style.display = 'block';
} else {
error.style.display = 'none'; } }
CSS File:
.error {
background: #f99;
border: #900 1px solid;
display: none; }
-
Disabling the Submit Button: no action is taken when the button is clicked. Most browsers will
also display the button in a lighter color to indicate that it
cannot be clicked on. Disabling the button when there are errors on
the form aids usability.
disabled attribute: adding it to the <input> element disables the button.
Code Example:
<button type='submit' id='submit' disabled>Submit</button>
using the disabled property of the <button> element with
JavaScript: disables the button conditionally. Code Example:
function disableSubmit(event) {
if(event.target.value === ''){
document.getElementById('submit').disabled = true;
} else {
document.getElementById('submit').disabled = false; } }
Using FormData Objects Effectively (Notes)
Using FormData to Parse Forms
-
FormData Object: reference it through the form tag’s id in the HTML. Contains
everything in the form that had a name attribute. Allowed to send the
FormData object as the body to the server.
-
name attribute: None of the inputs will come through to the form object without it
inside the HTML input tag’s
-
submit listener: Code Example:
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("myForm").addEventListener("submit", handleForm);
});
-
preventDefault: to stop form from loading and be able to handle the data with
JavaScript
-
target: is the form
-
set variable: make a new formData object passing in the form object
-
append: add any other data to formData object you want to include in
submission
-
key: the name of each of the form elements as well as the append’s
name
-
body: is the formData Object
-
.get with key passed in: gives you the value of the key
-
fetch: send fetch to url (the server)
Code Example:
function handleForm(ev) {
ev.preventDefault(); //stop the page reloading
let myForm = ev.target;
let fd = new FormData(myForm);
//add more things that were not in the form
fd.append("api-key", "myApiKey");
//look at all the contents
for (let key of fd.keys()) {
console.log(key, fd.get(key)); }
//send the request with the formdata
let url = "http://localhost:3000/";
let req = new Request(url, {
body: fd,
method: "POST" });
fetch(req)
.then((res) => res.json())
.then((data) => {
console.log("Response from server");
console.log(data); })
.catch(console.warn); }
-
server: listens for any request on port 3000 & sends back “just
a plain old json reply”
Code Example:
const http = require('http');
const server = http.createServer(function (req, res) {
req.on('data', function (data) {
//handle data as it is received... for POST requests
});
req.on('end', function () {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.writeHead(200, 'OK');
res.end('{ "data": "just a plain old json reply"
}'); }); });
server.listen(3000, (err) => {
if (err) {
console.log('bad things');
return; }
console.log('listening on port 3000'); });
-
server wanting json: use a function.
obj: create an object with a variable name
obj[key]: create a property on the object with the same name as the key &
set value to formData.get(key)
JSON.stringify: converts json object to a string.
return: the object is returned
Code Example:
function convertFD2JSON(formData) {
let obj = {};
for (let key of formData.keys()) {
obj[key] = formData.get(key); }
return JSON.stringify(obj); }
-
calling the convertFD2JSON function: pass in the formData object
Code Example:
Variable: json becomes variable for the data converted to a json file
let json = await convertFD2JSON(fd);
Header object: use to tell the server I am sending you some json data
let h = new Headers();
h.append("Content-type", "application/json");
headers: set equal to the Header object created
let req = new Request(url, {
headers: h,
body: json,
method: 'POST', });
iterator: considered to be asynchronous so add async to handleForm
function
async function handleForm(ev) {
Json data: put it inside handleForm function
let req = new Request(url, {
body: json,
method: "POST" });
MDN: Client-Side Form Validation (Notes)
-
Client-side form validation: ensuring all required form controls are filled out in the correct
format before submitting data to the server. Client-side validation is
too easy to bypass, so malicious users can still easily send bad data
through to your server, so it should not be considered an exhaustive
security measure!
-
form validation: When you enter data, the browser and/or the web server will check
to see that the data is in the correct format and within the
constraints set by the application.
-
Reasons for validation: #1 We want to get the right data, in the right format. #2 We want
to protect our users' data. #3 We want to protect
ourselves.
-
Built-in form validation: uses HTML5 form validation features, doesn't require much
JavaScript, has better performance than JavaScript, but it is not as
customizable.
-
JavaScript validation: is coded using JavaScript. This validation is completely
customizable, but you need to create it all (or use a library).
-
valid element: #1 The element matches the
:valid CSS pseudo-class, which lets you apply a specific style. #2 If the user tries to send
the data, the browser will submit the form, provided there is nothing
else stopping it from doing so (e.g., JavaScript).
-
invalid element: #1 The element matches the
:invalid CSS pseudo-class, and sometimes other
UI pseudo-classes (e.g., :out-of-range) depending on the error, which
lets you apply a specific style. #2 If the user tries to send the
data, the browser will block the form and display an error
message.
-
required: the element matches the :required pseudoclass whether it has a
value or not. If the <input> has no value, the input will match
the :invalid pseudoclass.
Only require users to input data you actually need.
-
pattern: Specifies a regular expression that defines a pattern the data
needs to follow. (The <textarea> element doesn't support
the pattern attribute.)
-
regular expression
(regex): a pattern that can be used to match character combinations in text
strings. Link
-
minlength and maxlength attributes: constrains the character length of all text fields created by
<input> or <textarea>.
A better user experience than just using maxlength is to also provide
character count feedback in an accessible manner and let them edit
their content down to size.
-
min and max attributes: provide a range of valid values
for number fields.
Users won't be able to use the increment/decrement arrows to
move the value outside of this range.
-
step attribute: specifies what increment the value will go up or down by when the
input controls are used. The default value is 1.
-
attributes that can be used to constrain input values: complete list - Link
-
Constraint Validation API: consists of a set of methods and properties available on the
following form element DOM interfaces: #1 <button> #2
<fieldset> #3 <input> #4 <output> #5 <select>
#6 <textarea>.
Properties made available to above 6 element through the API:
-
validationMessage: Returns a localized message describing the validation constraints
that the control doesn't satisfy (if any).
-
validity: Returns a ValidityState object that contains
several properties describing the validity state of the element.
ValidityState object properties: some of the more common ones are #1
patternMismatch #2 tooLong #3 tooShort #4 rangeOverflow #5
rangeUnderflow #6 typeMismatch #7 valid #8 valueMissing
-
willValidate: Returns true if the element will be validated when the form is
submitted; false otherwise.
Methods made available to above 6 element through the API:
-
checkValidity(): Returns true if the element's value has no validity problems;
false otherwise. If the element is invalid, this method also fires an
invalid event on the element.
-
reportValidity(): Reports invalid field(s) using events. Useful in combination with
preventDefault() in an
onSubmit event handler.
-
setCustomValidity(message): Adds a custom error message to the element; if you set a custom
error message, the element is considered to be invalid, and the
specified error is displayed.
-
customized error message: one of the most common use cases of the constraint validation
API.
-
novalidate attribute: turns off the browser's automatic validation, letting your
script take control over validation. However, this doesn't
disable support for the constraint validation API nor the application
of CSS pseudo-classes like :valid, etc.
-
aria-live attribute: custom error message will be presented to everyone, including it
being read out to screenreader users.
-
Validating forms without a built-in API: #1 remove the HTML validation features. #2 turn the :invalid CSS
pseudo-class into a real class #3 make big changes are in the
JavaScript code, which needs to do much more heavy lifting.
-
help the user to correct invalid data: In order to reduce the user's frustration, it's very
important to provide as much helpful information as possible in order
to guide them in correcting their inputs.