:HEADER-ARGS:html: :tangle w04/index.html :HEADER-ARGS:css: :tangle w04/css/style.css :HEADER-ARGS:js: :tangle w04/js/main.js

Prepare the environment

mkdir -p w04/{css,js,media}
mkdir -p w04/media/{img,video,fonts}
touch w04/index.html
touch w04/css/style.css
touch w04/js/main.js

Prepare the index html file

Include the Javascript

Consider the distinctions between placing the script tag at the end of the body or at the begin (or within the head tag). When you intend to select specific elements in the DOM, it’s crucial to be sure that the DOM nodes are fully rendered. To archive this, you have two options:

  1. Set the script tag at the end of the body
  2. Wrap the code into a function and call it when the web-site is fully loaded

First option

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <title>Document</title>
  </head>
  <body>
    <p>La madre de Beth tiene tres hijas. La mayor se llama Clara, la pequeña Sara. ¿Cómo se llama la mediana?</p>
    <button>Show answer</button>
    <script src="js/example1.js"></script>
  </body>
</html>

And the js:

let paragraph = document.querySelector("p"),
      button = document.querySelector("button"),
      texts = ["Beth"];

button.addEventListener("click", function(e) {
    if (typeof(button.dataset.isShow) === "undefined") { 
        texts.push(paragraph.innerText); // insert the text of the paragraph as a new entry in the array
        button.dataset.isShow = 0;
    } 
    paragraph.innerText = texts[button.dataset.isShow++];
    button.dataset.isShow %= 2;
});

Second Option

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <title>Document</title>
  </head>
  <body>
    <p>La madre de Beth tiene tres hijas. La mayor se llama Clara, la pequeña Sara. ¿Cómo se llama la mediana?</p>
    <button>Show answer</button>
    <script src="js/example2.js"></script>
  </body>
</html>

The js/example2.js file

//The function passes as argument, receives another arguments with the Event object
document.addEventListener("DOMContentLoaded", function(event) {
     let paragraph = document.querySelector("p"),
         button = document.querySelector("button"),
         texts = ["Beth"];

     button.addEventListener("click", function(event) {
         if (typeof(button.dataset.isShow) === "undefined") { 
             texts.push(paragraph.innerText); // insert the text of the paragraph as a new entry in the array
             button.dataset.isShow = 0;
         } 
         paragraph.innerText = texts[button.dataset.isShow++];
         button.dataset.isShow %= 2;
     });
 });

For more information about the DOMContentLoaded event, go to MDN documentation

Prepare the HTML

For the moment, we continue with the basic example

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="css/style.css" rel="stylesheet">
  </head>
  <body>
    <p>This is the default text</p>
    <script src="js/main.js"></script>
  </body>
</html>

Play with js

Why is important the use of semicolon ;

You can run the following code, and compare the results before and after removing the semicolon from line 7;

function sayHello (name) {
    console.log("Hola " + name );
    return name;
}

  sayHello("Pepe");
  const greeter = sayHello;
  (function pow(base, exp) {
      console.log(base**exp);
      return pow;
  })(2, 6)
greeter(6, 6);

Select elements from the DOM

As we have viewed in DOM Manipulation, there are many ways to select elements and manipulate them. In this example we will change a image src when user click the button

Manipulate attributes

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="css/style.css" rel="stylesheet">
  </head>
  <body>
  <img src="https://www.divinacocina.es/wp-content/uploads/2022/03/filetes-empanados-1.jpg.webp" >
  <button id="changeMe">Cambia</button>
  <hr>
  <p>La madre de Beth tiene tres hijas. La mayor se llama Clara, la pequeña Sara. ¿Cómo se llama la mediana?</p>
  <button id="answer">Show answer</button>

  <script src="js/main.js"></script>
  </body>
</html>

And the javascript code

// define some vars
  let img = document.querySelector("img");
  let routes = ["https://recetasdecocina.elmundo.es/wp-content/uploads/2023/09/patatas-fritas-perfectas.jpg", "https://www.divinacocina.es/wp-content/uploads/2022/03/filetes-empanados-1.jpg.webp"];
  let pos = 1;
//define a simple function to change the src
  function changes() {
      pos = ++pos%2;
      img.setAttribute("src", routes[pos]);
      console.log("The current value is " + img.getAttribute("src"));
  }

// Select the button by the ID and add the event onclick
let changeMe = document.getElementById("changeMe");
changeMe.addEventListener("click", changes);

If we want to ask for the current value, we can use the method getAttribute

Manipulate text

In the first example, we can see the process following to change the text inside a paragraph. But this process could be used with any other tag

At the beginning of the course, we talked about the attributes of the tags, and I emphasized the fact that we can create and use our own attributes, But we have to prepend it with the data- strings

Now we can see why. All the attributes that begin with data- are accessible by the dataset attribute of any node.

In this example, I will use the data-is-show attribute from the button. You can see who the button is changing the value from the developer tool of the browser.

let paragraph = document.querySelector("p");
let answer = document.getElementById("answer");
let texts = ["Beth"];

answer.addEventListener("click", function(e) {
    if (typeof(answer.dataset.isShow) === "undefined") { 
        texts.push(paragraph.innerText); // insert the text of the paragraph as a new entry in the array
        answer.dataset.isShow = 0;
    } 
    paragraph.innerText = texts[answer.dataset.isShow++];
    answer.dataset.isShow %= 2;
});

Insert new node

If we want to insert a new node or remove another, there are a few steps we have to follow. First the node must be created, then we modify it as needed, and finally we insert it into the node which will be its parents. The process could be repeated as many times as we needed.

Look the difference between appendChild and insertBefore

function appendWeirdText() {
    let numberOfSections = 3,
        numberOfArticles = 4,
        numberOfParagraphs = 12;

    for (let i = 0; i < numberOfSections; ++i) {
        const section = document.createElement("section");
        const title = document.createElement("h2");
        title.innerText = "Soy la sección " + i;
        section.appendChild(title);
        for (let j = 0; j < numberOfArticles; ++j) {
            const article = document.createElement("article");
            const subtitle = document.createElement("h3");
            subtitle.innerText = "Soy el artículo " + j + " en la sección " + i;
            article.appendChild(subtitle);
            for (let k = 0; k < numberOfParagraphs; ++k) {
                const paragraph = document.createElement("p");
                paragraph.innerText = "Soy el parrafo " + k + " en el artículo " + j + " y la sección " + i;
                article.appendChild(paragraph);
            }
            // When the article wont be updated more, add it to the section
            section.appendChild(article);
        }
        document.body.insertBefore(section, document.getElementsByTagName("script")[0]);
    }
  }

const newButton = document.createElement("button");
newButton.innerText = "Insert random text";
newButton.addEventListener("click", appendWeirdText);
document.body.insertBefore(newButton, document.getElementsByTagName("script")[0]);