This lab introduces JavaScript (JS) which is a programming language which runs in the Web Browser. In addition to being able to perform typical programming language tasks, like data storage and computation, it can additionally interact with the HTML and CSS on a web page through the Document Object Model (DOM), allowing real time interactions with the page performed on the client side. We’ll look at a small subset of the capabilities of JavaScript in this lab.
Lab 4: JavaScript and DOM
ENSE 374 - Software Engineering Management - Laboratory
University of Regina - Engineering and Applied Science - Software Systems Engineering
Lab Instructor: Adam Tilson
Computer running Windows, MacOS or Linux, with an Intel or AMD-based processor (x86 or x86-64) with administrator privileges.
- A modern web browser, with a strong preference for Firefox or Chrome
- A text editor, preferably VS Code
What is JavaScript
- A language designed to give your browsers autonomy so they do not need to communicate with the server for trivial operations, like addition
- Today a standard (ECMAscript) which browsers need to implement
- Interpreted, not compiled
Hello JavaScript World
- Open the Dev console (F12)
alert("Hello World"); console.log("Hello World");
Where to put JavaScript code?
While JavaScript can run from many places, just like CSS, external is preferable to use an external script, so that it is easy to identify the location of the code and modify it appropriately.
Inline (in a tag):
<a onclick="alert('hello');" href="#">Pop Up</a>
Internal:
<script type="text/javascript">
alert("hello")
</script>
External:
...
<body>
...
<script src="index.js" charset="utf-8"></script>
</body>
...
Always link the external page as the last element in the <body>
tag, this is to ensure necessary HTML elements are loaded before the script executes, in case we need to find HTML elements in the DOM
Learning and Mastering Javascript
- MDN - JavaScript
- JavaScript The Good Parts Read for Free on O’Reilly Higher Education
White Space
- C-style, typically optional, but recommended for readability
- Style Guide
Comments
// line style
/* block comments */
Strive for self-documenting code through good variable and method names and logical control structures. Wrong, obsolete and obvious comments are worse than none!
Creating / Assigning Variables
Block scoped variable:
let daysThisMonth = 30;
Once constants are set they cannot be changed:
const cmPerInch = 2.54;
Globally scoped variables should be avoided where possible:
var phrase = "Pretend I don't exist";
Type is inferred from the literal, and it can change later on
- If you want more rigorous typing, TypeScript is a JavaScript extension which imposes additional rules on the language during development, but compiles back to vanilla JavaScript.
Variable Names
- letter followed by letters, digits, underscores.
- no spaces (as in all programming languages!)
- no reserved words allowed!
- no dashes, as they represent minus (which will clash with CSS naming conventions in some contexts)
- camelCase is preferred
Primitives
- numbers, strings, booleans
null
- intentional absence of a value, assigned by you.undefined
- unintentional absence of a value. Returned by JS if you forgot to assign something
Numbers
All numbers are 64-bit floats (double).
1e2
means100
-37
NaN
means Not a Number, e.g. a 0/0 error.Infinity
exists if the magnitude of a number is huge (>310 0’s).- Also returned by div/0 errors.
- Signed.
-0
is legal.- There are methods for numbers, e.g.
Math.floor(number)
- Math object defines common methods, e.g.
Math.pow(...)
,Math.abs(...)
,Math.floor(...)
,Math.random(...)
+
,-
,+=
,-=
,++
,--
all work as expected
Number type built in functions:
number.toExponential()
number.toFixed(totalDigits)
number.toPrecision(decimalPoints)
number.toString(base)
Strings
- Single
'
or double"
quotes- Double is preferred most of the time
- Zero or more characters
\
used as an escape character:\\
,\'
,\"
,\n
, and others- No char type, only length one strings
length
property.>> "word".length 4
- Strings are immutable - once made they can’t be changed directly
+
for concatenation- Strings have methods, e.g.
toUpperCase()
>> "word".toUpperCase()
"WORD"
>> "WORD".toLowerCase()
"word"
- If your strings needs to include one type of quotes as a character in the string, you can use the other to delimit the string, e.g.
"He said 'hi' "
or'They said "see ya later!" '
- This can be more convenient than escaping
- Positions are indexed, like in arrays (but are read only!)
Template Literals
- strings which allow inline insertion of variables or other code
- strings declared surrounded by the backtick character: e.g. :`
`I counted ${ 3 + 5 } apples`
- Any JS in the ${ }`’s is evaluated.
- If you want the ‘$’ in the string, do ‘$$’.
parseInt
and parseFloat
extracts the leading number from a string until it something non numeric.
slice
lets you extract substrings
>> let name = "Robot"
>> name.slice(1,4)
`obo`
Some more useful built-in functions…
string.charAt(pos)
string.charCodeAt(pos)
string.concat(string...)
string.indexOf(searchString, pos)
string.lastIndxOf(searchString, pos)
string.match(regexp)
string.replace(searchValue, replaceValue)
string.search(regexp)
string.slice(start,end) - like substr
string.split(separator, limit)
string.substring(start, end)
string.toLowerCase()
string.toUpperCase()
string.trim()
String.fromCharCode(char...)
Can cascade methods, e.g. string.trim().toUpperCase()
Booleans
- Values that represent False:
false
,null
,undefined
,""
,0
,NaN
- Everything else represents
true
- Everything else represents
- Testing equality: always use
===
(also tests type) !
toggles truthiness
For an explanation on why to always use ===
over ==
, see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
Infix Operators
By precedence:
*
,/
,%
(modulo),**
(power).+
,-
>=
,<=
,>
,<
===
,!==
||
,&&
- override precedence with
( )
’s
*Technically ==
exists in JavaScript, you should pretend it doesn’t.
Typeof
- A prefix operator, not a function:
typeof x
- returns the type of a variable:
number
string
boolean
undefined
function
object
- arrays and null types map to objects
Statements
Types:
- expression
- disruptive (
break
,return
,throw
) - condition (
if
,try
,switch
) - loop (
for
,do
,while
)
Mostly work as expected in c++, exceptions:
- e.g. switch “cases” do not need to be const’s.
If you like syntax diagrams, JavaScript the Good Parts will show you what you need.
e.g., here’s one on whitespace
Source: JavaScript The Good Parts. Douglas Crockford. 2008.
Conditions
In JavaScript, if...else if...else
and switch-case
exist:
Example from W3Schools JS If Else ElseIf
if ( time < 10 ) {
greeting = "Good morning";
} else if ( time < 20 ) {
greeting = "Good day";
} else {
greeting = "Good evening";
}
Example from W3Schools JS Switch
switch (new Date().getDay()) {
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
default:
day = "Weekend";
}
- Cases can be any type
- Fall-through will occur until a
break
is encountered
Loops
There are several types of for
loops:
Examples from W3Schools JS Loop For
for (let i = 0; i < 5; i++) {
text += "The number is " + i + "<br>";
}
for...in
loops through properties of an object:
Examples from W3Schools JS Loop For In
const person = {fname:"John", lname:"Doe", age:25};
let text = "";
for (let x in person) {
text += person[x];
}
for...of
loops through iterables data structures:
Example from W3Schools JS Loop For Of
const cars = ["BMW", "Volvo", "Mini"];
let text = "";
for (let x of cars) {
text += x;
}
There are also while
loops:
Example from W3Schools Loop While
while (i < 10) {
text += "The number is " + i;
i++;
}
And do...while
loops:
Example from W3Schools Loop While
do {
text += "The number is " + i;
i++;
}
while (i < 10);
Try Throw Catches
An additional control structure for running risky code and catching errors is the try-throw-catch
Example from W3School JS Errors
function myFunction() {
const message = document.getElementById("p01");
message.innerHTML = "";
let x = document.getElementById("demo").value;
try {
// block for risky code to try
if(x == "") throw "is empty";
if(isNaN(x)) throw "is not a number";
x = Number(x);
if(x > 10) throw "is too high";
if(x < 5) throw "is too low";
}
catch(err) {
// runs if an error occurs
message.innerHTML = "Error: " + err + ".";
}
finally {
// always runs regardless of try/catch result
document.getElementById("demo").value = "";
}
}
Objects
- Similar to C++ classes
- Collections of key-value pairs.
- Can be nested
- Ad-hoc or prototyped
- No guarantee they will have all of the expected properties - test first!
- First we’ll look at ad-hoc objects - these are both declared and instantiated on the fly
Creating Objects
// string style keys
var personString = {
"first-name" : "Adam",
"last-name" : "Tilson"
}
// name style keys
var personName = {
firstName : "Adam",
lastName : "Tilson"
}
Reading Objects
//string style lookup
personString["first-name"];
//name style lookup
personName.firstName;
- If a value doesn’t exist, it returns undefined
- Can use
||
to fill in a default, eg.personName.firstName || "Adam"
- If you need to retrieve from a nested obj, make sure it exists first:
adam.schedule && adam.schedule.morning
- if you want to see all of the contents of an object in the console use:
console.dir(myObject)
Updating Objects
- Use the assignment operator,
personString["first-name"] = "A";
personName.firstName = "A";
Objects are passed by reference, not copied
Deleting Objects
delete personString["first-name"];
Prototyping
You can link an object to a prototype to inherit properties. This is like in C++ where you must first define a class before you can create an instance of it. This allows you to use a constructor:
function Person(first, last, age, eyeColor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyeColor;
}
var myFather = new Person("John", "Doe", 50, "blue");
var myMother = new Person("Sally", "Rally", 48, "green");
We can modify the prototype later by adding a new prototype with a default value:
Person.prototype.nationality = "English";
Add a function later
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
Rule: you can modify your own prototypes, but probably shouldn’t modify others’!
Arrays
Arrays are simply objects that allow using ints for the names, i.e. the index.
- They also have some shortcut operators and built in methods to make them operate like arrays do in other languages.
let x = [1, 2, 3];
let x = []
let x = ["one", "two", "three"] - associative arrays
- length property
>> x.length;
3
Two ways to append a value to the end of the list:
x[x.length] = 6
x.push(6)
- Deleting values leaves holes in the array
- Rather than deleting, you can splice instead e.g. start at 2 element, delete 1, and splice the two sub arrays together:
x.splice(2,1)
- No 2d support out of the box, but you can make an array of arrays.
Array class methods:
array.concat (item, ...)
array.join (separator) - make a string from an array
array.pop()
array.push(item, ...)
array.reverse()
array.shift() - like pop but for the first element
array.slice(start, end) - copy a portion of an array
array.sort(compareFunction)
array.splice(start, count)
array.unshift(item, ...) - push front
A simple addition function:
function add (x, y) {
return x + y;
}
Note: function
keyword, and no explicitly defined argument or return types
Variable Passing
Primitive types are passed by Value. This means modifying the variable inside the function will not change it outside the function.
Objects are passed by Reference - this means that modifying an object inside the function will modify the original.
Anonymous Functions
Functions can be created anonymously as expressions.
In this case we can assign these to variables, however, we’ll see later how we can also declare these functions directly from their parameter list of other functions as callbacks.
let add = function (x, y) {
return x + y;
}
Or using the popular arrow syntax:
let add = (x, y) => {
return x + y;
}
or even as a one-liner, but this is a bit difficult…
let add = (x, y) => x + y;
Arrow functions have a few syntax options
In JavaScript functions are objects, so they can be stored in variables or passed as parameters!
Calling Functions
add (3, 4)
The implicit arguments
array contains all of the arguments, even unnamed ones. e.g.:
var sum = function () {
var i, sum = 0;
for ( i = 0; i < arguments.length; i += 1 ) {
sum += arguments[i];
}
return sum;
};
Scope
When we use the var
keyword for variables, we have function scope, not block scope. If a function does know what a variable is, it will do a search up through blocks to try to find it. You will likely need to read through this a bunch of times!
var outer = function () {
var a = 3, b = 5;
console.log ("(1) At this point, a is 3, b is 5, and c is not defined")
console.log(`a = ${a}`);
console.log(`b = ${b}`);
console.log(`c is not defined`);
var inner = function () {
var b = 7, c = 11;
console.log ("(2) At this point, a is 3, b is 7, and c is 11")
console.log(`a = ${a}`);
console.log(`b = ${b}`);
console.log(`c = ${c}`);
a += b + c;
console.log ("(3) At this point, a is 21, b is 7, and c is 11")
console.log(`a = ${a}`);
console.log(`b = ${b}`);
console.log(`c = ${c}`);
};
inner ();
console.log ("(4) At this point, a is 21, b is 5, and c is not defined")
console.log(`a = ${a}`);
console.log(`b = ${b}`);
console.log(`c is not defined`);
};
outer();
A scope search happens where JS looks for the variable in local scope first, if not it will fall back to parent block scope, e.g. in nested functions, then grandparent, etc.
This is very difficult to trace, and rarely matches the programmer’s intention. Instead we should use let
!
High order functions and callbacks
A high order function is a function which takes a function as an argument, or returns a function:
Or a function expression:
var hello = function () {
console.log("Hello");
}
A simple example: call twice:
function callTwice(func) {
func()
func()
}
When we pass a function in here
- don’t include the ()’s,
- that is, we want to pass a reference to function
- we don’t want to run the function and pass in its return value
We can also have a function which returns a function. This is like a function factory:
function getAFunction () {
return function () {
console.log("Hello")
}
}
Here’s how we can use that factory:
function makeBetweenFunc (x, y) {
return function(num) {
return num >= x && num <= y;
}
}
isItNiceOutside = makeBetweenFunc(20, 30);
We sometimes need to invoke anonymous functions:
The following JavaScript built in function calls a function passed as an argument after 5000 ms:
setTimeout (func, 5000)
We can also define the callback function directly in the argument list:
setTimeout (function() {
alert("Welcome")
}, 5000)
Callbacks are extremely useful, and we’ll see them a lot when working with both UI operations and Node.js in a few weeks.
DOM Overview
The document object model (DOM) catalogs the elements of a webpage into JavaScript objects which you can manipulate, namely HTML and CSS.
- We can also listen to user interactions (Events) and respond to them.
- All of the HTML Attributes exist in the JS object, not only the ones we manually define through HTML Code.
- You can read it with
dir
- You can read it with
Single Responsibility
We will learn how to change individual CSS values in JS.
- Should we? No!
- Recall, all of our styles should be defined in CSS style sheets, e.g. using classes
- Instead, you could attach or detach classes in JS, which will update the styles
What you need to know for this lab?
You don’t need to memorize all of the syntax (We’ll use JQuery next week which simplifies the syntax)
Instead, spend more time learning what you can do, more than specifically how you do it.
Waiting for user interactions
We can attach event listeners, which wait for a user to do an action, and then call a function when a user does that action
btnObj.addEventListener("mouseover", function () {
alert("hi");
});
The Root of the DOM: The Document object
You can learn more about the document object using the:
console.dir(document)
You can also do this with individual elements.
Selecting and element from the DOM
Some commands for selecting elements from the DOM are:
let element = document.getElementById("hero-image") //(returns an HTMLElement)
let elements = document.getElementsByTagName("h1") //(returns HTMLCollection, like an Array)
let elements = document.getElementsByClassName("header") //(Also returns HTMLCollection)
- The returned elements is a JavaScript object representing a chunk of HTML.
- If you store it in a variable, e.g.
const img
.- Then you will have an object you can use. Using the CRUD principles we discussed, you can manipulate it!
-
HTML objects have prototypes, eg.
HTMLImageElement
- If you call any of these getElementBy…() functions on an HTML element, the returned objects will be from the HTML element’s children, rather than the documents children.
HTMLCollections
You can use array access []
and .length
, that’s likely all you’ll need.
let inputs = document.getElementsByTagName("input")
for (let input of inputs) {
console.log(input.value);
};
querySelector
- The newer, best selector by far
- Pass in a CSS-style selector, using the same syntax as in CSS
querySelector
returns 1,querySelectorAll
returns all.
const img = document.querySelector("#my-image");
- can even use the advanced CSS Selection rules like
ul li.second
for theli
with classsecond
that is a child of aul
querySelectorAll
returns a nodelist.
- Like an HTML collection, but slightly different.
- has a
.length
, array access,[]
, andforEach
.
Exercise: See if you can figure out how many of the smaller titles are on this page using javascript
Most important DOM properties and methods:
element.classList
element.getAttribute()
element.setAttribute()
element.appendChild()
element.append()
element.prepend()
element.removeChild()
element.remove()
element.createElement
element.innerText
element.textContent
element.innerHTML
element.value
element.parentElement
element.children
element.nextElementSibling
element.previousElementSibling
element.style
innerText and textContent
innerText
is the text that’s in the tags.<p>This is the The inner Text</p>
.- If there are multiple things inside with text, get all the text.
- You can even call it on the body
-
If you change it, it will drop all children, and overwrite it with just text
textContent
includes internal spacing, stuff that isn’t rendered on the page but is part of the document.- Less likely to use this one.
innerHTML
- similar to
innerText
, but returns all of the contained content as HTML as a string.- You can read and modify it as needed.
- However, you need to add things as string
- Generally DOM manipulation is preferred
innerHTML
parses tags, vs.innerText
would not parse them as tags.
Exercise: See if you can change the following title to Changing Attributes
Element Attributes such as value, src and href
We can access attributes as properties of the object
e.g. .value
, .checked
, .placeholder
Many of these can be easily accessed. However, not all!
Getters and Setters for less accessible attributes
getAttribute
, setAttribute
e.g. getAttribute('max')
e.g. setAttribute('max', 1000)
you can even change type attribute, e.g. for form elements
document.querySelector("a").attributes;
document.querySelector("a").getAttribute("href");
document.querySelector("a").setAttribute("href", "https://www.w3schools.com");
Traversing the DOM
If you’ve selected an element but want the next one, or child inside, what do you do?
parentElement
property gets the parent (Only one)
children
- returns an HTMLCollection element. (Many)
nextElementSibling
and previousElementSibling
get the next or previous sibling, respectively.
Creating Elements
let h1 = document.createElement('h1')
- From here you can add whatever you want, classes, attributes, etc.
h1.innerText = "A new heading!"
- Then you just need to add it to the DOM somewhere
- separately find the parent you would like to attach it to…
let parent = document.findElementById("my-div");
parent.appendChild(h1)
, appends it as the last child of the elementparent.prependChild(h1)
, prepends it as the first child of the elementinsertBerfore(newNode, existingNode)
allows insertion at a specific point
precise positioning with insertAdjacentElement
let div = document.createElement("div");
let span = document.createElement("span");
div.appendChild(span)
let newSpan = document.createElement("span");
div.insertBefore(newSpan, span);
Removing
remove, removeChild
self.remove ()
or
parent.removeChild(element)
Advanced: Creating elements from templates with template literals
Sometimes you need to create more advanced objects which have a greater amount of elements. As an example, here is a Bootstrap Accordion of 2 items:
let accordText1 = "hello";
let accordText2 = "goodbye";
let insertionPoint = document.querySelector("#insertion-point");
const template = document.createElement('template');
template.innerHTML = `
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Accordion Item #1
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
<div class="accordion-body">${accordText1}</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
Accordion Item #2
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
<div class="accordion-body">${accordText2}</div>
</div>
</div>
</div>`;
const accordion = template.content.firstElementChild;
insertionPoint.append(accordion);
We can even search inside our element and further modify things:
accordion.querySelectorAll(".accordion-body")[0].innerHTML = "Updating first accordion live!"
Changing styles
Changing styles from the DOM is legal, but weird and generally no preferred
- use the style property
- conceptually “write-only” because it only reads inline styles
- this is bad practice.
- Because “-“ is not allowed in JavaScript identifiers, we switch from css-style
kebab-case
to JavaScript stylecamelCase
.
e.g. font-family
becomes fontFamily
All of the properties must be assigned as strings, eg. “30px”, “30%”, “3rem”
Finding the Computed Style
getComputedStyle(element)
- returns an object-like structure with key-value pairs for all the CSS properties.
- Many value will be default.
Changing class with classList
A better way to change styles, particularly if there are many changes is to just define different classes in your external CSS which are not linked to any objects, and then use JavaScript to attach those classes.
classList returns a DOMTokenList object in which you can add elements easy enough
- functions:
classList.remove('classname')
classList.add ('classname')
classList.toggle('classname')
- With toggle, if the class is not there, add it. If it is there, remove it.
Events
A small set of events we can manage:
- clicks
- drags
- drops
- hovers
- scrolls
- form fill
- form submit
- focus or blur
- key presses
- double click
- screen resize
- audio
- animation
Check out the MDN event reference!
Events link an element, a user interaction, and a response (function)
Adding Events
Bad ways to register that you will likely see in examples, including mine:
- in the html tag
<a href="#" onclick="alert('hi')">Click Me</a>
- also not recommended, in JavaScript, simply as this way is older
let button = document.getElementById("my-button");
button.onclick = function () { alert("hi") }
The best way to register:
let button = document.getElementById("my-button");
button.addEventListener("click", function () { alert("hi") } );
The last method is universal, consistent between different types of events, and also uses callback syntax for declaring the function.
Event objects
Invoking an event sometimes creates an object which has more info about that event, eg. your mouse location, screen location, modifiers, etc. This is passed as the first arg of the callback, typically given the variable “e”
keydown, keyup, keypress
keydown
and keyup
fire on rising or falling edges for any key on the keyboard.
keypress
only fires once per rising edge and falling edge- Both
keydown
andkeypress
are subject to keyboard repeat - If you want to process an
enter
in a textbox, do a keypress event, look inside the evente
to see ifenter
was pressed, and if so, then execute code - If you want to only register one key press, avoiding keyboard repetition, set a flag variable on the
keydown
even, clear it on thekeyup
event, and use the flag variable to update your code. - Example from MDN Keypress Event
const log = document.getElementById('log');
document.addEventListener('keypress', function (e) {
log.textContent += ` ${e.code}`;
});
One useful property of e
is target
, which corresponds with the DOM object that was interacted with.
Bubbling
When a click input is captured, it registers on the targeted element, then bubbles up through all the parent elements.
Example from JavaScript.info Bubbling and Capturing
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
If you need to, you can use event.stopPropagation()
to halt the bubbling process prematurely. Just be careful this doesn’t break other expected functionality - in other words, bubbling in JavaScript / DOM is an intended feature, not a bug, so you should have a good reason for disabling it!
The bind
function and the this
keyword:
Navigating bubbling and events can be a hassle, particularly if you are using to try to find an object, e.g. the one that was clicked on. An alternative approach is to pass a reference to a found object using the bind
function, and then access that object in the function using the this
keyword. Be warned, this syntax is a bit weird!
For example, given the following:
<p id="par">Click the button</p>
<button id="but">Click me!</button>
We can access elements as follows:
par = document.getElementById("par")
but = document.getElementById("but")
but.addEventListener("click", function () { this.innerHTML = "Button clicked" }.bind(par) );
This may be particularly useful when dealing with components and objects created with loops!
Exercise:
Create a page with a title and some text. Have a button that swaps between a dark theme and a light theme by attaching or removing pre-created CSS classes.
We’re going to have two parts for today’s lab. The first part takes a break from our main project for now - we’ll get back to that in the next lab. This exercise is purely to understand Front End JavaScript and the DOM.
Part 1: Burn after Reading
For the first part of this lab, we’re going to implement a simple application where users can add sticky notes to a page, and delete them once they are done.
The purpose is to get you used to finding and modifying DOM elements with JavaScript.
In this application, you will create a simple form for adding sticky notes, using a bootstrap card component:
When you press post, this will add a new sticky note to the app:
Pressing the “burn” button on each note will cause the note to be removed from the application:
Extra: Make the notes rotate between different colors. Use the following colors:
#ff7eb9
#ff65a3
#7afcff
#feff9c
#fff740
Thanks to color-hex
When you delete notes, make sure the the colors of the notes do not change. Position can change.
Hint: There are two approaches you could use:
-
An ad-hoc method, where you use the post form to add elements directly to the DOM using JavaScript, and then remove them in a similar fashion with the Burn Button.
- An MVC approach where you store all of the data in a separate list of objects (model).
- When you post an item, add it to the model.
- Then, on the view side
- clear any elements that exist.
- loop through the model,
- and add each to the view separately.
- Then, on the view side
- When you delete an object, remove it from the model,
- then as before, on the view side:
- clear the view,
- loop through the model,
- and add each element back to the view.
- then as before, on the view side:
- When you post an item, add it to the model.
- This approach may seem more difficult and time consuming, but will actually make your life much easier!
For this lab, I am not going to force the MVC approach, but I will in the next lab!
Part 2: Note-Vote Model as JavaScript Objects
Recall in an MVC, the purpose is to separate the data for our application (model) from the presentation (view).
In the second part of the lab, you are to create a JavaScript Object to represent the model for the first prototype version of our Note-Vote app. This type of syntax is called JavaScript Object Notation (JSON), and when saved in a separate file, is a popular way to store database-like data.
This object should include:
- A unique identifier for the note, (numerical)
- The note creator, (text)
- The note’s text, (text)
- A list of usernames who upvoted the note, (list of text)
- A list of usernames who downvoted the note, (list of text)
- Anything else you think would be needed
Create 3 sample notes according to this model. Note that we will NOT display this in the view in this lab, it will only appear in Lab 5.
Submission
Your progress will be checked by a demo next week! Happy scripting.