Come codificare una divertente lista delle cose da fare con PHP e AJAX

Per il tutorial Tuts + Premium di questa settimana, lavoreremo con molte tecnologie diverse. In definitiva, creeremo un elenco di cose da fare che consentirà a te o al tuo utente di creare, aggiornare ed eliminare elementi in modo asincrono. Per svolgere il nostro compito, utilizzeremo le funzionalità AJAX di PHP e jQuery. Penso che scoprirai che non è così difficile come inizialmente potresti pensare. Ti mostrerò esattamente come!

Questo tutorial include uno screencast disponibile per i membri Tuts + Premium.



Passaggio 1: creazione di un nuovo database

Come puoi immaginare, non possiamo salvare, eliminare e aggiornare i record in un ambiente statico. Quindi, dobbiamo creare un database MySql che archivierà le informazioni.

Se utilizzi PHPMyAdmin, accedi al pannello di controllo visitando http: // localhost / phpmyadmin.


All'interno della casella di testo "Crea nuovo database", digita "db" e fai clic su "Crea". Successivamente, dovrai creare un tavolo. Digita "todo" e "3" per "numero di campi".


Creare le nostre colonne

Ora dovremo aggiungere le colonne appropriate.

  • id : id univoco per identificare ogni riga.
  • titolo : Il titolo del nostro articolo.
  • descrizione : Una descrizione che descrive cosa dobbiamo fare!

Assicurati che le opzioni di ogni campo corrispondano a quelle mostrate nell'immagine seguente.


Inserisci righe di prova

Ora che abbiamo creato il nostro database, aggiungiamo rapidamente alcune righe di test. Clicca sul tuo database "db"; quindi scegli "Sfoglia". Verrai indirizzato a una schermata che elenca i contenuti di ogni riga del tuo database. Ovviamente, questa sezione è vuota adesso. Scegli "Inserisci" e aggiungi alcune colonne. Scrivi quello che desideri qui.




Screencast completo



Passaggio 2: la classe Db


Sebbene non sia richiesto in alcun modo, trovo che sia più facile gestire le mie funzioni quando li raggruppo in una classe. Considerando questo, creeremo ora una classe "Db" che conterrà diverse funzioni.

  • __costruire : Questa funzione viene eseguita automaticamente non appena viene creata un'istanza dell'oggetto.
  • delete_by_id () : Elimina la riga necessaria passando l'ID univoco della riga.
  • update_by_id () : Aggiorna la riga passando il suo ID univoco.

Apri il tuo editor di codice preferito e crea un nuovo file chiamato "db.php". All'interno di questo documento vuoto, incolla le seguenti righe di codice.

 class Db private $ mysql; function __construct () $ this-> mysql = new mysqli ('localhost', 'root', 'yourPassword', 'db') o die ('problema');  // end class

Per creare una nuova classe, utilizziamo la sintassi illustrata di seguito.

 class 'myClass' 

Usando solo il codice sopra, abbiamo creato con successo una nuova classe. Non fa ancora niente, ma è comunque una classe!

__costruire()

Il metodo __construct () (talk di classe per "funzione") è noto come "metodo magico". Verrà eseguito immediatamente dopo l'istanza di una classe. Useremo questo metodo per rendere la nostra connessione iniziale al database MySql.

 function __construct () $ this-> mysql = new mysqli ('localhost', 'root', 'yourPassword', 'db') o die ('problema'); 

Se non hai familiarità con OOP, all'inizio potrebbe essere un po 'scoraggiante. Fortunatamente, non è troppo difficile da capire. Vogliamo che la nostra connessione mysql sia disponibile per tutti i metodi della nostra classe. Considerando questo, non sarebbe una buona idea memorizzare la variabile $ mysql all'interno di una funzione specifica. Invece, dovrebbe essere una proprietà di classe.

 $ mysql privato;

Accesso alle proprietà dai metodi

All'interno di un metodo, non possiamo semplicemente accedere alla nostra proprietà digitando "$ mysql". Dobbiamo prima fare riferimento all'oggetto.

 $ This-> mysql

Assicurati di prendere nota del fatto che, quando si accede a una proprietà, possiamo lasciare il segno del dollaro.

mySQLi


È preferibile utilizzare mysql improved (mysqli) piuttosto che il metodo tradizionale mysql_connect quando ci si connette a un database. Non solo è più veloce, ma ci consente anche di utilizzare un approccio OOP.

Quando creiamo una nuova istanza della classe mysqli, dobbiamo passare in quattro parametri.

  • ospite : "localhost"
  • nome utente : radice
  • parola d'ordine : 'la tua password'
  • nome del database : db

Questo dovrebbe farlo per ora. Torneremo alla nostra classe nel corso di questo tutorial per aggiungere nuovi metodi. Ricorda, quando creiamo una nuova istanza di questa classe ...

 richiede 'db.php'; $ db = new Db ();

... apriamo automaticamente una connessione al nostro database, grazie al metodo magico __construct ().

Il markup


Ora, abbiamo bisogno di creare il nostro markup per la home page. Aggiungi una nuova pagina alla tua soluzione e salvala come "index.php". Successivamente, incolla quanto segue.

      La mia lista delle cose da fare     

La mia lista delle cose da fare

  • Fare
...
...

Analisi

All'interno della testa del nostro documento, sto facendo riferimento al CDN di Google per accedere a jQuery. Questo è facilmente il metodo preferito quando si usa jQuery. Successivamente, faccio riferimento a un file "scripts.js" che verrà creato in seguito in questo tutorial.

Rivediamo rapidamente a cosa serve ciascuna div.

  • contenitore : Avvolgimento standard div.
  • ul # schede : La nostra navigazione Useremo Javascript per aggiungere le schede aggiuntive. Spiegherò perché a breve.
  • principale : Avvolgere per il contenuto principale.
  • fare : Scheda 1.
  • addNewEntry : Scheda 2

Passaggio 4: CSS


Questo non è un tutorial CSS, di per sé. Sei libero di rivedere il foglio di stile che ho usato. È nel pacchetto di download. Se desideri una recensione più approfondita, guarda lo screencast.


Passaggio 5: recupero dei record

Ora che ci siamo collegati al database e abbiamo creato il nostro markup / CSS, scriviamo un codice che recupererà le righe del database.

All'interno del div "todo", inserisci quanto segue.

 
mysql> query ($ query); if ($ results-> num_rows) while ($ row = $ results-> fetch_object ()) $ title = $ row-> title; $ description = $ row-> description; $ id = $ row-> id; eco '
'; $ data = << $ Titolo

$ descrizione

D E
EOD; echo $ data; eco '
'; // end while else echo "

Ci sono zero articoli Aggiungi uno ora!

";?>

Analisi

  • Usa 'require' per accedere alla nostra classe Db.
  • Crea una nuova istanza della classe Db.
  • Crea una query. Ciò recupererà tutti i record dalla tabella "todo" e li ordinerà in ordine crescente.
  • Ora dobbiamo eseguire la nostra query. $ Db-> mysql> query ($ query). $ db fa riferimento all'oggetto. $ mysql si riferisce alla classe mysqli. $ query è un metodo della classe mysqli che ci consente di passare una query. Qui, stiamo passando la stringa che abbiamo appena creato.
  • $ results-> num_rows restituirà il numero totale di righe recuperate dal database. Se uno o più vengono restituiti, utilizzeremo un'istruzione while per eseguire il ciclo delle righe.
  • Crea una variabile temporanea chiamata $ row che farà riferimento alle informazioni, per ogni iterazione. Creiamo quindi tre variabili che si riferiscono alle rispettive controparti all'interno del database.
  • Ogni oggetto sarà avvolto in un div con una classe di "item".
  • Successivamente, usiamo heredocs per formattare il nostro elemento delle cose da fare. Heredocs consente un modo facile e organizzato per mixare html e php. Per saperne di più, assicurati di recensire questo screencast.
  • Avvolgi il titolo all'interno di tag h4; la descrizione all'interno di tag p.
  • L'utente ha bisogno di un modo per modificare ed eliminare ogni elemento. Pertanto, abbiamo creato due tag di ancoraggio che ci consentiranno di farlo. Torneremo su questo più tardi.
  • Esamina le informazioni su heredocs e chiudi il div ".item".
  • Se dal database sono state restituite zero righe, echo "Ci sono zero elementi. Aggiungi uno ora!".

Speriamo che tutto ciò avesse senso. A questo punto, dovresti avere qualcosa di simile al seguente:


Passaggio 6: aggiungere un nuovo elemento


Vogliamo anche che l'utente abbia la possibilità di inserire nuovi record. Creiamo un modulo che consenta proprio questo.

 

Aggiungi nuova voce

Questa è la tua forma standard "run-of-the-mill". Abbiamo aggiunto input per un titolo e una descrizione. Quando si fa clic sul pulsante di invio, le informazioni inserite verranno pubblicate su "addItem.php". Creiamo quella pagina ora.


Passaggio 7: AddItem.php

Crea un nuovo documento e salvalo come "addItem.php". Incolla nel seguente codice:

 mysql-> prepare ($ query)) $ stmt-> bind_param ('ss', $ _POST ['title'], $ _POST ['description']); $ Stmt-> execute (); header ("location: index.php");  else die ($ db-> mysql-> error); 
  • Fare riferimento alla nostra classe di db.
  • Istanziare la classe.
  • Se il pulsante di invio con un nome "addEntry" esiste, quindi eseguire il seguente codice.
  • Crea una nuova query. Noterai che sto usando i punti interrogativi come valori. È il metodo preferito per utilizzare istruzioni preparate durante l'aggiornamento del nostro database. È un modo eccellente per proteggersi dall'iniezione sql.
  • Prepara la nostra variabile mysql passando la query che abbiamo appena creato.
  • Se è stato preparato con successo, associare i parametri appropriati. Il primo parametro richiede i tipi di dati per ciascun elemento. Ho usato "s" per riferirsi a "stringa". I secondi due parametri catturano i valori del titolo e della descrizione dall'array super globale POST.
  • Esegui la dichiarazione.
  • Infine, reindirizza l'utente alla pagina iniziale.

Passaggio 7: Aggiorna articoli


Usando le funzionalità AJAX di jQuery, permettiamo all'utente di aggiornare ogni elemento senza un postback. Crea un nuovo file all'interno di una cartella "js" e chiamalo "scripts.js". Ricorda, abbiamo già fatto riferimento a questo file nel nostro markup.

 $ (function () $ ('. editEntry'). click (function () var $ this = $ (this); var oldText = $ this.parent (). parent (). find ('p'). text (); var id = $ this.parent (). parent (). find ('# id'). val (); $ this.parent (). parent (). find ('p'). empty ( ).aggiungere(''); $ ('. newDescription'). blur (function () var newText = $ (this) .val (); $ .ajax (type: 'POST', url: 'updateEntry.php', dati: 'description = '+ newText +' & id = '+ id, success: function (results) $ this.parent (). parent (). find (' p '). empty (). append (newText);); ); restituisce falso; ); );

Se tornerai al nostro markup su index.php, vedrai:

 
D E

Decodifica di ogni linea

 $ ('. editEntry'). click (function () 

Usando jQuery, dobbiamo ascoltare quando viene fatto clic sul tag di ancoraggio con una classe di "editEntry".

 var $ this = $ (this);

Successivamente, stiamo memorizzando nella cache $ (this) - che si riferisce al tag anchor che è stato cliccato.

 var oldText = $ this.parent (). parent (). find ('p'). text ();

Abbiamo bisogno di memorizzare la descrizione originale. Diciamo al tag di ancoraggio per trovare il div genitore e cerchiamo il tag p - che contiene il testo della descrizione. Prendiamo quel valore usando "text ()".

 var id = $ this.parent (). parent (). find ('# id'). val ();

Per aggiornare la riga corretta nel nostro database, ho bisogno di sapere qual è l'id della riga specifica. Se fai riferimento al tuo codice, vedrai un campo di input nascosto che contiene questo valore.

 

Ancora una volta, usiamo "trova" per accedere a questo input nascosto, e quindi prendiamo il suo valore.

 $ This.parent (). Parent (). Find ( 'p'). Empty (). Append ('');

Ora, dobbiamo consentire all'utente di inserire una nuova descrizione. Ecco perché hanno cliccato su "Modifica voce", non è vero? Troviamo la descrizione della tag P, la svuotiamo e quindi aggiungiamo una textarea. Usiamo "empty ()" per assicurarci di eliminare tutto il testo; non è più necessario Il valore di questa textarea sarà uguale al vecchio testo - per comodità.


 $ ('. newDescription'). blur (function () 

Trova questa nuova textarea e quando l'utente lascia la casella di testo, esegui una funzione.

 var newText = $ (this) .val ();

Cattura il nuovo testo che gli utenti inseriscono in questa textarea.

 $ .ajax (tipo: 'POST', url: 'updateEntry.php', dati: 'description =' + newText + '& id =' + id, success: function (results) $ this.parent (). parent () .find ('p'). empty (). append (newText););

Chiama la funzione .ajax e passa alcuni parametri. Il tipo sarà "POST". L'URL di accesso è "updateEntry.php". I dati da passare a questa pagina sono il nuovo testo che l'utente ha inserito e l'ID univoco da quella riga nel database. Quando l'aggiornamento viene eseguito correttamente, eseguire una funzione e aggiornare il vecchio testo con il nuovo testo!

 restituisce falso;

Restituisci false per assicurarti che il clic sul tag di ancoraggio non indirizzi l'utente altrove.


Passaggio 7b: PHP

Ricorda, abbiamo chiamato la nostra pagina PHP 'updateEntry' con jQuery, ma in realtà non l'abbiamo creata! Facciamolo ora. Crea una nuova pagina chiamata "updateEntry.php" e incolla quanto segue.

 update_by_id ($ _ POST ['id'], $ _POST ['description']); ?>

Come prima, stiamo facendo riferimento alla nostra classe db, e quindi la istanziamo. Successivamente, stiamo creando una nuova variabile, chiamata $ response, e la stiamo rendendo uguale a tutto ciò che viene restituito dal metodo "update_by_id ()". Non abbiamo ancora creato questo metodo. Ora è un buon momento per farlo.

Aggiungere un nuovo metodo alla nostra classe

Torna alla tua pagina db.php e aggiungi un nuovo metodo in basso.

 function update_by_id ($ id, $ description) $ query = "UPDATE todo SET description =? WHERE id =? LIMIT 1"; if ($ stmt = $ this-> mysql-> prepare ($ query)) $ stmt-> bind_param ('si', $ description, $ id); $ Stmt-> execute (); ritorna 'buon lavoro! Aggiornato '; 

Questo metodo accetta due parametri: l'id e la descrizione dell'elemento. Quindi, quando chiamiamo questo metodo, dobbiamo ricordare di passare questi due parametri! Iniziamo creando la nostra query: aggiorna la tabella "todo" e cambia la descrizione in qualunque cosa venga passata, ma aggiorna solo la riga in cui l'id è uguale al parametro passato in.

Come l'ultima volta, utilizzeremo le istruzioni preparate per aggiornare il nostro database. È il modo più sicuro! Prepara la nostra query, associa i parametri (stringa e intero o 'si') ed esegui. Stiamo restituendo una stringa generica, ma in realtà non è richiesta affatto. Ora il nostro aggiornamento dovrebbe funzionare perfettamente!


Passaggio 8: Elimina elementi


Creiamo anche un bel modo asincrono per l'utente di cancellare le voci. Quando fanno clic sul pulsante Elimina per un elemento, dissolviamo il div out e aggiorniamo il database per riflettere la cancellazione. Apri il tuo file javascript e aggiungi quanto segue:

 // Elimina il tag di ancoraggio cliccato $ ('a.deleteEntryAnchor'). Click (function () var thisparam = $ (this); thisparam.parent (). Parent (). Find ('p'). Text ('Please Attendi ... '); $ .ajax (tipo:' GET ', url: thisparam.attr (' href '), success: function (results) thisparam.parent (). Parent (). FadeOut (' slow ') ;) return false;);

decodifica

 $ ('a.deleteEntryAnchor'). click (function () 

Quando si fa clic sul tag di ancoraggio con una classe di "deleteEntryAnchor", eseguire una funzione.

 var thisparam = $ (questo);

Cache $ (this) come thisparam.

 thisparam.parent (). parent (). find ('p'). text ('Please Wait ...');

Cambia il testo della descrizione in "Please Wait". Dobbiamo fare questo per dare all'utente un feedback, nel caso in cui ci vuole più tempo del previsto.

 $ .ajax (tipo: 'GET', url: thisparam.attr ('href'), success: function (results) thisparam.parent (). parent (). fadeOut ('slow');)

Proprio come l'ultima volta, passiamo in alcuni parametri che accedono a "delete.php". Invece di codificare la pagina nel valore dell'URL, sto accedendo a attr ('href') - che equivale a 'delete.php? Id = $ id'.

 D

Non abbiamo bisogno di un parametro "DATA", perché tutte le informazioni appropriate sono all'interno della query quer dell'URL. Una volta che la cancellazione è stata eseguita con successo, troviamo il genitore ".item" div e lo svaniscono lentamente.

delete.php

Abbiamo chiamato la nostra pagina di eliminazione con jQuery, ma non abbiamo ancora creato il PHP. Crea la tua nuova pagina e aggiungi il seguente codice.

 delete_by_id ($ _ GET [ 'id']); header ("Location: index.php");

Dovresti essere abituato a queste procedure ormai. Crea una nuova istanza della nostra classe e chiama il metodo "delete_by_id". Una volta completato correttamente, reindirizza l'utente a "index.php". Come avrai intuito, dobbiamo creare un nuovo metodo all'interno della nostra classe db. Torna a db.php e aggiungi la tua nuova funzione.

Metodo Delete_by_id ()

 function delete_by_id ($ id) $ query = "DELETE da todo WHERE id = $ id"; $ result = $ this-> mysql-> query ($ query) o die ("c'era un problema, man."); se ($ result) restituisce 'yay!'; 

Questo metodo accetterà un parametro - l'id. Ricorda: per aggiornare una riga, DEVE conoscere l'ID univoco della riga. Altrimenti, aggiornerà ogni riga. Stiamo eliminando tutte le righe dalla tabella, dove l'ID è uguale a ciò che viene passato. Poiché ogni riga ha il proprio ID univoco, ne verrà influenzato solo uno. Successivamente, passiamo questa query al nostro oggetto mysql. Ancora una volta, il ritorno non è necessario; è solo per divertimento.


Passaggio 9: jQuery aggiuntivo

Abbiamo terminato tutto il nostro lavoro in PHP! Il passo finale è aggiungere un po 'di jQuery per far funzionare tutto un po' meglio. Nella parte superiore del file Javascript, subito dopo il metodo document.ready, aggiungi il seguente codice:

 // Non visualizzare la scheda addNewEntry quando viene caricata la pagina. $ ('# addNewEntry'). css ('display', 'none'); // Usiamo jQuery per creare le nostre schede. Se Javascript è disabilitato, non funzionerà. Considerando // questo, dovremmo aggiungere le nostre schede, in modo che non vengano mostrate se disabilitate. $ ( '#') Schede. Accodare ('
  • Nuovo oggetto
  • '); // Nascondi la descrizione di ogni elemento attività. Visualizza solo il tag h4 per ognuno. $ ( 'Div.item') i bambini () non ( 'h4') nascondere ()...; // L'intero elemento div è cliccabile. Per fornire quel feedback, stiamo cambiando il cursore del mouse. // Quando si fa clic su questo div, si passa dalla visualizzazione visibile a quella nascosta ogni volta che si fa clic su di esso. // Tuttavia, quando l'utente fa clic sul pulsante "aggiorna", il div si chiude quando fa clic all'interno dell'area di testo // per modificare la loro descrizione. Questo codice rileva se l'obiettivo del clic era la textarea. Se lo fosse, // non facciamo niente. $ ('div.item'). css ('cursor', 'pointer'). click (function (e) if (! $ (e.target) .is ('textarea')) $ (this). children (). not ('h4'). slideToggle (); $ (this) .children ('h4'). toggleClass ('expandDown'););

    Ho commentato ogni passo abbastanza bene. Quindi, mi asterrò dal ripetermi. Il tuo file script.js finale dovrebbe assomigliare a questo.

     $ (function () // Non mostra la scheda addNewEntry quando viene caricata la pagina. $ ('# addNewEntry'). css ('display', 'none'); // Usiamo jQuery per creare le nostre schede Se Javascript è disabilitato, non funzionerà. Considerando // questo, dovremmo aggiungere le nostre schede, in modo che non vengano mostrate se disabilitate. $ ('# Tabs'). Append ('
  • Nuovo oggetto
  • '); // Nascondi la descrizione di ogni elemento attività. Visualizza solo il tag h4 per ognuno. $ ( 'Div.item') i bambini () non ( 'h4') nascondere ()...; // L'intero elemento div è cliccabile. Per fornire quel feedback, stiamo cambiando il cursore del mouse. // Quando si fa clic su questo div, si passa dalla visualizzazione visibile a quella nascosta ogni volta che si fa clic su di esso. // Tuttavia, quando l'utente fa clic sul pulsante "aggiorna", il div si chiude quando fa clic all'interno dell'area di testo // per modificare la loro descrizione. Questo codice rileva se l'obiettivo del clic era la textarea. Se lo fosse, // non facciamo niente. $ ('div.item'). css ('cursor', 'pointer'). click (function (e) if (! $ (e.target) .is ('textarea')) $ (this). children (). not ('h4'). slideToggle (); $ (this) .children ('h4'). toggleClass ('expandDown');); // aggiungi una nuova scheda oggetto fai clic su $ ('# tabs li'). click (function () $ ('# tabs li'). removeClass ('selected'); $ (this) .addClass ('selected'); if ($ (this) .attr ('id') == 'newitem_tab') $ ('# todo'). css ('display', 'none'); $ ('# addNewEntry'). css (' display ',' block '); else $ (' # addNewEntry '). css (' display ',' none '); $ (' # todo '). css (' display ',' block '); return false;); $ ('# todo div: first'). children ('h4'). addClass ('expandDown'). end (). children (). show (); // Elimina il tag di ancoraggio cliccato $ ('a.deleteEntryAnchor'). Click (function () var thisparam = $ (this); thisparam.parent (). Parent (). Find ('p'). Text ('Please Attendi ... '); $ .ajax (tipo:' GET ', url: thisparam.attr (' href '), success: function (results) thisparam.parent (). Parent (). FadeOut (' slow ') ;) return false;); // Modifica un oggetto in modo asincrono $ ('. EditEntry'). Click (function () var $ this = $ (this); var oldText = $ this.parent (). Parent (). Find ('p'). text (); var id = $ this.parent (). parent (). find ('# id'). val (); console.log ('id:' + id); $ this.parent (). parent () .find ( 'p'). vuoto (). append (''); $ ('. newDescription'). blur (function () var newText = $ (this) .val (); $ .ajax (type: 'POST', url: 'updateEntry.php', dati: 'description = '+ newText +' & id = '+ id, success: function (results) $ this.parent (). parent (). find (' p '). empty (). append (newText);); ); restituisce falso; ); );

    Passaggio 10: aspetta! il layout è strano in IE6.

    Non possiamo ancora chiamarlo un giorno! Quel divertente Internet Explorer 6 sta causando alcuni problemi di layout.


    1. I png di sfondo sono 24 bit. IE6 non supporta nativamente questo. Dovremo importare uno script per risolverlo.
    2. Le schede di navigazione non vengono visualizzate nel punto giusto.
    3. Ogni div.item non viene visualizzato correttamente quando espanso.
    4. I nostri pulsanti modifica ed elimina sono troppo lontani a destra del nostro div.

    La soluzione

    Anche se ci piacerebbe, non possiamo ancora ignorare questo browser. Fortunatamente, scoprirai che la maggior parte dei problemi di IE6 può essere risolta abbastanza facilmente. Per prima cosa, dobbiamo importare uno script che risolverà il nostro problema di trasparenza alfa. Dean Martin ha un fantastico file Javascript che porta IE6 agli standard. Semplicemente aggiungendo "-trans" alla fine dei nostri nomi di file png a 24 bit, possiamo risolvere il nostro problema. Assicurati di visitare la cartella delle immagini e modificare i nomi.

     

    Il CDN di Google viene nuovamente in soccorso fornendo una versione ospitata dello script IE7. Questo risolve il nostro problema di trasparenza, ma abbiamo ancora qualche stranezza.


    Si noti che, nella nostra istruzione condizionale, abbiamo anche importato un file "ie.css". Crea subito quel file e incolla quanto segue:

     body margin: 0; padding: 0;  #tabs height: 100%;  #main height: 100%;  #main div.item width: 100%; overflow: nascosto; posizione: relativa; 

    Scoprirai che l'aggiunta di "position: relative", "overflow: hidden" e "height: 100%" risolverà il 90% dei problemi di IE6. Ora, il nostro layout funziona perfettamente su tutti i browser!


    Hai finito!


    C'era MOLTO da coprire qui. Spero di essermi spiegato abbastanza bene. In caso contrario, è a questo che serve lo screencast associato! Assicurati di rivederlo per cancellare eventuali aree sfocate. Se hai ancora domande, chiedimi pure! Grazie mille per la lettura.