DOM: Selezionare Elementi

Impara a selezionare e accedere agli elementi HTML con JavaScript

🌳 Cos’è il DOM?

Il DOM (Document Object Model) è la rappresentazione ad albero di una pagina web.
JavaScript può accedere e modificare tutti gli elementi HTML attraverso il DOM!

💡 Come Funziona

Quando il browser carica una pagina HTML, crea un modello a oggetti del documento.
Ogni elemento HTML diventa un “nodo” che JavaScript può leggere, modificare, aggiungere o eliminare.

document (root)
  └─ html
      ├─ head
      │   ├─ title
      │   └─ meta
      └─ body
          ├─ header
          │   └─ h1
          ├─ main
          │   ├─ p
          │   └─ div
          └─ footer

🎯 In Questa Lezione

  • querySelector() – Selettore CSS moderno (⭐ CONSIGLIATO)
  • getElementById() – Seleziona per ID
  • getElementsByClassName() – Seleziona per classe
  • getElementsByTagName() – Seleziona per tag
  • Navigazione DOM – Parent, children, siblings
  • Best Practices – Quale metodo usare quando

⭐ querySelector() e querySelectorAll()

I metodi querySelector() sono i più moderni e versatili.
Usano la stessa sintassi dei selettori CSS!

1
querySelector() – Seleziona Primo Elemento

Restituisce il PRIMO elemento che corrisponde al selettore.

HTML di Esempio
<!DOCTYPE html>
<html>
<head>
    <title>Demo DOM</title>
</head>
<body>
    <h1 id="titolo">Benvenuto!</h1>
    <p class="testo">Primo paragrafo</p>
    <p class="testo">Secondo paragrafo</p>
    <button id="btn">Clicca</button>
    <div class="container">
        <span class="highlight">Importante</span>
    </div>
</body>
</html>

querySelector() Esempi
// Seleziona per ID (con #)
const titolo = document.querySelector('#titolo');
console.log(titolo);  // <h1 id="titolo">Benvenuto!</h1>

// Seleziona per classe (con .)
const paragrafo = document.querySelector('.testo');
console.log(paragrafo);  // Primo <p> con classe "testo"

// Seleziona per tag
const button = document.querySelector('button');
console.log(button);  // <button id="btn">Clicca</button>

// Selettori complessi (come CSS!)
const span = document.querySelector('.container .highlight');
console.log(span);  // <span class="highlight">Importante</span>

// Selettori attributo
const btnById = document.querySelector('[id="btn"]');

// Pseudo-classi
const primoP = document.querySelector('p:first-child');
const ultimoP = document.querySelector('p:last-child');

2
querySelectorAll() – Seleziona Tutti gli Elementi

Restituisce una NodeList con TUTTI gli elementi corrispondenti.

querySelectorAll() Esempi
// Seleziona TUTTI i paragrafi con classe "testo"
const tuttiParagrafi = document.querySelectorAll('.testo');
console.log(tuttiParagrafi);  // NodeList(2) [p.testo, p.testo]
console.log(tuttiParagrafi.length);  // 2

// Itera con forEach
tuttiParagrafi.forEach((p, indice) => {
    console.log(`Paragrafo ${indice + 1}: ${p.textContent}`);
});
// Output:
// Paragrafo 1: Primo paragrafo
// Paragrafo 2: Secondo paragrafo

// Converti in array per usare metodi array
const arrayP = Array.from(tuttiParagrafi);
// Oppure con spread
const arrayP2 = [...tuttiParagrafi];

const testi = arrayP.map(p => p.textContent);
console.log(testi);  // ["Primo paragrafo", "Secondo paragrafo"]

// Selettori multipli (con virgola)
const elementi = document.querySelectorAll('h1, p, button');
console.log(elementi.length);  // 4 (1 h1 + 2 p + 1 button)

// Tutti gli elementi con data attribute
const conData = document.querySelectorAll('[data-id]');

✅ Vantaggi querySelector()

  • 🌟 Sintassi CSS familiare
  • 🌟 Selettori complessi supportati
  • 🌟 Metodo moderno (ES5+)
  • 🌟 Più flessibile degli altri metodi
  • QUESTO È IL METODO CONSIGLIATO!

🆔 getElementById()

Seleziona un elemento tramite il suo ID univoco.
Metodo classico, veloce ma limitato.

1
Uso Base

HTML
<h1 id="titolo-principale">Benvenuto</h1>
<div id="container">Contenuto</div>
<button id="btn-submit">Invia</button>

getElementById() Esempi
// Sintassi: document.getElementById('id')
// NOTA: NON usa il simbolo #

const titolo = document.getElementById('titolo-principale');
console.log(titolo);  // <h1 id="titolo-principale">Benvenuto</h1>

const container = document.getElementById('container');
console.log(container.textContent);  // "Contenuto"

const button = document.getElementById('btn-submit');
console.log(button);

// Se l'ID non esiste, restituisce null
const nonEsiste = document.getElementById('fake-id');
console.log(nonEsiste);  // null

// Controlla sempre prima di usare
if (titolo) {
    console.log(titolo.textContent);
} else {
    console.log("Elemento non trovato");
}

💡 getElementById vs querySelector
// getElementById - veloce ma limitato
const el1 = document.getElementById('mio-id');

// querySelector - più flessibile
const el2 = document.querySelector('#mio-id');

// Entrambi selezionano lo stesso elemento!
// querySelector è più moderno e versatile ✅

📦 getElementsByClassName()

Seleziona TUTTI gli elementi con una specifica classe.
Restituisce una HTMLCollection live.

1
Uso Base

HTML
<p class="testo">Primo</p>
<p class="testo">Secondo</p>
<p class="testo highlight">Terzo</p>
<div class="box">Box</div>

getElementsByClassName() Esempi
// Sintassi: document.getElementsByClassName('classe')
// NOTA: NON usa il punto .

const paragrafi = document.getElementsByClassName('testo');
console.log(paragrafi);  // HTMLCollection(3) [p.testo, p.testo, p.testo]
console.log(paragrafi.length);  // 3

// Accesso per indice
console.log(paragrafi[0].textContent);  // "Primo"
console.log(paragrafi[1].textContent);  // "Secondo"

// ⚠️ HTMLCollection NON ha forEach!
// paragrafi.forEach(...);  // ERRORE!

// ✅ Converti in array prima
const arrayP = Array.from(paragrafi);
arrayP.forEach((p, i) => {
    console.log(`${i + 1}. ${p.textContent}`);
});

// Oppure usa for classico
for (let i = 0; i < paragrafi.length; i++) {
    console.log(paragrafi[i].textContent);
}

// for...of funziona!
for (let p of paragrafi) {
    console.log(p.textContent);
}

⚠️ HTMLCollection è "Live"

La collection si aggiorna automaticamente quando il DOM cambia!

const boxes = document.getElementsByClassName('box');
console.log(boxes.length);  // 1

// Aggiungi nuova box al DOM
const nuovaBox = document.createElement('div');
nuovaBox.className = 'box';
document.body.appendChild(nuovaBox);

console.log(boxes.length);  // 2 (aggiornato automaticamente!)

// querySelector invece NON è live (static)

🏷️ getElementsByTagName()

Seleziona TUTTI gli elementi di un certo tag HTML.
Restituisce una HTMLCollection live.

1
Uso Base

getElementsByTagName() Esempi
// Tutti i paragrafi
const paragrafi = document.getElementsByTagName('p');
console.log(paragrafi.length);

// Tutti i div
const divs = document.getElementsByTagName('div');

// Tutti i link
const links = document.getElementsByTagName('a');

// Tutte le immagini
const immagini = document.getElementsByTagName('img');

// Itera (converti in array)
const arrayP = Array.from(paragrafi);
arrayP.forEach((p, i) => {
    console.log(`P ${i + 1}: ${p.textContent}`);
});

// TUTTI gli elementi (*)
const tuttiGliElementi = document.getElementsByTagName('*');
console.log(`Totale elementi: ${tuttiGliElementi.length}`);

💡 Quando Usarlo

Usa getElementsByTagName() quando vuoi:

  • Selezionare TUTTI gli elementi di un tipo
  • Contare elementi (es: quante immagini ci sono?)
  • Applicare stile a tutti i tag di un tipo

⚠️ Ma querySelectorAll('p') è più moderno e fa lo stesso!

🧭 Navigazione DOM

Una volta selezionato un elemento, puoi navigare verso i suoi parenti, figli e fratelli!

1
Parent, Children, Siblings

HTML Struttura
<div id="container">
    <h2 id="titolo">Titolo</h2>
    <p id="paragrafo1">Primo paragrafo</p>
    <p id="paragrafo2">Secondo paragrafo</p>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</div>

Navigazione Parent/Children
const paragrafo1 = document.querySelector('#paragrafo1');

// PARENT - Genitore
const parent = paragrafo1.parentElement;
console.log(parent);  // <div id="container">

// CHILDREN - Figli diretti
const container = document.querySelector('#container');
console.log(container.children);  // HTMLCollection dei figli
console.log(container.children.length);  // 4

// Primo e ultimo figlio
console.log(container.firstElementChild);  // <h2>
console.log(container.lastElementChild);   // <ul>

// SIBLINGS - Fratelli
const primoP = document.querySelector('#paragrafo1');

// Fratello successivo
const next = primoP.nextElementSibling;
console.log(next);  // <p id="paragrafo2">

// Fratello precedente
const secondoP = document.querySelector('#paragrafo2');
const prev = secondoP.previousElementSibling;
console.log(prev);  // <p id="paragrafo1">

2
Proprietà Utili

Proprietà Navigazione
const elemento = document.querySelector('#paragrafo1');

// PARENT
elemento.parentElement       // Genitore (Element)
elemento.parentNode          // Genitore (Node)

// CHILDREN
elemento.children            // HTMLCollection di figli (solo Element)
elemento.childNodes          // NodeList di tutti i nodi (include testo)
elemento.firstElementChild   // Primo figlio Element
elemento.lastElementChild    // Ultimo figlio Element
elemento.childElementCount   // Numero di figli

// SIBLINGS
elemento.nextElementSibling      // Fratello successivo
elemento.previousElementSibling  // Fratello precedente

// Verifica se ha figli
if (elemento.children.length > 0) {
    console.log("Ha figli");
}

// Verifica se ha parent
if (elemento.parentElement) {
    console.log("Ha un genitore");
}

3
Closest() - Trova Antenato

Risale l'albero DOM fino a trovare un elemento che corrisponde al selettore.

closest() Esempi
<div class="container">
    <div class="card">
        <button id="btn">Clicca</button>
    </div>
</div>

// JavaScript
const button = document.querySelector('#btn');

// Trova il .card genitore (più vicino)
const card = button.closest('.card');
console.log(card);

// Trova il .container genitore
const container = button.closest('.container');
console.log(container);

// Uso pratico: event delegation
button.addEventListener('click', (e) => {
    const card = e.target.closest('.card');
    if (card) {
        console.log("Hai cliccato nella card!");
    }
});

📊 Metodi vs Proprietà

Relazione Proprietà Descrizione
⬆️ Genitore parentElement Elemento genitore diretto
⬇️ Figli children Tutti i figli diretti (HTMLCollection)
⬇️ Primo figlio firstElementChild Primo figlio Element
⬇️ Ultimo figlio lastElementChild Ultimo figlio Element
➡️ Fratello dopo nextElementSibling Fratello successivo
⬅️ Fratello prima previousElementSibling Fratello precedente

📊 Confronto Metodi di Selezione

Tabella Decisionale

Metodo Restituisce Live? Quando Usare
querySelector() 1 Element o null ❌ No ⭐ Selettore CSS (CONSIGLIATO)
querySelectorAll() NodeList (static) ❌ No ⭐ Tutti con selettore CSS
getElementById() 1 Element o null ❌ No Solo ID (veloce ma limitato)
getElementsByClassName() HTMLCollection ✅ Sì Classe (meglio querySelector)
getElementsByTagName() HTMLCollection ✅ Sì Tag (meglio querySelector)

💡 Best Practice

🌟 Usa querySelector() e querySelectorAll() come default!

  • ✅ Sintassi CSS familiare
  • ✅ Più flessibile e potente
  • ✅ Standard moderno
  • ✅ NodeList ha forEach()
  • ⚠️ Gli altri metodi sono legacy ma ancora funzionanti

🚀 Esempio Completo: Task List Navigator

HTML
<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>Task List</title>
    <style>
        .task { padding: 10px; margin: 5px 0; border: 1px solid #ddd; }
        .task.completed { background: #d4edda; text-decoration: line-through; }
        .task.priority-high { border-left: 4px solid #dc3545; }
        .task.priority-medium { border-left: 4px solid #ffc107; }
        .task.priority-low { border-left: 4px solid #28a745; }
    </style>
</head>
<body>
    <div id="app">
        <h1>Task List</h1>
        
        <div class="controls">
            <button id="btn-show-all">Mostra Tutti</button>
            <button id="btn-show-completed">Solo Completati</button>
            <button id="btn-show-pending">Solo Pendenti</button>
        </div>

        <div id="tasks-container">
            <div class="task priority-high" data-id="1">
                <input type="checkbox" class="task-checkbox">
                <span class="task-title">Studiare JavaScript</span>
                <span class="task-priority">Alta</span>
            </div>

            <div class="task priority-medium completed" data-id="2">
                <input type="checkbox" class="task-checkbox" checked>
                <span class="task-title">Fare la spesa</span>
                <span class="task-priority">Media</span>
            </div>

            <div class="task priority-low" data-id="3">
                <input type="checkbox" class="task-checkbox">
                <span class="task-title">Chiamare Mario</span>
                <span class="task-priority">Bassa</span>
            </div>

            <div class="task priority-high" data-id="4">
                <input type="checkbox" class="task-checkbox">
                <span class="task-title">Finire progetto</span>
                <span class="task-priority">Alta</span>
            </div>
        </div>

        <div id="stats"></div>
    </div>

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

JavaScript - script.js
// === SELEZIONE ELEMENTI ===

// Container principale
const app = document.querySelector('#app');
const tasksContainer = document.querySelector('#tasks-container');
const statsDiv = document.querySelector('#stats');

// Bottoni
const btnShowAll = document.querySelector('#btn-show-all');
const btnShowCompleted = document.querySelector('#btn-show-completed');
const btnShowPending = document.querySelector('#btn-show-pending');

// Tasks
const tuttiTasks = document.querySelectorAll('.task');
console.log(`Totale tasks: ${tuttiTasks.length}`);

// === FUNZIONI UTILITY ===

// Ottieni tutti i task (freschi dal DOM)
function getTasks() {
    return document.querySelectorAll('.task');
}

// Ottieni task completati
function getCompletedTasks() {
    return document.querySelectorAll('.task.completed');
}

// Ottieni task pendenti
function getPendingTasks() {
    const tutti = getTasks();
    return Array.from(tutti).filter(task => {
        return !task.classList.contains('completed');
    });
}

// Ottieni task per priorità
function getTasksByPriority(priority) {
    return document.querySelectorAll(`.task.priority-${priority}`);
}

// === STATISTICHE ===

function updateStats() {
    const tutti = getTasks();
    const completati = getCompletedTasks();
    const pendenti = getPendingTasks();
    
    const alte = getTasksByPriority('high');
    const medie = getTasksByPriority('medium');
    const basse = getTasksByPriority('low');
    
    statsDiv.innerHTML = `
        <h3>📊 Statistiche</h3>
        <p>Totale: ${tutti.length}</p>
        <p>Completati: ${completati.length}</p>
        <p>Pendenti: ${pendenti.length}</p>
        <hr>
        <p>Priorità Alta: ${alte.length}</p>
        <p>Priorità Media: ${medie.length}</p>
        <p>Priorità Bassa: ${basse.length}</p>
    `;
}

// === FILTRI ===

function showAll() {
    getTasks().forEach(task => {
        task.style.display = 'block';
    });
}

function showCompleted() {
    getTasks().forEach(task => {
        if (task.classList.contains('completed')) {
            task.style.display = 'block';
        } else {
            task.style.display = 'none';
        }
    });
}

function showPending() {
    getTasks().forEach(task => {
        if (!task.classList.contains('completed')) {
            task.style.display = 'block';
        } else {
            task.style.display = 'none';
        }
    });
}

// === EVENT LISTENERS ===

btnShowAll.addEventListener('click', showAll);
btnShowCompleted.addEventListener('click', showCompleted);
btnShowPending.addEventListener('click', showPending);

// === NAVIGAZIONE DOM ===

// Analizza struttura
console.log("=== ANALISI DOM ===");

const primoTask = document.querySelector('.task');
console.log("Primo task:", primoTask);

// Parent
console.log("Parent:", primoTask.parentElement);

// Siblings
const secondoTask = primoTask.nextElementSibling;
console.log("Secondo task:", secondoTask);

// Children
const checkbox = primoTask.querySelector('.task-checkbox');
const title = primoTask.querySelector('.task-title');
const priority = primoTask.querySelector('.task-priority');

console.log("Checkbox:", checkbox);
console.log("Titolo:", title.textContent);
console.log("Priorità:", priority.textContent);

// === INFO DETTAGLIATE OGNI TASK ===

console.log("\n=== DETTAGLI TASKS ===");
getTasks().forEach((task, indice) => {
    const id = task.getAttribute('data-id');
    const title = task.querySelector('.task-title').textContent;
    const isCompleted = task.classList.contains('completed');
    const priority = task.className.match(/priority-(\w+)/)[1];
    
    console.log(`Task ${indice + 1}:`);
    console.log(`  ID: ${id}`);
    console.log(`  Titolo: ${title}`);
    console.log(`  Completato: ${isCompleted ? 'Sì' : 'No'}`);
    console.log(`  Priorità: ${priority}`);
    console.log('');
});

// === INIZIALIZZAZIONE ===
updateStats();

// Output console:
// Totale tasks: 4
// === ANALISI DOM ===
// Primo task: <div class="task priority-high"...
// Parent: <div id="tasks-container">
// Secondo task: <div class="task priority-medium completed"...
// Checkbox: <input type="checkbox"...
// Titolo: Studiare JavaScript
// Priorità: Alta
// 
// === DETTAGLI TASKS ===
// Task 1:
//   ID: 1
//   Titolo: Studiare JavaScript
//   Completato: No
//   Priorità: high
// 
// Task 2:
//   ID: 2
//   Titolo: Fare la spesa
//   Completato: Sì
//   Priorità: medium
// ... (continua)

💡 Tecniche Usate
  • querySelector() - Selezione singoli elementi
  • querySelectorAll() - Selezione multipla
  • Selettori complessi - .task.completed, .priority-high
  • Data attributes - data-id
  • Navigazione DOM - parent, children, siblings
  • classList - Verifica classi
  • Array.from() - Converti NodeList

✅ Best Practices

🌟 Regole d'Oro

1
Usa querySelector() come Default

// ✅ CONSIGLIATO
const elemento = document.querySelector('#mio-id');
const tutti = document.querySelectorAll('.mia-classe');

// ❌ EVITA (a meno che non serva specificatamente)
const elemento = document.getElementById('mio-id');
const tutti = document.getElementsByClassName('mia-classe');

2
Cachea le Selezioni

Evita di selezionare lo stesso elemento più volte.

// ❌ MALE - Seleziona ogni volta
document.querySelector('#btn').addEventListener('click', () => {
    document.querySelector('#output').textContent = "Cliccato!";
});
document.querySelector('#btn').style.color = 'blue';

// ✅ BENE - Cachea la selezione
const btn = document.querySelector('#btn');
const output = document.querySelector('#output');

btn.addEventListener('click', () => {
    output.textContent = "Cliccato!";
});
btn.style.color = 'blue';

3
Controlla Sempre se Esiste

// ❌ PERICOLOSO - Può causare errori
const elemento = document.querySelector('#potrebbe-non-esistere');
elemento.textContent = "Test";  // TypeError se null!

// ✅ SICURO - Controlla prima
const elemento = document.querySelector('#potrebbe-non-esistere');
if (elemento) {
    elemento.textContent = "Test";
} else {
    console.log("Elemento non trovato");
}

// ✅ SICURO - Optional chaining (ES2020)
const elemento = document.querySelector('#potrebbe-non-esistere');
elemento?.classList.add('active');  // Non fa nulla se null

4
Scope le Ricerche

Cerca dentro un elemento specifico invece di tutto il document.

// ❌ LENTO - Cerca in tutto il documento
const button = document.querySelector('.container .card .button');

// ✅ VELOCE - Cerca in scope ridotto
const container = document.querySelector('.container');
const card = container.querySelector('.card');
const button = card.querySelector('.button');

// Oppure
const button = document.querySelector('.container')
                       .querySelector('.card')
                       .querySelector('.button');

🎯 Riepilogo Lezione

querySelector()

  • ⭐ CONSIGLIATO
  • Sintassi CSS
  • Primo elemento
querySelectorAll()

  • ⭐ CONSIGLIATO
  • Tutti gli elementi
  • NodeList con forEach
Navigazione

  • parentElement
  • children
  • nextElementSibling
Best Practices

  • Usa querySelector
  • Cachea selezioni
  • Controlla esistenza

Lezione 12 del Corso JavaScript Completo

Torna in alto