Så här kodar du en rolig lista med PHP och AJAX

För den här veckans Tuts + Premium handledning arbetar vi med många olika tekniker. I slutändan kommer vi att bygga en att göra-lista som gör det möjligt för dig eller din användare att skapa, uppdatera och radera objekt asynkront. För att uppnå vår uppgift använder vi PHP och jQuery's AJAX-funktioner. Jag tror att du kommer att upptäcka att det inte är så svårt som du kanske tänker. Jag ska visa dig exakt hur!

Denna handledning innehåller en skärmdump som är tillgänglig för Tuts + Premium-medlemmar.



Steg 1: Skapa en ny databas

Som du kan föreställa dig, kan vi inte spara, radera och uppdatera poster i en statisk miljö. Så måste vi skapa en MySql-databas som lagrar informationen.

Om du använder PHPMyAdmin, gå till kontrollpanelen genom att besöka http: // localhost / phpmyadmin.


I textrutan "Skapa ny databas" skriver du "db" och klickar på "Skapa". Därefter måste du skapa ett bord. Skriv "todo" och "3" för "antal fält".


Skapa våra kolumner

Vi måste nu lägga till lämpliga kolumner.

  • id : unikt id för att indrätta varje rad.
  • titel : Titeln på vårt objekt.
  • beskrivning : En beskrivning som beskriver vad vi behöver göra!

Se till att alternativen för varje fält matchar de som visas i följande bild.


Sätt in testrader

Nu när vi har skapat vår databas, låt oss snabbt lägga till några testrader. Klicka på din "db" databas; välj sedan "Bläddra". Du kommer till en skärm som visar innehållet i varje rad i din databas. Självklart är detta avsnitt tomt just nu. Välj "Infoga" och lägg till några kolumner. Skriv vad du än önskar här.




Full Screencast



Steg 2: Db-klassen


Även om det inte krävs något, finner jag att det är lättast att hantera mina funktioner när de grupperas i en klass. Med tanke på detta skapar vi nu en "Db" -klass som innehåller flera funktioner.

  • __konstruera : Den här funktionen körs automatiskt så snart objektet är instantierat.
  • delete_by_id () : Tar bort den nödvändiga raden genom att passera i radens unika id.
  • update_by_id () : Uppdaterar raden genom att passera i dess unika id.

Öppna din kodredigerare och välj en ny fil som heter "db.php". Inom det här tomma dokumentet klistra in i följande rader med kod.

 klass Db privat $ mysql; funktion __construct () $ this-> mysql = ny mysqli ('localhost', 'root', 'yourPassword', 'db') eller dö ('problem');  // slutklass

För att skapa en ny klass använder vi syntaxen som visas nedan.

 klass "myClass" 

Med hjälp av koden ovan har vi lyckats skapa en ny klass. Det gör inget just nu, men det är en klass ändå!

__konstruera()

Metoden __construct () (klasstal för "funktion") är känd som en "magisk metod". Det kommer att köras omedelbart efter det att en klass är instanserad. Vi ska använda den här metoden för att göra vår första anslutning till MySQL-databasen.

 funktion __construct () $ this-> mysql = ny mysqli ('localhost', 'root', 'yourPassword', 'db') eller dö ('problem'); 

Om du inte är bekant med OOP kan det vara lite skrämmande först. Lyckligtvis är det inte för svårt att förstå. Vi vill att vår mysql-anslutning ska vara tillgänglig för alla metoder i vår klass. Med tanke på detta skulle det inte vara en bra idé att lagra variabeln $ mysql inom en viss funktion. I stället bör det vara en klassegenskap.

 privat $ mysql;

Åtkomst till egenskaper från metoder

Inom en metod kan vi inte bara komma åt vår egendom genom att skriva "$ mysql". Vi måste först referera till objektet.

 $ This-> mysql

Var noga med att notera det faktum att vi, när vi får tillgång till en fastighet, kan lämna av dollartecknet.

mysqli


Det är att föredra att använda mysql (mysqli) snarare än den traditionella mysql_connect-metoden när du ansluter till en databas. Det är inte bara det snabbare, men det tillåter oss också att använda ett OOP-tillvägagångssätt.

När vi skapar en ny instans av mysqli-klassen måste vi passera i fyra parametrar.

  • värd : 'lokal värd'
  • Användarnamn : root
  • Lösenord : 'ditt lösenord'
  • Databas namn : db

Det borde göra det för nu. Vi kommer tillbaka till vår klass under denna handledning för att lägga till nya metoder. Kom bara ihåg, när vi skapar en ny instans av den här klassen ...

 kräver "db.php"; $ db = ny Db ();

... vi öppnar automatiskt en anslutning till vår databas tack vare __construct () magiska metoden.

Markup


Nu måste vi skapa vår markering för hemsidan. Lägg till en ny sida i din lösning och spara den som "index.php". Därefter klistra in i följande.

      Min To-Do-lista     

Min till-gör-lista

  • Att göra
...
...

Analys

Inom huvudet på vårt dokument hänvisar jag till Googles CDN för att komma åt jQuery. Detta är enkelt den föredragna metoden när du använder jQuery. Därefter hänvisar jag till en "scripts.js" -fil som vi kommer att skapa senare i den här handledningen.

Låt oss snabbt granska vad varje div är för.

  • behållare : Standardförpackning div.
  • ul # flikar : Vår navigering. Vi använder Javascript för att lägga till de extra flikarna. Jag ska förklara varför snart.
  • huvud : Omslag för huvudinnehållet.
  • att göra : Flik 1.
  • addNewEntry : Flik 2

Steg 4: CSS


Detta är inte en CSS-handledning, i sig. Du kan granska det stilark som jag har använt. Det finns i nedladdningsbuntet. Om du vill ha en djupare recension, titta på skärmen.


Steg 5: Hämta poster

Nu när vi har anslutit till databasen och har skapat vår markup / CSS, låt oss skriva en kod som kommer att hämta databasraderna.

Inför "todo" div, lägg in följande.

 
mysql-> query ($ query); om ($ results-> num_rows) while ($ row = $ results-> fetch_object ()) $ title = $ row-> title; $ description = $ row-> description; $ id = $ row-> id; eko "
'; $ data = << $ Titel

$ Beskrivning

D E
EOD; echo $ data; eko "
'; // slutet medan annat echo "

Det finns inga objekt. Lägg till en nu!

";?>

Analys

  • Använd "kräva" för att komma åt vår Db-klass.
  • Skapa en ny instans av Db-klassen.
  • Skapa en fråga. Detta hämtar alla poster från tabellen "todo" och sorterar dem i en stigande ordning.
  • Vi måste nu utföra vår fråga. $ DB> mysql-> fråga ($ fråga). $ db refererar till objektet. $ mysql avser mysqli-klassen. $ query är en metod för mysqli-klassen som tillåter oss att passera i en fråga. Här passerar vi i strängen som vi just skapat.
  • $ results-> num_rows returnerar det totala antalet retrived rader från databasen. Om en eller flera returneras, använder vi en stund uttalande för att slinga genom raderna.
  • Skapa en temporär variabel som heter $ rad som hänvisar till informationen, för varje iteration. Vi skapar då tre variabler som hänvisar till sina respektive motsvarigheter i databasen.
  • Varje objekt kommer att förpackas inom en div med en klass av "objekt".
  • Därefter använder vi heredocs för att formatera vår åtgärdspost. Heredocs möjliggör ett enkelt och organiserat sätt att blanda html och php. För att lära dig mer, var noga med att granska den här skärmbilden.
  • Wrap titeln inom h4-taggar; beskrivningen inom p-taggar.
  • Användaren behöver ett sätt att redigera och ta bort varje objekt. Så, vi har skapat två ankare taggar som tillåter oss att göra det. Vi kommer tillbaka till det senare.
  • Echo ut vår heredocs info, och stäng ut ".item" div.
  • Om noll rader returnerades från databasen, echo "Det finns noll objekt. Lägg till en nu!".

Förhoppningsvis var allt det förnuftigt. Vid denna tidpunkt borde du ha något som följande:


Steg 6: Lägg till ett nytt objekt


Vi vill också att användaren ska kunna lägga in nya poster. Låt oss skapa ett formulär som tillåter denna sak.

 

Lägg till ny post

Det här är din standard "run-of-the-mill" -form. Vi har lagt till inmatningar för en titel och beskrivning. När inmatningsknappen klickas läggs informationen in till "addItem.php". Låt oss skapa den sidan nu.


Steg 7: AddItem.php

Skapa ett nytt dokument och spara det som "addItem.php". Klistra in följande kod:

 mysql-> förbereda ($ query)) $ stmt-> bind_param ('ss', $ _POST ['title'], $ _POST ['description']); $ Stmt-> execute (); header ("location: index.php");  annars dör ($ db-> mysql-> fel); 
  • Se vår db-klass.
  • Förklara klassen.
  • Om inmatningsknappen med ett namn "addEntry" existerar, kör sedan följande kod.
  • Skapa en ny fråga. Du märker att jag använder frågeställningar som värden. Det är den föredragna metoden att använda beredda uttalanden när vi uppdaterar vår databas. Det är ett utmärkt sätt att skydda dig mot sql-injektion.
  • Förbered vår mysql-variabel genom att passera i den fråga som vi just skapat.
  • Om det var klart förberedt, binda lämpliga parametrar. Den första parametern frågar efter datatyperna för varje objekt. Jag har använt "s" för att hänvisa till "sträng". De andra två parametrarna tar tag i titel- och beskrivningsvärdena från POST super global array.
  • Utför uttalandet.
  • Slutligen omdirigera användaren tillbaka till hemsidan.

Steg 7: Uppdatera objekt


Med hjälp av jQuerys AJAX-funktioner, låt oss tillåta användaren att uppdatera varje objekt utan en postback. Skapa en ny fil i en "js" -mapp och kalla den "scripts.js". Kom ihåg att vi redan har refererat till den här filen i vår markering.

 $ (funktion () $ ('. editEntry'). klicka (funktion () var $ this = $ (detta); var oldText = $ this.parent (). parent (). hitta ('p'). text (); var id = $ this.parent (). parent (). hitta ('# id') .val (); $ this.parent () .förälder (). hitta ('p'). ).bifoga(''); $ ('; newDescription'). Blur (funktion () var newText = $ (detta) .val (); $ .ajax (typ: 'POST', url: 'updateEntry.php', data: 'description = '+ newText +' & id = '+ id, framgång: funktion (resultat) $ this.parent (). parent (). find (' p '). empty () .append (newText);); ); returnera false; ); );

Om du återkommer till vår markering på index.php ser du:

 
D E

Avkodning av varje rad

 $ ('. EditEntry'). klicka (funktion () 

Med jQuery behöver vi lyssna på när ankerkoden med en klass av "editEntry" klickas.

 var $ this = $ (detta);

Därefter cachar vi $ (detta) - som refererar till ankarkoden som klickades.

 var oldText = $ this.parent () .förälder (). hitta ('p'). text ();

Vi måste lagra den ursprungliga beskrivningen. Vi berättar för ankaretiketten för att hitta parent div, och leta efter p-taggen - som innehåller beskrivningstexten. Vi tar tag i det värdet genom att använda "text ()".

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

För att uppdatera den rätta raden i vår databas, behöver jag veta vad den specifika radens ID är. Om du hänvisar till din kod kommer du att se ett dolt inmatningsfält som innehåller detta värde.

 

Återigen använder vi "hitta" för att komma åt den här dolda inmatningen, och sedan ta tag i dess värde.

 $ This.parent (). Förälder (). Hitta ( 'p'). Tom (). Bifoga ('');

Nu måste vi tillåta användaren att ange en ny beskrivning. Det är därför de klickade på "Edit Entry", är det inte !? Vi hittar beskrivningen P-tagg, töm den och lägg sedan till en textarea. Vi använder "tomt ()" för att se till att vi blir av med hela texten. det behövs inte längre. Värdet på denna textarea kommer att vara lika med oldText - som en bekvämlighet.


 $ ('.NewDeskription'). Blur (funktion () 

Hitta denna nya textarea, och när användaren lämnar textrutan kör en funktion.

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

Fånga den nya texten som användarna kommer in i denna textarea.

 $ .ajax (typ: 'POST', url: 'updateEntry.php', data: 'description =' + newText + '& id =' + id, framgång: funktion (resultat) $ this.parent () .find ('p'). empty (). append (newText););

Ring .ajax-funktionen och skicka i några parametrar. Typen kommer att vara "POST". Url till åtkomst är "updateEntry.php". Data som ska skickas till den här sidan är den nya text som användaren angav och det unika idet från den raden i databasen. När uppdateringen utförs framgångsrikt, kör en funktion och uppdatera den gamla texten med den nya texten!

 returnera false;

Återgå falskt för att säkerställa att klicka på ankaretiketten inte riktar användaren någon annanstans.


Steg 7b: PHP

Kom ihåg att vi har ringt vår "UpdateEntry" PHP-sida med jQuery, men vi har inte skapat det! Låt oss göra det nu. Skapa en ny sida som heter "updateEntry.php" och klistra in i följande.

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

Som tidigare refererar vi till vår db-klass, och sedan instanserar vi den. Därefter skapar vi en ny variabel, kallad $ svar, och gör det lika med det som returneras från metoden "update_by_id ()". Vi har ännu inte skapat den här metoden. Nu är det bra att göra det.

Lägga till en ny metod i vår klass

Återgå till din db.php-sida och lägg till en ny metod längst ner.

 funktion update_by_id ($ id, $ description) $ query = "UPDATE todo SET beskrivning =? Vart id =? LIMIT 1"; if ($ stmt = $ this-> mysql-> förbereda ($ query)) $ stmt-> bind_param ( 'si', $ beskrivningen, $ id); $ Stmt-> execute (); returnera "bra jobb! Uppdaterad "; 

Denna metod accepterar två parametrar: id och beskrivning av objektet. Så när vi kallar den här metoden måste vi komma ihåg att passera i de två parametrarna! Vi börjar med att skapa vår fråga: uppdatera tabellen "todo" och ändra beskrivningen till vad som passeras in - men uppdatera bara raden där id är lika med parametern som passerat i.

Precis som förra gången använder vi förberedda uttalanden för att uppdatera vår databas. Det är det säkraste sättet! Förbered vår fråga, bind parametrarna (sträng och heltal, eller 'si') och kör. Vi återkommer en generisk sträng, men det är verkligen inte nödvändigt alls. Nu ska vår uppdatering fungera perfekt!


Steg 8: Radera objekt


Låt oss också skapa ett fint asynkront sätt för användaren att radera poster. När de klickar på raderingsknappen för ett objekt kommer vi att blekna ut div-filen och uppdatera databasen för att återspegla raderingen. Öppna din javascript-fil och lägg till följande:

 // Ta bort ankare taggade $ ('a.deleteEntryAnchor'). Klicka (funktion () var thisparam = $ (detta); thisparam.parent (). Parent (). Find ('p') text Vänta ... '); $ .ajax (typ:' GET ', url: thisparam.attr (' href '), framgång: funktion (resultat) thisparam.parent ;) returnera false;);

avkodning

 $ ('a.deleteEntryAnchor'). klicka (funktion () 

När ankerkoden med en klass av "deleteEntryAnchor" klickas, kör en funktion.

 var thisparam = $ (detta);

Cache $ (detta) som thisparam.

 thisparam.parent (). parent (). find ('p') text ('Vänta vänta ...');

Ändra texten i beskrivningen till "Vänta Vänta". Vi måste göra detta för att ge användaren lite feedback, bara om det tar längre tid än väntat.

 $ .ajax (typ: 'GET', url: thisparam.attr ('href'), framgång: funktion (resultat) thisparam.parent (). parent (). fadeOut ('slow');)

Precis som förra gången passerar vi i några parametrar som åtkomst till "delete.php". Istället för att kryptera sidan i URL-adressen, kommer jag åt attr ('href') - vilket är lika med 'delete.php? Id = $ id'.

 D

Vi behöver inte en "DATA" -parameter, eftersom all lämplig information finns inom URL-frågan. När raderingen utförs framgångsrikt hittar vi föräldrarnas ".item" div och bleknar det långsamt.

Delete.php

Vi har ringt vår raderingssida med jQuery, men vi har inte skapat PHP ännu. Skapa din nya sida och lägg till följande kod.

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

Du borde vara van vid dessa förfaranden nu. Skapa en ny instans av vår klass och ringa "delete_by_id" -metoden. När det väl har slutförts, omdirigerar användaren tillbaka till "index.php". Som du kanske har gissat behöver vi skapa en ny metod inom vår db-klass. Återgå till db.php och lägg till din nya funktion.

Delete_by_id () Metod

 funktion delete_by_id ($ id) $ query = "DELETE från todo WHERE id = $ id"; $ result = $ this-> mysql-> fråga ($ query) eller dö ("det var ett problem, man."); om ($ resultat) returnera 'yay!'; 

Denna metod kommer att acceptera en parameter - id. Kom ihåg: För att uppdatera en rad, måste vi veta den radens unika id. Annars uppdateras varje rad. Vi raderar alla rader från tabellen, där id är lika med vad som skickas in. Eftersom varje rad har sitt eget unika ID påverkas endast en. Därefter skickar vi denna fråga till vårt mysql-objekt. Återigen är återvändan onödig; det är bara för skojs skull.


Steg 9: Extra jQuery

Vi har avslutat allt vårt PHP-arbete! Det sista steget är att lägga till lite jQuery för att få allt att fungera lite bättre. Överst på din Javascript-fil, precis efter metoden document.ready, lägg till följande kod:

 // Visa inte fliken addNewEntry när sidan laddas. $ ('# addNewEntry'). css ('display', 'none'); // Vi använder jQuery för att skapa våra flikar. Om Javascript är inaktiverat fungerar de inte. Med tanke på // detta borde vi lägga till våra flikar, så att de inte kommer att dyka upp om de är funktionshindrade. $ ( '# Flikar'). Bifoga (
  • Nytt föremål
  • '); // Dölj beskrivningen för varje uppgift. Visa bara h4-taggen för var och en. $ (Div.item) barn () inte (H4) dölja ()... // Hela objektet div är klickbart. För att ge den feedbacken ändrar vi musens markör. // När den här diven klickar kommer vi att skicka skärmen från synliga till dolda varje gång den klickas. // Men när användaren klickar på "uppdatering" -knappen stängs diven när de klickar inuti textområdet // för att redigera beskrivningen. Denna kod upptäcker om målet för klicket var textområdet. Om det var, // gör vi ingenting. $ ('div.item'). css ('cursor', 'pointer'). Klicka på (funktion (e) if (! $ (e.target) .is ('textarea')) $ (detta). barn (). inte ('h4'). slideToggle (); $ (detta) .barn ('h4'). toggleClass ('expandDown'););

    Jag har kommenterat varje steg ganska bra. Så, jag avstår från att upprepa mig själv. Din sista scripts.js-fil ska se ut så här.

     $ (funktion () // Visa inte fliken addNewEntry när sidan laddas. $ ('# addNewEntry'). css ('display', 'none'); // Vi använder jQuery för att skapa våra flikar . Om JavaScript är inaktiverat, kommer de inte att fungera. Med tanke // detta bör vi lägga våra flikar, så att de inte kommer att dyka upp om inaktiverad. $ ( "# flikar). bifoga ('
  • Nytt föremål
  • '); // Dölj beskrivningen för varje uppgift. Visa bara h4-taggen för var och en. $ (Div.item) barn () inte (H4) dölja ()... // Hela objektet div är klickbart. För att ge den feedbacken ändrar vi musens markör. // När den här diven klickar kommer vi att skicka skärmen från synliga till dolda varje gång den klickas. // Men när användaren klickar på "uppdatering" -knappen stängs diven när de klickar inuti textområdet // för att redigera beskrivningen. Denna kod upptäcker om målet för klicket var textområdet. Om det var, // gör vi ingenting. $ ('div.item'). css ('cursor', 'pointer'). Klicka på (funktion (e) if (! $ (e.target) .is ('textarea')) $ (detta). barn (). inte ('h4'). slideToggle (); $ (detta) .barn ('h4'). toggleClass ('expandDown');); // Lägg till ny artikel flik klicka på $ ('# flikar li'). klicka (funktion () $ ('# flikar li'). removeClass ('selected'); $ (this) .addClass ('selected'); css ('display', 'none'); $ ('# addNewEntry'). css (' css ("display", "none"); $ ('# todo'). css ("display", "block"); else $ ('# addNewEntry' returnera false;); .... $ ( '# Todo div: först') barn (h4) addClass (expandDown) ände () barn () show ();. // Ta bort ankare taggade $ ('a.deleteEntryAnchor'). Klicka (funktion () var thisparam = $ (detta); thisparam.parent (). Parent (). Find ('p') text Vänta ... '); $ .ajax (typ:' GET ', url: thisparam.attr (' href '), framgång: funktion (resultat) thisparam.parent ;) returnera false;); // Redigera ett objekt asynkront $ ('. EditEntry'). Klicka (funktion () var $ this = $ (detta); var oldText = $ this.parent (). Parent (). Find ('p'). text (); var id = $ this.parent (). parent (). hitta ('# id') .val (); console.log ('id:' + id); $ this.parent () .Hitta ( 'p'). tom (). append (''); $ ('; newDescription'). Blur (funktion () var newText = $ (detta) .val (); $ .ajax (typ: 'POST', url: 'updateEntry.php', data: 'description = '+ newText +' & id = '+ id, framgång: funktion (resultat) $ this.parent (). parent (). find (' p '). empty () .append (newText);); ); returnera false; ); );

    Steg 10: Vänta! Layouten är konstig i IE6.

    Vi kan inte kalla det en dag ännu! Det roliga ole Internet Explorer 6 orsakar några layoutproblem.


    1. Bakgrunds-pngs är 24 bitar. IE6 stöder inte detta nationellt. Vi måste importera ett skript för att åtgärda det.
    2. Navigationsflikarna visas inte på rätt plats.
    3. Varje div.item visas inte korrekt när den expanderas.
    4. Våra redigera och ta bort knappar är för långt till höger om vår div.

    Lösningen

    Även om vi skulle vilja, kan vi inte ignorera den här webbläsaren ännu. Lyckligtvis hittar du att de flesta IE6-problem kan lösas ganska enkelt. Först måste vi importera ett skript som kommer att åtgärda vår alfa-transparensfråga. Dean Martin har en fantastisk Javascript-fil som ger IE6 upp till standarder som är kompatibla. Genom att lägga till "-trans" till slutet av våra 24-bitars png-filnamn kan vi lösa vårt problem. Var noga med att besöka bildermappen och redigera namnen.

     

    Googles CDN kommer till räddning igen genom att tillhandahålla en värdversion av IE7-skriptet. Det åtgärdar vår transparensfråga, men vi har fortfarande några fler egenskaper.


    Observera att vi i vårt villkorliga uttalande också importerade en "ie.css" -fil. Skapa den filen just nu och klistra in i följande:

     kropp marginal: 0; vaddering: 0;  #tabs höjd: 100%;  #main height: 100%;  #main div.item width: 100%; överflöde: gömd; position: relativ; 

    Du kommer att upptäcka att lägga till "position: relative", "overflow: hidden" och "height: 100%" kommer att fixa 90% av dina IE6-problem. Nu fungerar vår layout perfekt i alla webbläsare!


    Du är klar!


    Det var mycket att täcka här. Förhoppningsvis förklarade jag mig tillräckligt noggrant. Om inte, det är vad den tillhörande skärmdumpen är för! Var noga med att granska den för att rensa några suddiga områden. Om du fortfarande har frågor, fråga mig bara! Tack så mycket för att läsa.