JavaScript
History
- Originally designed as a language to run in the browser to
- Reduce the need for page reloads (e.g., by performing form validation locally).
- Add nice UI effects
- 1995: Netscape creates LiveScript (quickly changed to JavaScript)
- Microsoft introduces VBScript and then Jscript
- 1996: Netscape proposes ECMAScript specification as a standard
- ECMA: European Computer Manufacturers Association
- https://www.ecma-international.org
- 1997: First version of ECMA-262
- 2015: ES6 – later called ES2015
- Introduced many of the “modern” features (classes, imports, () => notation, etc.)
- New version every year since
- Current version is 10th Edition (also called ES2019)
Quick Start
- Every web page contains an object named
document
. This object describes the entire web page. - This object has several methods that allow us to grab specific elements
getElementById()
getElementsByClassName()
getElementsByTagName()
getElementsByName()
- Notice that all but the first one return a list of elements.
- Can run the above methods on other elements to search only part of the DOM.
- Once we have a “handle” on an element, we can manipulate it. We can
- Change the text
- Remove it from the DOM
- Add sub-elements to it.
- Change it’s style
- Load
basicDOMManipulation.html
. Open the console and rundocument.getElementById('favorite').innerHTML += " (My favorite")
document.getElementById('favorite').style.color = 'green'
document.getElementById('favorite').style.visibility='hidden'
document.getElementById('favorite').style.display='none'
document.getElementById('favorite').style.display='inline'
- Many fancy UI tricks are simply manipulating the DOM.
- First section: Callbacks
- Second section: Hiding elements
- Third section: Adding elements to the DOM
- Fourth section: Change listener / showing error message
- Note: Most of the
get
methods return a DOM list. This is not an array, so methods likeforEach
don’t work.
Add JavaScript to Rails
- Rails uses a tool called Webpacker to package all the Javascript into a few packages.
- By default, there is a single JavaScript package included on all pages
- Look at
app/views/layouts/application.html
- The
javascript_pack_tag
method loads a bundle of JavaScript. - Notice the
application
parameter. This corresponds toapp/javascript/packs/application.js
- We could
- Add code directly to
application.js
- Add code to a different file and import it into
application.js
- Add code directly to
- Look at
- But, our code will only apply to the Posts form, so we’ll create a second pack.
- Create a new file named
app/javascript/packs/postValidate.js
- Add a simple
console.log
statement to this file. -
Add this line to the end of
new.html.erb
andedit.html.erb
:<%= javascript_pack_tag 'validatePost', 'data-turbolinks-track': 'reload' %>
- Open
_form.html.erb
and add the parameterid: 'postForm'
to theform_with
method call. - Add
<div id='errorMessage'></div>
to the top of the form. -
Change the form submit to
<%= form.submit data: {disable_with: false} %>
-
Add the following to
postValidate.js
let form = document.getElementById('postForm'); let errorMessage = document.getElementById('errorMessage'); form.addEventListener('submit', (event) => { errorMessage.textContent = ''; let titleText = document.getElementsByName('post[title]')[0].value; console.log('titleText: ' + titleText); if (titleText.length < 10) { console.log("Error: Title not long enough"); errorMessage.innerHTML = "Title not long enough."; event.preventDefault(); } });
- Create a new file named
Key features / differences
- Template strings
- Uses “Java-style” comments (both
//
and/* ... */
) - Integers and floating point are the same type. (Try
typeof(1)
andtypeof(3.14159)
); - All objects behave like associative arrays.
==
vs===
==
converts both parameters to the same type before comparison (called coercion)===
does not coerce parameters. If the parameters are different types, the result isfalse
.- Use
===
unless you have a good reason to use==
. - When you use
==
add a comment explaining why. - See
keyFeatures.js
null
andundefined
are different.null == undefined
istrue
: Both convert tofalse
null === undefined
isfalse
: They are different types.- Be sure to check for both
null
andundefined
.
let
vsvar
- Variables declared using
let
have block scope (are local to the block) - Variables declared using
var
are visible throughout the function (are not local to the block.) - Use
let
unless you have a good reason to usevar
. - When you use
var
, and a comment explaining why.
- Variables declared using
- Look at
sortingStudents.js
- Look at
varVsLetSubtlty.js
(shows howlet
correctly sets up closure) - Look at
eventVsThis.html
(also shows how to clone nodes, when necessary) - Look at
placementOfScripts.html
(also shows how to clone nodes, when necessary)
Client-side web pages
- Consider Facebook: Notice that when you scroll down the page, you never get to the bottom. Instead, new posts get inserted and the list seems to go on “forever”
- This is an application of a technique called AJAX: Asynchronous Javascript and XML
- (Although, we tend to use JSON more than XML these days.)
- JavaScript running on the browser makes an HTTP request back to the server
- The server returns raw data (usually in XML or JSON form),
- The client-side JavaScript then inserts that data into the DOM (e.g., creates new posts and puts them at the end of the list.)
- This technique often involves creating new DOM elements on the fly (like we say last week).
- Client-side frameworks like React, Angular, and Vue take this to the extreme and construct the entire DOM on the client “on the fly”
Rails as an API
- Notice that our blog app can return raw data in JSON form:
- Visit this URL:
- However, Rails, by default, utilizes several security checks that make updates difficult
- CSRF token
- Same-origin policy
- I tried to covert an existing Rails app to serve as an API. It worked; but, it was clumsy, and I felt like I was opening security holes.
- There are ways to add and API to an existing app. These largely involve creating separate controllers for the API. (Thereby preserving security for the “regular” controllers)
- For our purposes, it will be easiest to simply create a new app from scratch designed specifically to serve as an API.
- Show <DemoScripts/RailsDemo05.html>