Lecture 11

classList Manipulation and JSON

Agenda

  • Manipulating classLists and styles
  • JSON

Reminders

  • "Do not use any global variables, and minimize the use of module-global variables. Do not everstore DOM element objects, such as those returned by the document.getElementById function, as global variables."
  • Make sure to make progress on HW2 this weekend - some more recommendations below.
  • Melissa is holding an extra OH on Sunday from 1-2PM (CSE 280)
  • More details on midterm exam are up - Midterm Cheatsheet is out with a Practice Midterm - we'll add 1-2 more Practice Exams this weekend

HW2 Tips

  1. Watch the video - use same strategy as QC from Tuesday's section
  2. Read the spec fully (refer to video as needed)
  3. Finish both of this week's section problems (Skittles and Dice Roller) for more review - these are both new this quarter, and are designed to help with HW2
  4. Take a blank piece of paper and draw out a sequence of events and UI elements interacted with (use video to guide) - draw arrows to represent response behavior (function[s]) from an event source (e.g. a button click) and the result change (e.g. toggling views)
  5. Start with CSS
  6. Populate your board with 12 cards having the same image
  7. Then tackle the random card attribute generation, generalizing difficulty/unlimited vs. timed mode, etc.
  8. Have fun!

Note: This assignment is also great preparation for the midterm next Friday!

I'm working on a creative project for another class right now and its nowhere near as cool as our students'...

Conner

Input Validation

What fields on this site warrant what types of validation?

HTML input validation

Other HTML5 input types that can prevent a user from entering in erroneous input are listed here and include:

  • attributes on single line input fields
    • email
    • password
    • search
    • tel (for phone numbers)
    • url
  • other widgets
    • select/option (drop down list boxes, single or multiple choice)
    • checkbox
    • radio buttons
  • advanced widgets
    • number
    • range (slider)
    • datetime-local
    • month
    • week
    • time
    • color

Manual validation of input fields

Indicating input validation results can also be done by changing style of elements via JavaScript.

We could change the element's style through element.style field but it's more manageable to change the element's classes through element.classList. For example, in llamas.js:

function checkInputsWithClasses() {
  let inputs = qsa("input");
  for (let i = 0; i < inputs.length; i++) {
    if (inputs[i].value.length < 1) {
      inputs[i].classList.add("invalid");
      inputs[i].classList.remove("valid");
    } else {
      inputs[i].classList.add("valid");
      inputs[i].classList.remove("invalid");
    }
  }
}

JS

We could add as many styles as neccessary to these classes in the .css file

Changing classList

Accessing the classList

The classList is a field on a DOM element

Example: If we look back at our Skittle example, after the <div>s have been created, we can use the console to show this:

> let firstSkittle = document.querySelector(".skittle");
> firstSkittle.classList
> DOMTokenList(2) ["skittle", "green", value: "skittle green"]

JS Console

The DOMTokenList is a JavaScript object that represents a space separated list of tokens.

Modifying the classList

You can manipulate the DOM element's classList with the following methods:

Name Description
add(classname) Adds the specified class(es) to the list of classes on this element. Any that are already in the classList are ignored.
remove(classname) Removes the specified class(es) to the list of classes from this element. Any that are already not in the classList are ignored without an error
toggle(classname) Removes a class that is in the list, adds a class that is not in the list.
contains(classname) Returns true if the class is in the the DOM element's classList, false if not.
replace(oldclass, newclass) Replaces the old class with the new class.

Examples

There were examples of this used in the Skittles code, eg, when a skittle was created, or when the game view was changed.

function addSkittle() {
  let skittle = document.createElement("div");
  skittle.classList.add("skittle");
  let randomColor = getRandomColor();
  skittle.classList.add(randomColor);
  $("jar").appendChild(skittle);
}
...
function gameView() {
  $("game-ui").classList.remove("hidden");
  $("game-setup").classList.add("hidden");
  $("start").classList.remove("hidden");
}

JS

More on reading & changing styles

Recall that the .style property of a DOM object lets you set any CSS style for an element

button { font-size: 16pt; }

CSS

<button id="clickme">Click Me</button>

HTML

window.addEventListener("load", initialize);
function initialize() {
  document.getElementById("clickme").addEventListener("click", biggerFont);
};
function biggerFont() {
  let button = document.getElementById("clickme");
  let size = parseInt(button.style.fontSize); // size === 16pt to start
  button.style.fontSize = (size + 4) + "pt"; // notice adding the units!
}

JS

output

Problem with reading & changing styles

Note! Be careful to

  • remove the units from a .style value before doing arithmetic on it.
  • add the units to numerical values (like pt, px, vw, etc) when setting .style values.

Also: a catch: you can only use this to read styles that have been set with the DOM .style earlier in the code or with inline CSS which we don't want you to do .

You cannot read style properties set in the .css file using .style.

Accessing elements' computed styles

getComputedStyle method of global window object accesses existing styles

window.getComputedStyle(element).propertyName;

JS (template)

img {
  height: 600px;
}

CSS (in llamas.css)

> let img = document.querySelector("img");
> img.style.height;
> ""
> img.style.height = "25%";
> "25%"
> window.getComputedStyle(img).height;
> "828.234px"

JS Console Output

Thanks to Daniel H for the example

Common bug: incorrect usage of existing styles

The following example attempts to add 100px to the top of main, but fails.

Consider the case when main has top set to "200px". Then this code would update style.top to be the invalid value of "200px100px"

let main = document.getElementById("main");
main.style.top = window.getComputedStyle(main).top + 100 + "px";

JS

A corrected version:

main.style.top = parseInt(window.getComputedStyle(main).top) + 100 + "px";

JS

CSE 154 Modules

  1. Webpage structure and appearance with HTML5 and CSS.
  2. Client-side interactivity with JS DOM and events.
  3. Using web services (API's) as a client with JS.
  4. Writing JSON-based web services with PHP.
  5. Storing and retreiving information in a database with MySQL and server-side programs.

JSON

JSON
JavaScript Object Notation

A data format that represents data as a set of JavaScript objects invented by JS guru Douglas Crockford of Yahoo! natively supported by all modern browsers (and libraries to support it in old ones)

But first... JavaScript objects

let myobj = {
  fieldName1: value1,
  ...
  fieldName: value
};

JS (example)

In JavaScript, you can create a new object without creating a "class" like you do in Java

You can add properties to any object even after it is created:

myobj.field87 = "wubba wubba wubba";

JS (example)

Example

let llamaSale = {
  buyer: "Llarry Floof",                           // string
  email: "llamaface@us.gov",                       // string
  "zip code": 11080,                               // number
  maxPrice: 172.50,                                // number
  choices: ["Llovey", "Llippy", "Richard"],        // array
  getChoice: function() { return this.name + " bought " + this.choices[1]; }
};
alert(llamaSale["zip code"]);                // 11080
alert(llamaSale.maxPrice);                   // 172.5
alert(llamaSale.choices[2]));                // Richard
alert(llamaSale.getChoice());                // Llarry Floof bought Llippy

JS (example)

An object can have methods (function properties) that refer to itself as this
can refer to the fields with .fieldName or  ["fieldName"] syntax
(field names can optionally be put in quotes (e.g. "zip code" above))

Practice: here, here, and here.

Examples of JS objects we've seen so far

  • DOM elements
  • document, window

JavaScript Objects and JSON

JSON is a way of saving or storing JavaScript objects.

(The technical term is "serializing" which is just a fancy word for turning an object into a savable string of characters)

Browser JSON methods:

JSON stringify/parse example

> let point = {x: 1, y: 2, z: 3}
> point
> {x: 1, y: 2, z: 3}
> let s = JSON.stringify(point);
> s
> "{"x":1,"y":2,"z":3}"
> s = s.replace("1", "4");
> "{"x":4,"y":2,"z":3}"
> let point2 = JSON.parse(s);
> point2
> {x: 4, y: 2, z: 3} 

JS (console)

What is JSON used for?

JSON data comes from many sources on the web:

  • web services use JSON to communicate
  • web servers store data as JSON files
  • databases sometimes use JSON to store, query, and return data

JSON is the de facto universal format for exchange of data

JSON Rules!

JSON has a few rules that differ from regular JS:

  • Strings must be quoted
  • All property/field names must be quoted
  • Values can be:
    • Number (23)
    • String ("string has to be quoted, like this")
    • Boolean (true, false)
    • Array ( [ "value1", 24, true, "hallo" ] )
    • Object ( { "nested" : "object", "which" : { "can" : "have more nested objects" } } )
    • null

Numerous validators/formatters available, eg JSONLint

JSON limitations

JSON can't handle certain data types, so these things just fall out of the object if you try to make JSON strings out of them:

  • Function
  • Date
  • RegExp
  • Error

To get Date objects or RegExp objects into your JSON, you could extract them as strings, and then rebuild them from strings.

However, since JSON is ideal for communicating across different types of systems, you can't put Javascript functions in JSON. Other languages wouldn't be able to read JSON effectively if it had Javascript code in it.

(This is also why Dates and RegExps can't go into the JSON object -- other languages wouldn't know how to interpret them for what they are.)

Valid JSON

{                          // no variable assignment
  "first_name": "Bart",    // strings and properties must be quoted
  "last_name": "Simpson",  // with double quotes
  "age" : 13,              // numbers can be here without quotes
  "cowabunga": true        // booleans can be here without quotes
}                          // no semicolon at the end

JSON

JSON exercise:

Given the JSON data at right, what expressions would produce. Assume the JSON data is stored in a string called data.

for instance, the window's title is data.window.title

  • What the debug flag is set to?
  • The image's third coordinate?
  • The number of messages?
  • The y-offset of the last message?
{
  "window": {
    "title": "Sample Widget",
    "width": 500,
    "height": 500
  },
  "image": {
      "src": "images/logo.png",
      "coords": [250, 150, 350, 400],
      "alignment": "center"
  },
  "messages": [
      {"text": "Save", "offset": [10, 20]},
      {"text": "Help", "offset": [ 0, 50]},
      {"text": "Quit", "offset": [30, 15]}
  ],
  "debug": "true"
}

Answers

let title = data.window.title;             // title === "Sample Widget"
let debug = data.debug;                    // debug === "true"
let coord = data.image.coords[2];          // coord === 350
let len = data.messages.length;            // len === 3
let y = data.messages[len - 1].offset[1];  // y === 15

JS