Vom einfachen AJAX-Request zum komplexen Objektaustausch mit JSON mittels jQuery

“Asynchronous JavaScript and XML” kurz AJAX ist die asynchrone Datenübertragen zwischen Client und Server. Dabei wird ein HTTP-Request abgeschickt, ohne ein komplettes Neu laden der Seite zu erzwingen. Es werden nur Teile nachgeladen, welche auch wirklich benötigt werden.

Anhand einer Beispielanwendung wird in diesem Tutorial vorgestellt, wie verschiedene Arten der Datenübertragung per AJAX möglich sind. Mittels Browser (Client) und einer PHP-Anwendung (Server) werden drei verschiedene Möglichkeiten vorgestellt, wie man Daten per Client und Server austauschen kann.

Das Beispielszenario

Als Beispiel soll eine einfach gestalte HTML-Seite dienen, welche drei Buttons besitzt und in Infoboxen die Ergebnisse erscheinen sollen. Dabei kommen die Technologien HTML5, CSS, jQuery und für eine hübsche Darstellung mit dem CSS-Framework Bootstrap zum Einsatz.

ajax_tutorial_example

Für ganz Ungeduldige kann auch der Projektordner am Ende des Artikels gedownloadet werden. Der Code ist recht gut strukturiert und auch kommentiert ;) .

Das Szenario wurde mittels Netbeans erstellt, welches folgende Ordnerstruktur aufweist:

ajax_tutorial_netbeans

Die Ansicht

Innerhalb der index.html werden die AJAX-Aufrufe mittels Buttons ausgeführt, welche verschiedene Aufrufe starten und unterschiedliche Ergebnisse liefern.

<!DOCTYPE html>
<html>
    <head>
        <title>AJAX-Tutorial</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

        <!-- Styles einbinden -->
        <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
        <link href="css/styles.css" rel="stylesheet">
    </head>
    <body>
        <div class="container well">
            <div class="row">
                <div class="span4">
                    <button id="ajaxCall_easy" class="btn btn-info">einfacher AJAX-Aufruf</button>
                </div>
                <div class="span4">
                    <button id="ajaxCall_template" class="btn btn-info">Template nachladen</button>
                </div>
                <div class="span4">
                    <div class="input-append pull-right control-group">
                        <input class="span2" id="inputNumber" name="inputNumber" type="text" placeholder="beliebige Ganzzahl">
                        <button id="ajaxCall_checkPrime" class="btn btn-info" type="button">Auf Primzahl prüfen</button>
                    </div>
                </div>
                <div class="clearfix"></div>
            </div>
            <div id="content">
                <div class="alert alert-block"> 
                <h4>Info!</h4>
                    <p id="info-text">Zur Zeit ist kein nachgeladener Inhalt vorhanden!
                </div>
            </div>
        </div>
        <!-- JavaScript einbinden -->
        <script src="js/jquery-2.0.0.min.js"></script>
        <script src="bootstrap/js/bootstrap.min.js"></script>
        <script src="js/ajax.js"></script>
    </body>
</html>

Mittels der Button-ID “ajaxCall_easy” wird ein einfache AJAX-Abfrage gestartet welches als Ergebnis einen Ergebnistext zurück bekommt.

<button id="ajaxCall_easy" class="btn btn-info">einfacher AJAX-Aufruf</button>

Mit dem Button “ajaxCall_template” wird ein vorhandenes Template, welches unter “templates/template1.html” abgelegt ist, nachgeladen.

<button id="ajaxCall_template" class="btn btn-info">Template nachladen</button>

Als dritter Abruf dient eine Abfrage ob eine eingebende Ganzzahl eine Primzahl ist. Dabei wird auch ein Template nachgeladen (“templates/template2.html”). Bei diesem Template werden verschiedene Platzhalter ersetzt und das Ergebnis direkt im Template gespeichert.

<input class="span2" id="inputNumber" name="inputNumber" type="text" placeholder="beliebige Ganzzahl">
<button id="ajaxCall_checkPrime" class="btn btn-info" type="button">Auf Primzahl prüfen</button>

Die JavaScript-Logik

Mit der fertigen Ansicht können wir uns um die Logik kümmern. Mittels jQuery werden mittels ClickEvents (Aufruf der Funktion wenn ein Button geklickt wird) die AJAX-Aufrufe gestartet. Die Logik für jQuery befindet sich in der Datei: “js/ajax.js”. Damit die Aufrufe funktionieren muss natürlich vorher jQuery eingebunden sein (“js/jquery-2.0.0.min.js”).

$(document).ready(function()
{   
    // Einfacher AJAX-Aufruf
    $("button#ajaxCall_easy").click(function() {

        $.ajax({
            type: "POST",
            url: "server.php",
            data: {
                method: "easy_call"
            },
            success: function(content) {
                $("#content").text(content);
            }
        });

        return false;
    });

    // AJAX-Aufruf mit Template nachladen
    $("button#ajaxCall_template").click(function() {

        $.ajax({
            type: "POST",
            url: "server.php",
            data: {
                method: "load_template"
            },
            success: function(content) {
                $("#content").html(content);
            }
        });

        return false;
    });

    // AJAX-Aufruf mit Template nachladen
    $("button#ajaxCall_checkPrime").click(function() {

        // Eingebene Zahl aus dem Eingabefeld beziehen
        var inputNumber = $("input#inputNumber").val();

        // Objekt mit Inhalt bilden
        var values = {
            "inputNumber": inputNumber
        };

        if(inputNumber != "")
        {
            // JSON-Objekt wird zu einem string konvertiert, da wir nur ein serialisiertes Objekt uebergeben koennen
            var jsonString = JSON.stringify(values);
            SendAjaxJsonRequest("server.php", "check_prime", jsonString);       
        }
        else
        {
            alert("Bitte geben Sie eine beliebige Ganzzahl ein!");
        }

        return false;
    });
});

/**
 * Sendet Ajax-Request
 */
function SendAjaxJsonRequest(url, method, jsonObject)
{
    $.ajax({
        type: "POST",
        url: url,
        data: {
            method: method,
            jsonObject: jsonObject
        },
        success: onSuccess
    });
}

/**
 * AJAX-Response auswerten
 */
function onSuccess(content)
{
    // Das empfangene Objekt wird wieder zum Objekt geparst
    var response = $.parseJSON(content);

    // geladenes Template im Container "content" austauschen
    $("#content").html(response.template);

    // Pruefen ob die Eingabe richtig ist,
    if(!response.result)
    {
        // Wenn ein Fehler auftritt wird das Eingabefeld rot gefaerbt
        $(".control-group").addClass("error");
    }
    else
    {
        // Wenn ein kein Fehler auftritt wird die vorhandene CSS-Klasse error entfernt (falls gesetzt)
        $(".control-group").removeClass("error");
    }
}

Für die verschiedenen Aufrufe werden auch unterschiedliche Ansätze verwendet. Für den ersten und zweiten Aufruf werden anonyme Funktionen benutzt. Für den dritten Aufruf wurden die Funktionen ausgelagert, welche eine Wiederverwendbarkeit gewährleistet.

Funktionsweise des AJAX-Aufrufes unter jQuery

Mit einem Klick auf den Button “Template nachladen” wird das AJAX-Objekt initialisiert und an den Server geschickt.

// AJAX-Aufruf mit Template nachladen
$("button#ajaxCall_template").click(function() {

    $.ajax({
        type: "POST",
        url: "server.php",
        data: {
            method: "load_template"
        },
        success: function(content) {
            $("#content").html(content);
        }
    });

    return false;
});

Dazu wird der Typ (type) des Request gesetzt. Das ist entweder GET oder POST. Mittels dem Parameter “url” wird das Serverscript (server.php) angesprochen und “data” enthält die Daten welche an den Server gesendet werden.
Im Parameter “success” wird schlussendlich der Response, die Antwort vom Server, ausgewertet. Hierbei wird das div mit der ID “content” angesprochen und die Antwort des Servers direkt in den HTML-Code (die nachgeladene Datei “template1.html”) zwischen dem div-Tag ersetzt. Weitere optionale Parameter können in der jQuery-API-Dokumentation nachgelesen werden.
Als Rückgabewert des ClickEvents wird noch false zurück gegeben, damit kein Neu laden der Seite erfolgt.

Die Serverlogik

Die AJAX-Anfrage wird an die “server.php” geschickt. Diese Datei beinhaltet jedoch nicht die Logik, sondern instanziiert nur den AjaxController. Das entspricht dem MVC-Pattern welche die Logik komplett auslagert. In einem Framework geschieht dies meist über die “index.php”, welche eine Controller-Logik initialisiert und unserem Aufruf auswertet.

<?php
// Benoetigter AjaxController wird eingebunden
require_once 'classes/AjaxController.php';

// Neue Instanz des Controllers anlegen
$ajaxController = new AjaxController();

// Controller ausgefuehren
echo $ajaxController->execute();

Der Controller – Die Auswertung des AJAX-Aufrufes

Unter dem Ordner “classes/AjaxController.php” finden wir unseren Controller welcher die Anfragen aus der “ajax.js” beantwortet.

<?php

/**
 * AjaxController
 *
 * @author Patrick Mosch
 */
class AjaxController
{

    /**
     * Standard-Konstruktor
     */
    public function __construct() {}

    /**
     * AJAX-Methode ausfuehren
     */
    public function execute()
    {
        // Aufgerufene Methode
        $method = "";

        // JSON-Objekt falls vorhanden
        $jsonObject = null;

        // Rueckgabeobjekt
        $result = "";

        // Rueckgabe als JSON-Objekt
        $responseJson = false;

        // Unsichere Methode um POST-Variablen zu speichern, sollte jedoch
        // fuer unser Tutorial ausreichend sein. Die POST-Variablen sollten aus 
        // Sicherheitsgruenden immer escaped werden!
        if (isset($_POST['method']))
        {
            $method = $_POST['method'];
        }

        // Pruefen ob ein JSON-Objekt gesetzt ist
        if (isset($_POST['jsonObject']))
        {
            // JSON-String parsen damit auf das Objekt zugegriffen werden kann
            $jsonObject = json_decode($_POST['jsonObject']);

            // Ausgabe soll als JSON-Objekt erfolgen
            $responseJson = true;
        }

        // Springt in die jeweilige Methode, welche beim AJAX-Aufruf angegeben wurde
        switch ($method)
        {
            case "easy_call":

                // Meldung als Rueckgabewert setzen
                $result = "Einfacher AJAX-Aufruf war erfolgreich!";

                break;
            case "load_template":

                // Template in Variable laden und als Rueckgabewert setzen
                $result = file_get_contents("./templates/template1.html");

                break;
            case "check_prime":
                // Ermitteln ob die uebergebene Zahl 
                $isPrimeNumber = $this->checkPrimeNumber($jsonObject->inputNumber);

                // Template in Variable laden
                $fileContent = file_get_contents("./templates/template2.html");

                // Pruefen ob es eine Primzahl ist. Anhand dessen werden unterschiedliche Ausgaben erzeugt
                if ($isPrimeNumber)
                {
                    // CSS-Klasse setzen -> die Box wird gruen
                    $templateContent = str_replace("###CONTAINER_CLASS###", "alert-success", $fileContent);

                    // Meldung in der Box setzen
                    $templateContent = str_replace("###PLACEHOLDER###", "Die eingebene Zahl " . $jsonObject->inputNumber . " ist eine Primzahl!", $templateContent);
                }
                else
                {
                    // CSS-Klasse setzen -> die Box wird rot
                    $templateContent = str_replace("###CONTAINER_CLASS###", "alert-error", $fileContent);

                    // Meldung in der Box setzen
                    $templateContent = str_replace("###PLACEHOLDER###", "Die eingebene Zahl " . $jsonObject->inputNumber . " ist KEINE Primzahl!", $templateContent);
                }

                // RueckgabeArray fuellen
                $responseArray = array(
                    "result" => $isPrimeNumber,
                    "template" => $templateContent
                );

                $result = json_encode($responseArray);

                break;
            default:
                $result = "Ein Fehler ist aufgetreten!";

                break;
        }

        return $result;
    }

    /**
     * Prueft ob uebergebene Zahl eine Primzahl ist
     * @param type $inputNumber
     * @return boolean
     */
    protected function checkPrimeNumber($inputNumber)
    {
        // Wurzel ziehen, dies bestimmt die maximale Anzahl an Durchlaeufen
        $squareRoot = sqrt($inputNumber);

        for ($i = 2; $i <= $squareRoot; ++$i)
        {
            // Per Modulo pruefen ob Restwert 0 ist
            if ($inputNumber % $i == 0)
            {
                return false;
            }
        }
        return true;
    }

}

In der Methode “execute” werden die übergebene Daten verarbeitet und die Auswertung zurück gegeben.

Anhand des dritten Buttons zeige ich den kompletten Ablauf des AJAX-Abrufes

Als erstes tragen wir eine “1” in das Eingabefeld ein:

ajax_tutorial_stepbystep_step1

Mittels dem Button “Auf Primzahl prüfen” wird folgendes ClickEvent gestartet:

// AJAX-Aufruf mit Template nachladen
$("button#ajaxCall_checkPrime").click(function() {

    // Eingebene Zahl aus dem Eingabefeld beziehen
    var inputNumber = $("input#inputNumber").val();

    // Objekt mit Inhalt bilden
    var values = {
        "inputNumber": inputNumber
    };

    if(inputNumber != "")
    {
        // JSON-Objekt wird zu einem string konvertiert, da wir nur ein serialisiertes Objekt uebergeben koennen
        var jsonString = JSON.stringify(values);
        SendAjaxJsonRequest("server.php", "check_prime", jsonString);       
    }
    else
    {
        alert("Bitte geben Sie eine beliebige Ganzzahl ein!");
    }

    return false;
});

In der Variable “inputNumber” wird der Wert unseres Eingabefeld abgerufen. Der Wert beträgt unsere eingebende Ganzzahl “1”. Jetzt wird ein JSON-Objekt gebildet (values), welches unsere Werte enthält. In unserem Beispiel ist das nur die Variable “inputNumber”. Als nächstes wird das Objekt serialisiert. Das heißt das Objekt wird in einen string umgewandelt, welches im Ergebnis so aussieht:

{"inputNumber":"1"}

Im Anschluss daran wird mittels der Methode “SendAjaxJsonRequest” der AJAX-Aufruf gestartet. Als Parameter übergeben wir die aufzurufende PHP-Datei, die Operation welche ausgeführt werden soll und das serialisierte Objekt.

SendAjaxJsonRequest("server.php", "check_prime", jsonString);

In der Methode “SendAjaxJsonRequest” wird der AJAX-Aufruf initialisiert und gestartet. Als POST-Variablen wird die Operation (method) und das JSON-Objekt übergeben (jsonObject).

Die Daten kommen im AjaxController als string an und werden wieder mittels der Funktion json_decode in ein Objekt umgewandelt.

$jsonObject = json_decode($_POST['jsonObject']);

Jetzt ist es möglich auf die Properties des Objektes zuzugreifen und diese der Methode “checkPrimeNumber” zu übergeben

$isPrimeNumber = $this->checkPrimeNumber($jsonObject->inputNumber);

Wenn es eine Primzahl ist, ist der Rückgabewert der Methode true. Im nächsten Schritt wird das Template geladen und die Platzhalter ###CONTAINER_CLASS### und ###PLACEHOLDER### mit den jeweiligen Inhalten ersetzt.
Im Anschluss daran wird das Rückgabe-Array erstellt. Mittels der Funktion json_encode wird das Array für die Übertragung serialisiert (wieder als string):

/ RueckgabeArray fuellen
$responseArray = array(
    "result" => $isPrimeNumber,
    "template" => $templateContent
);

$result = json_encode($responseArray);

Wir landen wieder in der “ajax.js”. Wenn der Aufruf erfolgreich war, wird die JavaScript-Funktion “onSuccess” aufgerufen. Unser serialisiertes Array wird als Parameter (content) an die Funktion übergeben. Die Variable “content” konvertieren wir wieder in ein Objekt, damit wir wieder bequem darauf zugreifen können und zeigen unser modifiziertes Template im div mit der ID “content” an.

// Das empfangene Objekt wird wieder zum Objekt geparst
var response = $.parseJSON(content);

// geladenes Template im Container "content" austauschen
$("#content").html(response.template);

Das Ergebnis sollte nun so aussehen:

ajax_tutorial_stepbystep_step2

Wenn wir als Zahl eine “4” eingeben, wird in dem div mit der CSS-Klasse “control-group” noch die CSS-Klasse “error” hinzugefügt. Dieses signalisiert die fehlerhafte Eingabe im Eingabefeld. Das Eingabefeld bekommt eine rote Umrandung:

ajax_tutorial_stepbystep_step3

Download unter GitHub: ajax_tutorial