Anzeige
Tutorialbeschreibung

Javascript und Ajax-Warenkorb

Javascript und Ajax-Warenkorb

Das nun folgende Tutorial ist ein Auszug aus der 7. Auflage des Buches: JavaScript und Ajax von Christian Wenz.

Kapitel 32 Warenkorb

Geld verdienen im Internet? Vor einigen Jahren waren die Experten noch der Meinung, das sei so sicher wie das Amen in der Kirche. Nach einiger Zeit stellten dieselben Experten fest, dass es dank des Internets zu vielen Angeboten ebenso viele kostenlose Alternativen gibt. Eine Zeit lang waren die Venture-Capital-Geber (zweck-)optimistisch, im Sommer 2001 jedoch war es mit dem Optimismus vorbei: Der Begriff »Dotcom-Pleite« tauchte jeden zweiten Tag in einschlägigen Newsdiensten auf, und die amerikanische neue Mode der »Pink-Slip-Parties« schwappte auch nach Deutschland über, wenngleich auch ohne nennenswerten Erfolg.

Eines der wenigen Dinge, die von der Konjunkturflaute unbeeindruckt blieben, war JavaScript. Und damit wäre auch die (arg konstruierte) Überleitung zum Thema dieses Kapitels geschafft. Ein Online-Shop sollte prinzipiell mit serverseitigen Mitteln erstellt werden. Sie haben dann die folgenden Vorteile:

gpBilder
Die Artikel können in einer Datenbank gehalten und damit bequem(er) gewartet werden.
gpBilder
Für bestimmte Aktionen wie etwa das endgültige Versenden der Bestellung benötigen Sie ohnehin serverseitige Mittel.
gpBilder
Ein JavaScript-Shop funktioniert bei deaktiviertem JavaScript natürlich nicht.
gpBilder
Bei einer serverseitigen Lösung haben Sie weniger Probleme mit JavaScript-Bugs oder -Unterschieden der Browser. Der zugrunde liegende Code Ihres Shops muss nur auf genau einem System laufen, Ihrem Webserver nämlich, und nicht auf allen Browsern.

Wir wollen in diesem Kapitel ein Konzept für die Erstellung eines einfachen Online-Shops vorstellen und auch implementieren. Dabei wollen wir auch unterschiedliche Ansätze vorstellen, die Informationen während des Einkaufs abzuspeichern.

Das Problem liegt auf der Hand: HTTP ist – wie bereits an einer anderen Stelle erwähnt – ein statusloses Protokoll; Daten, die auf einer Seite bekannt sind, können auf der nächsten Seite schon wieder unbekannt sein. Es gibt drei Hauptmöglichkeiten, wie sich Ihre Shop-Anwendung die Daten doch merken kann:

gpBilder
mit einem unsichtbaren Frame
gpBilder
mit Cookies
gpBilder
durch die Weitergabe der Daten in der URL

Wir werden für alle drei Möglichkeiten eine Lösung vorstellen. Der prinzipielle Ansatz in Sachen Variablen ist aber jedes Mal derselbe.

Es ist klar, dass an dieser Stelle weder die perfekte Lösung noch ein annähernd vollständiges System angeboten werden kann. Der hier vorgestellte Ansatz ist für Erweiterungen offen und kann in vielerlei Hinsicht ausgebaut werden. Aber: Der Ansatz funktioniert und ist damit eine geeignete Basis für Ihre eigenen Unternehmungen.


 

32.1 Datenstruktur 
topBilder
topBilder

Die einzelnen Artikel werden alle in JavaScript-Variablen abgespeichert. Dadurch lassen sich zwei Fliegen mit einer Klappe schlagen:

gpBilder
Die Artikelübersicht kann komplett mit JavaScript generiert werden.
gpBilder
Für die endgültige Bestellung samt Anzeige des Warenkorbs können dieselben Variablen verwendet werden.

Für die Speicherung der einzelnen Artikel in Variablen wird ein kleines Objekt erstellt:



function warenkorb_artikel(
nr, name, kurz, lang,
                            grafik, preis) {
   this.nr = nr;
   this.name = name;
   this.kurz = kurz;
   this.lang = lang;
   this.grafik = grafik;
   this.preis = preis;
   this.anzahl = 0;
   return this;
}

Wie Sie sehen, wird ein neues Objekt erstellt, in dem die an den Konstruktor übergebenen Daten abgespeichert werden. Als Parameter erwartet die Funktion die folgenden Angaben:

gpBilder
nr: die Bestellnummer des Artikels
gpBilder
name: den Namen des Artikels
gpBilder
kurz: die Kurzbeschreibung des Artikels
gpBilder
lang: eine lange Beschreibung des Artikels für die ausführliche Produktdarstellung
gpBilder
grafik: die URL der zum Artikel gehörenden Grafik
gpBilder
preis: den Preis des Artikels (in €)

Innerhalb der Funktion wird noch eine weitere Eigenschaft festgelegt, nämlich die anzahl. Dort wird während des Einkaufs erfasst, wie viele Stück des Artikels vom Benutzer in den Warenkorb gelegt worden sind.

Ein Artikel wird dann wie folgt erstellt (nachfolgend einige historische Bücher von Galileo Press, die alle nicht mehr erhältlich sind):



var buch_c1 = new warenkorb_artikel(
   "3–89842–149-X",
   "Wenz: JavaScript-Rezepte",
   "Christian Wenz: JavaScript-Rezepte. 2001 Galileo Press, Bonn",
   "Christian Wenz: JavaScript-Rezepte. Galileo Press, Bonn. 
      1. Auflage 2001. Lektorat: Judith Stevens-Lemoine. 
      Korrektorat: Friederike Daenecke. Einbandgestaltung: Barbara 
      Thoben.",
   "rezepte.png",
   35.74);
var buch_c2 = new warenkorb_artikel(
   "3–89842–132–5",
   "Wenz: JavaScript",
   "Christian Wenz: JavaScript – Browserübergreifende Lösungen. 
      2001 Galileo Press, Bonn",
   "Christian Wenz: JavaScript – Browserübergreifende Lösungen.
      Galileo Press, Bonn. 3. Auflage 2001. Lektorat: Judith
      Stevens-Lemoine. Korrektorat: Friederike Daenecke. 
      Einbandgestaltung: Barbara Thoben.",
   "javascript.png",
   40.85);
var buch_c3 = new warenkorb_artikel(
   "3–934358–29–2",
   "Williamson: Dynamic HTML browserübergreifend",
   "Heather Williamson: Dynamic HTML browserübergreifend. 
      2001 Galileo Press, Bonn",
   "Heather Williamson: Dynamic HTML browserübergreifend. 
      Galileo Press, Bonn. 1. Auflage 2001. Übersetzung: 
      Roman Impertro. Lektorat: Judith Stevens-Lemoine. Korrektorat: 
      Claudia Falk/Holger Schmidt. Einbandgestaltung: 
      Barbara Thoben.",
   "dhtml.png",
   35.74);
var buch_d1 = new warenkorb_artikel(
   "3–934358–05–5",
   "Wolter: Flash 4",
   "Sascha Wolter: Flash 4. 1999 Galileo Press, Bonn",
   "Sascha Wolter: Flash 4, mit CD. Galileo Press, Bonn. 1. Auflage 
      1999. Lektorat: Ruth Wasserscheid. Korrektorat: Marcus
      Pfitzenreuter. Einbandgestaltung: Helmut Kraus.",
   "flash.png",
   40.85);
var buch_d2 = new warenkorb_artikel(
   "3–89842-XXX-X",
   "Leske/Biedorf/Müller: Director 8 für Profis",
   "Christophe Leske/Thomas Biedorf/Regina Müller: Director 8
      für Profis. 2000 Galileo Press, Bonn",
   "Christophe Leske/Thomas Biedorf/Regina Müller: Director 8
      für Profis. Galileo Press, Bonn. 1. Auflage 2000. Lektorat: 
      Ruth Wasserscheid. Korrektorat: Sandra Gottmann/Marcus 
      Pfitzenreuter. Einbandgestaltung: Helmut Kraus.",
   "director.png",
   51.08);

Die Artikel können in verschiedene Kategorien unterteilt werden. Dazu wird zunächst ein weiterer Konstruktor in der Bibliothek warenkorb.js definiert:



function warenkorb_kategorie(
name, artikel) {
   this.name = name;
   this.artikel = artikel;
   return this;
}

Die Eigenschaft name enthält die textuelle Beschreibung der Kategorie. In der Eigenschaft artikel werden die einzelnen Artikel als Array gespeichert.



var computing = new warenkorb_kategorie(
   "Galileo Computing",
   new Array(buch_c1, buch_c2, buch_c3));
var design = new warenkorb_kategorie(
   "Galileo Design",
   new Array(buch_d1, buch_d2));

Um einen schnellen und bequemen Zugriff zu gewährleisten, werden die einzelnen Kategorien in einem Array zusammengefasst:



var kategorie = new Array(computing, design);

Die Artikel sind nun in Variablen gespeichert, und wir können uns an die Umsetzung machen. Die einzelnen Dateien haben folgende Inhalte:

gpBilder
In der Datei warenkorb.js stehen alle nötigen Hilfsfunktionen.
gpBilder
Die Datei artikel.js muss von Ihnen angepasst werden; dort gehören alle Artikel hinein.
gpBilder

Die restliche JavaScript-Logik – die Anzeige von Artikel und Warenkorb – wird in den HTML-Dateien untergebracht, die wir im Folgenden entwickeln werden.

 

 

 

32.2 Mit unsichtbaren Frames arbeiten 
topBilder

Unsichtbare Frames haben den Vorteil, dass ein Teil der Website nie geändert wird. Sie können also in dem Frame Variablen speichern, und der Benutzer bekommt es (fast) nicht mit.

Schlecht sieht es jedoch aus, wenn die Frame-Struktur verlassen wird – beispielsweise, wenn der Benutzer einen Link in einem neuen Fenster öffnet. Sie sollten dann auf jeden Fall eine Warnmeldung ausgeben:



if (self == top) {
   alert("Bitte keine Frames im neuen Fenster öffnen!");
   window.close();
}

Zwar erscheint beim Schließen des Fensters eine Warnmeldung, aber hier ist nur wichtig, dass der Benutzer im Hauptfenster bleibt.

In der vorgestellten Lösung verwenden wir drei Frames:

gpBilder
Einer der Frames ist der Hauptframe. Dies ist der Platz für die eigentlichen Inhalte: die Artikel, die Kategorien und den Warenkorb.
gpBilder
Der zweite Frame gibt aus, wie viele Artikel sich im Warenkorb befinden und wie viel sie zusammen kosten. Zusätzlich wird ein Link angeboten, über den direkt auf den Warenkorb zugegriffen werden kann. Damit wird dann die Bestellung generiert.
gpBilder
Der dritte Frame ist nicht sichtbar und enthält den gesamten JavaScript-Code. Dort wird auch der Inhalt des Warenkorbs abgespeichert.

Der HTML-Code dafür sieht folgendermaßen aus:



<html>
<head>
<title>Online-Shop</title>
</head>
<frameset rows="*, 50, 1" border="0" frameborder="0">
   <frame src="kategorien_frames.html" name="Inhalt" />
   <frame src="uebersicht_frames.html" name="Uebersicht" />
   <frame src="code_frames.html" name="Code" scrolling="no" />
</frameset>
</body>
</html>

Die Datei code_frames.html ist am schnellsten erstellt:



<html>
<head>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body onload="if (top.frames['Inhalt']) top.frames['Inhalt'].location.reload();">
</body>
</html>

Sie sehen also: Es ist gar nicht viel los. Das ist aber auch verständlich, da die Hauptarbeit in den zwei eingegliederten JavaScript-Dateien erledigt wird:

gpBilder
warenkorb.js enthält die Hilfsfunktionen für unseren JavaScript-Shop.
gpBilder
artikel.js enthält nach dem oben skizzierten Muster alle Artikel, nach Kategorien unterteilt.

Die einzige Besonderheit besteht darin, dass nach dem vollständigen Laden des Dokuments (inklusive aller Artikel) der Inhaltsframe neu geladen wird. In der Regel ist es nämlich so, dass der Inhaltsframe weniger lange zum Laden braucht als der Codeframe und dass deswegen erst nach dem Laden des Codeframes auf die Variablen im Codeframe zugegriffen werden darf.

Die Datei warenkorb.js werden wir im Laufe dieses Abschnitts schrittweise erweitern, so dass Ihnen am Ende eine funktionsfähige Applikation zur Verfügung steht.


32.2.1 Warenkorb füllen  

Um den Warenkorb zu füllen, schreiben wir eine Funktion, die zwei Parameter erwartet:

gpBilder
die Bestellnummer des Artikels, der hinzugefügt werden soll
gpBilder
die Angabe, wie viel Stück des betreffenden Artikels in den Warenkorb gelegt werden sollen

Wie Sie in der Funktion warenkorb_artikel() gesehen haben, wird die Anzahl der Artikel in der Eigenschaft anzahl gespeichert. Sie müssen also nur auf diese Eigenschaft zugreifen.



function warenkorb_hinzufuegen_frames(
nr, stueck) {
   if (top.frames["Code"]) {
      c = top.frames["Code"];
      for (var i=0; i<c.kategorie.length; i++) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            if (c.kategorie[i].artikel[j].nr == nr) {
               c.kategorie[i].artikel[j].anzahl += stueck;
            }
         }
      }
   }
}

Zunächst wird überprüft, ob top.frames["Code"] existiert (aufgrund von Browserunterschieden müssen Sie so umständlich auf die Variablen zugreifen, die im selben Frame definiert worden sind). Dann wird derjenige Artikel gesucht, der die gewünschte Bestellnummer hat.

Um also ein Exemplar der dritten JavaScript-Auflage in den Warenkorb zu legen, muss die Funktion folgendermaßen aufgerufen werden:



warenkorb_hinzufuegen_frames("3–89842–132–5", 1);

Alternativ dazu wird noch eine Funktion angeboten, die die Anzahl für einen Artikel im Warenkorb auf eine bestimmte Stückzahl setzt, sie also nicht stupide erhöht. Somit ist es später auch möglich, Artikel aus dem Warenkorb zu entfernen.



function warenkorb_editieren_frames(
nr, stueck) {
   if (top.frames["Code"]) {
      c = top.frames["Code"];
      for (var i=0; i<c.kategorie.length; i++) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            if (c.kategorie[i].artikel[j].nr == nr) {
               c.kategorie[i].artikel[j].anzahl = stueck;
            }
         }
      }
   }
}

Der Unterschied zwischen den beiden Funktionen besteht also tatsächlich nur im Zuweisungsoperator: warenkorb_hinzufuegen_frames() verwendet +=, warenkorb_editieren_frames() verwendet dagegen =.


32.2.2 Artikel anzeigen  

Die Artikel sind in Kategorien unterteilt. Sie benötigen also drei verschiedene Seiten:

gpBilder
eine Seite, auf der alle Kategorien angezeigt werden: kategorien_frames.html
gpBilder
eine Seite, auf der alle Artikel innerhalb einer Kategorie angezeigt werden: artikel_gesamt_frames.html
gpBilder
eine Seite, auf der ein Artikel en detail angezeigt wird: artikel_einzeln_frames.html

Beginnen wir zunächst mit der Datei kategorien_frames.html. In dieser Datei wird das Array artikel aus dem Frame namens Code durchlaufen, und es werden die Namen aller Kategorien angezeigt. Diese stehen in der Eigenschaft name der jeweiligen Kategorie.

Die Namen der Kategorien sollen gleichzeitig Links auf die Übersichtsseite sein. Dazu muss die Seite artikel_gesamt_frames.html aufgerufen werden. Als Parameter wird der Name der Kategorie übergeben, also beispielsweise artikel_gesamt_frames.html?Galileo%20Computing.

Sie sehen hierbei, dass der Name der Kategorie in ein URL-fähiges Format umgewandelt worden ist. Dazu steht unter JavaScript die Funktion escape() zur Verfügung. Die Rückverwandlung kann mit unescape() erreicht werden.

In Abbildung 32.1 sehen Sie die folgende HTML-Seite, die alle Kategorien ausgibt:

Die Datei artikel_gesamt_frames.html zeigt dann alle Artikel innerhalb der angegebenen Kategorie an (siehe Abbildung 32.2). Der Code ist hier sehr ähnlich:

gpBilder
Zunächst wird die entsprechende Kategorie gesucht.
gpBilder
In einer Schleife werden alle Artikel innerhalb dieser Kategorie ausgelesen und ausgegeben.
gpBilder
Jeder Artikel wird verlinkt, und zwar mit der Datei artikel_einzeln_ frames.html. Als Parameter wird die Bestellnummer des gewählten Artikels angehängt, beispielsweise artikel_einzeln_frames.html? 3-89842-132-5.

Bilder

Abbildung 32.1     Die Kategorienübersicht

Hier sehen Sie die Datei artikel_gesamt_frames.html:

<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte w&auml;hlen Sie einen Artikel!
<ul>
<script type="text/javascript"><!--
if (top.frames["Code"] && location.search.length > 1) {
   var name = location.search.substring(1,
      location.search.length);
   name = unescape(name);
   c = top.frames["Code"];
   for (var i=0; i<c.kategorie.length; i++) {
      if (c.kategorie[i].name == name) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            var a = c.kategorie[i].artikel[j];
            document.write("<li>");
            document.write("<a href=
              "artikel_einzeln_frames.html?");
            document.write(escape(a.nr));
            document.write("">");
            document.write(a.name);
            document.write("</a></li>");
         }
      }
   }
}
//--></script>
</ul>
</p>
<p><a href="kategorien_frames.html">Zur&uuml;ck zur
  &Uuml;bersicht</a></p>
</body>
</html>

Bilder

Abbildung 32.2     Alle Artikel in einer Kategorie

Nun fehlt nur noch die Datei artikel_einzeln_frames.html. In dieser muss der einzelne Artikel mit allen Informationen (z.  B. Name, Kurzbeschreibung und ausführliche Beschreibung sowie Grafik) ausgegeben werden.

Bevor Sie sich aber an der Programmierung nach obigem Muster versuchen, sollten Sie sich in Erinnerung rufen, was auf der Seite noch geschehen soll. In der Artikel-Einzelansicht soll dem Benutzer die Möglichkeit geboten werden, den Artikel auch in den Warenkorb zu legen. Sie benötigen dazu die folgenden Elemente:

gpBilder
ein Texteingabefeld für die Stückzahl, die von dem Artikel in den Warenkorb gelegt werden soll
gpBilder
eine Schaltfläche, die auf Knopfdruck dann warenkorb_hinzu-fuegen_frames() mit den richtigen Parametern aufruft

In reinem HTML sieht das ungefähr folgendermaßen aus:



<input type="text" name="anzahl3–89842–132–5" size="2" 
value="1" /> Wenz: JavaScript

<input type="button" value="In den Warenkorb"
onclick="javascript:hinzu(this.form, "3–89842–132–5")" />
<br />

Beachten Sie Folgendes:

gpBilder
Das name-Attribut des Feldes für die Stückzahl setzt sich aus dem Wort "anzahl" und der Bestellnummer des gewünschten Artikels zusammen.
gpBilder
Die JavaScript-Schaltfläche ruft eine (noch zu schreibende Funktion) hinzu() auf. Als Parameter werden eine Referenz auf das aktuelle Formular sowie die Bestellnummer übergeben.

Die Funktion hinzu() muss dann

gpBilder
die Anzahl aus dem Formular auslesen,
gpBilder
die Funktion warenkorb_hinzufuegen_frames() aufrufen,
gpBilder
eine entsprechende Meldung ausgeben und
gpBilder
den Übersichtsframe neu laden.


function hinzu(f, nr) {
   if (top.frames["Code"]) {
      var c = top.frames["Code"];
       if (f.elements["anzahl" + nr]) {
          var anzahl = f.elements["anzahl" + nr].value;
          anzahl = parseInt(anzahl); //Umwandlung in Int
          if (isNaN(anzahl)) {
             anzahl = 0;
          }
         c.warenkorb_hinzufuegen_frames(nr, anzahl);
         alert("Artikel hinzugefügt!");
         if (top.frames["Uebersicht"]) {
            top.frames["Uebersicht"].location.reload();
         }
      }
   }
}

Solange nur ein Artikel angezeigt wird, kann die Funktion hinzu() etwas kürzer gestaltet werden. Da wir aber an späterer Stelle Codeteile daraus wiederverwenden möchten, ist sie hier ein wenig allgemeiner gehalten.

In der Datei artikel_einzeln_frames.html muss dann nur noch das Formular mit den Artikeldaten entsprechend ausgegeben werden.

Der Name der Kategorie wird nicht an die Seite mit übergeben, er kann auch anhand der Bestellnummer mit ein wenig zusätzlichem Code ermittelt werden:



function kategoriename(nr) {
   if (top.frames["Code"]) {
      c = top.frames["Code"];
      for (var i=0; i<c.kategorie.length; i++) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            if (c.kategorie[i].artikel[j].nr == nr) {
               return c.kategorie[i].name;
            }
         }
      }
   }
  return "";
}

Es folgt nun die komplette Datei artikel_einzeln_frames.html (siehe auch Abbildung 32.3):



<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p> Bitte geben Sie die St&uuml;ckzahl an!
<script type="text/javascript"><!--
function kategoriename(nr) {
   if (top.frames["Code"]) {
      c = top.frames["Code"];
      for (var i=0; i<c.kategorie.length; i++) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            if (c.kategorie[i].artikel[j].nr == nr) {
               return c.kategorie[i].name;
            }
         }
      }
   }
  return "";
}

function hinzu(f, nr) {
   if (top.frames["Code"]) {
      var c = top.frames["Code"];
      if (f.elements["anzahl" + nr]) {
         var anzahl = f.elements["anzahl" + nr].value;
         anzahl = parseInt(anzahl); //Umwandlung in Int
         if (isNaN(anzahl)) {
            anzahl = 0;
         }
         c.warenkorb_hinzufuegen_frames(nr, anzahl);
         alert("Artikel hinzugefügt!");
         if (top.frames["Uebersicht"]) {
            top.frames.location["Uebersicht"].reload();
         }
      }
   }
}

document.write("<ul>");

if (top.frames["Code"] && location.search.length > 1) {
   var nr = location.search.substring(1,
      location.search.length);
   nr = unescape(nr);
   var name = kategoriename(nr);
   c = top.frames["Code"];
   for (var i=0; i<c.kategorie.length; i++) {
      if (c.kategorie[i].name == name) {
         for (var j=0; j<c.kategorie[i].artikel.length; j++) {
            if (c.kategorie[i].artikel[j].nr == nr) {
               var a = c.kategorie[i].artikel[j];
               document.write("<h2>" + a.name + "</h2>");
               document.write("<b>" + a.kurz + "</b>");
               document.write("<img src="" + a.grafik + "" /
                 >");
               document.write("<br />" + a.lang + "<br />");
               document.write("<form>");
               document.write("<input type="text" ");
               document.write("name="anzahl" + nr + "" ");
               document.write("size="2" value="1" /> ");
               document.write(name + " ");
               document.write(a.preis + "&euro; "); // Preis in _
                                     document.write("<input type="button" value="In
                 den Warenkorb" ");
               document.write("onclick=
                 "javascript:hinzu(this.form, '"
                              + nr + "')" /><br />");
               document.write("</form>");
            }
         }
      }
   }
   document.write("</ul><a href="artikel_gesamt_frames.html?");
   document.write(escape(name));
   document.write("">");
   document.write("Zurück zu Kategorie " + name +"</a>");
} else {
   document.write("</ul>");
}
//--></script>
</ul>
</p>
</body>
</html>

Bilder

Abbildung 32.3     Detailansicht samt Bestellmöglichkeit

Einen Punkt haben wir jedoch noch unterschlagen: den Übersichtsframe. Dieser enthält wie versprochen die folgenden Elemente:

gpBilder
die Anzahl der (verschiedenen) Artikel im Warenkorb
gpBilder
einen Link zur Bestellseite
gpBilder
(als besonderes Extra) den aktuellen Gesamtwert des Warenkorbs

Auf dieser Seite müssen in mehreren verschachtelten Schleifen alle Variablen aus der Datei artikel.js durchlaufen werden, also das gesamte Artikelsortiment. Die einzelnen gewünschten Werte werden wie folgt ermittelt:

gpBilder
Wenn die Eigenschaft anzahl eines Artikels größer als 0 ist, wird die Anzahl der Artikel um eins erhöht und die gesamte Artikelstückzahl um den Wert in anzahl.
gpBilder
Die Eigenschaft anzahl wird mit dem Preis (Eigenschaft preis) multipliziert, um die aktuelle Gesamtsumme zu ermitteln.


<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<script type="text/javascript"><!--
if (top.frames["Code"] && top.frames["Code"].kategorie) {
   c = top.frames["Code"];
   var anzahl = 0;
   var stueck = 0;
   var summe = 0;
   for (var i=0; i<c.kategorie.length; i++) {
      for (var j=0; j<c.kategorie[i].artikel.length; j++) {
         var a = c.kategorie[i].artikel[j];
         if (a.anzahl>0) {
            anzahl ++;
            stueck += a.anzahl;
         }
         summe += a.anzahl * a.preis;
      }
   }
   document.write(anzahl + " Artikel, ");
   document.write(stueck + " Stück, ");
   document.write(summe + " &euro; ");
}
//--></script>
<a href="warenkorb_frames.html" target="Inhalt">Bestellung
aufgeben</a>
</body>
</html>

Bilder

Abbildung 32.4     Die Übersicht zeigt die Stückzahl und den Wert des Warenkorbs an.


32.2.3 Warenkorb ändern 
topBilder

Kommen wir nun zum letzten Schritt – zur Änderung und Versendung des Warenkorbs. Diese Seite ist relativ komplex, weil sie eine Reihe von Funktionen erfüllen muss.

Wir werden an dieser Stelle die Funktionen einzeln vorstellen und die zugehörigen Codefragmente zeigen. Am Ende dieses Abschnitts finden Sie das komplette Listing.

gpBilder
Es muss eine Schaltfläche zum Verschicken der Bestellung angeboten werden.

Dazu können Sie eine einfache Versenden-Schaltfläche (

<input type="submit" />

) verwenden. Die Formulardaten werden dann an dasjenige Skript verschickt, das im

action

-Attribut des Formulars angegeben worden ist.

In vielen Quellen finden Sie den »heißen Tipp«, die Daten ohne den Einsatz von serverseitigen Mitteln direkt per E-Mail zu verschicken:



<form method="post" enctype="text/plain"
  action="mailto:ihre.adresse@xy.de">

Dieser Code führt beim Formularversand zu einer Warnmeldung an den Benutzer – wenn der Browser das Ganze überhaupt unterstützt. Insbesondere der Internet Explorer hat mit diesem Code oft seine Probleme. Setzen Sie lieber auf serverseitige Lösungen. Wenn Ihnen diese nicht zur Verfügung stehen, verwenden Sie einen Dienst wie etwa

http://www.formmailer.com/

.

gpBilder
Alle Artikel im Warenkorb müssen ausgegeben werden. Dazu verwenden Sie eine Schleife, die so ähnlich wie die Schleife aus der Datei uebersicht_frames.html aussieht:


c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
   for (var j=0; j<c.kategorie[i].artikel.length; j++) {
      var a = c.kategorie[i].artikel[j];
      if (a.anzahl>0) {
         document.write("<p>");
         document.write("<i>" + a.nr + "</i> ");
         document.write("<b>" + a.name + "</b> ");
         document.write((a.anzahl * a.preis) + " &euro; ");
         document.write("</p>");
      }
   }
}
gpBilder
Die Anzahl der einzelnen Elemente im Warenkorb muss änderbar sein.

Dazu muss es zunächst neben jedem Element im Warenkorb noch zusätzlich ein Textfeld geben, das die aktuelle Anzahl enthält:



document.write("<input type="text" ");
document.write("name="anzahl" + a.nr + "" ");
document.write("size="2" ");
document.write("value="" + a.anzahl + "" /> ");

Eine Schaltfläche startet dann den Update-Prozess:



<input type="button" onclick="update(this.form)"
  value="Aktualisieren" />

In der Funktion

update()

werden dann in einer Schleife alle Formularelemente durchsucht, die Textfelder sind. Das

name

-Attribut besteht aus

"anzahl"

und der Bestellnummer, das

value

-Attribut gibt die gewünschte Anzahl an. Diese Werte können Sie dann als Parameter an

warenkorb_editieren_frames()

übergeben:



function update(f) {
   if (parent.frames["Code"]) {
      var c = parent.frames["Code"];
      for (var i=0; i<f.elements.length; i++) {
         if (f.elements[i].type == "text" &&
            f.elements[i].name.substring(0, 6) == "anzahl") {
            var nr = f.elements[i].name.substring(6,
                     f.elements[i].name.length);
            var anzahl = f.elements[i].value;
            anzahl = parseInt(anzahl);
            if (isNaN(anzahl)) {
               anzahl = 0;
            }
            c.warenkorb_editieren_frames(nr, anzahl);
         }
      }
   }
   if (parent.frames["Uebersicht"]) {
      parent.frames["Uebersicht"].location.reload();
   }
   location.reload();
}

Beachten Sie, dass das aktuelle Dokument am Ende der Funktion neu geladen wird. Dann werden die Änderungen, die zuvor ja nur im Variablensatz vorgenommen worden sind, auch auf der Website sichtbar.

gpBilder
Die Summe der einzelnen Artikel wird am Ende der Seite ausgegeben. Dazu müssen Sie bei der Ausgabe der einzelnen Artikel lediglich in einer Variable mitzählen, welchen Betrag Sie bereits erreicht haben.

Nachfolgend sehen Sie das komplette Skript. Dabei wurde die Ausgabe noch leicht kosmetisch aufbereitet, unter anderem durch die Verwendung einer Tabelle (siehe Abbildung 32.5):



<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Warenkorb</h1>
<form method="post" action="skript.php">
<script type="text/javascript"><!--
function update(f) {
   if (parent.frames["Code"]) {
      var c = parent.frames["Code"]; {
      for (var i=0; i<f.elements.length; i++)
         if (f.elements[i].type == "text" &&
            f.elements[i].name.substring(0, 6) == "anzahl") {
            var nr = f.elements[i].name.substring(6,
                     f.elements[i].name.length);
            var anzahl = f.elements[i].value;
            anzahl = parseInt(anzahl);
            if (isNaN(anzahl)) {
               anzahl = 0;
            }
            c.warenkorb_editieren_frames(nr, anzahl);
         }
      }
   }
   if (parent.frames["Uebersicht"]) {
      parent.frames["Uebersicht"].location.reload();
   }
   location.reload();
}

document.write("<table border="1" cellpadding="2">");

var summe = 0;
if (top.frames["Code"]) {
   var c = top.frames["Code"];
   for (var i=0; i<c.kategorie.length; i++) {
      for (var j=0; j<c.kategorie[i].artikel.length; j++) {
         var a = c.kategorie[i].artikel[j];
         if (a.anzahl>0) {
            document.write("<tr><td>");
            document.write("<input type="text" ");
            document.write("name="anzahl" + a.nr + "" ");
            document.write("size="2" ");
            document.write("value="" +a.anzahl+ "" /> ");
            document.write("</td><td>");
            document.write("<i>" + a.nr + "</i> ");
            document.write("</td><td>");
            document.write("<b>" + a.name + "</b> ");
            document.write("</td><td>");
            document.write((a.anzahl * a.preis) + " &euro; ");
            document.write("</tr>");
            summe += a.anzahl * a.preis;
         }
      }
   }
}

document.write("</table>");
//--></script>
<br>
<input type="button" onclick="update(this.form)"
  value="Aktualisieren" />
<input type="submit" value="Bestellung aufgeben" />
</form>
<a href="kategorien_frames.html">Zur&uuml;ck zur
&Uuml;bersicht</a>
</body>
</html>

Bilder

Abbildung 32.5     Letzte Änderungsmöglichkeit vor der Bestellung

Ihnen steht nun ein funktionierender Warenkorb zur Verfügung. Als Erweiterung sollen Sie nun noch beispielsweise Eingabefelder für die Adress- und Rechnungsdaten Ihrer Kunden einfügen.

 

 

32.3 Mit Cookies arbeiten 
downBilder
topBilder

Wenn Sie nicht mit Frames arbeiten können oder wollen, besteht eine Alternative darin, auf Cookies zurückzugreifen.

Mit Cookies sind Sie etwas flexibler als mit Frames, da Sie mit Cookies das Problem mit dem Öffnen von Links in einem neuen Fenster einfach umgehen können.

Das Hauptproblem besteht darin, sich ein Muster zum Speichern der Cookies zu überlegen. In Kapitel 12 wurden zwei Funktionen entwickelt, die an dieser Stelle sehr nützlich sein können:

gpBilder
schreiben_collection()
gpBilder
lesen_collection()

Mit den beiden Funktionen (die in der Datei cookies.js liegen) können Sie ein assoziatives Array schreiben, das wiederum in einem Cookie abgespeichert werden kann. So benötigen Sie nur einen einzigen Cookie, um den kompletten Warenkorb zu behalten.

Als Namen beziehungsweise Schlüssel im assoziativen Array verwenden wir die Bestellnummern, als Wert die jeweiligen Anzahlen.

Galileo ComputingBilder

32.3.1 Warenkorb füllen 
downBilder
topBilder

Die Funktion zum Füllen des Warenkorbs ist um einiges kürzer als die Funktion aus dem vorigen Abschnitt. Es gibt nämlich ein paar Unterschiede, die im Folgenden erläutert werden:

gpBilder
Die Daten werden mit den beiden zuvor genannten Funktionen aus der Datei cookies.js in einem Cookie gespeichert.
gpBilder
Die Frame-Abfragen sind nicht mehr nötig, ebenfalls muss nicht mehr direkt auf die Daten aus artikel.js zugegriffen werden. Das geschieht an anderer Stelle.

Zunächst betrachten wir, wie man von einem Artikel eine bestimmte Stückzahl zusätzlich in den Warenkorb legt:



function warenkorb_hinzufuegen_cookies(
nr, stueck) {
   var anzahl = lesen_collection(nr);
   anzahl = parseInt(anzahl); // in Integer umwandeln
   if (isNaN(anzahl)) {
      anzahl = 0;
   }
   anzahl += stueck;
   schreiben_collection(nr, anzahl);
}

Aus dem Cookie wird die aktuelle Anzahl ausgelesen und in einen Integerwert umgewandelt. Dann wird die neue Anzahl hinzuaddiert und der Wert wieder zurückgeschrieben.

Ganz ähnlich ist die Funktion aufgebaut, die einem Element im Warenkorb eine ganz bestimmte Stückzahl zuweist:



function warenkorb_editieren_cookies(
nr, stueck) {
   schreiben_collection(nr, stueck);
}

Dank der Vorarbeiten in Kapitel 12 besteht die Funktion, die zuvor noch recht umfangreich war, aus nur noch einer Codezeile.

Galileo ComputingBilder

32.3.2 Artikel anzeigen 
downBilder
topBilder

Um alle Artikel anzuzeigen, werden wieder drei verschiedene Dateien erstellt:

gpBilder
eine Seite, auf der alle Kategorien angezeigt werden: katego-rien_cookies.html
gpBilder
eine Seite, auf der alle Artikel innerhalb einer Kategorie angezeigt werden: artikel_gesamt_cookies.html
gpBilder
eine Seite, auf der ein Artikel in aller Ausführlichkeit angezeigt wird: artikel_einzeln_cookies.html

Der Hauptunterschied zu der zuvor entwickelten Lösung auf Frames-Basis ist, dass die Artikel und Kategorien auf der aktuellen Seite in JavaScript-Variablen zur Verfügung stehen, da die Datei artikel.js direkt eingebunden ist.

Ansonsten ist der Code sehr ähnlich. Die Kategorien werden aus den JavaScript-Variablen ausgelesen und in einer Schleife ausgegeben. Die Kategorienamen werden zudem mit der Datei artikel_gesamt_cookies. html verlinkt. Die Datei warenkorb.js muss wegen der in artikel.js verwendeten Konstruktorfunktionen ebenfalls eingebunden werden:



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte w&auml;hlen Sie eine Kategorie!
<ul>
<script type="text/javascript"><!--
for (var i=0; i<kategorie.length; i++) {
   document.write("<li>");
   document.write("<a href="artikel_gesamt_cookies.html?");
   document.write(escape(kategorie[i].name));
   document.write("">");
   document.write(kategorie[i].name);
   document.write("</a></li>");
}
//--></script>
</ul>
</p>
</body>
</html>

In der Datei artikel_gesamt_cookies.html werden alle Artikel aus einer Kategorie ausgegeben. Auch hier gibt es kaum einen Unterschied zur Datei artikel_gesamt_frames.html; lediglich der Zugriff auf die Daten aus artikel.js ändert sich, und die Frame-Referenz entfällt:



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte w&auml;hlen Sie einen Artikel!
<ul>
<script type="text/javascript"><!--
if (location.search.length > 1) {
   var name = location.search.substring(1,
      location.search.length);
   name = unescape(name);
   for (var i=0; i<kategorie.length; i++) {
      if (kategorie[i].name == name) {
         for (var j=0; j<kategorie[i].artikel.length; j++) {
            var a = kategorie[i].artikel[j];
            document.write("<li>");
            document.write("<a href=
              "artikel_einzeln_cookies.html?");
            document.write(escape(a.nr));
            document.write("">");
            document.write(a.name);
            document.write("</a></li>");
         }
      }
   }
}
//--></script>
</ul>
</p>
<p><a href="kategorien_cookies.html">Zur&uuml;ck zur
  &Uuml;bersicht</a></p>
<p><a href="warenkorb_cookies.html">Bestellung
  aufgeben</a></p>
</body>
</html>

Auf der Seite artikel_einzeln_cookies.html muss dann der einzelne Artikel angezeigt werden und – auf Knopfdruck – zum Warenkorb hinzugefügt werden. Auch dazu verwenden wir wieder eine Hilfsfunktion namens hinzu(), die ein wenig anders aussieht als zuvor. Sie ahnen es bereits: Alle Frame-Referenzen sind verschwunden.



function hinzu(f, nr) {
   if (f.elements["anzahl" + nr]) {
      var anzahl = f.elements["anzahl" + nr].value;
      anzahl = parseInt(anzahl); //Umwandlung in Int
      if (isNaN(anzahl)) {
         anzahl = 0;
      }
      warenkorb_hinzufuegen_cookies(nr, anzahl);
      alert("Artikel hinzugefügt!");
   }
}

AbbildungBilder

Hier klicken, um das Bild zu Vergrößern

Abbildung 32.6     Ein (mehr oder weniger) kryptischer Cookie repräsentiert den Warenkorb.

Der Rest der Seite sieht so wie oben aus, wenn man von Frame-Verweisen einmal absieht. Ebenso wird der (nicht mehr vorhandene) Übersichtsframe nicht mehr neu geladen, da diese Anweisung ins Leere führen würde:



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
<script type="text/javascript" src="cookies.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte geben Sie die St&uuml;ckzahl an!
<script type="text/javascript"><!--
function kategoriename(nr) {
   for (var i=0; i<kategorie.length; i++) {
      for (var j=0; j<kategorie[i].artikel.length; j++) {
         if (kategorie[i].artikel[j].nr == nr) {
            return kategorie[i].name;
         }
      }
   }
   return "";
}

function hinzu(f, nr) {
   if (f.elements["anzahl" + nr]) {
      var anzahl = f.elements["anzahl" + nr].value;
      anzahl = parseInt(anzahl); //Umwandlung in Int
      if (isNaN(anzahl)) {
         anzahl = 0;
      }
      _warenkorb_hinzufuegen_cookies(nr, anzahl);
      alert("Artikel hinzugefügt!");
   }
}

document.write("<ul>");

if (location.search.length > 1) {
   var nr = location.search.substring(1,
      location.search.length);
   nr = unescape(nr);
   var name = kategoriename(nr);
   for (var i=0; i<kategorie.length; i++)  {
      if (kategorie[i].name == name) {
         for (var j=0; j<kategorie[i].artikel.length; j++) {
            if (kategorie[i].artikel[j].nr == nr) {
               var a = kategorie[i].artikel[j];
               document.write("<h2>" + a.name + "</h2>");
               document.write("<b>" + a.kurz + "</b>");
               document.write("<img src="" + a.grafik + "">");
               document.write("<br>" + a.lang + "<br>");
               document.write("<form>");
               document.write("<input type="text" ");
               document.write("name="anzahl" + nr + "" ");
               document.write("size="2" value="1" /> ");
               document.write(name + " ");
               document.write(a.preis + "&euro; "); // Preis in €

               document.write("<input type="button" value="In 
                 den Warenkorb" ");
               document.write("onclick=
                 "javascript:hinzu(this.form, '" + 
                 nr + "')" /><br />");
               document.write("</form>");
            }
         }
      }
   }
   document.write("</ul><a href="artikel_gesamt_cookies.html?");
   document.write(escape(name));
   document.write("">");
   document.write("Zurück zu Kategorie " + name +"</a>");
} else {
   document.write("</ul>");
}
//--></script>
</p>
<p><a href="warenkorb_cookies.html">Bestellung
  aufgeben</a></p>
</body>
</html>

Mit relativ wenig Aufwand haben Sie die Artikelseiten des Frame-Warenkorbs in eine Lösung ohne Frames umgeschrieben, die auf Cookie-Basis arbeitet.

Galileo ComputingBilder

32.3.3 Warenkorb ändern 
topBilder
topBilder

Jetzt fehlt nur noch eine Datei: der Warenkorb. Dieser wird mit der zuvor erläuterten Taktik umgeschrieben:

gpBilder
Die Datei artikel.js wird eingebunden, ebenso die Dateien warenkorb.js und cookies.js.
gpBilder
Alle Frame-Referenzen werden entfernt.

Dass das Ganze so einfach funktioniert, liegt an der Routine zum Auslesen der Stückzahlen aus dem Cookie:



var anzahl = lesen_collection(nr);
anzahl = parseInt(anzahl); // in Integer umwandeln
if (isNaN(anzahl)) {
   anzahl = 0;
}

Auch, wenn zu einem Artikel keine Daten in dem Cookie gespeichert sind, wird die korrekte Anzahl ermittelt, in diesem Fall 0.

Werfen wir noch einen Blick auf die Aufgabenverteilung: Wir müssen hier zweigleisig fahren:

gpBilder
Die Artikelnummern werden aus den Variablen in der Datei artikel.js ermittelt.
gpBilder
Die zugehörigen Stückzahlen kommen aus dem Cookie bzw. der Cookie-Collection (mit kräftiger Mithilfe der Funktionen in der Datei cookies.js).

Ansonsten sind keine weiteren Änderungen nötig. Aus diesem Grund finden Sie im Folgenden sofort das komplette Listing:

<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
<script type="text/javascript" src="cookies.js"></script>
</head>
<body>
<h1>Warenkorb</h1>
<form method="post" action="skript.php">
<script type="text/javascript"><!--
function update(f) {
   for (var i=0; i<f.elements.length; i++) {
      if (f.elements[i].type == "text" &&
         f.elements[i].name.substring(0, 6) == "anzahl") {
         var nr = f.elements[i].name.substring(6,
                  f.elements[i].name.length);
         var anzahl = f.elements[i].value;
         anzahl = parseInt(anzahl);
         if (isNaN(anzahl)) {
             anzahl = 0;
         }
         warenkorb_editieren_cookies(nr, anzahl);
      }
   }
   location.reload();
}
document.write("<table border="1" cellpadding="2">");

var summe = 0;
for (var i=0; i<kategorie.length; i++) {
   for (var j=0; j<kategorie[i].artikel.length; j++) {
      var a = kategorie[i].artikel[j];
      var anzahl = lesen_collection(a.nr);
      if (anzahl>0) {
         document.write("<tr><td>");
         document.write("<input type="text" ");
         document.write("name="anzahl" + a.nr + "" ");
         document.write("size="2" ");
         document.write("value="" + anzahl + "" /> ");
         document.write("</td><td>");
         document.write("<i>" + a.nr + "</i> ");
         document.write("</td><td>");
         document.write("<b>" + a.name + "</b> ");
         document.write("</td><td>");
         document.write((anzahl * a.preis) + " &euro; ");
         document.write("</tr>");
         summe += anzahl * a.preis;
      }
   }
}

document.write("</table>");
//--></script>
<br />
<input type="button" onclick="update(this.form)"
  value="Aktualisieren" />
<input type="submit" value="Bestellung aufgeben" />
</form>
<a href="kategorien_cookies.html">Zur&uuml;ck zur
&Uuml;bersicht</a></body>
</html>

Der Warenkorb funktioniert nun vollständig ohne Frames, aber mit Cookies. Sie müssen die Vor- und Nachteile hier sorgfältig abwägen. Auf jeden Fall sollten Sie überprüfen, ob der Browser des Benutzers Cookies unterstützt oder nicht. Das geht in zwei Schritten (natürlich wieder unter Verwendung von Features aus Kapitel 12). Zunächst benötigen Sie eine Funktion, die einen Cookie löscht, indem ein Ablaufdatum in der Vergangenheit gesetzt wird:



function cookie_loeschen()   {
   var anzParameter = cookie_loeschen.arguments.length;
   var parameter = cookie_loeschen.arguments;
   // 1. Cookie-Name
   var name = parameter[0];
   // 2. Domain
   var domain = (anzParameter >= 2) ? parameter[1] : null;
   // 3. Pfad
   var path = (anzParameter >= 3) ? parameter[2] : null;
   if (path != null) {
      path = escape(path); // Sonderzeichen umwandeln
   }
   // 4. Sicherheitsstufe
   var secure = (anzParameter >= 4) ? parameter[3] : null;
   // Haltbarkeitsdatum
   var expires = new Date(1977, 0, 1, 0, 0, 1);
   // Aufruf von cookie_setzen
   cookie_setzen(name, "", expires, domain, path, secure);
}

Damit lässt sich die Funktion cookie_support() erstellen. Sie setzt erst ein Cookie, prüft, ob es erfolgreich gesetzt werden konnte, und löscht es dann wieder.

function cookie_support()   {
   cookie_setzen("testcookie", "ok");
   if (cookie_lesen("testcookie") == "ok") {
      cookie_loeschen("testcookie");
      return true;
   } else {
      return false;
   }
}

Sie sollten dann auf der Hauptseite Ihres Angebots eine Abfrage nach folgendem Muster integrieren:

if (!cookie_support()) {
   location.href = "keine-cookies.html";
}

Auf der Seite keine-cookies.html können Sie dann einen entsprechenden Hinweis anbringen und die Benutzer darauf hinweisen, dass sie die Cookie-Unterstützung ihrer Browser aktivieren müssen.

 

 

32.4 Über die URL 
downBilder
topBilder

Neben Cookies und JavaScript-Variablen in anderen Frames gibt es noch eine dritte Möglichkeit, Daten während mehrerer Sitzungen zu behalten: in der URL!

Sie rufen also keine Datei irgendwas.html auf, sondern rufen irgendwas.html?daten im Browser auf und fragen per JavaScript ab, was hinter dem Fragezeichen alles angegeben worden ist. Diese Methode haben wir bereits bei der Auflistung der Produkte eingesetzt. Dort wurde in der URL der Name der Produktkategorie bzw. der Bestellnummer (bei der Einzelansicht) übergeben.

Das Problem an dieser Lösung ist, dass die URL je nach Browser und Webserver eine enorme Länge hat: irgendeinen Wert zwischen 500 und 2000 Zeichen. Bei vielen Artikeln im Warenkorb könnte das zu einem echten Problem ausarten.

Ein weiteres Problem entsteht durch den Internet Explorer, der beim Zugriff auf lokale HTML-Dateien in einigen Versionen die benötigte Eigenschaft location.search nicht zur Verfügung stellt. Hier müssen Sie unter Umständen einen lokalen Webserver installieren und mit diesem Server testen.

Als Datenformat verwenden wir den Weg, den wir bereits bei der Cookie-Lösung implementiert hatten. Nur dürfen dieses Mal die Daten nicht in Cookies gespeichert werden, sondern müssen über die URL an die nächste Seite weitergeleitet werden. Dazu verwenden wir den Code aus den entsprechenden Cookie-Versionen, aber schreiben das Ergebnis nicht in einen Cookie, sondern liefern es zurück. Beim Auslesen der Daten wird ebenfalls nicht auf den Cookie zugegriffen, sondern auf die URL.

Bei den Artikelübersichtsseiten wird in der URL die Bestellnummer oder der Kategoriename der Artikel übergeben. Hier müssen also besondere Vorkehrungen getroffen werden. Im Folgenden unterscheiden wir daher zwei Fälle:

gpBilder
In der URL werden nur die Warenkorb-Daten übergeben. Dann werden diese einfach an den Dateinamen angehängt: datei.html?warendaten
gpBilder
In der URL werden neben den Warenkorb-Daten auch noch weitere Daten wie etwa die Bestellnummer des anzuzeigenden Artikels übergeben. Dann werden diese beiden Daten durch ein kaufmännisches Und (&) getrennt: datei.html?anderedaten&warenkorbdaten

Damit lassen sich die Hilfsfunktionen – in Anlehnung an die entsprechenden Cookie-Funktionen – erstellen:



var warenkorb_daten = warenkorb_laden_collection();

function warenkorb_laden_collection() {
   var ls = location.search;
   if (ls.length > 1) {
      if (ls.indexOf("&") > –1) {
         var str = ls.substring(ls.indexOf("&") + 1,
                                ls.length);
      } else {
         var str = ls.substring(1, ls.length);
      }
   }
   str = unescape(str);
   var temp = new Array();
   // Daten aus der URL in ein Array umwandeln
   if (str != "") {
      str = str.replace(/,/g, "","");
      str = str.replace(/</g, "");
      str = str.replace(/>/g, "");
      str = """ + str + """;
      eval("temp = [" + str + "]");
   }
   // assoziatives Array erstellen
   var c = new Array();
   for (var i=0; i<temp.length; i+=2) {
      c[temp[i]] = temp[i+1];
   }
   // Array zurückgeben
   return c;
}

function warenkorb_lesen_collection(
name) {
   return warenkorb_daten[name];
}

function warenkorb_speichern_collection()
   {
   var temp = new Array();
   for (var e in warenkorb_daten) {
      temp[temp.length] = e;
      temp[temp.length] = warenkorb_daten[e];
   }

   return temp.toString();
}

function warenkorb_schreiben_collection(
name, wert) {
   warenkorb_daten[name] = wert;
   warenkorb_speichern_collection();
}

Der Rest gestaltet sich fast genauso wie bei der Cookie-Lösung.

Galileo ComputingBilder

32.4.1 Den Warenkorb füllen 
downBilder
topBilder

Die Funktionen für das Füllen des Warenkorbs müssen als Erstes angepasst werden:



function warenkorb_hinzufuegen_url(
nr, stueck) {
   var anzahl = warenkorb_lesen_collection(nr);
   anzahl = parseInt(anzahl); // in Integer umwandeln
   if (isNaN(anzahl)) {
      anzahl = 0;
   }
   anzahl += stueck;
   warenkorb_schreiben_collection(nr, anzahl);
}

function warenkorb_editieren_url(
nr, stueck) {
   warenkorb_schreiben_collection(nr, stueck);
}

Damit stehen nun die notwendigen Hilfsfunktionen zur Verfügung, die bei den Artikelseiten und auf der Warenkorb-Seite aufgerufen werden müssen.

Galileo ComputingBilder

32.4.2 Artikel anzeigen 
downBilder
topBilder

Zur Anzeige der einzelnen Artikel werden auch dieses Mal drei Dateien erstellt:

gpBilder
eine Seite, auf der alle Kategorien in einer Übersicht angezeigt werden: kategorien_url.html
gpBilder
eine Seite, auf der alle Artikel einer Kategorie angezeigt werden: artikel_gesamt_url.html
gpBilder
eine Seite, auf der alle Informationen über einen Artikel angezeigt werden (und auf der auch bestellt werden kann): artikel_einzeln_url.html

Wir beginnen wieder mit der Übersicht über alle Kategorien. Der einzige Unterschied zur Cookie-Lösung ist folgender: Sollten schon Daten in der URL stehen (also schon Artikel im Warenkorb vorhanden sein), müssen diese bei jedem Link weiter übergeben werden.



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte w&auml;hlen Sie eine Kategorie!
<ul>
<script type="text/javascript"><!--
for (var i=0; i<kategorie.length; i++) {
   document.write("<li>");
   document.write("<a href="artikel_gesamt_url.html?");
   document.write(escape(kategorie[i].name));
   if (location.search.length > 0) {
      document.write("&" + location.search.substring(1,
                           location.search.length));
   }
   document.write("">");
   document.write(kategorie[i].name);
   document.write("</a></li>");
}
//--></script>
</ul>
</p>
</body>
</html>

Im nächsten Schritt werden alle Artikel einer Kategorie angezeigt, und zwar in der Datei artikel_gesamt_url.html. Beachten Sie bei den Änderungen, dass die Daten in der URL auf jeden Fall weitergegeben werden müssen! Wenn Sie diesen Parameter an einer Stelle weglassen, sind damit die gesamten Bestellinformationen verloren.



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte w&auml;hlen Sie einen Artikel!
<script type="text/javascript"><!--
document.write("<ul>");

var ls = location.search;
if (ls.length > 1) {
   if (ls.indexOf("&") > –1) {
      var name = ls.substring(1, ls.indexOf("&"));
      var daten = ls.substring(ls.indexOf("&")+1, ls.length);
   } else {
      var name = location.search.substring(1,
         location.search.length);
      var daten = "";
   }
   name = unescape(name);

   for (var i=0; i<kategorie.length; i++) {
      if (kategorie[i].name == name) {
         for (var j=0; j<kategorie[i].artikel.length; j++) {
            var a = kategorie[i].artikel[j];
            document.write("<li>");
            document.write("<a href="artikel_einzeln_url.html?");
            document.write(escape(a.nr));
            if (daten != "") {
               document.write("&" + daten);
            }
            document.write("">");
            document.write(a.name);
            document.write("</a></li>");
         }
      }
   }
}
document.write("</ul></p><p>");
document.write("<a href="kategorien_url.html?" +
   escape(warenkorb_speichern_collection()) +
   "">Zurück zur Übersicht </a></p><p>");
document.write("<a href="warenkorb_url.html?" +
   escape(warenkorb_speichern_collection()) +
   "">Bestellung aufgeben</a></p>");
//--></script>
</body>
</html>

Jetzt fehlt nur noch eine Datei: artikel_einzeln_url.html. Dort wird die Einzelansicht für den Artikel präsentiert. Ein wichtiges Element dieser Seite ist die Funktion hinzu(), die einen Artikel zum Warenkorb hinzufügt:



function hinzu(f, nr) {
  if (f.elements["anzahl" + nr]) {
    var anzahl = f.elements["anzahl" + nr].value;
    anzahl = parseInt(anzahl); //Umwandlung in Int
    if (isNaN(anzahl)) {
      anzahl = 0;
    }
    warenkorb_hinzufuegen_url(nr, anzahl);
    alert("Artikel hinzugefügt!");
    location.search = "?" + escape(nr)
       + "&" + escape(warenkorb_speichern_collection());
   }
}

Die Daten werden im Array warenkorb_daten gespeichert, das in der Seite definiert ist. Sie müssen lediglich bei allen Links den neuen Datenbestand weitergeben. Deswegen müssen Sie an jeden Link die entsprechenden Daten anfügen. Sie erhalten diese Daten, wie Sie bereits in den vorhergehenden Listings gesehen haben, über folgenden Funktionsaufruf:



escape(warenkorb_speichern_collection())

Hier folgt der komplette Code der Seite:



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte geben Sie die St&uuml;ckzahl an!
<script type="text/javascript"><!--
function kategoriename(nr) {
   for (var i=0; i<kategorie.length; i++) {
      for (var j=0; j<kategorie[i].artikel.length; j++) {
         if (kategorie[i].artikel[j].nr == nr) {
            return kategorie[i].name;
         }
      }
   }
   return "";
}

function hinzu(f, nr) {
   if (f.elements["anzahl" + nr]) {
      var anzahl = f.elements["anzahl" + nr].value;
      anzahl = parseInt(anzahl); //Umwandlung in Int
      if (isNaN(anzahl)) {
         anzahl = 0;
      }
      warenkorb_hinzufuegen_url(nr, anzahl);
      alert("Artikel hinzugefügt!");
      location.search = "?" + escape(nr)
         + "&" + escape(warenkorb_speichern_collection());
   }
}

document.write("<ul>");

var ls = location.search;
if (ls.length > 1) {
   if (ls.indexOf("&") > –1) {
      var nr = ls.substring(1, ls.indexOf("&"));
      var daten = ls.substring(ls.indexOf("&")+1, ls.length);
   } else {
      var nr = location.search.substring(1,
         location.search.length);
      var daten = "";
   }
   nr = unescape(nr);
   var name = kategoriename(nr);
   for (var i=0; i<kategorie.length; i++) {
      if (kategorie[i].name == name) {
         for (var j=0; j<kategorie[i].artikel.length; j++) {
            if (kategorie[i].artikel[j].nr == nr) {

               var a = kategorie[i].artikel[j];
               document.write("<h2>" + a.name + "</h2>");
               document.write("<b>" + a.kurz + "</b>");
               document.write("<img src="" + a.grafik + 
                 "" />");
               document.write("<br>" + a.lang + "<br>");
               document.write("<form>");
               document.write("<input type="text" ");
               document.write("name="anzahl" + nr + "" ");
               document.write("size="2" value="1" /> ");
               document.write(name + " ");
               document.write(a.preis + "&euro; "); // Preis in €
               document.write("<input type="button" value="In
                 den Warenkorb" ");
               document.write("onclick=
                 "javascript:hinzu(this.form, '" + nr + "')" />
                 <br />");
               document.write("</form>");
            }
         }
      }
   }
   document.write("</ul><a href="artikel_gesamt_url.html?");
   document.write(escape(name));
   var d = warenkorb_speichern_collection();
   document.write("&" + escape(d));
   document.write("">");
   document.write("Zurück zu Kategorie " + name +"</a>");
} else {
   document.write("</ul>");
}

document.write("</p><p>");
document.write("<a href="warenkorb_url.html?" +
   escape(warenkorb_speichern_collection()) +
   "">Bestellung aufgeben</a></p>");
//--></script>
</body>
</html>

Bilder

Abbildung 32.7     Im Feld Location sehen Sie die kryptische URL mit den Warenkorb-Daten.


32.4.3 Den Warenkorb ändern 
topBilder

Zum Abschluss des Beispiels fehlt noch eine Seite, und zwar der Warenkorb selbst. Das Codestück für das Neuladen einer Seite nach einer Änderung muss (im Vergleich zur Cookie-Lösung) am stärksten geändert werden. Sie müssen hier wie folgt vorgehen:

gpBilder
Zunächst nehmen Sie die Änderungen am Array vor.
gpBilder
Dann lassen Sie sich das zum String gemachte Array von warenkorb_speichern_collection() zurückgeben.
gpBilder
Diesen Wert hängen Sie – nach Vorbehandlung mit escape() – an die URL an und laden dadurch die Seite neu.

Without any further ado – also ohne weitere Vorrede – folgt hier der Code:



<html>
<head>
<title>Online-Shop</title>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body>
<h1>Warenkorb</h1>
<form method="post" action="skript.php">
<script type="text/javascript"><!--
function update(f) {
   for (var i=0; i<f.elements.length; i++) {
      if (f.elements[i].type == "text" &&
         f.elements[i].name.substring(0, 6) == "anzahl") {
         var nr = f.elements[i].name.substring(6,
                  f.elements[i].name.length);
         var anzahl = f.elements[i].value;
         anzahl = parseInt(0 + anzahl);
         warenkorb_editieren_url(nr, anzahl);
      }
   }
   location.search = "?" +
      escape(warenkorb_speichern_collection());
}

document.write("<table border="1" cellpadding="2">");

var summe = 0;
for (var i=0; i<kategorie.length; i++) {
   for (var j=0; j<kategorie[i].artikel.length; j++) {
      var a = kategorie[i].artikel[j];
      var anzahl = warenkorb_lesen_collection(a.nr);
      if (anzahl>0) {
         document.write("<tr><td>");
         document.write("<input type="text" ");
         document.write("name="anzahl" + a.nr + "" ");
         document.write("size="2" ");
         document.write("value="" + anzahl + "" /> ");
         document.write("</td><td>");
         document.write("<i>" + a.nr + "</i> ");
         document.write("</td><td>");
         document.write("<b>" + a.name + "</b> ");
         document.write("</td><td>");
         document.write((anzahl * a.preis) + " &euro; ");
         document.write("</tr>");
         summe += anzahl * a.preis;
      }
   }
}

document.write("</table>");
//--></script>
<br />

<input type="button" onclick="update(this.form)"
  value="Aktualisieren" />
<input type="submit" value="Bestellung aufgeben" />
</form>
<script type="text/javascript"><!--
document.write("<a href="kategorien_url.html?" +
  escape(warenkorb_speichern_collection()) +
  "">Zur&uuml;ck zur &Uuml;bersicht</a>");
//--></script>
</body>
</html>

 

 

 

32.5 Fazit 
topBilder
topBilder

Sie haben in diesem Kapitel drei unterschiedliche Ansätze kennengelernt, einen Warenkorb mit JavaScript zu realisieren. Welchen dieser Ansätze Sie für Ihre Website verwenden, ist Ihren persönlichen Präferenzen überlassen. Um Ihnen die Entscheidung ein wenig zu erleichtern – oder um sie zumindest mit einigen Argumenten zu untermauern –, führen wir im Folgenden noch einige der Nachteile der jeweiligen Alternativen auf.

Gegen die Lösung mit Frames spricht Folgendes:

gpBilder
Beim Öffnen eines Links in einem neuen Fenster funktioniert der Warenkorb nicht mehr.
gpBilder
Beim Öffnen eines Links in einem neuen Fenster funktioniert der Warenkorb nicht mehr. (Das ist so ein schwerwiegender Nachteil, dass er gleich zweimal erwähnt wird.)

Die Lösung mit Cookies könnte an Folgendem scheitern:

gpBilder
Viele Benutzer (oder Systemverwalter) deaktivieren Cookies.
gpBilder
Da auf jeder Seite ein Cookie gesetzt wird, werden Benutzer, die sich vom Browser Warnmeldungen beim Eintreffen eines Cookies anzeigen lassen, langsam, aber sicher wahnsinnig und deaktivieren im schlimmsten Fall ebenfalls die Cookies.

Gegen die URL-Lösung spricht Folgendes:

gpBilder
Die URL wird unter Umständen sehr lang.
gpBilder
Das Setzen von Bookmarks ist nicht möglich.
gpBilder
Der Shop kann nicht in mehreren Fenstern gleichzeitig betrachtet werden (das eine Fenster bekommt die Änderungen im anderen Fenster nicht mit).

Der größte Nachteil von allen Ansätzen besteht darin, dass der Browser des Benutzers JavaScript unterstützen muss. Für »echte« E-Commerce-Anwendungen sollten Sie also auf serverseitige Mittel setzen. Für den Hausgebrauch und kleinere Firmen kommen Sie auch mit den in diesem Kapitel vorgestellten Listings sehr weit.

 

Das Tutorial ist ein Auszug aus der 7. Auflage des Buches von Christian Wenz:

JavaScript und Ajax - Das umfassende Handbuch
Galileo Computing, 853 Seiten, 8. aktualisierte Auflage

Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von Galileo Press.

Mehr Informationen zum aktualisierten Fachbuch für Webentwickler gibt es hier: JavaScript und Ajax
 
Alle Kapitel des Buches:
1 Grundlagen
2 JavaScript-Praxis
3 Professionelles JavaScript
4 Web 2.0 und Ajax
5 Kommunikation
6 Serverseitige Programmierung
7 Sicherheit
8 Praxis
9 Anhang
Bilder


 

Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von AMielke
  • 23.02.2012 - 09:00

Ich bitte um Verzeihlichung, aber dieser Download ist unsinnig. In der PDF-Datei ist keinerlei Codebeispiel zu sehen oder fast keines. Kann also die Beispiele nicht nachbauen.

x
×
×