Eine exemplarische Gegenüberstellung von Web Toolkit, Silverlight und AngularJS

Diplomarbeit zur Erlangung des akademischen Grades Mag. rer. soc. oec. im Diplomstudium Wirtschaftsinformatik

Eingereicht von: Michael WALTER (9655406)

Angefertigt am: Institut für Wirtschaftsinformatik - Software Engineering

Beurteiler: a. Univ.-Prof. Dr. Alois Stritzinger

Juni 2015 Inhaltsverzeichnis

1 Einleitung – Problembeschreibung...... 7 2 Merkmale von Rich Internet Applications...... 9 3 Anforderungsspezifikation der Beispielanwendung...... 12 3.1 Zielbestimmungen...... 12 3.2 Produkteinsatz...... 12 3.3 Produktfunktionen...... 12 3.4 Produktdaten...... 15 3.5 Produktleistungen...... 16 3.6 Qualitätsanforderungen...... 16 3.7 Ergänzungen...... 16 4 Client-Server-Kommunikation...... 18 4.1 Klassische, seitenbasierte Webapplikation...... 18 4.2 HTML-Anwendungen mit AJAX...... 19 4.3 Same Origin Policy (SOP)...... 28 4.4 SOP beim Browser deaktivieren...... 31 5 Serverseitige Infrastruktur...... 36 6 Datenquelle...... 39 6.1 Datenbankmanagementsystem MySQL...... 39 6.2 Zugriff mit PHP auf eine MySQL-Datenbank...... 43 6.3 Serverseitige Funktionalitäten...... 44 6.4 Zeitbasierte Ausführung mit Cron...... 50 7 Schichtenmodelle (MVC - MVVM)...... 51 8 (GWT)...... 55 8.1 Entwicklungsumgebung...... 55 8.2 Neues Projekt erstellen...... 56 8.3 RIA im Development-Mode ausführen...... 57

Seite 2 / 136 8.4 RIA im Production-Mode ausführen...... 60 8.5 Aufbau einer GWT-Anwendung...... 61 8.6 GWT-Widgets...... 62 8.7 Einbindung externer Module...... 68 8.8 JavaScript Native Interface (JSNI)...... 69 8.9 Kommunikation mit dem Server...... 70 8.10 GWT - Fazit...... 76 9 Silverlight...... 78 9.1 Entwicklungsumgebung...... 78 9.2 Extensible Application Markup Language (XAML)...... 81 9.3 Programmaufbau...... 83 9.4 GUI-Komponenten - UserControls...... 84 9.5 GUI- - ChildWindow...... 89 9.6 Datenbindung...... 90 9.7 Kommunikation Client-Server...... 92 9.8 Silverlight - Fazit...... 94 10 AngularJS...... 97 10.1 Entwicklungsumgebung...... 97 10.2 Direktiven...... 98 10.3 Templates...... 106 10.4 Filter...... 108 10.5 Two-Way-Data-Binding...... 109 10.6 ...... 110 10.7 Services...... 111 10.8 Routes...... 113 10.9 AngularJS - Fazit...... 115 11 Vergleich der Frameworks...... 117 11.1 Allgemein...... 117

Seite 3 / 136 11.2 Kommunikation...... 119 11.3 Framework-Features...... 121 11.4 Elemente der Benutzerschnittstellen...... 122 11.5 RIA-Implementierungen: Portfoliomanager...... 125 11.6 Praktische Verwendbarkeit der RIAs...... 127 11.7 Vergleich - Fazit...... 130

Seite 4 / 136 Eigenständigkeitserklärung

Ich erkläre an Eides statt, dass ich die vorliegende Diplomarbeit selbstständig und ohne fremde Hilfe verfasst, andere als die angegebenen Quellen und Hilfsmittel nicht benutzt bzw. die wörtlich oder sinngemäß entnommenen Stellen als solche kenntlich gemacht habe. Die vorliegende Diplomarbeit ist mit dem elektronisch übermittelten Textdokument identisch.

______Datum Unterschrift

Seite 5 / 136 Danksagungen

An dieser Stelle möchte ich mich bei allen Personen bedanken, die mich während der Erstellung dieser Arbeit motiviert und unterstützt haben.

Ich bedanke mich besonders bei meinem Betreuer, Herrn a. Univ.-Prof. Dr. Alois Stritzinger, der jahrelang meine Arbeit und somit auch mich betreute. Vielen Dank für Ihre Geduld!

Weiterer Dank gebührt meinem Kollegen, Herrn DI Mag. Wolfgang Fischer, für die zahlreichen Stunden, in denen er diese Arbeit Korrektur gelesen hat und dem zu verdanken ist, dass einige Rechtschreib-, Beistrich-, und Fallfehler aus diesem Dokument flogen.

Ich bedanke mich natürlich auch bei meiner Partnerin Helene Knoll, die mich immer wieder ermutigte, diese Arbeit abzuschließen. Danke für dein Verständnis an den vielen Abenden, die du allein verbringen musstest, während ich diese Arbeit schrieb.

Mein besonderer Dank gilt meinen Eltern Nelly und Reinalt, die mir dieses Studium erst ermöglichten und mich in meinen Entscheidungen unterstützt haben. Danke für die moralische und finanzielle Unterstützung und verzeiht mir die Sorgen, die ich euch sicher öfters bereitet habe.

Seite 6 / 136 1 Einleitung – Problembeschreibung

Meinen ersten Kontakt mit dem Internet hatte ich im ersten Studienjahr. Meine Freunde und ich verbrachten viele Nächte vor den Bildschirmen im Computerlabor des TNF-Turms, um die Welt des World-Wide-Webs zu erkunden. An einen eigenen Internetanschluss war zu dieser Zeit noch nicht zu denken. Faszinierend fand ich nicht nur all die Informationen, die man auf statischen Webseiten finden konnte, sondern auch, dass sich Webseiten ändern konnten, je nachdem welche Daten in Formulare eingegeben wurden. Einige Semester später war ich schon fähig, eine Internetanwendung für eine Grundstücksbörse zu implementieren. Diese wurde mit PHP und MySQL realisiert und funktionierte komplett ohne JavaScript, Sessions oder Cookies. Die Benutzeroberfläche war noch durchwegs statisch, was aber den damaligen Internetstandards entsprach. In den Ferien des zweiten Studienabschnitts arbeitete ich drei Sommer bei der Siemens AG – Zentrale Technik in München. Im Sommer 2004 war meine Aufgabe, eine Desktopanwendung in eine Webapplikation umzuwandeln. Damals half ich mir mit automatisch erstellten Screenshots der Desktopanwendung, die in der HTML-Seite mit sensiblen Bereichen (maps) unterlegt wurde. Diese sensiblen Bereiche waren Links auf weitere Screenshots oder simple Formularseiten, mit denen Werte erfasst und geändert werden konnten. Die Webapplikation funktionierte zwar, aber die Benutzeroberfläche und Benutzerführung war kompliziert und umständlich und die Internetanwendung kam in keinster Weise an die Produktivität der Desktopanwendung heran. Jetzt weiß ich, dass damals bei Siemens eine Rich Internet Applikation von mir verlangt wurde. Nur war zu dieser Zeit der Begriff der RIA noch nicht gebräuchlich. Sucht man heute im Word-Wide-Web nach „Rich Internet Application“ findet man schnell Frameworks, die versprechen, den Programmierer bei der Umsetzung seiner RIA zu unterstützen. Doch nun steht der Programmierer vor einem weiteren Problem: Welches Framework sollte er verwenden?

Seite 7 / 136 Bei der Lösung dieses Problems will ich mit dieser Arbeit helfen. Ich habe mir folgende drei Frameworks für die weitere Arbeit ausgesucht: • GWT – Google Web Toolkit • MS Silverlight • AngularJS Um einen Vergleich anstellen zu können, wurde in Absprache mit meinem Betreuer eine Beispielanwendung spezifiziert, die mit jedem der drei Frameworks implementiert wurde. Bei der Beispielanwendung handelt es sich um ein Börseninformationssystem mit Portfoliofunktion für die Werte des ATX und ATX-Prime mit grafischer Unterstützung durch ein Liniendiagramm. Bei der Implementierung sollte der Funktionsumfang jedes Frameworks möglichst gut ausgenutzt werden. Da es bei dieser Arbeit vor allem um die RIA-Clients geht, wird die Datenhaltung am Server nur ein einziges Mal implementiert und von allen drei Clients benutzt. Ziel, neben den drei lauffähigen RIAs, sollten Erkenntnisse sein, welches Framework für welche Aufgaben empfohlen werden kann.

Seite 8 / 136 2 Merkmale von Rich Internet Applications

RIA wird mit Rich Internet Application oder auch mit Rich Interactive Application übersetzt, wobei sich momentan der Begriff Rich Internet Application durchgesetzt hat. Im Folgenden wurden Definitionen zusammengestellt, um zu erkennen, was eine RIA ausmacht: Nach Janssen handelt es sich bei einer RIA um eine Webapplikation, die das Erscheinungsbild und viele Eigenschaften einer Desktopapplikation hat. Eine RIA benötigt zur Ausführung einen Browser, ein Browserplugin oder eine virtuelle Maschine. Die Datenmanipulation geschieht am Server, während die Darstellung der Client übernimmt [Janssen]. Rouse sieht eine RIA ähnlich wie Janssen: Eine RIA ist eine Webapplikation, welche Eigenschaften und Funktionen zur Verfügung stellen sollte, wie sie von einer Desktopapplikation erwartet werden. RIAs verteilen die Berechnungen der Benutzeroberfläche auf den Client und die Datenmanipulation auf den Server. RIAs laufen normalerweise in einem Webbrowser und benötigen meistens keine zusätzliche Softwareinstallation. Wegen Sicherheitsbedenken laufen RIAs in einem speziell isolierten Bereich auf dem Client, auch Sandbox genannt. Diese Sandbox beschränkt den Zugriff auf das Datei- und Betriebssystem. [Rouse 2007] Adobe hat mit seinem Produkt „“ eine Plattform für RIAs im Angebot. Auf der Seite von Adobe werden RIAs folgendermaßen beschrieben: RIAs bieten eine reichhaltige und bezaubernde Erfahrung (der Benutzerschnittstelle), welche die Benutzerzufriedenheit verbessern und die Produktivität steigern. [Adobe 2015] -Experte Leahy definiert eine RIA so: Eine RIA läuft normalerweise innerhalb einer Webseite, stellt aber die selbe Funktionalität zur Verfügung, wie eine Desktopapplikation. RIAs stellen mehr Funktionalitäten als herkömmliche Webapplikationen zur Verfügung, zum Beispiel: Animationen oder Drag&Drop.[Leahy 2015] Laut Crane zeichnet sich ein Rich Client durch zwei Schlüsselmerkmale aus: Er ist reich (reichhaltig), und er ist ein Client. Als Maßstab für die Reichhaltigkeit

Seite 9 / 136 des Interaktionsmodells orientiert sich Crane an dir derzeitigen Generation von Desktopanwendungen wie Textverarbeitungs- oder Tabellenkalkulations- programme [Crane et al. 2006]. Die oben genannten Definitionen lassen sich nun zusammenfassen: Eine RIA läuft in einer Browserumgebung. Der RIA-Client ist für eine an Interaktionsmöglichkeiten reichhaltige Benutzerschnittstelle ähnlich einer Desktopanwendung zuständig, während der Server für die Datenhaltung und -manipulation zuständig ist, und den Client mit Daten versorgen muss.

Abbildung 1: Barly Out Of Beta [Hunter 2007]

Einige Technologien für RIAs benötigen zusätzliche Browserplugins, andere kommen mit den Bordmitteln des Browsers, HTML und JavaScript mit AJAX aus. Adobe Flash und benötigen das Plugin des Adobe Flashplayers, benötigt das Silverlight-Plugin für Windows bzw. das -Plugin für und Java-Applets bzw. JavaFX benötigt das Java- Plugin unter Windows bzw. das IcedTea-Plugin unter Linux. Will ein Anwender RIA-Technologien verwenden, die Plugins benötigen, muss er zusätzliche Software installieren. Dabei können folgende Probleme auftreten wenn das Plugin noch nicht installiert ist: • Der Benutzer will das Plugin nicht installieren, weil er keine Zeit für die Installation investieren will. • Der Benutzer will das Plugin nicht installieren, weil er nicht durch Sicherheitslücken der Plugins angreifbar sein will.

Seite 10 / 136 • Der Benutzer kann das Plugin nicht installieren, weil ihm das notwendige Know-How fehlt. • Der Benutzer kann das Plugin nicht installieren, weil ihm die nötigen Rechte fehlen. • Der Benutzer kann das Plugin nicht installieren, weil es für seine Plattform (vor allem bei mobilen Geräten wie Smartphones oder Tablets) nicht verfügbar ist. • Der Benutzer kann das Plugin nicht nutzen, weil es vom Browser wegen Sicherheitsbedenken standardmäßig deaktiviert ist und dem Benutzer das Know-How fehlt, es zu aktivieren. • Der Benutzer kann das Plugin nicht nutzen, weil es vom Browser wegen Sicherheitsbedenken gesperrt ist. Egal, wieso der Benutzer das Plugin nicht benutzen will oder kann: Er wird die RIA nicht starten und somit auch nicht nutzen können.

Framework Windows Linux Typ Adobe Flash Adobe Flashplayer Apache Flex MS - Silverlight Silverlight-Plugin Moonlight-Plugin Plugins Java-Applets Java-Plugin IceTea-Plugin JavaFX GWT AngularJS HTML5 und JavaScript mit AJAX Ember.js (direkt im Browser ohne zusätzlich Software lauffähig) Dojo jQuery UI Tabelle 1: RIA-Frameworks - Plugin oder HTML5

Wenn eine RIA erstellt werden soll, die für viele Benutzer mit unterschiedlichen Plattformen und Browser erreichbar sein soll bzw. sogar erreichbar sein muss, sollte auf Frameworks, die Plugins benötigen, verzichtet werden.

Seite 11 / 136 3 Anforderungsspezifikation der Beispielanwendung

3.1 Zielbestimmungen Der Benutzer kann sich über das Internet über die Kurse des ATX, ATX-Prime und deren enthaltene Werte informieren. Weiters kann der Benutzer Aktien in Portfolios organisieren und deren Performance grafisch mit einem Liniendiagramm darstellen lassen. Die Portfolios sind durch Benutzername und Passwort vor öffentlichem Zugriff geschützt.

3.2 Produkteinsatz Dieses System ist für Benutzer gedacht, die sich über die Kurse bzw. Kursentwicklungen im ATX bzw. ATX-Prime informieren möchten. Das System ist auch geeignet, Portfolios ohne Risiko zusammenzustellen und deren Performance zu beobachten.

3.3 Produktfunktionen

3.3.1 Benutzerfunktionen Ein Benutzer kann das System erst nutzen, wenn er registriert und angemeldet ist.

/LF0110/ Ein Benutzer kann sich durch Bekanntgabe von Benutzername, Passwort und E-Mail-Adresse registrieren. Das Passwort wird codiert übertragen und gespeichert.

/LF0120/ Ein Benutzer kann sich unter Angabe von Benutzername und Passwort am System anmelden. Das Passwort wird codiert übertragen.

/LF0130/ Der angemeldete Benutzer kann sich vom System abmelden.

3.3.2 Portfoliofunktionen Portfoliofunktionen sind nur für angemeldete Benutzer verfügbar.

/LF0210/ Alle Portfolios des Benutzers werden in Tabs angezeigt.

/LF0220/ Der Benutzer kann zwischen seinen Portfolios wechseln.

/LF0230/ Der Benutzer kann ein neues Portfolio unter Angabe von Portfolionamen und Startbetrag des Kontos anlegen. Es wird ein Eintrag zur Kontoführung hinzugefügt. Es wird ein neuer Portfoliotab hinzugefügt.

Seite 12 / 136 /LF0240/ Der Benutzer kann eine Aktienposition unter Angabe der Aktie (Auswahl über Dropdown), Stückanzahl, Kaufpreis pro Stück, Spesen und Kaufdatum kaufen und zu einem Portfolio hinzufügen. Der Betrag des Kontos verringert sich um die Spesen und das Produkt von Kaufpreis mal Stückanzahl. Es wird ein Eintrag zur Kontoführung hinzugefügt.

/LF0250/ Der Benutzer kann Aktien unter Angabe der Aktie (Auswahl über Dropdown), Verkaufspreis pro Aktie, Aktienanzahl, Spesen und Verkaufsdatum verkaufen. Der Kontostand verringert sich um die Spesen und erhöht sich um das Produkt Aktienanzahl mal Verkaufspreis. Es wird ein Eintrag zur Kontoführung hinzugefügt.

/LF0260/ Alle zehn Sekunden werden die Werte der Aktien aktualisiert.

3.3.3 Chartfunktionen Am Bildschirm ist ein Liniendiagramm verfügbar: Auf der vertikale Achse werden die Werte der Aktien und Indizes (absolut bzw. relativ) eingetragen, die horizontale Achse steht für den zeitlichen Verlauf.

/LF0310/ Das Liniendiagramm kann maximal fünf Datenreihen (Linien) anzeigen. Das Diagramm beinhaltet eine Legende.

/LF0320/ Das Liniendiagramm zeigt standardmäßig die Performance des Portfolios in EURO der letzten sechs Monate an. Es ist nur eine Linie sichtbar.

/LF0330/ Alle Aktien des ATX-Prime, der ATX, der ATX-Prime, der Kontostand des Portfolios, die Summe der Aktienwerte des Portfolios und den Gesamtwert des Portfolios (Kontostand plus Aktienwerte) können als Datenreihen ausgewählt werden. Die Auswahl erfolgt über ein Drop-Down. Das Diagramm aktualisiert sich bei einer Änderung automatisch.

/LF0340/ Das Diagramm kann drei verschiedene Darstellungsformen anzeigen: absolut, relativ und Referenzwert. Bei einer Änderung der Darstellungsform aktualisiert sich das Diagramm automatisch.

/LF0350/ Die absolute Darstellungsform zeigt die absoluten Werte der Datenreihen an.

/LF0360/ Die relative Darstellungsform zeigt jede Datenreihe relativ zum ersten Datenpunkt (Startdatum), welcher mit 100 % angenommen wird, an.

Seite 13 / 136 /LF0370/ Die Darstellungsform Referenzwert nimmt die erste Datenreihe als Referenzwert mit 100 % an. Alle anderen Datenreihen berechnen sich nun relativ zur ersten Datenreihe und dem ersten Datenpunkt (Startdatum).

/LF0380/ Das Start- und Enddatum kann frei gewählt werden. Die Datumseingabe wird durch ein Datumseingabefeld vereinfacht, welches nur gültige Daten zulässt. Das Diagramm aktualisiert sich bei Änderung des Start- bzw. Enddatums automatisch.

3.3.4 Portfoliokontofunktionen Zu jedem Portfolio werden alle relevanten Aktivitäten wie • Eröffnung eines Portfolios • Kauf einer Aktie • Verkauf einer Aktie gespeichert.

/LF0410/ Alle relevanten Aktivitäten im Portfolio werden tabellarisch und chronologisch sortiert mit den Spalten Datum, Betrag und Kommentar angezeigt.

3.3.5 Indexfunktionen Die Anwendung hat noch zwei zusätzliche Menüpunkte: Einen für den Index ATX und einen für den Index ATX-Prime.

/LF0510/ Der Benutzer kann sich mit einem Chart über den ausgewählten Index (ATX oder ATX-Prime) informieren (siehe 3.3.3 Chartfunktionen).

/LF0520/ Änderung bei Indexfunktionen zu /LF0320/: Das Liniendiagramm zeigt standardmäßig die Performance des Index in EURO der letzten sechs Monate an. Es ist nur eine Linie sichtbar.

/LF0530/ Änderung bei Indexfunktionen zu /LF0330/: Als Datenreihen für das Chart sind nur die Aktien des ausgewählten Index und der Index an sich verfügbar.

/LF0540/ Alle Werte des Index sind tabellarisch mit ISIN, Aktienbezeichnung und Wert aufgeführt.

Seite 14 / 136 3.3.6 Funktionen für die Datenhaltung Die Datenhaltung übernimmt ein Datenbankserver. Die Schnittstelle zum Datenbankserver erfolgt über das HTTPS-Protokoll mit PHP-Skripts.

/LF0610/ Das System aktualisiert die Werte in der Datenbank für alle Aktien- und Indizeskurse täglich. Die Speicherung der täglichen Schlusskurse ist dabei ausreichend.

3.4 Produktdaten Folgende Daten sind persistent abzuspeichern:

/LD010/ Die Benutzerdaten umfassen • Benutzername • Passwort • E-Mail-Adresse

/LD020/ Die Portfoliodaten umfassen den Portfolionamen und alle Aktiendaten, auch jene, die in der Vergangenheit im Portfolio waren. • Portfolioname • ISIN der Aktie • Aktienkaufdatum • Aktienkaufkurs • Spesen des Aktienkaufs • aktuelle Stückzahl • Aktienverkaufsdatum • Aktienverkaufskurs • Spesen des Aktienverkaufs

/LD030/ Umsatzdaten des Portfolios Alle Bewegungen im Portfolio wie Eröffnung, Kauf oder Verkauf werden gespeichert. • Datum der Bewegung • Betrag

Seite 15 / 136 • Kommentar: Im Kommentarfeld werden die Bewegungen textuell gespeichert: Bei Eröffnung des Portfolios sollte der Text auch den Startbetrag enthalten. Bei Kauf und Verkauf einer Aktie, sollte der Text die Spesen, den Kaufs-/Verkaufskurs und die Stückanzahl beinhalten.

/LD040/ Aktiendaten Für jede Aktie werden neben Namen und ISIN auch die täglichen Schlusskurse gespeichert. • ISIN • Aktienname • Aktienwert • Datum des Aktienwerts

3.5 Produktleistungen

/LL010/ Das System braucht nicht mit aktuellen Aktienwerten arbeiten, da der Fokus dieses Produkts auf der Benutzerschnittstelle, und nicht der Aktualität der Daten liegt. Die Verarbeitung der täglichen Schlusswerte für Berechnungen und Darstellung ist ausreichend.

/LL020/ Fehlerhafte Benutzereingaben werden vom System erkannt. Der Benutzer bekommt eine Fehlermeldung und die Möglichkeit den Eingabefehler zu korrigieren.

3.6 Qualitätsanforderungen An erster Stelle steht die Benutzerfreundlichkeit der Oberfläche, sowie die Effizienz mit der der Benutzer die Aufgaben erfüllen kann. Robustheit und Zuverlässigkeit spielen eine untergeordnete Rolle, da dieses System nur für die Evaluierung von Benutzeroberflächen und nicht für den produktiven Einsatz gedacht ist. Die Web-Schnittstelle zur Datenbank sollte kompatibel mit allen gängigen RIA- Frameworks sein.

3.7 Ergänzungen Die Realisierung sollte mit lizenzkostenfreier Software erfolgen.

Seite 16 / 136 Das Betriebssystem des Servers ist ein Ubuntu-System. Dieser Umstand muss bei der Realisierung des serverseitigen Programmteils berücksichtigt werden! Als Datenbankserver kommt MySQL, als Webserver Apache zum Einsatz. Am Webserver ist unter anderen das PHP- und SSL-Modul aktiviert. Passwörter dürfen nicht im Klartext abgespeichert werden. Die Implementierungen der Applikation mit den verschiedenen Frameworks sind durch unterschiedliche Verzeichnisnamen bzw. Subdomains erreichbar.

Seite 17 / 136

Nachdem die HTML-Seite inklusive JavaScript-Programmcode vom Browser geladen wurde, hat der JavaScript-Programmcode die Aufgabe, Daten vom Server zu holen und die HTML-Struktur damit zu befüllen. Bei Benutzerinteraktionen wird nun nicht mehr die ganze Seite neu geladen, sondern über JavaScript nur mehr die sich ändernden Bereiche. Dadurch wird weniger Datenvolumen produziert und die Anwendung reagiert schneller auf Benutzeraktionen. Ein weiterer Vorteil ist, dass die Weboberfläche immer zu sehen ist, da keine kompletten Seitenwechsel mehr stattfinden und daher dazwischen keine leeren, weißen Browserfenster zu sehen sind. Ein Nachteil ist die gesteigerte Komplexität, da nun auch Programmcode am Client und nicht nur am Server vorhanden ist. Diese Programmteile müssen auch aufeinander abgestimmt sein. Diese Art von Webanwendungen, bei denen nur eine einzige Seite geladen wird, nennt man Single-Page Application (SPA). Diese eine Seite kontrolliert den weiteren Programmablauf und lädt gegebenenfalls weiteren Daten, wie CSS, JavaScript, HTML, XML, JSON und Andere nach. Die Logik der Anwendung verlagert sich dadurch vom Server zum Client. Die Hauptaufgabe des Clients (Webbrowser) ist nicht mehr,, wie bei den klassischen Webanwendungen, die Darstellung der meist statischen Seiten, sondern auch die Steuerung des Programmablaufs, die Kommunikation mit den Webservern und die Verarbeitung der Daten. Der Client wird somit zu einem Thick-Client.

4.2.1 Die vier Grundprinzipien von AJAX Crane schreibt von vier Grundprinzipien, die bei AJAX-Anwendungen beachten werden sollen [Crane et al. 2006]. Kurz zusammengefasst: (1) Der Browser beherbergt eine Anwendung, keinen Inhalt. Bei klassischen, seitenbasierten Webanwendungen wurden an den Browser HTML-Dateien geschickt, die Inhalt und Struktur enthielten. Der Browser hatte nur die Aufgabe, diese HTML-Dateien anzuzeigen. Die gesamte Anwendungslogik lag beim Server. Bei AJAX-Anwendungen wird nun ein Teil der Anwendungslogik Richtung Browser verschoben. Der Browser erhält ein komplexeres HTML-Dokument, welches vor allem JavaScript-Programmcode enthält. Der Browser kann mittels dieses Programmcodes entscheiden, welche

Seite 20 / 136 Benutzerinteraktionen er selbst verarbeiten kann (zum Beispiel Gültigkeitsprüfungen), bzw. wann er eine Anfrage an den Server stellen muss, um weitere Daten zu bekommen [vgl. Crane et al. 2006, S. 42- 44]. (2) Der Server übermittelt Daten, keinen Inhalt. Die HTML-Dateien, welche bei klassische Webanwendungen vom Server generiert wurden, waren eine Mischung aus Struktur, Inhalt und Daten. Bei AJAX-Anwendungen stellt die HTML-Datei die Struktur der Seite zur Verfügung, welche mittels JavaScript und AJAX mit Daten vom Server befüllt werden. Da nur mehr die Daten, und nicht mehr das Gemisch von Struktur, Inhalt und Daten vom Server zurückgegeben wird, verringert sich der Datenverkehr unter Umständen enorm. Dies resultiert in einer effizienteren Kommunikation zwischen Client und Server, einer geringeren Reaktionszeit am Client und einem geringeren Bandbreitenverbrauch [vgl. Crane et al. 2006, S. 44-46]. (3) Die Interaktion von Benutzer und Anwendung kann flüssig ablaufen. Bei klassischen Webanwendungen gab es hauptsächlich nur zwei Arten der Benutzerinteraktion: der Klick auf einen Link (Text bzw. Bild), oder das Abschicken eines Formulars. Beide Ereignisse schicken eine Anfrage an den Server, der die Daten der Anfrage verarbeiten, eine neue Seite dynamisch erstellen und an den Client zurücksenden muss. In der Zwischenzeit muss der Benutzer warten: sein Arbeitsfluss wird unterbrochen. Oft passiert es auch, dass der Benutzer während der Wartezeit die Seite im Browser noch sieht und sich entscheidet die gleiche Anfrage noch einmal zu senden bzw. auf einen anderen Link zu klicken. Beides kann zu unvorhersehbaren, negativen Folgen in der Webanwendung führen. Eine Webanwendung, die JavaScript und AJAX verwendet, kann sicherstellen, dass der Arbeitsfluss nicht gestört wird, indem auf jede Benutzeraktion sofort eine Reaktion der Anwendung erfolgt. Für den Benutzer sollte sich die Webanwendung wie eine Desktopanwendung anfühlen. Mit JavaScript sind auch Formularelemente wie Baumstrukturen, bearbeitbare Raster, Datumsauswahlfelder, und

Seite 21 / 136 Ähnliches möglich, welche von HTML nicht unterstützt werden. Ein gelungenes Beispiel für einen ungestörten Arbeitsfluss ist das Suchfeld von Google: Während der Benutzer den Suchbegriff eingibt werden über AJAX im Hintergrund häufig genutzte Suchbegriffe von den Google-Servern heruntergeladen und vorgeschlagen [vgl. Crane et al. 2006, S. 46-48]. (4) AJAX erfordert Programmierarbeit und Disziplin. In den Anfangszeiten von JavaScript wurde die Programmiersprache nur verwendet um Webseiten zu verzieren. Teilweise wurde sogar empfohlen, JavaScript zu deaktivieren, da von einem Sicherheitsrisiko ausgegangen wurde, wenn am Client Programmcode ausgeführt wird. Daher hatte JavaScript den Ruf als triviale Sprache, die für ernsthafte Anwendungen nicht geeignet ist. Das Ansehen von JavaScript hat sich aber gewandelt: Eine AJAX- Anwendung zu implementieren ist komplexer und benötigt mehr Code als eine klassische Webanwendung. Die Anwendung muss nach dem ersten Ladevorgang ohne Unterbrechung, ohne Verlangsamung und ohne Speicherleck laufen, bis die Anwendung mit dem Browserfenster geschlossen wird. [vgl. Crane et al. 2006, S. 48]

4.2.2 XMLHttpRequest (XHR) AJAX ist ein Konzept zur Übermittlung von Daten zwischen dem Webbrowser und dem Server. Dabei nutzt AJAX das XMLHttpRequest-Objekt. Zuerst implementierte Microsoft die XMLHttpRequst-Schnittstelle im InternetExplorer. Erst ab 2006 kümmerte sich das W3C um die Standardisierung des XHR. Der Name „XMLHttpRequest“ ist unglücklich gewählt, da nicht nur XML-Daten sondern alle textbasierten Daten, wie JSON, CSV, HTML, … übertragen werden können. Auch ist die Übertragung nicht an HTTP gebunden: Es ist auch HTTPS möglich [vgl. Kesteren et al. 2014]. Nun ein Codeausschnitt einer AJAX-Verbindung aus der XHR-Referenz des W3C [Kesteren et al. 2014].

1 function handler() { 2 if(this.readyState == this.DONE) { 3 if(this.status == 200 && 4 this.responseXML != null && 5 this.responseXML.getElementById('test').textContent) { 6 // success!

Seite 22 / 136 7 processData(this.responseXML.getElementById('test').textContent); 8 return; 9 } 10 // something went wrong 11 processData(null); 12 } 13 } 14 15 var client = new XMLHttpRequest(); 16 client.onreadystatechange = handler; 17 client.open("GET", "unicorn."); 18 client.send();

In Zeile 15 wird das XHR-Objekt erstellt. Die Eigenschaft onreadystatechange des XHR-Objekts (Zeile 16) bekommt die Referenz auf die Funktion zugewiesen, die ausgeführt wird, wenn sich der Kommunikationsstatus ändert. Mit der Methode open() in Zeile 17 wird dem XHR-Objekt die HTTP- Anfragemethode (hier: „GET“) und die Ziel-URL (hier: „unicorn.xml“) bekanntgegeben. Mit der Methode send() wird der Request schließlich an den Server gesendet. Jedes Mal, wenn sich der Kommunikationsstatus ändert, wird die Funktion handler() aufgerufen. Folgende fünf Kommunikationsstati werden unterschieden: nicht gesendet (0), Verbindung hergestellt (1), Headerdaten empfangen (2), Daten werden empfangen (3) und Daten wurden empfangen – fertig (4). Die erste if-Bedingung in Zeile 2 überprüft, ob die Kommunikation beendet ist, die zweite if-Bedingung in Zeile 3 überprüft, ob die Anfrage vom Server erfolgreich bearbeitet wurde (HTTP-Code: 200 OK) und ob der Antworttext Daten enthält (Zeile 4). Die vom Server gesendeten Daten können mit der Eigenschaft responseText als Text bzw. JSON oder mit der Eigenschaft responseXML als HTML- bzw. XML-Dokument abgerufen werden. Bei der Methode open() kann mit einem dritten Parameter vom Typ Boolean noch eingestellt werden, ob die Kommunikation asynchron (true) oder synchron (false) ablaufen sollte. Standardmäßig findet eine asynchrone Kommunikation statt: der Benutzer braucht auf die Antwort des Servers nicht zu warten und der Arbeitsfluss wird nicht gestört. Bei einer synchronen Kommunikation hingegen wartet der Browser nach dem Ausführen der send()- Methode bis eine Antwort vom Server eingetroffen ist. In der Zwischenzeit

Seite 23 / 136 kann der Benutzer mit der Anwendung nicht interagieren: das Browserfenster ist wie eingefroren.

4.2.3 Formate für Datenaustausch Für den Datenaustausch zwischen Server und Browser des zu implementierenden Börsenkursinformationssystems kamen folgende Formate in die engere Wahl: • Text Textdaten sind normalerweise unstrukturiert und daher für die Speicherung einer Menge an strukturierten Daten ungeeignet. Um dennoch Daten strukturiert als Text abzuspeichern, braucht es ein Format wie XML oder JSON. Ein eigenes Format zu erfinden ist nicht sinnvoll. • HTML HTML (HyperText Markup Language) ist eine Auszeichnungssprache, die vor allem für die Speicherung und Übertragung von Webseiten an einen Browser benutzt wird. In HTML werden Struktur und Inhalt gespeichert. Da über AJAX aber nur Daten und keine Inhalte [Crane et al. 2006 S. 44] übertragen werden sollen, scheidet HTML als Übertragungsformat ebenfalls aus. • CSV CSV (Comma-Separated Values) speichert Daten textuell und strukturiert ab. Als Trennzeichen zwischen den Werten wird meist ein Strichpunkt (Semikolon) verwendet. CSV eignet sich sehr gut für die Repräsentation von Tabellen. Da sich die Kommunikation aber nicht nur auf Tabellen beschränkt, sondern auch komplexere Datengebilde, wie Datensätze oder Arrays, übertragen werden müssen, scheidet CSV ebenfalls aus. • XML XML (eXtensible Markup Language) erlaubt eine hierarchische und strukturierte Form der Speicherung von Daten. Die Daten sind Inhalt bzw. Attributwerte von Elementen, wobei die Namen der Elemente und Attribute beliebig vergeben werden können. In XML können Datenstrukturen wie Datensätze oder Arrays abgebildet werden. Für die meisten Programmiersprachen existieren Parser, die eine XML-Datei einlesen und deren Daten und Struktur als DOM () bereitstellen. Das DOM liefert Schnittstellen um einen relativ

Seite 24 / 136 einfachen Zugriff auf die Daten (lesend und schreibend) zu erhalten. Einer der gravierendsten Nachteile von XML ist der große Anteil an Verwaltungsinformationen (Overhead), die zur Speicherung notwendig sind. Da sich durch diese Zusatzinformationen die zu übertragende Datenmenge enorm erhöht, schied XML ebenfalls aus. • JSON JSON (JavaScript Object Notation) ist ein kompaktes textuelles Datenformat, welches sich für das Versenden von Daten sehr gut eignet. JSON kann von JavaScript mit der eval()-Funktion direkt interpretiert werden. Der Einsatz eines Parsers fällt für JavaScript- Anwendungen somit weg. Da zwei der zu verwendenden Frameworks auf JavaScript basieren, fiel die Entscheidung auf JSON als Datenaustauschformat. • GWT-RPC für GWT-Anwendungen GWT-RPC (Google Web Toolkit – ) ist ein Framework für die Übermittlung von Java-Objekten. Auf der Serverseite liefert ein Serlet-Container serialisierte Java-Objekte an den Client, meist eine GWT-Anwendung. Der Vorteil von GWT mit GWT-RPC ist, dass sowohl Client als auch Server in Java geschrieben werden können. Für komplett neu zu entwickelnde Anwendungen ist GWT mit GWT-RPC und Servlets eine gute Wahl. Wenn jedoch der serverseitige Teil der Anwendung bereits besteht, oder auch von anderen Frameworks benutzt werden muss, sollte auf GWT-RPC verzichtet werden. GWT kann auch mit XML- und JSON-Datenlieferanten umgehen. [vgl. Seemann 2008 S. 85] Da AngularJS, bzw. Silverlight nicht mit GWT-RPC kommunizieren können, schied dessen Einsatz aus. • WCF-RIA-Services für Silverlightanwendungen WCF-RIA (Windows Communication Foundation – Rich Internet Applications – Services) wurden von Microsoft eingeführt, um asynchrone Aufrufe zwischen einer Silverlightanwendung und einem WCF-Service für die Entwickler zu vereinfachen. WCF-RIA-Services bauen auf WCF auf, welche wiederum ASP.NET am Server voraussetzen. Falls für die Silverlight-RIA noch keine vordefinierte

Seite 25 / 136

4.3 Same Origin Policy (SOP) Alle modernen Browser haben einen Schutzmechanismus eingebaut, der verhindern soll, dass schädlicher Programmcode am Client ausgeführt wird. Von den Browserherstellern wird davon ausgegangen, dass der Benutzer einer Webanwendung der Domäne, von der er die Anwendung herunterlädt, vertraut. Daher darf diese Anwendung auch nur mit dem Server, von dem die Anwendung heruntergeladen wurde, eine Verbindung aufbauen. Diese Sicherheitsregel wird Same Origin Policy, kurz SOP genannt. Diese Sicherheitsregel ist dafür verantwortlich, dass man mit Hilfe des XMLHttpRequest-Objekts Inhalte anderer Domains nicht nachladen kann [Seemann 2008 S. 108]. Webbrowser haben ein stark eingeschränktes Verständnis dafür, was sich in der gleichen Domäne befindet. Zur Identifikation wird ausschließlich der Anfang der URLs herangezogen. Es wird nicht kontrolliert, ob sich hinter zwei Domänen die selbe IP-Adresse befindet, bzw. die IP-Adresse der Domäne ermittelt [vgl. Crane et al. 2006 S. 282]. Neben den Domänennamen muss auch die Portnummer des Servers ident sein. Nun einige Beispiele um zu verdeutlichen, in welchen Fällen SOP die Kommunikation erlaubt bzw. verweigert. Die Seite der ersten URL beinhaltet die Webapplikation, welche mit dem XMLHttpRequest-Objekt die Daten des PHP-Skripts mit der zweiten URL aufrufen will.

Seite 28 / 136 URLs Kommentar

http://abenteuerbox.at/index.html ✔ Die Domainnamen und Ports http://abenteuerbox.at/data.php stimmen überein.

http://riapf.abenteuerbox.at/index.html ✗ Die Domainnamen stimmen http://abenteuerbox.at/data.php nicht überein: Subdomains werden wie eigene Domainnamen behandelt.

http://abenteuerbox.at/index.html ✗ Die Portnummern stimmen https://abenteuerbox.at/data.php nicht überein: http:// (Port 80), bzw. https:// (Port 443).

http://abenteuerbox.at/index.html ✗ Die Domain abenteuerbox.at http://84.201.40.159/data.php verweist zwar auf die IP-Adresse 84.201.40.159, aber für den Browser handelt es sich um einen anderen Domainnamen.

http://abenteuerbox.at/index.html ✔ Die Domainnamen und Ports http://abenteuerbox.at/mysql/data.php stimmen überein. Das Verzeichnis, in dem sich die Dateien befinden, ist egal.

http://abenteuerbox.at/index.html ✗ Die Domainnamen stimmen http://abenteuerbox.info/data.php nicht überein, obwohl die Domainnamen auf die selbe IP- Adresse und somit Server verweisen. Der Browser geht dem aber nicht nach.

http://localhost/index.html ✗ Die Domainnamen stimmen http://abenteuerbox.info/data.php nicht überein.

http://localhost:8080/index.html ✗ Die Portnummern stimmen http://localhost/data.php nicht überein.

Tabelle 2: Beispiele für die Arbeitsweise von SOP (Fortsetzung)

Seite 29 / 136 Die letzten beiden Beispiele waren bei der Programmierung der Beispielapplikationen von relevanter Bedeutung. Bei der Entwicklungsarbeit der GWT-Anwendung auf dem lokalen Rechner wurde der Entwicklungsserver der -Programmieroberfläche verwendet. Dieser benutzt einen eigenen Port, damit es zu keinen Konflikten mit bereits gestarteten Webservern kommt. Die Datenhaltung wurde aber in PHP geschrieben und lief auf einem Apache-Webserver auf Port 80. Durch diesen Umstand griff die Sicherheitsregel von SOP. Da AngularJS ebenfalls das XMLHttpRequest-Objekt nutzt, gelten die Einschränkungen von SOP auch für dieses Framework. Bei Silverlight existiert ebenfalls ein Mechanismus ähnlich wie SOP um Cross- Domain-Zugriffe zu unterbinden. Dieser Mechanismus kann aber relativ einfach durch die Konfigurationsdatei clientaccesspolicy.xml, welche am Server liegt, ausgeschaltet werden. [vgl. Huber 2010 S. 700ff.] SOP hat zwar sicherheitstechnisch für den Benutzer einen Nutzen, aber es erschwert das Testen der Webanwendungen während der Programmierarbeit enorm! Mit folgendem kleinen Programm kann man die Sicherheitsregeln von SOP testen:

Seite 30 / 136 Die HTML-Datei wird über einen Webserver im Browser aufgerufen. Im Formularfeld wird anschließend die URL der Seite angeben, die die Daten liefern sollte. Wenn eine Kommunikation erlaubt ist, werden die Daten als Textausgabe angezeigt.

4.4 SOP beim Browser deaktivieren Einige Browser bieten die Möglichkeitan, die Beschränkungen von SOP zu umgehen. Durch spezielle Parameter beim Start, zusätzliche Addons oder Browsereinstellungen kann SOP deaktiviert werden. • (Windows und Linux) Bei älteren Versionen von Firefox war es möglich durch die Konfigurationsseite SOP zu umgehen. Die Konfigurationsseite wird mit Eingabe von about:config in der Adressleiste geladen. Der Schlüssel security.fileuri.strict_origin_policy musste auf den Wert false gestellt werden. Bei neueren Firefox-Versionen funktioniert diese Variante leider nicht mehr. Auf der Seite http://spenibus.net/files/gitbin/cors- everywhere-firefox-addon/ kann man das Addon CORS-Everywhere herunterladen und anschließend in Firefox installieren. CORS- Everywhere ändert die Serverantwort indem es CORS-Headerdaten einfügt. Mit CORS (Cross-Origin Resource Sharing) kann eine Seite bestimmen, von welcher Seite sie aufgerufen werden darf. Dies geschieht mit dem Headerattribut Access-Control-Allow-Origin gefolgt von der URL der aufrufenden Seite [Kesteren 2014]. Das Addon gaukelt dem Browser somit vor, dass der Server Cross-Origin-Request erlaubt. Mit CORS-Everywhere kann für jeden Tab separat SOP aktiviert bzw. deaktiviert werden. • Chrome (Windows) bzw. (Linux) Wird der Webbrowser mit der Command Line Option --disable-web- securtiy gestartet, wird die Sicherheitsregel von SOP deaktiviert. Unter Windows kann die Verknüpfung auf Chrome über das Eigenschaftsfenster geändert werden: Nach dem Programmaufruf fügt man dann die Option --disable-web-security hinzu. Unter Linux wird mit + das „Anwendung ausführen“- Dialogfenster geöffnet. In der Befehlszeile „chromium-browser

Seite 31 / 136

4.4.1 JSON with Padding (JSONP) Zwei HTML-Elemente, die auf Daten verweisen, sind von SOP ausgenommen: das Element und das Element 13 14 15 16

17
18

19 22 23

In dem Textfeld wird die URL vom Server mit dem Namen der Callback- Funktion eingegeben, zum Beispiel:

http://riapf.abenteuerbox.at/portfolios.php? todo=getPort&callback=JSON_CALLBACK

Diese URL wird von JavaScript als src-Verweis in ein

Der Server generiert nun JavaScript-Code, der einen Aufruf der Funktion JSON_CALLBACK() enthält:

JSON_CALLBACK([{"port":"Lele","portid":21}, {"port":"Vorsorge","portid":33}])

Der Browser führt diese Funktion sofort nach Erhalt aus. Die Daten (hier JSON) werden als Parameter an die Funktion übergeben, die diese von JSON in Text umwandelt und ausgibt. Bei JSONP brauchen nicht unbedingt JSON-Daten übertragen werden. Es funktioniert mit beliebigen Textdaten, wie zum Beispiel XML oder CSV. Die Datenübertragung funktioniert bei JSONP asynchron. Der HTTP-Request wird durch die Manipulation des

Der Einsprungspunkt der GWT-RIA ist die Methode onModuleLoad(). Im Beispielcode wird zuerst ein Widget (siehe 8.6 GWT-Widgets) vom Typ Login erzeugt. Danach wird mit dem Befehl RootPanel.get("riaportfolio") direkt auf das Element mit der ID riaportfolio im DOM der HTML-Datei zugegriffen und mit der Methode add() in diesem Element das Widget eingefügt.

public void onModuleLoad() { login = new Login(this); // ... RootPanel.get("riaportfolio").add(login); }

Auf diese Weise wird die Verknüpfung zwischen den GWT-Komponenten in Java und dem Grundgerüst in HTML bewerkstelligt.

Seite 61 / 136 Das GUI wird in GWT nach dem Bottom-Up-Prinzip aufgebaut. Es werden aus einzelnen, einfachen Bauteilen wie Buttons oder Textboxen immer größere und komplexere Elemente zusammengesetzt. Folgender Code ergibt das GUI des Login-Widgets (siehe Abbildung 23: Widget des Logins).

// Login textBoxUser = new TextBox(); passTextBox = new PasswordTextBox(); Button buttonLogin = new Button("anmelden"); buttonLogin.addClickHandler(new ClickHandler() { // ... );

Anchor anchorNew = new Anchor(); anchorNew.setText("neuen Benutzer anlegen"); anchorNew.addClickHandler(new ClickHandler() { // ... );

tableLogin = new FlexTable(); tableLogin.setText(0, 0, "Benutzername: "); tableLogin.setWidget(0, 1, textBoxUser); tableLogin.setText(1, 0, "Passwort: "); tableLogin.setWidget(1, 1, passTextBox); tableLogin.setWidget(2, 0, buttonLogin); tableLogin.setWidget(3, 0, anchorNew);

tableLogin.getFlexCellFormatter().setColSpan(2, 0, 2); tableLogin.getFlexCellFormatter().setColSpan(3, 0, 2); tableLogin.getFlexCellFormatter().setHorizontalAlignment(2, 0, HasHorizontalAlignment.ALIGN_RIGHT);

Verwendet wurden für das Login eine TextBox, eine PasswortTextBox, ein Button und ein Link (Anchor). Diese Elemente wurden mit Hilfe eines FlexTables positioniert und formatiert. Dem Button und dem Anchor wurden auch noch ClickHandler hinzugefügt. Das Ergebnis dieser paar Zeilen Code kann man am nachfolgenden Screenshot sehen:

Abbildung 23: Widget des Logins

8.6 GWT-Widgets Widgets sind eigenständige Teile einer Benutzeroberfläche, die eine spezielle Funktion übernehmen. Widgets können über jar-Dateien zwischen Projekten und Entwicklern ausgetauscht werden [vgl. Steyer 2007, S. 26].

Seite 62 / 136 GWT stellt von Haus aus viele Widgets zur Verfügung. Einen Überblick, inklusive Beispiele, kann man sich auf der Widget Gallery unter http://www.gwtproject.org/doc/latest/RefWidgetGallery.html verschaffen. Dort findet man zum Beispiel die Widgets: Button, PushButton, RadioButton, CheckBox, DatePicker, ToggleButton, TextBox, PasswordTextBox, TextArea, Hyperlink, ListBox, CellList, MenuBar, Tree, CellTree, SuggestBox, RichTextArea, FlexTable, Grid, CellTable, CellBrowser, TabBar oder DialogBox. Weiters kann man sich auch über die verschiedenen Möglichkeiten informieren, wie man die Benutzeroberfläche strukturiert. Angeboten werden die Panels: PopupPanel, StackPanel, StackLayoutPanel, HorizontalPanel, VerticalPanel, FlowPanel, VerticalSplitPanel, HorizontalSplitPanel, SplitLayoutPanel, DockPanel, DockLayoutPanel, TabPanel, TabLayoutPanel oder DisclosurePanel. In GWT können Widgets als wiederverwendbare Komponenten erstellt werden. Ein selbst erstelltes Widget erbt von der Klasse Composite und erhält dadurch unter anderen die Methoden onLoad() und onAttach(). Im Konstruktor sollte das GUI zusammengebaut werden. Als nächstes wird die Methode onAttach() ausgeführt, wenn das Widget in das DOM eingebunden wird. Wenn diese Aktion beendet ist, wird sofort onLoad() ausgeführt. Muss bei der GUI- Erstellung auf Objekte des DOMs zugegriffen werden, wie z.B. auf Werte von Elementen, oder auf native JS-Objekte, darf dieser Code erst nach der erfolgreichen Einbindung ins DOM ausgeführt werden. Wie im Beispiel angedeutet, kann die Datenkommunikation mit dem Server über JSONP, bei der die Daten als JS-Objekt im

Seite 96 / 136 Mit dem Attribut ng-app markiert man den Teil des DOMs, welches durch AngularJS bearbeitet werden darf. Will man, dass AngularJS die ganze Seite verwaltet, so schreibt man das Attribut ng-app bereits in das -Element. Hier ein Auszug aus meiner index.html-Datei:

< html ng-app ="RIA"> RIA-Portfolio < body ng-controller ="ContentCtrl as content">

< p menu logindata = "logindata" portfolios = "portfolios" class ="col-md- 12">
< div ng-hide = "logindata.boolvalue" class ="row"> < p login logindata = "logindata" class = "col-md-6 col-md-offset-3">
< div ng-show ="logindata.boolvalue"> < div class = "row" ng-view portfolios = "portfolios">