MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Încărcarea HTML folosind XMLHttpRequest

Adesea, în codul paginii este necesar să obții de pe server un anumit cod HTML. De exemplu, pagina poate reprezenta un site web pe o singură pagină, care prin intermediul unei solicitări ajax încarcă codul HTML necesar și îl inserează pe pagină. Prin urmare, să examinăm cum să încărcăm codul HTML prin AJAX.

Ca server, la fel ca în articolul anterior, vom utiliza Node.js ca opțiunea cea mai simplă, dar, bineînțeles, dacă doriți, puteți utiliza orice altă tehnologie de nivel server sau un server web.

Așadar, să definim pentru proiect un folder pe hard disk, în care vom crea trei fișiere:

  • index.html: pagina principală a aplicației
  • home.html: pagina cu codul HTML pe care îl vom încărca prin AJAX
  • server.js: fișierul aplicației server, care va utiliza Node.js

Definirea serverului

Fișierul server.js va reprezenta codul serverului Node.js. Să definim în el următorul cod:

const http = require("http");
const fs = require("fs");

http.createServer((request, response)=>{
   // obținem calea după slash, slash-ul - primul caracter în cale
   let filePath = request.url.substring(1);
   // dacă calea este goală, trimitem pagina principală index.html
   if(!filePath) filePath = "index.html";  
   // ca tip de răspuns stabilim html
   response.setHeader("Content-Type", "text/html; charset=utf-8;");
   fs.readFile(filePath, (error, data)=>{
       if(error){                              // dacă este o eroare
           response.statusCode = 404;
           response.end("<h1>Resursa nu a fost găsită!</h1>");
       }  
       else{
           response.end(data);
       }
   });
}).listen(3000, ()=>console.log("Serverul a fost lansat la adresa http://localhost:3000"));

Să parcurgem pe scurt codul. Mai întâi se conectează pachetele cu funcționalitatea pe care intenționăm să o utilizăm:

const http = require("http");   // pentru prelucrarea cererilor de intrare
const fs = require("fs");       // pentru citirea fișierelor de pe hard disk

Pentru crearea serverului se utilizează funcția http.createServer(). În această funcție se transmite o funcție-handler, care este apelată de fiecare dată când la server sosește o cerere. Această funcție are doi parametri: request (conține datele cererii) și response (gestionează trimiterea răspunsului).

În funcția-handler, folosind proprietatea request.url putem obține calea resursei către care a fost trimisă cererea. Trebuie să procesăm cererile către paginile "index.html" și "home.html" (și, în perspectivă, către orice alte pagini HTML). Calea începe întotdeauna cu slash-ul "/". De exemplu, o cerere către pagina "home.html" va reprezenta calea "/home.html". Respectiv, pentru a obține din calea solicitată calea către fișierele de pe hard disk, trebuie să înlăturăm slash-ul inițial:

let filePath = request.url.substring(1);

Totuși, dacă cererea este adresată rădăcinii site-ului, atunci calea constă doar dintr-un slash - "/". Respectiv, dacă eliminăm acest slash, vom obține un șir gol. Prin urmare, dacă cererea este adresată rădăcinii aplicației web, atunci vom considera că cererea este adresată paginii principale - index.html:

if(!filePath) filePath = "index.html";

Și, deoarece în cazul nostru răspunsul serverului va reprezenta codul HTML, atunci cu ajutorul metodei setHeader() stabilim pentru antetul "Content-Type" valoarea "text/html":

response.setHeader("Content-Type", "text/html; charset=utf-8;");

Adică răspunsul serverului va reprezenta HTML.

Apoi, cu ajutorul funcției fs.readFile citim fișierul către care este adresată cererea. Primul parametru al funcției - adresa fișierului (în acest caz se presupune că fișierul se află în același folder cu fișierul serverului server.js). Al doilea parametru - o funcție care este apelată după citirea fișierului și primește conținutul său prin al doilea său parametru data. Este foarte posibil ca fișierul solicitat să nu fie prezent, și în acest caz trimitem eroarea 404:

fs.readFile(filePath, (error, data)=>{
   if(error){                              // dacă este o eroare
       response.statusCode = 404;
       response.end("<h1>Resursa nu a fost găsită!</h1>");
   }

Dacă nu există erori, fișierul a fost găsit și citit cu succes, atunci trimitem parametrul data, care conține datele fișierului:

else{
   response.end(data);
}

La final, cu ajutorul funcției listen() lansăm serverul web pe portul 3000. Adică serverul va fi lansat la adresa http://localhost:3000/

Definirea codului HTML pentru încărcare

Fișierul home.html va conține un cod simplu, care va fi încărcat de pagina web. Să presupunem că este următorul cod:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>Pagina de Acasă</title>
</head>
<body>
   <h1>Pagina de Acasă</h1>
   <p>Textul Paginii de Acasă</p>
</body>
</html>

Definirea paginii principale și încărcarea datelor

Acum să definim codul paginii principale index.html, care va încărca pagina home.html:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>FDC.COM</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest();
xhr.onload = () => {                        // handler pentru primirea răspunsului serverului
   if (xhr.status == 200) {                // dacă codul răspunsului este 200
       const html = xhr.responseText;      // obținem răspunsul
       console.log(html);      // afișăm răspunsul obținut în consola browserului
   } else {                                // altfel afișăm textul stării
       console.log("Răspunsul serverului: ", xhr.statusText);
   }
};
xhr.open("GET", "/home.html");                  // solicitare GET către resursa /home.html
xhr.setRequestHeader("Accept", "text/html");    // acceptăm doar html
xhr.send();     // executăm solicitarea
</script>
</body>
</html>

În handler-ul de încărcare xhr.onload obținem textul răspunsului prin xhr.responseText și afișăm răspunsul în consolă.

Acum, în consolă, ne vom deplasa la folderul serverului folosind comanda cd și vom lansa serverul folosind comanda node server.js

După lansarea serverului, putem accesa în browser adresa http://localhost:3000, ne va fi afișată pagina, în codul JavaScript al căreia va avea loc apelul către pagina "home.html". Codul JavaScript va obține această pagină și va afișa conținutul său în consolă:

Gestionarea conținutului HTML

În exemplul de mai sus, am obținut conținutul paginii ca text obișnuit. Cu toate acestea, având în vedere că acest text conține de fapt marcaj HTML, îl putem încărca pe pagina web. Astfel, să modificăm codul paginii index.html în următorul mod:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>FDC.COM</title>
</head>
<body>
<div id="content"></div>
<script>
const contentDiv = document.getElementById("content");  // element pentru încărcarea html
const xhr = new XMLHttpRequest();

xhr.onload = () => {
   if (xhr.status == 200) {
       contentDiv.innerHTML = xhr.responseText;  // afișăm răspunsul obținut în contentDiv
   } else {                                // altfel afișăm textul stării
       console.log("Răspunsul serverului: ", xhr.statusText);
   }
};
xhr.open("GET", "/home.html");                  // solicitare GET către resursa /home.html
xhr.setRequestHeader("Accept", "text/html");    // acceptăm doar html
xhr.send();     // executăm solicitarea
</script>
</body>
</html>

În acest caz, încărcăm codul obținut al paginii "home.html" în elementul cu id=content

Cu toate acestea, problema în acest caz constă în faptul că codul paginii "home.html" pe lângă conținutul propriu-zis conține și elemente head, title, descrieri ale paginii prin intermediul tag-urilor <meta>. Aceste elemente nu au sens să fie încărcate pe o altă pagină web.

Sau poate dorim să încărcăm un anumit element de pe pagina "home.html", nu întregul său cod. În acest caz, putem obține răspunsul prin proprietatea responseXML și apoi să manipulăm răspunsul ca un document HTML standard. De exemplu, să modificăm codul JavaScript în următorul mod:

const contentDiv = document.getElementById("content");

const xhr = new XMLHttpRequest();
xhr.onload = () => {                        // handler pentru primirea răspunsului serverului
   if (xhr.status == 200) {
       // încărcăm doar conținutul elementului body
       contentDiv.innerHTML = xhr.responseXML.body.innerHTML;
   } else {                                
       console.log("Răspunsul serverului: ", xhr.statusText);
   }
};
xhr.open("GET", "/home.html");                  // solicitare GET către resursa /home.html
xhr.responseType = "document";              // stabilim tipul de răspuns
xhr.setRequestHeader("Accept", "text/html");    // acceptăm doar html
xhr.send();     // executăm solicitarea

Aici trebuie să remarcăm două momente. În primul rând, stabilim pentru răspuns tipul "document":

xhr.responseType = "document";

Acest lucru ne va permite să obținem răspunsul ca un obiect de tip Document, similar cu ceea ce reprezintă proprietatea document pe o pagină web.

Pentru a obține răspunsul sub formă de html/xml utilizăm proprietatea responseXML. Și apoi, deoarece această proprietate reprezintă un obiect Document, utilizăm proprietatea body pentru a accesa conținutul direct al paginii:

contentDiv.innerHTML = xhr.responseXML.body.innerHTML;

Ca rezultat, în contentDiv va fi încărcat conținutul elementului body al paginii "home.html".

În mod similar, putem accesa alte proprietăți ale obiectului Document. De exemplu, putem obține titlul:

document.title = xhr.responseXML.title;

Sau încărcăm pe pagină doar textul din titlul <h1>:

contentDiv.innerHTML =  xhr.responseXML.querySelector("h1").textContent;

Încărcarea dinamică a componentelor

Posibilitatea de a încărca codul HTML și de a-l insera pe o pagină ne permite să mergem mai departe și să împărțim funcționalitatea aplicației în mai multe componente și, dacă este necesar, să le încărcăm. De exemplu, să presupunem că în proiect avem următoarele fișiere:

  • server.js: fișierul aplicației server pe Node.js
  • index.html: pagina principală a aplicației
  • home.html: fișierul componentei home
  • about.html: fișierul componentei about
  • contact.html: fișierul componentei contact

Fișierul aplicației server pe Node.js - server.js rămâne același ca cel definit mai sus în acest articol.

Să presupunem că fișierul home.html conține un cod simplu de genul următor:

<h1>Pagina de Acasă</h1>
<p>Textul Paginii de Acasă</p>

Fișierul about.html să arate în mod similar:

<h1>Pagina Despre Noi</h1>
<p>Textul Paginii Despre Noi</p>

Și codul fișierului contact.html:

<h1>Pagina de Contact</h1>
<p>Textul Paginii de Contact</p>

Aceste fișiere reprezintă componente, care vor fi încărcate pe pagina principală.

Pe pagina principală index.html, să definim următorul cod:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>FDC.COM</title>
</head>
<body>
<nav><a href="home">Acasă</a> | <a href="about">Despre Noi</a> | <a href="contact">Contact</a></nav>
<div id="content"></div>
<script>
const contentDiv = document.getElementById("content");

function loadContent(fileName){
   const xhr = new XMLHttpRequest();
   xhr.onload = () => {
       if (xhr.status == 200) {
           contentDiv.innerHTML = xhr.responseText; // xhr.responseXML.body.innerHTML;
           document.title = fileName;
       }
   };
   xhr.open("GET", fileName + ".html");              // solicitare GET după adresa linkului
   xhr.setRequestHeader("Accept", "text/html");    // acceptăm doar html
   xhr.send();     // executăm solicitarea
}

// stabilim handler-ul pentru apăsarea butoanelor
const links = document.getElementsByTagName("a");
for (let i = 0; i < links.length; i++) {
   links[i].addEventListener("click", (e)=>{
       loadContent(links[i].getAttribute("href"));
       e.preventDefault();
   });  
}
// implicit încărcăm componenta home
loadContent("home");
</script>
</body>
</html>

Aici, pentru navigația între componente, pe pagină plasăm o serie de linkuri:

<nav><a href="home">Acasă</a> | <a href="about">Despre Noi</a> | <a href="contact">Contact</a></nav>

Adresa fiecărui astfel de link corespunde numelui paginii componentei corespunzătoare fără extensia ".html".

Fiecare dintre componentele va fi încărcată pe pagină în elementul cu id="content", pe care îl obținem în codul JavaScript în constanta contentDiv:

const contentDiv = document.getElementById("content");

De asemenea, în codul JavaScript, pentru fiecare link stabilim handleri, în care apelăm funcția loadContent și în care transmitem valoarea atributului href al linkului - adică adresa componentei

const links = document.getElementsByTagName("a");
for (let i = 0; i < links.length; i++) {
   links[i].addEventListener("click", (e)=>{
       loadContent(links[i].getAttribute("href"));
       e.preventDefault();
   });  
}

În funcția loadContent utilizăm adresa linkului pentru a trimite o solicitare ajax, iar răspunsul (HTML-ul obținut) îl încărcăm în elementul contentDiv.

contentDiv.innerHTML = xhr.responseText; // xhr.responseXML.body.innerHTML;

La încărcarea paginii, încărcăm imediat codul componentei home, ca componentă implicită:

loadContent("home");

Astfel, pe pagina principală vom putea accesa componente specifice, navigând prin linkuri.

← Lecția anterioară Lecția următoare →