Andrea De Lorenzo, University of Trieste
| Day | Time | Room |
|---|---|---|
| Monday | 09:30am - 11:00am | Aula V - Building G |
| Tuesday | 03:00pm - 04:30pm | Aula 4C - Building H2 bis |
| Wednesday | 01:00pm - 02:30pm | Aula 4C - Building H2 bis |
Telegram Channel
Some Numbers:
Principles, methods, and techniques of web programming
Practical Course, a lot of technologies:
In practice: how to create a web application
We will only use products available online, for free:
Programming Books:
Design Books:
Some details:
WARNING!!
The technologies we will see:
Final goal: teach how to fish, rather than give the fish.
Always evaluate:
Language used to describe the content and the structure of the information in a web document
It does not describe the presentation of the information!
web page = web document
much more complicated, actually
Important enhancements:
<!DOCTYPE html>)
<article>,
<section>,
<nav>,
<aside>
<audio>,
<video>
Official reference on the differences
To ensure backward compatibility, some things may be allowed for HTML interpreters but not for authors
<!DOCTYPE html>
<html>
<head>
<title>Hello HTML</title>
</head>
<body>
<p>
Hello <a href="http://www.units.it">UniTs</a>!<br/>
We are learning!
</p>
</body>
</html>
<title>Hello HTML</title> →
element
<title> → start tag
Hello HTML → content</title> → end tag
<a href="http://www.units.it">UniTs</a>
href="http://www.units.it" → attribute
href → attribute namehttp://www.units.it → attribute value
<img src="white-dog.png"/>
<br/><input type="checkbox" checked/>
<!--...-->:
<!--nobody can see this-->
<head> → head, additional information about the document
<body> → informational content of the document
<title> → document title<meta name="..." content="...">
name="author" → document author
name="description" → document description
name="keywords" → document keywords ("...,...,...")
Browser: HTML → DOM tree → screen rendering
Tree representation of the document, in memory
Alternatives to the screen:
Different levels of correctness:
Elements can be nested but not overlapped
<p>Example <strong>correct</strong></p> → correct
<p>Example <strong>correct</p></strong> → invalid
Attribute values must be in quotes if they contain spaces
<img src="white-dog.png" alt="White dog"/>
→ correct
<img src=white-dog.png alt="White dog"/>
→ correct
<img src="white-dog.png" alt=White dog/>
→ invalid
To avoid mistakes, always use quotes!
Special characters with a name:
↓ →
down arrow (↓)
ℚ → rationals
(ℚ)
Rules:
&s if s is
the name of one of the characters
There are many more!
What to do?
The specification = THE manual = the bible:
HTML5 W3C Recommendation,
https://html.spec.whatwg.org/multipage/
What does it contain?
Also as an introduction to HTML
Example: start tag? end tag? />?
The start and end tags of certain normal elements can be omitted, as described later
complicated, better to always include the end tag
Another example: <em>
em element
… the teacher is familiar with the W3C Validator
Style → de gustibus?
Usability
they are not only about HTML (HTML ≠ representation)
<!-- --> → defines a comment<!DOCTYPE> → defines the document type
<a> → defines a hyperlink<abbr> → defines an abbreviation<address> → defines an address element
Complete list:
| Tag | Description |
|---|---|
| <!--...--> | Defines a comment |
| <!DOCTYPE> | Defines the document type |
| <a> | Defines a hyperlink |
| <abbr> | Defines an abbreviation or an acronym |
| <acronym> |
Not supported in HTML5. Use
<abbr>
instead. Defines an acronym |
| <address> | Defines contact information for the author/owner of a document |
| <applet> |
Not supported in HTML5. Use
<embed> or
<object>
instead. Defines an embedded applet |
| <area> | Defines an area inside an image-map |
| <article> | Defines an article |
| <aside> | Defines content aside from the page content |
| <audio> | Defines sound content |
| <b> | Defines bold text |
| <base> | Specifies the base URL/target for all relative URLs in a document |
| <basefont> |
Not supported in HTML5. Use CSS instead. Specifies a default color, size, and font for all text in a document |
| <bdi> | Isolates a part of text that might be formatted in a different direction from other text outside it |
| <bdo> | Overrides the current text direction |
| <big> |
Not supported in HTML5. Use CSS instead. Defines big text |
| <blockquote> | Defines a section that is quoted from another source |
| <body> | Defines the document's body |
| <br> | Defines a single line break |
| <button> | Defines a clickable button |
| <canvas> | Used to draw graphics, on the fly, via scripting (usually JavaScript) |
| <caption> | Defines a table caption |
| <center> |
Not supported in HTML5. Use CSS instead. Defines centered text |
| <cite> | Defines the title of a work |
| <code> | Defines a piece of computer code |
| <col> | Specifies column properties for each column within a <colgroup> element |
article → a piece of independent content;
if nested, the inner one is related to the outer one (e.g., a blog post and its comments).
section → a grouping of content that is part
of a broader piece of content, typically with a heading
nav → a section with navigation linksaside → a piece of content complementary to its context (e.g., notes, Twitter messages, etc.)
h1, ..., h6 → headings
(⚠ do not use for subtitles or taglines!)
header → introductory content (e.g., title and navigation)
footer → information related to the section
(e.g., author, additional links, copyright, etc.)
address → contact information (⚠ not for generic addresses)
h1 larger than that of
h2?
section elements larger than
that after an article?
address tag rendered?Wrong, you shouldn’t be asking yourself that!
Language used to describe the content and structure of the information in a web document
Not the representation!
<h2>My memoirs</h2>
<p>
I don’t remember them anymore...
</p>
p → paragraphhr → topic change (not needed between
sections)
pre → preformatted textblockquote → external quotationmain → main content of the page, not
repeated across the site. ⚠ only one per page!
<h3>Ingredients</h3> <ul> <li>Sicilian pesto</li> <li>fusilli</li> <li>grated cheese</li> </ul> <h3>Preparation</h3> <ol> <li>cook the pasta</li> <li>add the pesto</li> <li>garnish with cheese to taste</li> </ol>
ul → unordered listol → ordered listli → list item⚠ must not be placed inside paragraphs!
CR+LF ≠ new linebr → line break, part of the content
brelements must be used only for line breaks that are actually part of the content, as in poems or addresses.
must be used
? → semantic correctness (HTML)
em → the content of the element deserves emphasis
strong → the content is importantmark → highlighted text for reference (e.g., searched text)
s → the content is no longer accurate or relevant
sub and sup → subscript and
superscript text
i → different reading (e.g., another language, technical term, etc.)
u → text with non-textual annotation (e.g., intentionally incorrect)
Authors are encouraged to avoid using the u element where it could be confused for a hyperlink.
b → draw attention
The b element should be used as a last resort when no other element is more appropriate.
code → the content is a piece of source code
samp → output produced by the codevar → a variablekbd → keyboard input... sort ofsamp → the key was pressed by the user and displayed on screen
samp tag → a menu was selected
kbd → key combination
kbdPlease press
Ctrl + Shift + R
to reload a page.
Please press Ctrl + Shift + R to reload a page.
samp in kbdTo create a new file, choose the menu option
File⇒New Document
.
Don't forget to click the OK button
to confirm once you've entered the name of the new file.
To create a new file, choose the menu option File⇒New Document.
Don't forget to click the OK button to confirm once you've entered the name of the new file.
I go to the <a href="http://www.units.it">university</a>
a → link (anchor) to another document
href="" → location of the other document
href="udine.html"
href="http://www.units.it"
href="#people"
href="mailto:andrea.delorenzo@units.it"
link is something else
<img src="white-dog.jpg" alt="The white dog"/>
src → location of the image resourcealt → fallback content:
content that is to be used when the external resource cannot be used
altIs alt mandatory?
Except where otherwise specified, the
altattribute must be specified and its value must not be empty; the value must be an appropriate replacement for the image.One way to think of alternative text is to think about how you would read the page containing the image to someone over the phone, without mentioning that there is an image present.
In some cases, the icon is supplemental to a text label conveying the same meaning. In those cases, the
altattribute must be present but must be empty.[...] In such cases, the
altattribute may be omitted, but one of the following conditions must be met [...]
“Almost” mandatory to include it, but it can be alt=""
<table>
<caption>Line 36 Timetable</caption>
<thead>
<tr><th>Hour</th><th>Minute</th></tr>
</thead>
<tbody>
<tr><td>8</td><td>00 15 30 45</td></tr>
<tr><td>9</td><td>15 45</td></tr>
</tbody>
</table>
caption → title, headingthead; tfoot → column labels; totals, etc. (header, footer)
tbody → body (with the values)tr → row (table row)td, th → cell (table data/header cell)
Do not use them for formatting!
Tables must not be used as layout aids. Historically, some Web authors have misused tables in HTML as a way to control their page layout. This usage is non-conforming, because tools attempting to extract tabular data from such documents would obtain very confusing results. In particular, users of accessibility tools like screen readers are likely to find it very difficult to navigate pages with tables used for layout.
There are a variety of alternatives to using HTML tables for layout, primarily using CSS positioning and the CSS table model.
div and spanThe
divelement has no special meaning at all. It represents its children. It can be used with theclass,lang, andtitleattributes to mark up semantics common to a group of consecutive elements.
→ BLOCK level
The
spanelement doesn't mean anything on its own, but can be useful when used together with the global attributes, e.g.class,lang, ordir. It represents its children.
→ inside a text line
div: example<article lang="en-US">
<h1>My use of language and my cats</h1>
<p>My cat's behavior hasn't changed much since her absence, except
that she plays her new physique to the neighbors regularly, in an
attempt to get pets.</p>
<div lang="en-GB">
<p>My other cat, coloured black and white, is a sweetie. He followed
us to the pool today, walking down the pavement with us. Yesterday
he apparently visited our neighbours. I wonder if he recognises that
their flat is a mirror image of ours.</p>
<p>Hm, I just noticed that in the last paragraph I used British
English. But I'm supposed to write in American English. So I
shouldn't say "pavement" or "flat" or "colour"...</p>
</div>
<p>I should say "sidewalk" and "apartment" and "color"!</p>
</article>
span: example<code class="lang-c"><span class="keyword">for</span> (<span class="ident">j</span> = 0; <span class="ident">j</span> < 256; <span class="ident">j</span>++) {
<span class="ident">i_t3</span> = (<span class="ident">i_t3</span> & 0x1ffff) | (<span class="ident">j</span> << 17);
<span class="ident">i_t6</span> = (((((((<span class="ident">i_t3</span> >> 3) ^ <span class="ident">i_t3</span>) >> 1) ^ <span class="ident">i_t3</span>) >> 8) ^ <span class="ident">i_t3</span>) >> 5) & 0xff;
<span class="keyword">if</span> (<span class="ident">i_t6</span> == <span class="ident">i_t1</span>)
<span class="keyword">break</span>;
}</code>
for (j = 0; j < 256; j++) {
i_t3 = (i_t3 & 0x1ffff) | (j << 17);
i_t6 = (((((((i_t3 >> 3) ^ i_t3) >> 1) ^ i_t3) >> 8) ^ i_t3) >> 5) & 0xff;
if (i_t6 == i_t1)
break;
}
id Attributeid → unique identifier
<section id="abstract">It can be used for:
<a href="#abstract">Identifiers are opaque strings. Particular meanings should not be derived from the value of the id attribute.
title Attributetitle → descriptive indication
<a href="udine.html" title="Info page of the neighboring city">Udine</a>
<abbr title="Cascading Style Sheet">CSS</abbr>
Advisory information for the element, such as would be appropriate for a tooltip.
lang and translate Attributeslang → main language of the content
<p lang="it">L'inglese è difficile da pronunciare:
per sempio la parola <span lang="en-UK">Wednesday</span>.</p>
<p lang="de"><span lang="en-UK">Wednesday</span>
ist ein schwieriges Wort auszusprechen.</p>
translate → whether or not this content should be localized
Enumerated values:
yesnoExample: code fragments, keyboard input, menus, etc.
class attribute
Value: a set of space-separated names:
<span class="content keyword">if</span>
Authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content
semantic correctness (HTML)
data-* Attribute
<section data-dog-weight="12.8kg" data-dog-speed="75%">
<h1>White dog</h1>
<p>The white dog is stocky but fast.</p>
</section>
data- is the name of the
custom attribute
dir and style Attributesdir → text direction
style → appearance of the element, we’ll see later
<header> | |
<nav> | |
<section> | <aside> |
<article> | |
<footer> | |
article inside section or the other way around?The article element specifies independent, self-contained content.
The section element defines a section in a document.
Can we use the definition to decide how to nest these elements? No.
In some HTML pages a section will contain an article,
and in others an article will contain a section.
Write a (HTML-only) document about your city or neighborhood.
Content (items):
We will assess the syntactic, semantic, and stylistic correctness of the HTML document.
Rules:
aside, i, em,
strong, nav, lang,
li
Choose whichever you like, I suggest:
Recommended extensions:
Recommended packages:
Features:
Fewer plugins than VS Code or Sublime, but designed for speed and teamwork.
Language used to describe the content and the structure of the information in a web document
The browser renders the document:
how does it draw it on the screen?
How?
HTML
<!DOCTYPE html>
<html>
<head>
<title>Sample page</title>
</head>
<body>
<h1>Sample page</h1>
<p>This is a <a href="demo.html">simple</a> sample.</p>
<!-- this is a comment -->
</body>
</html>
DOM tree:
htmlhtml head #text: ⏎␣␣title #text: Sample page#text: ⏎␣#text: ⏎␣body #text: ⏎␣␣h1 #text: Sample page#text: ⏎␣␣p #text: This is a a href="demo.html" #text: simple#text: sample.#text: ⏎␣␣#comment: this is a comment #text: ⏎␣⏎Let’s consider the subtree of the node body (some #text omitted):
body is the parent of the node h1p, #comment, ... are sibling of the node h1h1, p, ... are children of the node bodya, h1, p, ... are descendant of the node bodybody, p, h1, a are elements#text are text (they have no children!)For each node of the DOM tree:
reading the document: "drawn" → "spoken", "where" → "when"
Imagine you are the browser, or that you have to write the browser program’s code...
Goal: DOM tree → boxes tree
Main transformation rules:
An element is drawn if and only if all the following conditions are valid:
Premise: types of boxes
What they can contain:
strong element)Roughly speaking:
consecutive block-level boxes are placed one below the other inside the parent block-level box
They try to fill all the available horizontal space
consecutive inline-level boxes are placed side by side inside the parent line-level box
They only occupy the strictly necessary space
"consecutive" → follows the order of the DOM tree
Non-exhaustive list:
ptablenavdivformmain, article, sectionh1, h2, ...Non-exhaustive list:
aspanemstronginput, button, textareaimgAnd which elements generate Line Boxes?
They are generated automatically!
The rectangular area that contains the boxes that form a line is called a line box.
When several inline-level boxes cannot fit horizontally within a single line box, they are distributed among two or more vertically-stacked line boxes. Thus, a paragraph is a vertical stack of line boxes.
When an inline box exceeds the width of a line box, it is split into several boxes and these boxes are distributed across several line boxes. If an inline box cannot be split (e.g., if the inline box contains a single character, or language specific word breaking rules disallow a break within the inline box, or if the inline box is affected by a white-space value of nowrap or pre), then the inline box overflows the line box.
We’re missing something:
"box type", "margin", ... → style properties of boxes
A document that specifies which values to assign to which elements’ properties
A document that specifies which values to assign to which elements’ properties
"the element of type p must correspond to a block-level box with a 1cm margin"
But the browser still displays my page, even though I haven’t provided any CSS!
↓
implicit rules
The CSS rules given in these subsections are, except where otherwise specified, expected to be used as part of the user-agent level style sheet defaults for all documents that contain HTML elements.
In the specification, a CSS follows
You don't need to be a programmer or a CS major to understand the CSS specifications. You don't need to be over 18 or have a Bachelor's degree. You just need to be very pedantic, very persistent, and very thorough.
Less simple compared to HTML: the specification is modular
As the popularity of CSS grows, so does interest in making additions to the specification. Rather than attempting to shove dozens of updates into a single monolithic specification, it will be much easier and more efficient to be able to update individual pieces of the specification. Modules will enable CSS to be updated in a more timely and precise fashion, thus allowing for a more flexible and timely evolution of the specification as a whole.
For resource constrained devices, it may be impractical to support all of CSS. For example, an aural browser may be concerned only with aural styles, whereas a visual browser may care nothing for aural styles. In such cases, a user agent may implement a subset of CSS. Subsets of CSS are limited to combining selected CSS modules, and once a module has been chosen, all of its features must be supported.
An ordered list of rules
does not apply only to HTML documents
selector {
property-name: property-value;
property-name: property-value;
...
}
selector { /* comment */
property-name: property-value;
property-name: property-value;
...
}
/* comment */
The specification defines:
@:
@charset@import@namespace@media@viewportBut we’ll talk about them later...
Attention: if the syntax of a rule is incorrect, the browser must ignore the entire rule!
"must ignore" = "the specification recommends that the browser ignore it" → the browser may not ignore...
different from what happens with HTML
Three levels of correctness:
there is a CSS validator
Who defines the style?
Where do I specify that I want to use certain rules for a given HTML document d? Three methods:
<link rel="stylesheet" type="text/css" href="...">
style element:
<style>...</style>
style attribute of the element I want to style (the selector is not needed!):<p style="...">
@importThe @import rule allows you to import other style sheets into a CSS code
@charset is allowedExample: importing a Google Web Font
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" >
font-family: 'Roboto', sans-serif;
All methods can be used together → they are all applied!
<link ...>)
link is also used for other purposes
If a property P is not defined for an element E, the element inherits the value of P from its parent (parent of E)
Inheritance → cascading style sheet
How do I compute the value of each property?
Six values for each property...
Examples:
| Declared | Inherited | Specified | Computed | Used | Actual |
|---|---|---|---|---|---|
| text-align: left | left | left | left | left | left |
| width: (none) | (none) | auto | auto | 120px | 120px |
| font-size: 1.2em | 1.2em | 1.2em | 14.1px | 14.1px | 14px |
| width: 80% | 80% | 80% | 80% | 354.2px | 354px |
em is the font size →
2em = 2 times the font size.
What if multiple rules are in conflict?
style="...", most important)<style>)<link>)!importantCSS attempts to create a balance of power between author and user style sheets. By default, rules in an author’s style sheet override those in a user’s style sheet.
!important changes the priority:
Example:
{ background-color: lightgrey !important; }
!important!important solves the problem!important.button {
background-color: #8c8c8c;
color: white;
padding: 5px;
border: 1px solid black;
}
#myDiv a {
color: red;
background-color: yellow;
}
.button {
background-color: #8c8c8c !important;
color: white !important;
padding: 5px !important;
border: 1px solid black !important;
}
#myDiv a {
color: red;
background-color: yellow;
}
Some keywords allow forcing certain behaviors:
initial → default valueinherit → taken from the parent elementunset, revert)An expression that, when applied to an element, returns a boolean
fselector(E) ∈ {true, false}
The specification describes all the possible functions f
* → any element (f*(E) = true, ∀ E)e → elements of type <e>f e → elements of type <e> that are descendants of elements of type <f>e.className → elements of type <e> with class "className"e#idName → elements of type <e> whose id attribute value is equal to "idName"descendant ≠ child
<img class="photo old" src="..."/> is selected by both img.photo and img.old
* → universal selectore → type selector (e.g., <div>, <p>).className → class selector#idName → ID selectorSelectors can be "combined":
e.c1 f → an <f> that is a descendant of an <e> with class "c1"e f g → a <g> that is a descendant of an <f> that is a descendant of an <e>e * → all descendants of an <e>The universal selector * can be omitted in certain cases:
*.c1=.c1 → any element with class "c1"*#id1=#id1 → any element with id "id1"e > f → an <f> that is a child of an <e> (child combinator)e + f → an <f> that is immediately preceded by its sibling <e> (adjacent sibling combinator)e ~ f → an <f> that is preceded by its sibling <e> (general sibling combinator)e[a] → an <e> with an attribute ae[a="val"] → an <e> with attribute a equal to "val"e[a~="val"] → an <e> with a="v1 v2 v3 ... val ..." (space-separated values)e[a^="val"] → an <e> with a="valrest"e[a$="val"] → an <e> with a="restval"e[a*="val"] → an <e> with a="somethingvalsomething"e[a|="val"] → an <e> with a="val-v2-v3" (values separated by "-")
f[lang|="en"](<p lang="en-US">) = f[lang|="en"](<p lang="en-UK">) = true
Pseudoclasses: classes not explicitly defined, but matching elements present in the HTML
e:nth-child(n), e:nth-last-child(n) → an <e> that is the n-th (n-th from the end) child of its parente:nth-of-type(n), e:nth-last-of-type(n) → an <e> that is the n-th (n-th from the end) child of its parent among children of type <e>e:first-child, e:last-child, e:first-of-type, e:last-of-typee:only-child, e:only-of-type → an <e> that is the only child (without siblings of type e)e:root → the <e> that is the root of the documente:empty → an <e> without children, not even textnth-child: detailse:nth-child(n): n can be an expression that is a bit more complex:
e:nth-child(3) → the third childe:nth-child(even) = e:nth-child(2n) → even childrene:nth-child(odd) = e:nth-child(2n+1) → odd childrene:nth-child(5n+2) → the 2nd, 7th, 12th, ... childe:visited, e:link → an <e> that is a link to a visited (unvisited) document
(*link pseudo-classes*)e:active, e:hover, e:focus → an <e> in certain states related to user interaction
(*user action pseudo-classes*)e:enabled, e:disabled, e:checked → an <e> that is part of the UI and in certain states
(*UI element states pseudo-classes*)e:lang(en) → an <e> whose content is in English
(*:lang() pseudo-class*)e:target → an <e> that has been targeted by an anchor (URL#anchor)
(*:target pseudo-class*)
http://units.it/bandi.html#scaduti → <section id="scaduti"> is :target
Pseudoelements: elements not explicitly defined, thus generated
e::first-line → a generated element representing the first line of text in an <e>e::first-letter → a generated element representing the first letter of an <e>e::before, e::after → a generated element inserted before (after) the content of an <e>
content property<p>Nel mezzo di cammin di nostra vita</p>
↓
<p><span::first-letter>N</span>el mezzo di cammin di nostra vita</p>
e:not(selector) → an <e> to which the selector does not apply
(only simple selectors allowed, div > div is invalid).
p:not(:first-child) → all p elements that are not the first child of their parent
:has()The :has() CSS pseudo-class represents an element if any of the selectors passed as parameters match at least one element.
e:has(selector) → an <e> that is the parent of an element matching the selectore:has(f):has(g) or e:has(f, g)Support is limited to some browsers
Remember? It is one of the mechanisms for resolving inheritance conflicts.
A "number" is generated, composed of three digits, obtained by counting in the selector:
The larger the number, the higher the specificity.
A great example based on Star Wars.
tr:nth-child(even) {
background-color: #8be9fd; /* we’ll see... */
}
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 |
p::first-letter {
font-size: 200%; /* we’ll see ... */
color: #8be9fd; /* this too ... */
}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique velit eget neque ornare, vitae luctus magna mollis. Donec arcu ligula, tristique et porttitor nec, feugiat et tortor. Suspendisse vel nisi a mauris consectetur hendrerit. Fusce congue leo est, et suscipit massa venenatis vitae. Sed nec molestie nibh. Sed purus tortor, molestie sed justo non, iaculis ultricies orci. Nullam quis quam justo. Nunc finibus aliquet tincidunt. Nunc mattis metus at arcu tristique semper. Vivamus iaculis lacus porttitor, pretium leo tincidunt, euismod nisi. Morbi sodales pharetra ante in congue. Aenean sed erat dui. Aenean eget elementum metus.
figure:has(figcaption) img {
outline: 10px dashed #8be9fd;
}
We will only see a few...
color → text colorbackground-color → background colorborder-color → border colorValues:
color: red; → by named color keyword (including extended color keywords)color: #ff0000; → hexadecimal RGB notationcolor: rgb(255,0,0), color: rgb(100%,0%,0%) → functional RGB notation (integer and percentage values)color: rgba(255,0,0,0.33), color: rgba(100%,0%,0%,0.33) → functional RGBA notation with alpha channelcolor: transparent; → transparent keywordbackground-color → background colorbackground-image → background imagebackground-repeat → background-repeat property (repeat, repeat-x, repeat-y, no-repeat)background-attachment → background-attachment property (scroll, fixed, local)background-position → background-position property (keywords, lengths, or percentages)background → shorthand property for all background-related propertiesExample:
body {
background-image: url('img_tree.png');
background-repeat: no-repeat;
background-position: right top;
}
font-family → font family name / generic familyfont-size → absolute-size keyword | relative-size keyword | length | percentagefont-weight → font weight (normal, bold, 100–900)font-variant → small-caps variantfont-style → normal | italic | obliquefont → shorthand property for all font-related propertiesExample:
h1 {
font-family: Helvetica, Verdana, sans-serif;
font-weight: bold;
font-size: x-large;
}
font-family: Helvetica, Verdana, sans-serif → the first available one is used
font-family and @font-faceThe author may want to use a specific font, but it may not be installed on the user’s system:
font-family: "Fancy Design Font", sans-serif;
↓
@font-face defines a downloadable font resource
@font-face {
font-family: 'Ubuntu';
src: local('Ubuntu'),
local('Ubuntu-Regular'),
url('http://themes.googleusercontent.com/font?kit=2Q-AW1e_taO6pHwMXcXW5w') format('truetype');
}
h1 { font: "Ubuntu" 10px;}
@font-face is an at-rule
font-sizefont-size: absolute-size keyword | relative-size keyword | length | percentage | inherit
Examples:
font-size: medium; /* absolute-size keyword */
font-size: large; /* absolute-size keyword */
font-size: 115%; /* percentage */
font-size: larger; /* relative-size keyword */
font-size: 10px; /* length */
font-size: 0.75cm; /* length */
Some properties accept a value of type length.
Absolute length units:
in → inches; 1in = 2.54cm
cm → centimeters
mm → millimeters
Q → quarter-millimeters (1Q = 0.25mm)
pt → points; 1pt = 1/72in
pc → picas; 1pc = 12pt
px → reference pixels (CSS pixel)
How does the browser know how many device pixels make up 1cm?
In CSS, absolute units are defined relative to the reference pixel and a standard pixel density; on many screens physical sizes are mapped heuristically.
Relative length units:
em → font size of the element (for
font-size, relative to the parent’s font size)
ex → x-height of the element’s font
ch → width of the "0" (zero) glyph in the used font
rem → font size of the root element
lh → computed line height of the element
rlh → line height of the root element
vw → 1% of the viewport’s width
vh → 1% of the viewport’s height
vmin → 1% of the smaller viewport dimension
vmax → 1% of the larger viewport dimension
The unit px is the CSS reference pixel; it’s treated as an absolute unit in CSS specifications.
line-heightletter-spacingtext-aligntext-decorationtext-indenttext-transformvertical-alignExamples (more here):
.draft span.note {
text-transform: uppercase;
}
.draft span.old-version {
text-decoration: overline;
}
They behave like variables
counter-reset: counterName;counter-increment: counterName;content propertyExample:
body {
counter-reset: sectionCount;
}
h2::before {
counter-increment: sectionCount;
content: "Section " counter(sectionCount) ": ";
}
Defines how the box will be rendered
There are three possible values
Various options:
display PropertySummarizes in a single value how to set Inner/Outer Display Type
In short, it determines the type of box that will be generated
display: inline → inline flow → inline-level boxdisplay: block → block flow → block-level boxdisplay: none → does not generate a boxdisplay: inline-block → inline flow-root → we’ll see laterdisplay: flex → block flex → we’ll see laterdisplay has a major impact on the representation of a document!
visibility: visible → drawsvisibility: hidden → does not drawWarning:
visibility: hidden → the box takes up the expected space but is not visibledisplay: none → the box does not existWe use width and height:
max-widthIs it enough to know width and height to calculate the occupied space?
NO!
They refer to the content; you also need to know margin and padding
But I can cheat:
box-sizing: border-box; → padding and borders are included
Hint: consider adding it in a * { } block
How can I move the box?
position property:
static → default, follows the normal flow; not affected by top/bottom/right/left and formally not positionedrelative → extra properties must be used (top, right, bottom, or left)
position: relative; top: -20px; left: 20px; makes the second block overlap the first
How can I move the box?
position property:
fixed → positioned relative to the browser window
absolute → behaves like fixed but relative to the nearest positioned ancestor
<HTML>Example:
nav {
position: absolute;
left: 0px;
width: 200px;
}
section {
/* position is static by default */
margin-left: 200px;
}
footer {
position: fixed;
bottom: 0;
left: 0;
height: 70px;
background-color: white;
width: 100%;
}
A floating box is shifted in the line to the right or left until it bumps into the edge of its parent box
The rest of the content flows alongside; line boxes are shortened
float: left, float: right → it floatsfloat: none → does not float (default)Ex: style="float: left; width: 200px;height: 100px;margin: 1em;"
A floating box can be taller than the containing box; even the lines of the following block-level box are shortened if necessary… how to avoid this?
clear
clear: left, clear: right, clear: both → don’t align with floating boxes on the left and/or rightclear: none → allow alignment.clearfix {
overflow: auto;
zoom: 1; /* for IE6 */
}
float and clear: examplep {clear: left;}
img {float: left;}
float and clearAt what point in the HTML document is the image inserted?
I want to create a grid of boxes that fills the entire width of the browser: I can do it with
float: left → inconvenient, I need to apply clear to the next blockdisplay: inline-block (some issues with IE6 and IE7)And I don’t need any clearing!
column allows me to split text into columns
.three-column {
padding: 1em;
column-count: 3;
column-gap: 1em;
}
display: flex; comes with CSS3 → not all browsers handle it well
It has several properties, which can be grouped by applicability:
flex-direction: row | row-reverse | column | column-reverse
flex-direction: row | row-reverse | column | column-reverse
flex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)
flex-direction: row | row-reverse | column | column-reverse
flex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly
flex-direction: row | row-reverse | column | column-reverseflex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)justify-content: flex-start | flex-end | center | space-between | space-around | space-evenlyalign-items: flex-start | flex-end | center | baseline | stretch (aligns a flex row)align-content: flex-start | flex-end | center | space-between | space-around | stretch (aligns multiple rows)order: <integer> → reorders the contentflex: <integer> → how to share the space
align-self: overrides the container’s valueSimply put: we make sure our website works well on every device.
The ViewPort is the area of the page visible to the user.
Smartphone & tablet browsers automatically shrink the page to fit the screen: let’s avoid this
<meta name="viewport" content="width=device-width, initial-scale=1.0">
You can make certain rules apply only to specific media (or media with certain characteristics):
link:
<link ... media="screen" href="css1.css"> <link ... media="print,tty" href="css2.css">
@media:
@media print {
/* style sheet for print goes here */
}
Some media: screen, print, handheld, braille, speech, tty, ...
We want a layout like this:
How can I switch between the three layouts or create the third one?
Slides inspired by the presentation of Morten Rand-Hendriksen
Terminology
display: grid;
Terminology
display: grid;How is it used?
That's it!
Defining the grid:
display: grid;grid-template-columns and grid-template-rows: draw the rows;
they take a list of values that specify the distances between rows.
Units of measurement: em, px, %, fr (fractions), auto (fits content).
main{
display: grid;
grid-template-columns: 2fr 1fr 1fr;
}
Done! The grid items are placed inside (top-bottom, left-right).
Spanning multiple cells
grid-column: x/y; → from vertical line X to Ygrid-row: x/y; → from horizontal line X to YProblem: working with numbers is tricky, it’s easy to get confused (though you can actually name the lines)
Using textual descriptions to assign names to the grid container’s cells...
main{
display: grid;
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas:
"title title title"
"main header header"
"main sidebar sidebar";
}
...and in the grid items you specify the name
h1{
grid-area: title;
}
And the magic happens with media queries...
@media screen and (max-width: 700px) {
main {
grid-template-areas:
"title title title"
"header header header"
"main main sidebar";
}
}
Some details:
@supports (grid-area: auto){...}In practice:
Some useful references:
But does it always work?
NO!
And not only that — the problem also applies to other features (e.g., column)
Solution: prefixes
By specification, properties will never start with
.foo {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-orient: horizontal;
-moz-box-orient: horizontal;
-webkit-box-direction: normal;
-moz-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
Do I always have to do everything manually?
No! I can get help
One line to rule them all, and in the darkness bind them...
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/[...]" >
Optional: some JavaScript
It’s worth reading the official guide
A CSS development tool written in JavaScript, usable
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="less.js" type="text/javascript"></script>
@red: #FF0000;
a {color: @red}
→ a {color: #ff0000}
div{
width: 200px;
p{ font-size: 20px; }
}
→ div{ width: 200px;}
→ div p{ font-size: 20px;}
.mixin{
color: red;
font-weight:bold;
}
p{
font-size:18px;
.mixin;
}
→ .mixin{color: red; font-weight:bold;}
→ p{font-size: 18px; color: red; font-weight:bold;}
.mixin(){
color: red;
font-weight:bold;
}
p{
font-size:18px;
.mixin;
}
→ p{font-size: 18px; color: red; font-weight:bold;}
.mixin(@param){
color: @param;
font-weight:bold;
}
p{
font-size:18px;
.mixin(red);
}
Using the HTML document from exercise HTML-1, write CSS that renders the document like a medieval illuminated manuscript.
Using the HTML document again: the content of each section must be invisible by default and become visible under some user action.
For example:
only HTML and CSS
Some more changes:
section → @page;
some help only HTML and CSS
I can ask the browser to execute compiled code (or code running on a VM)
Language used to describe the content and structure of the information in a web document
In reality, the goal of HTML is explicitly broader:
This specification is limited to providing a semantic-level markup language and associated semantic-level scripting APIs for authoring accessible pages on the Web ranging from static documents to dynamic applications.
Execution of the author’s code in the context of the web document
Code? → JavaScript
... but not only
During execution, the code can access the DOM tree, and thus the information within the document
But also external resources (the window, storage, ...)
HTML Document → DOM tree → representation
Manipulating the DOM means changing the representation — in real time!
The specification also describes the interface of the various elements:
DOM interface:[NamedConstructor=Image(), NamedConstructor=Image(in unsigned long width), NamedConstructor=Image(in unsigned long width, in unsigned long height)] interface HTMLImageElement : HTMLElement { attribute DOMString alt; attribute DOMString src; attribute DOMString useMap; attribute boolean isMap; attribute unsigned long width; attribute unsigned long height; readonly attribute unsigned long naturalWidth; readonly attribute unsigned long naturalHeight; readonly attribute boolean complete; };
This is the documentation of the DOM interface for the img element
Note:
→ they don’t have a specific “when”...
It is executed when it is encountered
The browser reads (parses) the HTML document, and when it finds a script, it executes it
Two main methods:
<script type="text/javascript">
/* do something */
</script>
<script type="text/javascript" src="..."></script>
src and Start of ExecutionFor external scripts, you can specify the defer attribute:
<script type="text/javascript" src="..." defer></script>
→ execution is postponed until the browser reaches the end of the document
for embedded scripts, see onload
defer or not defer?What’s the difference?
The code can access the DOM...
↓
HTML half-read → DOM only half-complete
Association of a piece of code (function) with an event
there’s a click on this button → do these things
the browser reaches the end of the document → do these things
The association can be defined:
<p onclick="/* piece of code */">click me!</p>
What will we learn?
Meanwhile:
Engine = pair (VM, dialect)
There are many:
Sophisticated: for example, JIT
We won’t go into detail
Some peculiarities:
boolean, break, delete, extends, static, ... many unusedWe’ll see more as we go
5 basic immutable types:
nullundefinedAll other values are objects (mutable): arrays, functions, regexes, and objects.
typeoftypeof x is a string which describe the type of x
typeof 1 // → "number"
typeof "a" // → "string"
typeof true // → "boolean"
typeof {a: 1} // → "object"
typeof undefined // → "undefined"
typeof null // → ???
typeof: nulltypeof null // → "object"!!!
But why???
In memory: 32 bits per value
Null: dato = 0x00]typeof: nulltypeof null // → "object"!!!
Value decoding (original code):
if (JSVAL_IS_UNDEFINED(v)) {
type = JSTYPE_UNDEFINED;
} else if (JSVAL_IS_OBJECT(v)) {
obj = JSVAL_TO_OBJECT(v);
if (obj [..] clasp == js_FunctionClass)) {
type = JSTYPE_FUNCTION;
} else {
type = JSTYPE_OBJECT;
}
} else if (JSVAL_IS_NUMBER(v)) {
type = JSTYPE_NUMBER;
} else if (JSVAL_IS_STRING(v)) {
type = JSTYPE_STRING;
} else if (JSVAL_IS_BOOLEAN(v)) {
type = JSTYPE_BOOLEAN;
}
return type;
typeoftypeof x is a string that describes the type of x
typeof 1 // → "number"
typeof "a" // → "string"
typeof true // → "boolean"
typeof {a: 1} // → "object"
typeof undefined // → "undefined"
typeof null // → "object"!!!
typeof typeof 44?
There’s a sixth possibility: we’ll see it later.
It would have been better if typeof null returned "null".
typeof and SyntaxRelaxed syntax...
Which ones work, and why?
typeof 1?typeof(1)?typeof (1)?typeof and SyntaxRelaxed syntax...
Which ones work, and why?
typeof 1?typeof(1)?typeof (1)?typeof is an operator, and what is inside the parentheses is an expression to be evaluated.
Numbers, strings, and booleans are object-like: you can access their methods
(22).toExponential() // → "2.2e+1"
"job".charAt(2) // → "b"
true.toLocaleString() // → "true"
but they are immutable!
There is only one number type: float (IEEE 754 Double Precision)
Remember the issues this causes?
There is only one number type: float (IEEE 754 Double Precision)
0.1 + 0.2 == 0.3 /* → false */
9999999999999999 == 10000000000000000 /* → true */
null vs undefinedAn identifier refers to:
undefined if no value (other than undefined) has been assigned to itnull only if it has been explicitly assigned nullWhy do both exist? Is there a reason?
An object is a mutable collection of properties.
Collection of key-value couples comma-separated.
var simba = {
name: "simba",
animalType: "dog",
legs: 4,
"sound": "bark",
collar: {
material: "leather",
size: "M"
}
};
"animalType", "dog" is a property: "animalType" is the name (string type), "dog" is the value (string type).
The value of the property named "collar" is of type object.
var statementvar simba = {
name: "simba",
animalType: "dog",
legs: 4,
"sound": "bark"
}
simba as visible within the scope.What is the scope? We’ll see.
simba.namesimba["name"]Both expressions access the name property of the object referred to by simba.
The second form is necessary if the property name has certain characteristics, e.g. simba["is cute"].
If simba refers to undefined or null, then a TypeError exception is thrown.
. and [] are refinement operators.
Spacing is flexible:
simba.namesimba["name"]simba .namesimba. namesimba . namesimba ["name"]All are equivalent and syntactically correct.
But not all are stylistically good...
var name = simba.name;
If it’s not defined, the value is undefined.
simba.nickname = "White dog";
If it’s not defined, it’s added; otherwise, it’s modified.
delete simba.nickname;
Objects are always passed by reference.
var simba = {
name: "simba",
collar: {
material: "leather",
size: "M"
}
};
var whitedog = simba;
var c = whitedog.collar;
delete whitedog.collar;
whitedog.collar? → undefined
simba.collar? → undefined
c? → Object {material: "leather", size: "M"}
var simba = {
name: "simba",
legs: 4
};
for (var propName in simba) {
console.log("simba." + propName + " = " + simba[propName] + ", of type " + (typeof simba[propName]));
}
A function is an object with two additional hidden properties:
typeof f returns "function" if f is a function.
Here is the sixth element.
var sum = function(a, b) {
var c = a + b;
return c;
}
sum(2,3); /* → 5 */
sum refers to a function object, whose two statements (lines 2 and 3) form its body.
var sum = function(a, b) {
return a + b;
}
sum.name /* → "" (or the variable name) */
Anonymous function — sum refers to the function.
This is the recommended option.
Why does it have a name property? Who added it? We’ll see.
var sum = function summation(a, b) {
return a + b;
}
sum.name /* → "summation" */
Named function — sum refers to the function, summation is not a defined identifier.
The name is still useful for:
function summation(a, b) {
return a + b;
}
summation.name /* → "summation" */
Named function — summation is defined and refers to the function.
Functions are objects, i.e. mutable collections of properties!
var sum = function(a, b) {
return a + b;
}
sum.p = "hello";
The scope is the region in which identifiers are defined (visible).
In JavaScript, the scope is the function body.
Despite the block syntax (curly braces), the scope is not the block!
In JavaScript, the scope is the function body.
var maxSumProd = function(a, b) {
var s = a + b; /* s is defined */
var p = a * b; /* s, p are defined */
for (var i = 0; i < 4; i++) {
var c = i; /* s, p, i, c are defined */
}
if (s > p) { /* s, p, i, c are defined */
return s;
} else {
return p;
}
};
Different from Java!
Scopes are hierarchical: inside a function’s scope, identifiers (except for this and arguments) defined in the outer scope are visible.
var fun = function() {
var a = 1;
var b = 2;
var innerFun = function() {
var c = a + b;
return c;
};
return innerFun();
};
var defines a variable; if omitted, it implies the global scope.
var a; → a is defined (but uninitialized) in the local scopevar a = 0; → a is defined and refers to 0 in the local scopea = 0;
a was defined in a parent scope, it now refers to 0Watch out!
var calculateTopTenCosts = function() {
var sum = 0;
for(top = 0; top < 10; top++) {
sum += getRankCosts(top);
}
return sum;
};
var is missing before top in the looptop becomes a global variable (in a browser: the top-level window object)top is not a number)var declares the variable in the function scope.
And if I want one at the block level?
Since ECMAScript 6 you can use: let
There are four Function Invocation Patterns:
What changes?
thisargumentsthis depends on the invocation pattern.If and only if:
this is the object containing itundefined
var o = {
n: 3,
sum: function(m) {
return this.n + m;
},
dec: function(m) {
return n - m;
}
};
o.sum(2)? → 5
o.dec(1)? → error! n undefined
var f = o.sum; f(2)? → NaN
var f = o.sum(); f(2)? → f is not a function
thisthis is not optional!
given the same semantics.
When the function is not a property of an object and is invoked directly:
var sum = add(3, 4); // sum is 7
this is the global object.window object.this of the outer function!If done correctly, this would refer to the outer function...
var myObject = {
value: 1,
double: function() {
var helper = function() {
this.value = this.value * 2;
};
helper();
}
}
console.log(myObject.value); /* → 1 */
myObject.double(); /* Method Invocation */
console.log(myObject.value); /* → ?? */
Workaround
var myObject = {
value: 1,
double: function() {
var that = this;
var helper = function() {
that.value = that.value * 2;
};
helper(); /* Function Invocation */
}
}
console.log(myObject.value); /* → 1 */
myObject.double(); /* Method Invocation */
console.log(myObject.value); /* → 2 */
Every function also has an apply method: when called, the first parameter becomes this and the second one becomes arguments.
var sum = function(a, b) {
return a + b;
};
sum.apply(undefined, [2, 3]); /* → 5 */
[2, 3] is an array literal — we’ll cover that later.
var myObject = {
value: 1,
double: function() {
var helper = function() {
this.value = this.value * 2;
};
helper.apply(this); /* Apply Invocation */
}
}
console.log(myObject.value); /* → 1 */
myObject.double(); /* Method Invocation */
console.log(myObject.value); /* → 2 */
new)If a function is called with the keyword new:
this is a new objectthis is returnedThe new object has a hidden link to the function’s prototype property.
It looks like a constructor, but it can be misused.
By convention (and to avoid misuse), functions intended as constructors start with a capital letter.
var Dog = function(name, size) {
this.name = name;
this.size = size;
this.sound = "bark";
this.makeSound = function() {
return this.sound;
}
};
var whiteDog = new Dog("Simba", "M");
var brownDog = new Dog("Gass", "M");
var Dog = function(name, size) {
this.name = name;
this.size = size;
this.sound = "bark";
this.makeSound = function() {
return this.sound;
}
};
var weirdDog = Dog("Simba", "M");
weirdDog? → undefined!
argumentsarguments is a (quasi) array
length property...arguments may contain more parameters than the function definition:
function myConcat(separator) {
var result = '';
var i;
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
myConcat(', ', 'red', 'orange', 'blue');
// → "red, orange, blue, "
argumentsTheir values are linked:
var sum = function(a, b) {
var c = a + b;
return c;
}
a and arguments[0] always share the same value.
argumentsvar surpriseMe = function (a) {
console.log(a + " - " + arguments[0]);
a = 3;
console.log(a + " - " + arguments[0]);
};
surpriseMe(2)?
2 - 2
3 - 3
argumentsFor non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object’s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.
JavaScript oddities
but luckily there’s Stack Overflow
It used to be done manually:
function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1;
return a * b;
}
...now it can go in the signature (ECMAScript 2015)
function multiply(a, b = 1) {
return a * b;
}
Aggregates multiple parameters into an array:
function myConcat(separator, ...values) {
var result = '';
var i;
for (i = 0; i < values.length; i++) {
result += values[i] + separator;
}
return result;
}
myConcat(', ', 'red', 'orange', 'blue');
// → "red, orange, blue, "
Functions always have a return value.
undefined.Execution (obviously) stops when the return statement is reached.
return and whitespaceThe syntax of the return statement is “not very tolerant” of line breaks/whitespace
var f = function() {
return
{word: "hello"};
}
is equivalent to
var f = function() {
return undefined;
{word: "hello"};
}
...
return and whitespaceIt is not equivalent to
var f = function() {
return {word: "hello"};
}
which, in turn, is equivalent to
var f = function() {
return {
word: "hello"
};
}
By convention: all var statements go at the start of the body:
var fun = function() {
var a, b, s;
a = 1;
b = 2;
var innerFun = function() {
var c;
c = a + b;
return c;
}
s = innerFun();
return s;
};
var fun = function() {
var a = 1;
var innerFun = function() {
console.log(a);
};
innerFun();
};
fun() /* prints 1: all good */
var fun = function() {
var a = 1;
var innerFun = function() {
console.log(a);
var a = 2;
};
innerFun();
};
fun() /* prints undefined!!! */
Why?
Internally, JavaScript moves all var declarations to the top of the body:
var fun = function() {
var a, innerFun;
a = 1;
innerFun = function() {
var a;
console.log(a); /* local a in scope, it’s undefined */
a = 2;
};
innerFun();
};
fun() /* prints undefined */
Why?
Why?
Because the interpreter does two passes:
For completeness, let’s mention that actually at the implementation level things are a little more complex. There are two stages of the code handling, where variables, function declarations, and formal parameters are created at the first stage, which is the stage of parsing and entering the context. In the second stage, the stage of runtime code execution, function expressions and unqualified identifiers (undeclared variables) are created. But for practical purposes, we can adopt the concept of hoisting, which is actually not defined by ECMAScript standard but is commonly used to describe the behavior.
In fact the specifications don’t say anything about “hoisting” explicitly!
Note: this does not apply to variables defined with let.
It also applies to functions, when defined directly (declarations):
function exampleOK() {
console.log(foo); /* → function’s code */
/* (the function itself) */
foo(); /* → "bar" */
function foo() {
console.log('bar');
};
};
It also applies to functions, when defined directly:
function exampleNotOK() {
console.log(foo); /* → undefined */
foo(); /* → TypeError: foo is not a function */
var foo = function() {
console.log('bar2');
};
}
Why?
foo is hoisted.How can we expose functionality without exposing internal variables?
Let’s take a counter:
var counter = 0;
function add() {
counter += 1;
}
add();
add();
add();
add() can also modify counter.What if we put the variable inside the function?
var counter = 0;
function add() {
var counter;
counter += 1;
}
add();
add();
add();
counter is 0.What if we remove the global variable and just return the value?
function add() {
var counter;
counter += 1;
return counter;
}
add();
add();
add();
counter is 1.Let’s try nesting functions:
function add() {
var counter = 0;
function plus() { counter += 1; }
plus();
return counter;
}
plus has access to the enclosing scope, and therefore to counter.plus() from outside?A self-invoking function:
var add = (function () {
var counter = 0;
return function () {
counter += 1;
return counter;
}
})();
add(); /* 1 */
add(); /* 2 */
add(); /* 3 */
counter? No.var add = (function () {
var counter = 0;
return function () {
counter += 1;
return counter;
}
})();
add(); add(); add();
add contains the result of a self-invoking function.add is itself a function → it has access to the scope that contains it → it can access counter, which still exists.counter.We can also create more advanced closures:
var counter = function() {
var n;
n = 0;
return {
inc: function() {
n = n + 1;
return n;
}
};
}();
counter.inc();
inc is a closure.n is an enclosed variable.Some operators also apply to unexpected types: it's useful to know how things work to avoid surprises.
Operator +:
often the source of unpleasant issues when reading a number from the DOM
Every value in JS also has an implicit boolean value:
We can use a function to test it:
function truthyOrFalsy(a) {
return a ? "truthy" : "falsy";
}
truthyOrFalsy(0) → falsytruthyOrFalsy(10 == 5) → falsytruthyOrFalsy(1) → truthytruthyOrFalsy(-1) → truthytruthyOrFalsy({}) → truthyThere are some values that are truthy but == false
"0" == false:
== → converts the string to a number0 == false"0" == 0"0" == falseOperator ===:
Operator ==: tries to perform type conversion
false == undefined /* false */
false == null /* false */
null == undefined /* true */
Goodbye transitivity of equality: better === than == !
An array is an object that:
Arrays are objects
var a = [2, 3, "pippo"];
var a = new Array(2, 3, "pippo"); /* → alternative */
a[0]; /* → 2 */
a[2]; /* → "pippo" */
a["2"]; /* → "pippo" */
a.length; /* → 3 */
a[3]; /* → undefined */
a.addedProperty = "I’m an object";
a.length; /* → 3*/
Other useful methods:
slice() → copies a portion of the array,splice() → removes (and replaces) elements,length ≠ upper bound → I can exceed it!
var myArray = [];
myArray.length; /* → 0*/
myArray[10000] = "pippo";
myArray.length; /* → 10001*/
Adding elements:
numbers[numbers.length] = 'shi'; /*or...*/
numbers.push('go');
Assigning a smaller value to length removes the trailing elements.
You can remove any element, but it leaves a hole:
var a = [2, 3, 79];
a.length; /* → 3 */
delete a[1];
a.length; /* → 3 */
typeof(a[1]); /* → "undefined" */
...better to use the splice method
typeof (array) → "object"
Let’s write our own function:
var is_array = function (value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
};
length property?splice function?length appear in a for ... in?Be careful...
[5, 12, 9, 2, 18, 1, 25].sort(); → [1, 12, 18, 2, 25, 5, 9]
The default behavior is to sort alphabetically!
We must specify a sorting function:
[5, 12, 9, 2, 18, 1, 25].sort(function(a, b){
return a - b;
});
Be careful...
var a = [2, 3, 79];
for (var name in a){
console.log(name)
};
/*output: 0, 1, 2*/
We are iterating over the object’s properties, including any added manually (or by other frameworks)!
We should use the old-fashioned way:
var a = [2, 3, 79];
for (var i = 0; i < a.length; i += 1) {
console.log(a[i]);
}
/*output: 2, 3, 79*/
Or use the forEach method:
a.forEach(function(value){
console.log(value);
});
/*output: 2, 3, 79*/
Sometimes I need to reuse already computed results...
var fibonacci = function (n) {
if (n < 2){
return n
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
};
for (var i = 0; i <= 10; i += 1) {
console.log('// ' + i + ': ' + fibonacci(i));
}
Inefficient: function called 453 times
Let’s use a closure to store previously computed results:
var fibonacci = (function() {
var memo = [0, 1];
var fib = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fib(n - 1) + fib(n - 2);
memo[n] = result;
}
return result;
};
return fib;
})();
Nice! fibonacci called only 18 times
Traditionally (Java, C++, C#) there are two entities: classes and instances.
In addition:
JavaScript is loosely-typed: every object derives from another object from which it inherits properties, called its prototype.
How is this achieved?
prototype property containing the object to be used as prototype in a constructor invocation
in fact, this property exists in every function; a function becomes a constructor when it is invoked with new
The new object has a hidden link to the value of the constructor function’s prototype property: __proto__
undefinedpublic class Employee {
public String name;
public String dept;
public Employee () {
this("", "general");
}
public Employee (String name) {
this(name, "general");
}
public Employee (String name, String dept) {
this.name = name;
this.dept = dept;
}
}
function Employee(name="", dept="general") {
this.name = name;
this.dept = dept;
}
public class Engineer extends Employee {
public String machine;
public Engineer () {
this("");
}
public Engineer (String mach) {
dept = "engineering";
machine = mach;
}
}
function Engineer(mach = "") {
this.dept = 'engineering';
this.machine = mach;
}
Engineer.prototype = new Employee;
function Employee(name="", dept="general") {
this.name = name;
this.dept = dept;
}
function Engineer(mach = "") {
this.dept = 'engineering';
this.machine = mach;
}
Engineer.prototype = new Employee;
var luca = new Engineer("computer");
What are the values of the following expressions:
luca.machine → "computer"luca.dept → "engineering"luca.name → ""An object’s prototype is itself an object, so if you
a property to/from the prototype, this affects all objects that have that prototype (through delegation).
...
Engineer.prototype = new Employee;
var luca = new Engineer("computer");
Employee.prototype.salary = 100;
luca.salary; /* → 100*/
ObjectFunctionCreating an object as a literal is equivalent to creating it with a constructor invocation of Object
var o = new Object();
is equivalent to
var o = {};
and the object can be filled later.
Object.prototype is the prototype object from which both derive.
Literal creation is recommended
For example, I can add read-only properties:
var o = new Object();
Object.defineProperty(o, "prop", {
value: "test",
writable: false
});
o.prop; /* → "test"*/
o.prop = "Ciao";
o.prop; /* → "test"*/
Creating a function as a literal is equivalent to creating it with a constructor invocation of Function
var f = new Function();
is equivalent to
var f = function(){};
but the function cannot be filled later (in its body).
Function.prototype is the object from which both derive (the prototype).
Literal creation is necessary
var sum = function(a, b) {
return a+b;
};
sum.creator; /* → undefined*/
Function.prototype.creator = "Eric Medvet";
sum.creator; /* → Eric Medvet (delegation)*/
var prod = function(a, b) {
return a*b;
}
prod.creator; /* → Eric Medvet (delegation)*/
prod.creator = "Simba";
prod.creator; /* → Simba (no delegation)*/
sum.creator; /* → Eric Medvet*/
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
var dog = {sound: "bark"};
var coloredDog = Object.create(dog);
coloredDog.sound; /* → bark*/
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
Objectcreate is invoked with argument o
Fonew F()
(a new object with a hidden link to the prototype property of the creating function, that is o)
Object.create = function(o) {
...
};
ObjectAugmenting a base type (Object)
This can also be done with strings, numbers, etc...
String.reverse = function() {
...
};
don’t overuse it
Adding new functionality to the system library by extending it
Example: we want to add a function to String that capitalizes the first letter
String.prototype.capitalize = function() {
return this[0].toUpperCase() + this.substr(1);
}
const capitalName = 'jacob'.capitalize(); /* → "Jacob" */
It should be avoided!
If other libraries do the same thing, what would happen?
This problem has already occurred in the past: smooshgate
The MooTools library, widely used at the time, had added the flatten function
Array.prototype.flatten = function(){...}
...but in 2019, flatten was introduced into ECMAScript!
Object.prototype.version = "7.2.11";
"uh".version; /* → 7.2.11*/
Why? Isn’t "uh" a primitive String?
typeof true; /*"boolean"*/
typeof Boolean(true); /*"boolean"*/
typeof new Boolean(true); /*"object"*/
typeof (new Boolean(true)).valueOf(); /*"boolean"*/
typeof "abc"; /*"string"*/
typeof String("abc"); /*"string"*/
typeof new String("abc"); /*"object"*/
typeof (new String("abc")).valueOf(); /*"string"*/
typeof 123; /*"number"*/
typeof Number(123); /*"number"*/
typeof new Number(123); /*"object"*/
typeof (new Number(123)).valueOf(); /*"number"*/
To execute "uh".version, a new String object (wrapper) is created, used only to access the property, and then discarded by the Garbage Collector.
So, can I add properties to primitives?
var primitive = "september";
primitive.vowels = 3;
primitive.vowels; /* → ??*/
So, can I add properties to primitives? NO!
var primitive = "september";
primitive.vowels = 3; /* → create a new wrapper:*/
(new String("september")).vowels = 3;
primitive.vowels; /*→ create a new wrapper to
read the property:*/
(new String("september")).vowels; /* → undefined*/
Wrappers easily revert to their primitive type:
var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; /*15*/
typeof fifteen; /*"number" (primitive)*/
typeof Twelve; /*"object"; (still object)*/
But it’s still JavaScript:
if (new Boolean(false)) {
console.log("true");
} else{
console.log("false");
}
Output?
Wrappers easily revert to their primitive type:
var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; /*15*/
typeof fifteen; /*"number" (primitive)*/
typeof Twelve; /*"object" (still object)*/
But it’s still JavaScript:
if (new Boolean(false)) {
console.log("true");
} else{
console.log("false");
}
Output? → "true", because objects are truthy.
For booleans, use the value: new Boolean(false).valueOf();
Create a JavaScript function wordCounter that returns a <word, frequency> "map" computed from the input string.
wordCounter("la mamma di mio figlio è anche mamma di mia figlia"); /* → <"mamma", 2/11>, <"figlio", 1/11>, ...*/
see String.split()
And what if there are punctuation marks? See regular expressions and their literal syntax.
Create a JavaScript function such that:
var f = ...;
f(1) /* → 1*/
f()(3) /* → 3*/
f()()()()("a") /* → "a"*/
f()...()("x") /* → "x"*/
var g = f;
f = 33;
g()()()()(f) /* → 33*/
Remember?
Tree representation of the document, in memory
Programmatic interface for:
Essentially, it connects web pages to scripts or programming languages.
HTMLDocument: extends Document, but with HTML5 many methods/properties are already included in it.HTMLElement: for all types
HTMLAnchorElementHTMLParagraphElementHTMLFormElementNot just HTML! There’s also the entire world of SVG...
The document object contains the DOM:
document.getElementById("...") → returns the element (HTMLElement) with the specified IDdocument.getElementsByTagName("...") → returns the elements with the specified tag name ("a", "span", ...);
"*" returns all of themdocument.getElementsByClassName("...") → returns the elements with the specified class (a list of space-separated values)document.querySelectorAll("...") → returns all elements matching the given CSS selectordocument.querySelector("...") → returns the first element matching the given CSS selectordocument.createElement("...") → creates an element of the specified typeelement.appendChild(child) → adds the element as the last child of the specified element node.innerHTML → reads/sets the HTML code that defines the element’s descendantsvar mainSection = document.getElementById("mainSection");
var newP = document.createElement("p");
newP.innerHTML = "this is the <b>new</b> paragraph";
mainSection.appendChild(newP);
element.style → accesses the element’s style attribute → ignores inherited/external styles
element.style.color = "#ff3300";
element.style.marginTop = "30px";
window.getComputedStyle(element) → returns the computed style for the elementThere are several ways to bind to events:
<button onclick="alert('Hello world!')">
Ugly:
There are several ways to bind to events:
/* Assume myButton is a Button */
myButton.addEventListener('click', function(){
alert('Hello world');
}, false);
Nice!
Note: not supported in Internet Explorer 6–8, where EventTarget.attachEvent is used instead → it's better to use libraries for maximum compatibility.
There are several ways to bind to events:
/* Assume myButton is a Button */
myButton.onclick = function(event){
alert('Hello world');
};
Note: only one handler per element per event.
There are three phases:
td)bubbleManually stop bubbling propagation:
ev.stopPropagation();
Note: this does not stop the function’s execution.
Write an HTML document with an input box and a button: when the user clicks the button, the page shows a list with the first 20 permutations of the word typed into the box.
Hints:
inputWe’ve already seen some basics:
const – use by defaultlet – use if the value may changefunction a(par1 = 1){...Old style:
let name = "Luca";
console.log("Hi " + name + ", how are you?");
ES6: backticks and interpolation!
let name = "Luca";
console.log(`Hi ${name}, how are you?`)
Old style:
function createProduct(price, quantity){
return {
price: price,
quantity: quantity
};
};
ES6: shorter syntax
function createProduct(price, quantity){
return {
price,
quantity
};
};
Old style:
var product = {
descr: "computer",
price: 10
};
var price = product.price;
var descr = product.descr;
ES6:
const product = {
descr: "computer",
price: 10
};
const {price, descr} = product;
Anonymous functions with benefits:
thisOld style:
var x = function(params){...}
ES6:
const x = (params) => {...}
() optional with one parameter (not with 0 or more)We know how to use constructor invocation...
function Person(name, age){
this.name = name;
this.age = age;
};
var luca = new Person("Luca", 21);
...and we know how inheritance works (though it’s awkward)
ES6 solution: class
class XYZ{
constructor(par1, ...){
this.par1 = par1;
}
}
Important notes:
Alternative syntax:
var XYZ = class {...}
var XYZ = class XYZ {...}
Constructor
→ a special method, valid only inside a class, that creates an instance of it
getter, setter, or asyncInheritance
class X extends Y{
constructor(par1, par2, ...){
super(par1);
...
}
}
Voilà!!
Inheritance
You can extend any constructor function that has a prototype property
function OldStyle() {
this.someProperty = 1;
}
OldStyle.prototype.someMethod = function () {};
class Modern extends OldStyle {}
class Modern {
someProperty = 1;
someMethod() {}
}
class AnotherClass extends Modern {}
Public Fields
class ClassWithFields {
instanceField;
instanceFieldWithInitializer = "instance field";
static staticField;
static staticFieldWithInitializer = "static field";
constructor(instanceField) {
this.instanceField = instanceField;
}
}
Private Fields
Declared using the # prefix
class ClassWithPrivateFields {
#privateField;
#privateFieldWithInitializer = 42;
#privateMethod() { }
static #privateStaticField;
static #privateStaticFieldWithInitializer = 42;
constructor(x) {
this.#privateField = x;
}
}
setTimeout(), setInterval()code and an optional delaycode after delay milliseconds (0 if not specified)
setInterval() repeats the operationsetTimeout(function(){
console.log("Delayed for 5 seconds.");
}, 5000);
console.log("Hello!");
setTimeout() is asynchronous...that is, managing asynchronous operations.
"When you’re done sending the message, let me know — but let me keep working meanwhile..."Before: a custom design pattern to solve the problem
function sendMessage(msg, callback){
function doAsync(){
/* asynchronous operation */
let success = contactServerAndSendData(msg);
callback(success);
};
doAsync();
}
sendMessage("Pippo", function(result){
console.log(result);
});
...that is, managing asynchronous operations.
"When you’re done sending the message, let me know — but let me keep working meanwhile..."Before: a design pattern to handle this
ES6: Promise — a built-in object representing the completion (or failure) of an async operation.
var promiseObj = new Promise(executorFunction);
executorFunction: a function run by the constructor with two parameters:
This function performs the asynchronous operation.
...that is, managing asynchronous operations.
"When you’re done sending the message, let me know — but let me keep working meanwhile..."Before: a design pattern to handle this
ES6: Promise — a built-in object representing the completion (or failure) of an async operation.
var promiseObj = new Promise(executorFunction);
promiseObj.then(
/* function executed if everything goes well */
).catch(
/* function executed if an error occurs */
);
The executor function takes two parameters — two callbacks for success and failure.
resolve(value) → called if the operation completes successfully, with value as the resultreject(error) → called if an error occurs, passing errorlet promise = new Promise(function(resolve, reject) {
/* executor: time-consuming operation */
resolve("Done!"); /* completes and returns "Done!" */
});
The executor is not run until the Promise is explicitly invoked by a consumer.
then(): takes two functions — one for success, one for failurecatch(): takes one function to handle errorslet promise = new Promise(function(resolve, reject) {
/* executor: time-consuming operation */
resolve("Done!");
});
promise.then(
function(result){ console.log(result) },
function(error){ console.log(error) } /* optional */
);
We can rewrite everything using arrow functions:
let promise = new Promise((resolve, reject) => {
/* executor: time-consuming operation */
resolve("Done!");
});
promise.then(
result => console.log(result),
error => console.log(error) /* optional */
);
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("Done!"), 2000)
});
promise.then(result => console.log(result));
console.log("Hello");
Prints "Hello" first, then "Done!"
function setTimeoutPromise(delay) {
return new Promise((resolve, reject) => {
if (delay < 0) return reject("No delay");
setTimeout(() => {
resolve(`You waited ${delay} milliseconds`);
}, delay);
});
}
setTimeoutPromise(250).then(msg => {
console.log(msg);
return setTimeoutPromise(500);
}).then(msg => {
console.log(msg);
});
Once upon a time, everything worked fine:
Now:
“It would be nice to split code into multiple, easy-to-maintain files...”
You can probably guess the name of the solution ↑
Browser support is quite good — if we pretend IE doesn’t exist...
Two keywords:
export → exports something from a JS fileimport → imports something into a JS fileOption 1: at the bottom of the file
export default something; → exports “something” as defaultexport {foo, bar}; → exports “foo” and “bar”Option 2: inline (nicer)
export default class Something {...}
export function foo(){...}
export function bar(){...}
Only one default export per file
Import the default export:
import Something from './module.js';
let x = new Something();
Import the rest:
import Something, {foo, bar} from './module.js';
let x = new Something();
Alias for non-default imports:
import {foo as funkyFoo} from './module.js';
Aliases help resolve name conflicts across modules
When including a script in HTML, you can use several attributes:
defer → runs after the DOM is loadednomodule → script ignored if the browser supports modules (ES6) → fallback for older browserstype="module" → runs only if the browser supports modules:
deferasync is added, runs immediatelyIntroduced with ES5, still valid in ES6 and later.
Forces a stricter interpretation of JavaScript.
"use strict";
x = 10; /* Error! x is not declared */
Without "use strict", that line would silently create a global variable.
let, const or varthis in functions not bound to objects is undefined (not window)implements, package) cannot be used as identifiersfunction test(){
"use strict";
console.log(this); /* undefined */
}
test();
Always a good idea in modern JS — or use ES modules, which are strict by default.
"use strict";
/* 1. No implicit globals */
x = 3.14; /* ReferenceError */
/* 2. No deleting variables or functions */
var a = 1;
delete a; /* SyntaxError */
/* 3. No duplicate parameters */
function f(x, x) { } /* SyntaxError */
"use strict";
/* 4. 'this' not bound to window */
function show() {
console.log(this); /* undefined */
}
show();
/* 5. Reserved words */
var private = 1; /* SyntaxError */
ES6 modules are strict by default — no need for "use strict".
JavaScript is a single-threaded, non-blocking, asynchronous, concurrent programming language with lots of flexibility
JavaScript maintains a stack in memory called the function execution stack, which keeps track of the currently executing function.
function f1(){
...
}
function f2(){
...
}
function f3(){
...
}
f1();
f2();
f3();
f1()f2()f3()Function Execution Stack
function f1(){
...
}
function f2(){
f1();
}
function f3(){
f2();
}
f3();
f1()f2()f3()Function Execution Stack
Some functions may finish “later”: I can have a function with a set delay, or one whose result depends on something external (data from a server, a database query, ...).
In these situations, I don’t want to block the execution of the code, but rather continue running other functions.
There are two main types of operations that are executed asynchronously (non-blocking):
setTimeout()function printme() { /* callback */
console.log('print me');
}
function test() {
console.log('test');
}
setTimeout(printme, 2000);
test();
In what order are the two sentences printed?
stampami() and then test() are executed?test() executed first, and after 2 seconds stampami()?JavaScript has a dedicated queue for callbacks (Callback Queue)
A loop is created that periodically checks the queue and moves callbacks to the stack (Event Loop):
function f1() {
console.log('f1');
}
function f2() {
console.log('f2');
}
function main() {
console.log('main');
setTimeout(f1, 0);
f2();
}
main();
console.log('f2')
f2()
setTimeout()
console.log('main')
console.log('f1')
main()
f1()
Function Execution Stack
API => f1()Browser API
f1()Callback Queue
function f1() {
console.log('f1');
}
function f2() {
console.log('f2');
}
function main() {
console.log('main');
setTimeout(f1, 0);
new Promise((resolve, reject) =>
resolve('promise')
).then(resolve => console.log(resolve))
f2();
}
main();
console.log('f2')
f2()
setTimeout()
console.log('main')
console.log('f1')
console.log('promise')
main()
f1()
anonymous
Function Execution Stack
API => f1()Browser API
f1()Callback Queue
anonymousJob Queue
async functionsWith ECMAScript 2017, support was added for writing asynchronous functions — another way to handle Promises.
An asynchronous function is a function that:
async keywordawait keyword inside itasync function hello() { return "Hello!"; }
hello(); /* returns a Promise */
async functionsThey can be written in a more elegant form
let hello = async function() { return "Hello!"; };
Or using an arrow function
let hello = async () => "Hello!";
async functionsTo consume the Promise, you can use then()
hello().then((value) => console.log(value));
Or use the shorthand version
hello().then(console.log);
awaitThe advantages of asynchronous functions become clear when combined with the await keyword:
async function hello() {
return await Promise.resolve("Hello");
};
hello().then(console.log);
function after2sec() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Done!');
}, 2000);
});
}
async function asincrona() {
console.log('Exec and await');
const result = await after2sec();
console.log(result);
}
asincrona();
function setTimeoutPromise(delay) {
return new Promise((resolve, reject) => {
if (delay < 0) return reject("No delay")
setTimeout(() => {
resolve(`You waited for ${delay} milliseconds`);
}, delay);
})
}
asincrona();
async function asincrona() {
const msg1 = await setTimeoutPromise(250)
console.log(msg1)
const msg2 = await setTimeoutPromise(500)
console.log(msg2)
}
With promises:
setTimeoutPromise(-10).then(msg => {
console.log(msg);
}).catch(error => {
console.error(error)
}).finally(() => {
console.log("Exec anyway!");
});
With async code:
asincrona();
async function asincrona() {
try {
const msg = await setTimeoutPromise(-10);
console.log(msg);
} catch (error) {
console.error(error);
} finally {
console.log("Exec anyway!");
}
}
When you enter a URL in the browser:
Some URLs invoke programs executed by the web server, passing parameters:
http://www.sailing.org/16937.php?meetid=82
Changing data === reloading the page
But we want to build Web Applications — that is, websites that behave much more like desktop applications.
Asynchronous JavaScript + XML: a way of using JavaScript to enrich an HTML document with new information (without reloading it)
Ajax is the key to interactivity in Web Applications!
In practice: Ajax = using the JavaScript object XMLHttpRequest
XMLHttpRequestThe XMLHttpRequest specification defines an API that provides scripted client functionality for transferring data between a client and a server.
It’s not a programming language, but a way of using JavaScript.
Specification available at http://www.w3.org/TR/XMLHttpRequest, documentation on w3schools
as of today, specification ≠ implementations
XMLHttpRequest"Use it" ≈ read it and update the DOM with the new information
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = myFunction;
xhr.open("GET", url, true);
xhr.send(null);
You need to tell the XMLHttpRequest object:
open specifies that the request is asynchronous"When the response arrives"...
xhr.onreadystatechange → handler, the function invoked on every state changexhr.readyState → state of the interaction (between the object and the server):
new ...)open())send())Usually, we’re only interested in state 4.
When it’s available (readyState == 4) and no errors occurred, the response is found in:
xhr.responseText → response body as a stringxhr.responseXML → response body as a Document object, only if:
Which one should you use? It depends!
xhr.onreadystatechange = function() {
var text;
if (xhr.readyState == 4) {
if (xhr.status == 200) {
text = xhr.responseText;
/* use text in the DOM */
} else {
/* handle the error */
}
}
};
Some options:
document.getElementById("toRewrite").innerHTML = xhr.responseText;
one,two,three):
var listEl = document.getElementById("list");
var pieces = xhr.responseText.split(",");
var i, newLi;
for (i = 0; i < pieces.length; i++) {
newLi = document.createElement("li");
newLi.innerHTML = pieces[i];
listEl.appendChild(newLi);
}
<?xml version="1.0" encoding="UTF-8"?>
<animals>
<animal type="dog">
<name>Simba</name>
<color>white</color>
</animal>
<animal type="dog">
<name>Gass</name>
<color>brown</color>
</animal>
</animals>
A concise introduction to XML can be found at w3schools
var xmlDoc = xhr.responseXML;
var animals = xmlDoc.getElementsByTagName("animal");
var i, name, nameEl;
for (var i = 0; i < animals.length; i++) {
var nameEl = animals[i].getElementsByTagName("name")[0];
var name = nameEl.childNodes[0].nodeValue;
...
}
Note: it’s possible to convert XML into an object.
Do we always have to use XML to communicate? NO!
A standard for transmitting data in a readable format, made up of attribute–value pairs and ordered lists of values.
Derived from JavaScript’s Object Literal syntax:
{ "employees": [
{"firstName":"Mick","lastName":"Jagger"},
{"firstName":"Ronnie","lastName":"Wood"},
{"firstName":"Keith","lastName":"Richards"},
{"firstName":"Charlie","lastName":"Watts"} ]
}
JSON.parse() takes care of everything:
xhr.onreadystatechange = function() {
var obj;
if (xhr.readyState == 4) {
if (xhr.status == 200) {
obj = JSON.parse(xhr.responseText);
/* use obj in the DOM */
} else {
/* handle the error */
}
}
};
Restriction that prevents a script from communicating with servers different from the one that hosts the document it originates from.
The script on www.trieste.it/index.html cannot do xhr.open("GET", "http://udine.it", true)
Create (at least) 3 files (JSON or XML or text), each containing a profile for an animal. Each profile has at least 3 attributes (for example: name, color, ...).
Create an HTML document with a text box. When the user types the animal’s name, the document updates with a table containing the data for the requested animal, if available.
In Chrome, there’s a restriction that prevents loading documents via the file:/// protocol.
When loading documents via the file:/// protocol in Firefox, the values of xhr.status are not the usual HTTP ones.
Use the embedded web servers in VS Code or Atom.
fetch()Using XMLHttpRequest is cumbersome:
asyncfetch function was introduced more recentlyfetch(): exampleInspired by jQuery’s ajax(), but:
Response and Request objectsfetch('url')
.then(response => response.json())
.then(data => console.log(data));
fetch(): exampleasync function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
postData('https://example', { data: 'xxx' })
.then(data => {
console.log(data);
});
Hyper Text Transfer Protocol - RFC 2616
Three sections per request:
<CR><LF>GET /index.html HTTP/1.1
Host: www.example.com
<CR><LF>
Key-value pairs, one per line
Accept: acceptable content types in the response
accept-language, accept-encoding (compression), accept-charset, ...User-agent: program making the requestHost: DNS name of the server being contactedCookiesAuthorizationHandled in the Request Headers
Basic:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Warning:
Handled in the Request Headers
Digest (RFC-2617):
WWW-Authenticate: Digest realm="testrealm@host.com",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093"Authorization: Digest username="Mufasa", ...,
MD5(MD5(username:realm:password):nonce)The browser stores credentials to avoid asking every time: how do I log out?
Not supported!
logout() JavaScript function (not supported)In short: the logout problem arises ⇛ use a session-based authentication system
Three sections per response:
HTTP/1.0 200 OK
Date: Mon, 28 Jun 2004 10:47:31 GMT
Server: Apache/1.3.29 (Unix) PHP/4.3.4
X-Powered-By: PHP/4.3.4
Vary: Accept-Encoding,Cookie
Cache-Control: private, s-maxage=0,
max-age=0, must-revalidate
Content-Language: it
Content-Type: text/html; charset=utf-8
Age: 7673
X-Cache: HIT from wikipedia.org
Connection: close
Application that handles web page transfer requests via the HTTP or HTTPS protocol
Multi-Processing Modules: when Apache was created, HTTP keep-alive connections did not exist
Apache
nginx
Apache
nginx
Apache
nginx
Apache
nginx
A set of practices that combine software development (Dev) and IT operations management (Ops)
To run a container, you need two things: an image and a Container Runtime
A Container Runtime is software that runs and manages the components of a container
runC is a widely used runtime (others include gVisor and Kata)
The container runs as a process
The container runs as a process
/sys/)Limit the memory available to the process with PID 1102 to 50MB (52428800 bytes)
$ mkdir /sys/fs/cgroup/memory/group
$ echo 52428800 > /sys/fs/cgroup/memory/group/memory.limit_in_bytes
$ echo 1102 > /sys/fs/cgroup/memory/group/cgroup.procs
Containers are based on images
docker ps: list running containersdocker ps -a: list all containers, including inactive onesdocker run --name con_name: run a container with name con_namedocker run -d con_name: run in detached (background) modedocker run -it con_name: run in interactive modedocker rm id: remove the container with a specific iddocker start id: start a stopped container with iddocker attach id: attach to a running container with iddocker stop id: stop the container with idThe filesystem of each container is completely isolated
docker run -v /home/andrea:/home/container con_name
The network of each container is completely isolated
docker run -p 8088:80 con_name
Script that contains the operations to initialize the container
FROM ubuntu RUN apt update RUN apt install –y apache2 RUN apt install –y apache2-utils RUN apt clean EXPOSE 80 CMD [“apache2ctl”, “-D”, “FOREGROUND”]
FROM: base image to start fromENV key=value: sets environment variablesRUN: executes commands inside the image (creates a new layer)ADD: adds a file (including remote files) to the imageCOPY: like ADD, but only for local files and fasterENTRYPOINT: executes an instruction when the container starts; does not create a new layerWORKDIR: container’s working directoryEXPOSE: ports on which the container will listen (not opened by default)VOLUME: path in the container where a volume can be mounted (to be set at runtime)To create an image from a Dockerfile, you need to build it
docker build -t TAG build_contextDockerfile:
FROM httpd:2.4
EXPOSE 80
COPY ./src/ /usr/local/apache2/htdocs/
docker build -t our_server:1.0 .
docker run -d -P our_server:1.0
Configuration tool that allows you to compose a container
version: '3.9'
services:
apache:
image: httpd:latest
container_name: my-apache-app
ports:
- '8080:80'
volumes:
- ./website:/usr/local/apache2/htdocs
Program that delivers web documents upon request
Simple case:
http://www.units.it/exam-results.html)GET /exam-results.html HTTP/1.1)someone had previously placed the document on disk
(Example of) normal case:
The web server is a program that receives requests according to the HTTP protocol.
When it receives a request, it performs some operations — some of them to produce the HTML document:
What should the program do when “generating the document”? It depends:
Do we need to rewrite a web server for every situation? No!
↓
Server-side scripting/programming
There are many:
We will look at a solution based on Node.js
Request handled by a traditional language (PHP, Java, ASP, ...):
Request handled by Node.js:
A single non-blocking thread is executed, and programming is done asynchronously.
node executable$ node myfile.js
require()const http = require('http');
Modules can be created and included as desired
mymodule.js
exports.myFunction = function () {
return "something";
};
const myf = require('./mymodule');
console.log(myf.myFunction());
Main built-in module: http
const http = require('http');
http.createServer(function (req, res) {
res.write('Good morning!');
res.end();
}).listen(8080);
http ModuleIt provides various methods; the one we’re interested in is createServer():
requestListener:
request: an IncomingMessage objectresponse: a ServerResponse objectHTTPServer object
HTTP Response writing
const http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('Good morning!');
res.end();
}).listen(8080);
I can read the HTTP Request
const http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(req.url);
res.end();
}).listen(8080);
I can parse the parameters from the query string
const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
const q = url.parse(req.url, true).query;
res.write(`${q.name} ${q.surname}`);
res.end();
}).listen(8080);
Let's read a document from disk:
fs moduleconst http = require('http');
const fs = require('fs');
http.createServer(function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
return res.end();
});
}).listen(8080);
fs provides several functionalities:
fs.open()fs.appendFile()fs.writeFile()fs.unlink()fs.rename()const http = require('http');
const fs = require('fs');
http.createServer( (req, res) => {
fs.readFile('index.html', (err, data) => {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
return res.end();
});
}).listen(8080);
we can use arrow functions, promises, async, ...
events moduleconst http = require('http');
const events = require('events');
const eventEmitter = new events.EventEmitter();
const myEventHandler = function () {
console.log('I heard something!');
}
eventEmitter.on('noise', myEventHandler);
eventEmitter.emit('noise');
const http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('');
return res.end();
}).listen(8080);
const http = require('http');
const formidable = require('formidable');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
const form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.write('File uploaded');
res.end();
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('');
return res.end();
}
}).listen(8080);
const fs = require('fs');
/* ... */
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
const form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
const oldpath = files.filetoupload.filepath;
const newpath = `${__dirname}/${files.filetoupload.originalFilename}`;
fs.copyFile(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('...');
return res.end();
}
}).listen(8080);
Creating a web document from scratch is inconvenient
Solution: templates
HTML structure with variable parts:
Which module?
Create (at least) 3 files (JSON, XML, or text) objects, each containing a record for an animal. Each record must include at least 3 attributes (for example: name, color, ...).
Create an HTML document with a text box. When the user types the name of an animal, the document updates to show a table with that animal’s data, if available.
Provide the response through a Node.js server.
Write an HTML document with an input box and a button: when the user clicks the button, the page displays a list of the first 20 permutations of the word typed into the box.
The permutations are computed on the server using Node.js and sent back to the web page.
httpSolution? Let’s use a framework!
The most widely used framework in the Node.js ecosystem is Express
Frameworks can be divided into two categories:
Express is unopinionated
const express = require("express");
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Good morning!");
});
app.listen(port, () => {
console.log(`Listening on port ${port}!`);
});
get()post()delete()put()all()const express = require("express");
const app = express();
const port = 3000;
app.get('/book', (req, res) => { res.send('Read book') });
app.post('/book', (req, res) => { res.send('Add book') });
app.put('/book', (req, res) => { res.send('Edit book') });
app.listen(port, () => {
console.log(`Listening on port ${port}!`);
});
It can be compacted
const express = require("express");
const app = express();
const port = 3000;
app.route('/book')
.get((req, res) => { res.send('Read book') })
.post((req, res) => { res.send('Add book') })
.put((req, res) => { res.send('Edit book') });
app.listen(port, () => {
console.log(`Listening on port ${port}!`);
});
res.end() ends the responseres.json() sends a JSON objectres.redirect() forces the client to perform a redirectres.render() calls a template engineres.send() sends a general-purpose responseIt is often useful to group handlers for a section of the site
wiki.js
const express = require("express");
const router = express.Router();
router.get("/", function (req, res) {
res.send("Wiki home page");
});
router.get("/about", function (req, res) {
res.send("Information");
});
module.exports = router;
app.js
const wiki = require("./wiki.js");
/* … */
app.use("/wiki", wiki);
?: the resource may have 0 or 1 repetition of the previous character/group+: the resource may have 1 or more repetitions of the previous character/group*: the resource can have an arbitrary string in place of the symbol(): the string between parentheses is a groupA part of the resource can be parametric: a named segment
A named segment is defined with the : prefix
app.get("/user/:userId/book/:bookId", (req, res) => {
console.log(req.params.userId, req.params.bookId);
res.send(req.params);
});
Middleware functions:
next()use() methodnext()const express = require("express");
const logger = require("morgan");
const app = express();
app.use(logger("dev"))
Interface specification for the various methods get(), post(), delete(), ...
app.METHOD(path, callback [, callback ...])
path → The path for which the middleware function is invoked; can be any of:callback → Callback functions; can be:Run a function for every request
app.use((req, res, next) => {
/* do something */
next();
})
Run a function for a specific resource
app.use('/user/:id', (req, res, next) => {
/* do something */
next();
});
Run a function when a GET request is made to a specific resource
app.get('/user/:id', (req, res, next) => {
/* do something */
next();
});
Run a sequence of functions
app.use('/user/:id', (req, res, next) => {
/* do something */
next();
}, (req, res, next) => {
/* do something */
next();
})
A built-in middleware to manage static content in Express is express.static
Useful when handling requests for images, CSS, JavaScript, and static pages. If the file isn’t found, the request is passed to the next middleware.
const express = require("express");
app.use(express.static("public"));
app.use(express.static("media"));
app.listen(port, function () {
console.log('Static file server example');
});
The body of an HTTP request can contain different kinds of data
There is Express middleware to parse the request body
express.urlencoded()express.json()const express = require("express");
app.use(express.urlencoded());
app.post("/form", (req, res) => {
console.log(req.body.param1)
});
app.listen(port, function () {
console.log('Static file server example');
});
HTTP is a stateless communication protocol
Simple case:
The second request is independent of the first: resp2 is produced solely based on req2!
otherwise it’s called stateful
Real-world need (web application):
From another viewpoint:
From another viewpoint:
s is the state of the dialogue between C and S
The web server S is multithreaded:
Wrong answer:
S knows who Ci is and “fetches” si from a list/map
S, on the “first” request from C:
When a request req arrives from a C:
Requires client cooperation!
The token could be S; usually it’s much “smaller”
S includes in the response:
“in all subsequent requests, include this token t”
Mechanisms:
href="store/dogs/index.jsp?type=jack_russel&sess_id=t
sess_idexpress-session middlewaresession property is created on the req objectsecret: required parameter, the token used to sign the session ID cookieresave: forces saving the session; not generally required, and the default value (true) is deprecatedconst session = require('express-session');
app.use(session({
secret: 'secret',
resave: false
}));
app.post('/login', (req, res) => {
/* code to verify if the user exists */
if(user !== null) {
req.session.user = {
email: user.email,
name: user.name
};
res.redirect('/account');
} else {
/* Invalid login */
}
});
app.get('/info', (req, res) => {
if(!req.session.user) {
res.redirect('/login');
} else {
res.send(req.session.user);
}
});
Access to certain resources must be restricted
Why restrict access? Security!
Access to certain resources must be restricted based on the identity of the requester
At this point, the server considers C as logged in for a certain time or number of requests (~ sessions)
S: “Who are you?” C: “I’m C” S: “Is the client really C? Yes”
S: “Can C access req? Yes”
For us, “security” ≈ “authentication/authorization”
Declarative → authentication/authorization processes are defined in the configuration
Programmatic → authentication/authorization processes are defined (also) in the code
resource req can be accessed by users U1, U2, U3 only if user U0 has accessed req at least 5 times
Defined manually by the programmer
It can be implemented in two ways
passportCustom-built
app.post('/login', function(req, res){
/* retrieve credentials from DB */
if(user.id === req.body.id && user.pass === req.body.pass){
req.session.user = user;
res.redirect('/restricted');
}
res.send('Invalid credentials');
});
app.get('/restricted', checkSignIn, function(req, res){
res.send('protected data');
});
function checkSignIn(req, res, next){
if(req.session.user){ return next() }
next(new Error("Not logged in!"));
}
Passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local');
passport.use(new LocalStrategy((user, pass, done) => {
/* check if username and password are in the DB */
if(!authenticated){ return done(null, false); }
if(authenticated) return done(user);
});
app.get("/restricted", (req, res, next) => {
/* handle login */
if (req.isAuthenticated()) { return next(); }
res.redirect('/')
},
(req, res) => {
/* method body if authenticated */
});
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Three sections, separated by “.” and Base64 encoded
How is the token sent to the server?
Authorization: Bearer tokenWhat are the benefits?
const jwt = require('jsonwebtoken');
app.post('/api/login', (req,res)=>{
const user = { /* user data */ };
jwt.sign({user:user},'secretkey',(err,token)=>{
res.json({token,});
});
});
app.post('/api/profile', (req,res,next) => {
const bearerHeader = req.headers['authorization'];
if(typeof bearerHeader!=='undefined'){
const bearerToken = bearerHeader.split(' ')[1];
req.token=bearerToken;
next();
} else {
res.sendStatus(403);
}, (req,res)=>{
jwt.verify(req.token, 'secretkey', (err, authData)=>{
if(err){ res.sendStatus(403);}
else{ res.json({ /* data */ });}
});
});
const jwt = require('jsonwebtoken');
app.post('/api/login', (req,res)=>{
const user = { /* user data */ };
const token = jwt.sign({user:user},'secretkey',{expiresIn: 86400});
res.cookie("token", token, {httpOnly: true});
res.json("Authenticated!");
});
app.post('/api/profile', (req,res,next) => {
const bearerHeader = req.headers['authorization'];
if(typeof bearerHeader!=='undefined'){
const bearerToken = bearerHeader.split(' ')[1];
req.token=bearerToken;
next();
} else {
res.sendStatus(403);
}, (req,res)=>{
jwt.verify(req.token, 'secretkey', (err, authData)=>{
if(err){ res.sendStatus(403);}
else{ res.json({ /* data */ });}
});
});
It can be created easily with npm init
npm install something --save
Why --save?
node_modules folderpackage.jsonnpm install something --save-devnpm install
npm install --productionnpm uninstall something --savenpm update somethingnpm listsomething can specify a version using @Versions always follow the Major.Minor.Patch format
^Maj.min.patch → installs the latest minor/patch version
~Maj.min.patch → installs the latest patch version
Maj.min.patch → installs exactly that version
* → installs the most recent version (dangerous)
By default, packages are local, specific to a single project.
Global packages are installed system-wide.
npm install -g something
May require sudo
npm remove -g somethingAllow you to run custom tasks
package.jsonnpm run scriptNamestart script
It can be executed directly with npm start, without run
As seen in the course:
↕
↕
↕
The user can use the app through:
Everyone wants to talk to us through the Internet...
Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.
But what changes compared to a regular web page?
Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.
But what changes compared to a regular web page?
The recipient changes:
Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.
There are three possible paths:
Which one to choose?
We define the standard used to expose the service
const express = require('express');
const app = express();
app.get('*', (req, res) => {
if(req.query.program !== undefined){
/*create XML response for the calling program*/
} else {
/*create HTML page for the human user*/
}
});
We define the standard used to expose the service.
Problems:
And what about C, which isn’t object-oriented?
Firewalls aren’t happy—doesn’t use port 80
XML-RPC was created because Microsoft hesitated to approve SOAP!
A W3C standard, currently at version 1.2. Main elements:
Envelope
Header: meta-information (e.g., version, transaction info, etc.)
Only Envelope and Body are mandatory
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Header>
...
</soap:Header>
<soap:Body>
...
<soap:Fault>
...
</soap:Fault>
</soap:Body>
</soap:Envelope>
The data encoding is not predefined, and multiple encoding types can coexist
Used for Requests...
<soap:Body>
<m:GetPrice xmlns:m="http://www.w3c.com/prices">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>
...and Response
<soap:Body>
<m:GetPriceResponse xmlns:m="http://www.w3c.com/prices">
<m:Price>1.90</m:Price>
</m:GetPriceResponse>
</soap:Body>
...and possible errors
So far, we haven’t talked about the channel or the server we communicate with...
If HTTP is used, the headers must specify:
Content-Type: usually application/soap+xmlContent-LengthSOAPAction: "URI"
POST /InStock HTTP/1.1
Host: www.example.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: nnn
SOAPAction: "/GetStockPrice"
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Body xmlns:m="http://www.example.org/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
The server in response should only return:
And what if we need to send attachments?
Solution 1: encoded in the envelope using BASE64
...very inefficient...
And what if we need to send attachments?
Solution 2: Message Transmission Optimization Mechanism
using MIME and Multipart
MIME-version: 1.0
Content-Type: Multipart/Related; ...
--MIME_boundary
Content-Type: text/xml; ...
<?xml version="1.0" ?>
<env:Envelope ...
<someTag href="cid:attached.gif@company.com"/>
</end:Envelope>
...
--MIME_boundary
Content-Type: image/gif
Content-Transfer-Encoding: binary
Content-ID: <"attached.gif@company.com">
... image's binary...
How do I build a Web Service?
How do I build a Web Service?
node-soap:
But I still have a big problem: how can the user know
Do I have to write documentation?
But I still have a big problem: how can the user know
Do I have to write documentation? NO!
Web Services Description Language, W3C standard
Uses XML to define interfaces, composed of four elements:
<types>: data types used by the WS (not necessary if using already known primitives)<message>: definition of the data being transmitted<portType>: operations that can be performed and related messages<binding>: protocol and data format used for each port<portType> doesn’t handle only request/response:
You switch between them by changing the order and presence of input/output elements
<message name="getTermRequest">
<part name="term" type="xs:string"/>
</message>
<message name="getTermResponse">
<part name="value" type="xs:string"/>
</message>
<portType name="glossaryTerms">
<operation name="getTerm">
<input message="getTermRequest"/>
<output message="getTermResponse"/>
</operation>
</portType>
<binding type="glossaryTerms" name="b1">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation>
<soap:operation soapAction="http://example.com/getTerm"/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
</binding>
Representational State Transfer (RESTful)
Originates from Roy T. Fielding’s dissertation
http://myapp.com/api/entry
http://myapp.com/api/entry/17
it’s not necessary to implement all of them
| Resource | Method |
|---|---|
| Book list | [GET] /books |
| Book details | [GET] /books/<id> |
| Create a book | [POST] /books |
| Edit a book (or create a book with a specific ID) | [PUT] /books/<id> |
| Delete a book | [DELETE] /books/<id> |
GET http://myapp.com/api/entry
[{
id: 17,
date: "2013/15/5 11:58:00",
amount: 17.38,
currency: "eur",
description: "pranzo"
}, {
id: 185,
date: "2013/15/5 8:30:00",
amount: 1.20,
currency: "eur",
description: "caffè"
}]
Some REST ideas are great, but in practice unworkable... documentation is needed!
OpenAPI is an API description format for REST APIs
Some options:
Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable.
I need to include Vue in my web document
It’s convenient to use a CDN:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
Production version (without warnings and debug):
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
Every application starts by creating a new Vue instance through createApp():
const { createApp } = Vue
const app = createApp({
/* options */
})
An application must be attached to a container, an HTML element where the application is rendered
This is done using the mount() method:
app.mount('#app')
Vue.js is based on the reactivity system: if a JavaScript object is modified, the view gets updated
Objects that I want to control with the reactivity system must be passed through the data property
data will be a method that returns the objects to monitor.
The reactivity system will "react" every time one of these properties changes by performing a re-render.
var data = { a: 1 }
const app = createApp({
data() { return data }
})
Vue.js uses a syntax based on dynamic HTML templates. To bind data to the render, it provides interpolation features
{{ x }}, called "mustache", is replaced in the HTML with the evaluation of xx must be rendered as HTML, I must use the v-html directivemethods propertyv- prefix:Now you see me
The v-if directive removes/inserts the element depending on whether the "seen" expression is false/true
v-if shows or hides an element if the expression is true or falsev-for repeats the component for each element of an iterable objectv-on:event associates a function to the event eventv-bind:attr binds the value of an attribute attr to an expressionv-html sets the element’s innerHTML with the expressionv-on:event → @eventv-bind:attr → :attrcomputed propertyconst { createApp } = Vue
const data = {firstname: "Andrea", lastname: "De Lorenzo"};
const app = createApp({
data() {
return data
},
computed: {
fullname: function() {
return this.firstname + ' ' + this.lastname;
}
}
});
app.mount('#app');
class attribute using the :class directive:class="{ 'cl1': hasCl1, 'cl2': hasCl2}":class="['cl1','cl2']"v-on:event or @event we can handle events.stop: stops bubbling.prevent: prevents the default action.once: calls the callback only once, then removes it<a href="..." @click.prevent="onClick">Link</a>
v-model directive<main id="app">
{{text}}
</main>
const app = createApp({
data() {
return { text: "" }
}
});
<my-comp></my-comp>Global registration
app.component('mio-comp', {
[...]
});
Local registration
export default {
[...],
components: {
'mio-comp': {
[...]
}
}
});
datadata propertydata represents the reactive data model for that componentexport default {
data: function() {
return {
name: 'Andrea',
age: 37
};
}
}
templatetemplate parameterInline string
const ButtonCounter = {
data() {
return {
count: 0
}
},
template: `
`
}
String in a separate module
export default {
data() {
return {
count: 0
}
},
template: `
`
}
propsprops propertyprops<div id="app">
<people-list :people="people"></people-list>
<div>
<input v-model="name" placeholder="name" /><br />
<input v-model="surname" placeholder="surname" /><br />
<button @click.prevent="addPerson">Add person</button>
</div>
</div>
propsconst { createApp } = Vue
const PeopleList = {
props: ['people'],
template: ` `
}
const Person = {
props: ['person'],
template: `{{ person.name }} {{ person.surname }}`
}
const app = createApp({
data() { return { people: [{ name: 'Andrea', surname: 'De Lorenzo' }], name: '', surname: ''}},
methods: {
addPerson: function() {
this.people.push({
name: this.name,
surname: this.surname
});
this.name = '';
this.surname = '';
}
}
});
app.component("Person", Person);
app.component("PeopleList", PeopleList);
app.mount('#app');
Output
{{msg.title}}
Functionality
Stile
<template><script><style>Web apps often rely on the concept of a Single Page Application
The entire application lives inside a single HTML page whose components change dynamically depending on the content
It’s useful to offer permalinks to resources in a Single Page Application
This is done by using URL anchors (the part after #)
In Vue.js, routing is used to load templates based on the URL
import Home from './Home.js'
import About from './About.js'
import NotFound from './NotFound.js'
const routes = {
'/': Home,
'/about': About
}
export default {
data() {
return { currentPath: window.location.hash }
},
computed: {
currentView() {
return routes[this.currentPath.slice(1) || '/'] || NotFound
}
},
mounted() {
window.addEventListener('hashchange', () => {
this.currentPath = window.location.hash
})
},
template: `<a href="#/">Home</a> |<a href="#/about">About</a> | <a href="#/non-existent-path">Broken Link</a>
<current-view><</current-view>`
}
Every Vue component goes through a life cycle, from creation to destruction
Lifecycle Hooks allow you to run code at specific moments of this cycle
created(): initial data availablemounted(): component is in the DOMupdated(): the view has been updatedunmounted(): cleanup before removalExecuted after the instance is created but before mounting
created() {
console.log("Component created");
}
Executed when the component is mounted into the DOM
mounted() {
console.log("DOM ready!");
console.log(this.$el); // DOM node reference
}
Executed every time the view updates as a result of reactive data changes
updated() {
console.log("Component updated");
}
Executed when the component is removed
unmounted() {
console.log("Component removed");
}
Vue allows you to observe changes in reactive data and run custom logic.
Useful for asynchronous operations, API calls, validation, and reacting to specific changes.
Watching a single data property
export default {
data() {
return { name: '' }
},
watch: {
name(newVal, oldVal) {
console.log("Name changed:", oldVal, "→", newVal)
}
}
}
Useful for API calls triggered by changes
watch: {
searchQuery: async function (value) {
const res = await fetch(`/api?q=${value}`)
this.results = await res.json()
}
}
To avoid excessive API calls (e.g. during fast typing), use a debounce strategy.
Debouncing delays the execution until the user stops typing.
let debounceTimer = null
watch: {
searchQuery(value) {
clearTimeout(debounceTimer)
debounceTimer = setTimeout(async () => {
if (!value) {
this.results = []
return
}
try {
const res = await fetch(`/api?q=${encodeURIComponent(value)}`)
this.results = await res.json()
} catch (err) {
console.error("API error:", err)
}
}, 400) /* wait 400ms */
}
}
This prevents sending a request for every keystroke, improving performance and user experience.
watch: {
settings: {
handler(val) {
console.log("Settings changed", val)
},
deep: true,
immediate: true
}
}
For larger apps, managing shared state becomes complex.
Vue provides libraries for centralized state management:
Pinia is the recommended store for Vue 3
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
}
}
})
import { useCounterStore } from './stores/counter'
export default {
setup() {
const counter = useCounterStore()
return { counter }
}
}
{{ counter.count }}
Vuex uses a more rigid structure: state, mutations, actions, getters
const store = createStore({
state() {
return { count: 0 }
},
mutations: {
increment(state) { state.count++ }
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => commit('increment'), 1000)
}
}
})
Typical case of a web application: interacting with a database
The type of database is not important (SQL/NoSQL, doesn’t matter)
The pairing of Node.js and MongoDB comes “naturally”
We will use the mongodb module
Connection URI:
MongoClient object to manage the connectionconnect() promise that opens the connectionclose()MongoClient returns the MongoDB database through db()collection()const { MongoClient } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function connect() {
try {
await client.connect();
} finally {
await client.close();
}
}
connect().catch(console.log);
FindCursor
Collection.find()Collection.findOne()Collection.aggregate()Collection.insert()Collection.insertOne()Collection.updateOne()Collection.updateMany()Collection.replaceOne()Collection.deleteMany()Collection.deleteOne()const query = { title: "Desired Title" };
const options = {
sort: { "imdb.rating": -1 }
};
const movie = await movies.findOne(query, options);
const query = { runtime: { $lt: 15 } };
const options = {
sort: { "imdb.rating": -1 }
};
const cursor = movies.find(query, options);
await cursor.forEach(console.dir);
console.log(await cursor.toArray());