WPF-Blogger.com [Language: de] http://www.wpf-blogger.com All news and information about Windows Presentation Foundation and Silverlight at one place. Freitag, 18. Mai 2012 Neuerdings im Web (April 2012) Einen schönen Round-Up bringt uns NETTUTS über derzeitige Features und neuen nützlichen Javascript/jQuery Libraries für die Webentwicklung. Gut finde ich jQuery Scroll Path &#34;jQuery Scroll Path is a plugin that lets you define your own custom scroll path. What this means exactly is best understood by checking out the demo. The plugin uses canvas flavored [...] http://feedproxy.google.com/~r/BigglesBlog/~3/VH69TCISgV0/neuerdings-im-web-april-2012 Mario Priebe 3745 2012-05-02T08:41:08 Nachlese zur Visual Studio 2011 Beta Roadshow Am 25.April habe ich die Roadshow zu den Neuerungen von Visual Studio 11 in Frankfurt besucht und möchte nun einige der vielen Features, die in der fünfstündigen Veranstaltung erörtert wurden, kurz vorstellen. Auf den ersten Blick fallen die Änderungen am User Interface auf. So wurden alle Icons neu gestylt und die Toolbars aufgeräumt. Beispielsweise wurden die Icons für [...]<img src="http://feeds.feedburner.com/~r/UxDevelopa/~4/HyKOoJ9WRhE" height="1" width="1"/> http://feedproxy.google.com/~r/UxDevelopa/~3/HyKOoJ9WRhE/ Kazim Bahar 3744 2012-05-01T22:01:12 Buch: Perry Rhodan Neo 1 - Sternenstaub - Frank Borsch <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Perry Rhodan Neo 1 - Sternenstaub - Frank Borsch" border="0" alt="Perry Rhodan Neo 1 - Sternenstaub - Frank Borsch" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_167.png" width="113" height="164" /></p> <p><em>Das Jahr 2036: Überbevölkerung, Klimawandel und Terrorismus - die Menschheit steht kurz vor dem Untergang. Zudem steigen die Spannungen zwischen den Machtblöcken. In dieser Lage startet der amerikanische Astronaut Perry Rhodan mit drei Kameraden zum Mond - denn dort geschieht Unheimliches. Mit einer uralten Rakete brechen die vier Astronauten ins Abenteuer ihres Lebens auf. Auf dem Mond treffen sie auf die menschenähnlichen Arkoniden. Rhodan erkennt die Schwäche der Aliens - und er schlägt ihnen einen gewagten Handel vor. Sein Ziel: Er will Frieden für die Menschheit. Sein Preis: Er muss sich gegen alle Regierungen der Welt stellen.</em></p> <p>Bis jetzt hatte ich immer einen Bogen um Perry Rhodan gemacht. Warum kann ich nicht genau sagen, unterschwellig müssen wohl dennoch Gründe vorhanden gewesen sein. Mit der Anschaffung eines Kindle habe ich dann aber dann doch den Sprung gewagt und mich via Neo an den Neustart von Perry Rhodan gemacht. Ohne also irgendeiner Altlast aufzusitzen, ohne Vorurteile, ohne den ständigen Vergleich, konnte ich mich daher auf den Inhalt und die Erzählung konzentrieren. Und ich muss sagen: Ich bin begeistert. Die einzelnen Charaktere sind gut herausgearbeitet, die Story selbst ist interessant und modern. Für mich ein gelungener Einstieg und ganz klar empfehlenswert!</p> <p><strong>Bewertung</strong>: 5/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Perry-Rhodan-Neo-1-Sternenstaub-Frank-Borsch.aspx Norbert Eder [MVP] 3732 2012-04-23T14:13:51 Interaction Event-Trigger als Style auslagern In einem Caliburn.Micro Projekt setze ich den EventTrigger ein, um meine Commands an einem ViewModel zu binden. Nun möchte ich gerne immer den selben EventTrigger an mehreren Stellen einsetzen und verhindern, dass der Code an “tausend” Stellen redundant eingesetzt wird. Aus diesem Grund, soll diese Interaktion als Style zu Verfügung gestellt werden. Der folgende Code [...] http://feedproxy.google.com/~r/BigglesBlog/~3/pEBiI19Veec/interaction-event-trigger-als-style-auslagern Mario Priebe 3730 2012-04-23T12:26:31 Outlook als GTD Applikation GTD steht für Getting Things Done und beschreibt Methodiken, seinen täglichen Aufgaben produktiv und effizient zu erledigen. Lesenswerte Artikel zum Thema GTD stehen am Ende des Tutorials. Zieldefinition Ziel ist es, im Outlook ein Dashboard bereit zu stellen, welches einem alle Aufgaben, den Posteingang, den Kalender, Notizen und die Kontakte anzeigt. Das Besondere dabei ist, [...] http://feedproxy.google.com/~r/BigglesBlog/~3/2cZWDhVpoWw/outlook-als-gtd-applikation Mario Priebe 3723 2012-04-18T09:05:57 Working Hours Tracker 1.4 - Vorabinfo <p><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Working Hours Tracker für Windows Phone Logo" border="0" alt="Working Hours Tracker für Windows Phone Logo" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_166.png" width="100" height="100" />In Kürze wird die Version 1.4 der kostenlosen Zeiterfassung <a title="Working Hours Tracker für Windows Phone" href="http://devtyr.com/wht.html" target="_blank">Working Hours Tracker</a> für Windows Phone veröffentlicht. In dieser Version wurden sehr große Änderungen und Erweiterungen vorgenommen. Dieser Beitrag gibt einen Überblick über neue Funktionen und Verbesserungen, die mit der neuen Version verfügbar sein werden. Zusätzlich gibt es Informationen zum Beta-Test.</p> <p>&#160;</p> <h2>Beta-Test</h2> <p>Aktuell startet ein größer angelegter Beta-Test. Dieser soll etwaige Fehler, Hindernisse in der Bedienung und offene Fragen beseitigen. Zusätzlich zu den eigenen Tests soll so die Stabilität weiter verbessert werden. Wer daran teilhaben möchte, möge sich bei mir via <a title="http://devtyr.norberteder.com/contact.aspx" href="http://devtyr.norberteder.com/contact.aspx">http://devtyr.norberteder.com/contact.aspx</a> melden. Ich bitte um die Angabe der E-Mail-Adresse, unter der man auf seinem Windows Phone an Windows Live angemeldet ist, damit eine Freischaltung erfolgen kann.</p> <h2>Neue Funktionen</h2> <p>Die Version 1.4 bringt sehr sehr viele Neuerungen mit sich. Hier seien die wichtigsten neuen Funktionen kurz aufgezählt:</p> <ul> <li>Projekte können nun mit einer Pauschale hinterlegt werden </li> <li>Verwaltung von Tätigkeiten (inkl. Standard-Stundensatz) und Zuweisung zu Projekten (mit geänderten Stundensätzen) </li> <li>Erfassung von Pausenzeiten </li> <li>Zusätzlich zur zeitlichen Sicht auf die Zeiteinträge gibt es nun eine Projektsicht </li> <li>Beim Export von Daten zu einem Monat können zusätzlich die zu exportierenden Projekte gewählt werden </li> </ul> <p>Zusätzlich zu diesen Erweiterungen wurde der gesamte Start-Bereich erneuert. Hier existiert nun ein Schnellzugriff auf die Historie der App, News und der Möglichkeit, die Anwendung zu bewerten. Ebenfalls neu ist eine integrierte Hilfe, die eine grundlegende Einführung geben soll.</p> <h2>Verbesserungen</h2> <p>Der größte Teil betrifft die Verbesserung von bestehenden Funktionalitäten, sowohl in Richtung Oberfläche, als auch unter der Haube. Hier eine ausgewählte Übersicht:</p> <ul> <li>Wesentliche Steigerung der Performance </li> <li>Umstellung auf neuen Anmeldeprozess für Dropbox </li> <li>Erneute Anmeldung an Dropbox ist nicht mehr notwendig </li> <li>Erweiterung des Exports (Tätigkeiten, Zeitsumme, etc.) </li> <li>Optimierungen der UI - viele Schritte sind nun wesentlich schneller durchzuführen </li> <li>Vergrößerung der Icons des Timers </li> <li>Die Software-Tastatur passt sich nun durchgehend an die einzugebenden Daten an </li> <li>App-Tile passt sich dem eingestellten Theme an </li> <li>Via den “Über”-Schirm kann direktes Feedback gesendet werden. Dabei werden Systeminformationen (Typ Handy, Version des Betriebssystems etc. ebenfalls übermittelt) </li> <li>Aufgetretene Fehler werden gespeichert und können über den “Über”-Schirm direkt gesendet werden (Schaltflächen sind nur aktiv, wenn Fehler vorhanden sind) </li> <li>E-Mail-Adresse für das Exportieren von Daten via E-Mail wird gespeichert und muss nicht erneut eingegeben werden </li> <li>Unterstützung Querformat bei Eingabe </li> </ul> <p>An vielen Stellen werden nun verbesserte Meldungen ausgegeben, das Design wurde verbessert und Löschungen erfordern nun eine Bestätigung. Sämtliche Texte wurden überarbeitet.</p> <h2>Behobene Fehler</h2> <p>Natürlich wurden auch bekannte bzw. gemeldete Probleme behoben:</p> <ul> <li>Diverse Übersetzungsfehler </li> <li>Upload bei Umlauten im Dateinamen für deutschsprachige Benutzer </li> <li>Aktualisierung der Zeit des Timers beim erneuten Start der Anwendung </li> </ul> <h2>Screenshots</h2> <p>Nachfolgend ein paar Screenshots.</p> <p><img style="margin: 0px 10px 10px 0px" title="Working Hours Tracker: Übersicht Zeiteinträge Monat" alt="Working Hours Tracker: Übersicht Zeiteinträge Monat" src="http://a5.sphotos.ak.fbcdn.net/hphotos-ak-ash4/485675_369383313095205_213517652015106_1133504_706636597_n.jpg" width="150" height="250" /><img style="margin: 0px 10px 10px 0px" title="Working Hours Tracker: Projektsicht auf Zeiteinträge" alt="Working Hours Tracker: Projektsicht auf Zeiteinträge" src="http://a1.sphotos.ak.fbcdn.net/hphotos-ak-ash3/540265_373841429316060_213517652015106_1145351_749589614_n.jpg" width="150" height="250" /><img style="margin: 0px 10px 10px 0px" title="Working Hours Tracker: Detaileingabe mit Tätigkeit" alt="Working Hours Tracker: Detaileingabe mit Tätigkeit" src="http://a8.sphotos.ak.fbcdn.net/hphotos-ak-ash4/295120_370137546353115_213517652015106_1135560_157866271_n.jpg" width="150" height="250" /><img style="margin: 0px 10px 10px 0px" title="Working Hours Tracker: Anmeldung Dropbox" alt="Working Hours Tracker: Anmeldung Dropbox" src="http://a1.sphotos.ak.fbcdn.net/hphotos-ak-ash3/532353_376283645738505_213517652015106_1152292_1728832340_n.jpg" width="150" height="250" /></p> <p>Weitere Screenshots können <a title="Working Hours Tracker 1.4 für Windows Phone - Screenshots" href="http://www.facebook.com/media/set/?set=a.255090154524522.65817.213517652015106&amp;type=3" target="_blank">hier</a> bezogen werden.</p> <h2>Weitere Informationen &amp; Feedback</h2> <p>Eine gesamte Liste aller Veränderungen und Erweiterungen ist unter <a title="http://devtyr.com/wht.html" href="http://devtyr.com/wht.html">http://devtyr.com/wht.html</a> zu finden. Über diese Seite können auch Erweiterungswünsche etc. eingebracht werden. Gerne nehme ich Feedback auch hier im Blog entgegen.</p> http://devtyr.norberteder.com/post/Working-Hours-Tracker-14-Vorabinfo.aspx Norbert Eder [MVP] 3703 2012-04-11T18:37:44 Unable to write * ‘obj\Release\ Bekommt man diese, oder eine ähnliche Fehlermeldung “Unable to write * &#8216;obj\Release\”, löscht man am besten einmal den obj Ordner und prüft ob dieser eventuell im TFS mit eingecheckt wurde, was verhindert, das der Schreibschutz effektiv aufgehoben wird. Also dann einfach auf dem TFS löschen, einchecken und Projekt bauen. &#160; Viel Spaß beim entwickeln : [...] http://feedproxy.google.com/~r/BigglesBlog/~3/8Sp2I777hJ8/unable-to-write-objrelease Mario Priebe 3702 2012-04-11T08:18:16 Buch - Engelssturz - Timothy Zahn <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Engelssturz - Timothy Zahn" border="0" alt="Engelssturz - Timothy Zahn" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_165.png" width="113" height="170" /></p> <p><em>Stellen Sie sich vor, alle Politiker der Welt wären selbstlos, vernunftorientiert und unfähig zu lügen. Unmöglich? Nicht in Empyrea, einer menschlichen Kolonie in den Weiten des Alls. Doch hinter den vorbildlichen Staatsmännern verbirgt sich ein gefährliches Geheimnis, und das feindliche Imperium der Pax ist entschlossen, dieses zu ergründen und Empyrea notfalls unschädlich zu machen.</em></p> <p>Timothy Zahn steht für Qualität. Das ließ also viel für dieses Buch erhoffen. Die Story selbst ist an sich gut gelungen. Gut ausgeprägte Charaktere, ein tolles Konzept. Leider aber etwas langatmig geraten. In Teilen wird die Geschichte verschleppt, wenngleich sie sich aber dennoch gut lesen lässt. Der Schluss ist - aus meiner Sicht - erste Sahne, wenn auch einige Fragen (leider) offen bleiben. Aus dieser Idee hätte man mehr machen können.</p> <p><strong>Bewertung</strong>: 3/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Engelssturz-Timothy-Zahn.aspx Norbert Eder [MVP] 3699 2012-04-10T18:26:25 WPF und Windows Forms – Die Wahl zwischen den Windows GUI Technologien. Wenn wir Entwickler für Windows grafische Benutzeroberflächen (GUIs) entwickeln möchten, haben wir die Wahl zwischen Windows Forms und WPF. Jede dieser Technologien haben ihre Vor- und Nachteile. In diesem Artikel möchte ich auf die Hauptunterschiede beider Technologien eingehen und bei der Entscheidung helfen, welche der beiden für den Einsatzzweck vom Vorteil ist. Windows Forms Windows [...] http://feedproxy.google.com/~r/BigglesBlog/~3/KxNLIdE1fm4/wpf-und-windows-forms-die-wahl-zwischen-den-windows-gui-technologien Mario Priebe 3693 2012-04-07T15:11:36 MVVM in der Praxis Das Entwurfsmuster MVVM (Model-View-ViewModel) erfreut sich größter Beliebtheit beim Einsatz der XAML-Technologien WPF, Silverlight und WP7. Die mächtigen Frameworks Prism und Caliburn.Micro bieten weit mehr als nur die Unterstützung zur Umsetzung des MVVM Design Patterns. Die Entkopplung der Komponenten per Dependency Injection oder Konzepte zur Kommunikation zwischen den Modulen sind nur einige unter vielen anderen Features. Allerdings ist die Einarbeitungszeit [...]<img src="http://feeds.feedburner.com/~r/UxDevelopa/~4/RpkEJfAPYGw" height="1" width="1"/> http://feedproxy.google.com/~r/UxDevelopa/~3/RpkEJfAPYGw/ Kazim Bahar 3674 2012-03-28T15:09:01 BASTA! on Tour & SharePoint Summit 2012 BASTA! on Tour &#8211; Architecture &#38; Good Practices &#8211; Das große Trainingsevent für .NET-Architekturen Am 25. bis 27. April 2012 startet in Köln die nächste Ausgabe der BASTA! on Tour &#8211; Architecture &#38; Good Practices. Das große Trainingsevent bietet eine Vertiefung von wichtigen Themen der BASTA! &#8211; der größten unabhängigen .NET-Konferenz im deutschsprachigen Raum. Entwickler [...] http://feedproxy.google.com/~r/BigglesBlog/~3/nM4MgHAwtrs/basta-on-tour-sharepoint-summit-2012 Mario Priebe 3670 2012-03-25T20:07:29 Visual Studio Tipps für XAML Entwickler Ich habe ich hier ein paar Tipps und Tricks zusammengestellt, die die tägliche Arbeit mit XAML-Dateien innerhalb der Visual Studio Umgebung erleichtern. Legen wir gleich mal los &#8230; Tipp 1: Zeilenummern im XAML-Editor einblenden Um Fehlermeldung mit Zeilenangaben besser nachgehen zu können, kann man Zeilennummern im C# Code Editor einschalten. Ich schätze, diese Option kennen bereits [...]<img src="http://feeds.feedburner.com/~r/UxDevelopa/~4/BgcmLawwaXo" height="1" width="1"/> http://feedproxy.google.com/~r/UxDevelopa/~3/BgcmLawwaXo/ Kazim Bahar 3665 2012-03-22T20:18:26 Liste von Strings mittels Entity Framework speichern Wenn man eine Liste von Strings in die Datenbank mittels Entity Framework (4.2) speichern möchte, muss man entweder eine extra Klasse dafür erstellen, oder sich mit folgendem Workaround behelfen. public string Staatsangehoerigkeit { get { return Staatsangehoerigkeiten != null ? String.Join(&#34;;&#34;, Staatsangehoerigkeiten) : null; } set { Staatsangehoerigkeiten = value.Split(';').ToList(); } } [NotMapped] public List&#60;String&#62; [...] http://feedproxy.google.com/~r/BigglesBlog/~3/io846qx7Hdc/liste-von-strings-mittels-entity-framework-speichern Mario Priebe 3653 2012-03-15T10:03:56 Kostenloses E-Book zu Knockout.js - Endstand und Conclusio <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Kostenloses Knockout.js E-Book" border="0" alt="Kostenloses Knockout.js E-Book" src="http://devtyr.norberteder.com/image.axd?picture=image_162.png" width="900" height="266" /></p> <p>In den letzten Wochen wurde mein <a title="Knockout.js" href="http://books.norberteder.com/books/knockoutjs.html" target="_blank">E-Book zum Thema Knockout.js</a> kostenlos über eine Aktion verteilt. Seit Anfang dieser Woche ist die Aktion beendet, da das Maximum erreicht wurde. Insgesamt wurden <strong>250 Exemplare</strong> zur Verfügung gestellt. Zusammen mit der Aktion wurde eine Umfrage zu interessanten Themen gestellt, zu denen ein weiteres E-Book erwünscht wäre. Laut der Zwischenauswertung hatte das Thema HTML5 die Nase vorne. Hat es einen Führungswechsel gegeben?</p> <h2>Auswertung</h2> <p>Zur Erinnerung: Folgende Themen standen bei der Umfrage zur Auswahl:</p> <ul> <li>Backbone.js</li> <li>HTML5</li> <li>Bootstrap</li> <li>Node.js</li> <li>Microsoft LightSwitch</li> </ul> <p>Insgesamt haben <strong>81,6%</strong> aller Teilnehmer ihre Stimme abgegeben (Mehrfachnennungen möglich). Nachfolgend nun das Ergebnis.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_163.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Gesamtauswertung Umfrage Knockout.js E-Book" border="0" alt="Gesamtauswertung Umfrage Knockout.js E-Book" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_102.png" width="608" height="414" /></a></p> <p>Die Änderung im Vergleich zum <a title="Kostenloses E-Book zu Knockout.js - Zwischenstand" href="http://devtyr.norberteder.com/post/Kostenloses-E-Book-zu-Knockoutjs-Zwischenstand.aspx">erhobenen Zwischenstand</a>:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_164.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Veränderung zur Zwischenauswertung Umfrage Knockout.js E-Book" border="0" alt="Veränderung zur Zwischenauswertung Umfrage Knockout.js E-Book" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_103.png" width="608" height="414" /></a></p> <p>Die Umfrage zeigt schon ganz gut, in welche Richtung die Interessen gehen. Dass hierbei Microsoft LightSwitch (quasi als Kontrastprogramm) nicht mithalten kann, hatte ich zwar angenommen, war dann aber doch wegen die Deutlichkeit überrascht.</p> <h2>Wie geht es weiter?</h2> <p>Aktuell wird das E-Book in die Formate MOBI und EPUB gebracht. Alle Teilnehmer an dieser Aktion werden zusätzlich diese Formate zugesandt bekommen. Danach wird das E-Book veröffentlicht. Im Anschluss beginnt die Arbeit an einem neuen E-Book.</p> <h2>Feedback</h2> <p>Natürlich freue ich mich über Feedback zum E-Book. Dieses kann jederzeit unter <a title="http://books.norberteder.com/contact.html" href="http://books.norberteder.com/contact.html">http://books.norberteder.com/contact.html</a> abgegeben werden. Gerne auch kritische Stimmen.</p> http://devtyr.norberteder.com/post/Kostenloses-E-Book-zu-Knockoutjs-Endstand-und-Conclusio.aspx Norbert Eder [MVP] 3649 2012-03-14T08:51:20 JavaScript-Validierung im Visual Studio Build mit Node.js und JSLint <p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Node.js" border="0" alt="Node.js" src="http://devtyr.norberteder.com/image.axd?picture=image_159.png" width="900" height="120" /></p> <p>Webentwicklung, viel JavaScript. Da benötigt man recht bald eine saubere Validierung. <a title="JSLint" href="http://jslint.com/" target="_blank">JSLint</a> von <a title="Douglas Crockford" href="http://www.crockford.com/" target="_blank">Douglas Crockford</a> hat sich hier durchgesetzt und wird weitläufig verwendet. Es gibt zahlreiche Add-Ins für Visual Studio, Web-Validatoren usw. Meine Anforderung bestand nun darin, alle JavaScripts einer Solution bei einem Build zu validieren und gefundene Fehler in der Error-Liste zu haben. Zusätzlich sollte dies ohne Installation in einer Team-Umgebung funktionieren, wodurch sämtliche Add-Ins nicht von Relevanz sind. Dieser Beitrag zeigt, wie dieser Task innerhalb einiger Minuten erledigt werden kann.</p> <h2>Voraussetzungen</h2> <p>Wie der Titel schon besagt, werden sowohl <a title="Node.js" href="http://nodejs.org/" target="_blank">Node.js</a>, als auch JSLint benutzt. In meinem Fall kommt Node.js für Windows zum Zuge. Dieses wird als MSI-Paket ausgeliefert und kann direkt installiert werden. Damit nun aber nicht jedes Team-Mitglied dieses ebenfalls zu installieren hat, empfiehlt es sich, alles aus </p> <p><font face="Courier New">%ProgramFiles(x86)%\nodejs</font></p> <p>in ein Verzeichnis, welches im Source Control liegt, zu kopieren. Dazu sollte entsprechend auch die Struktur vorhanden sein. Hier meine Struktur als Beispiel:</p> <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Struktur einer Solution im Source Control" border="0" alt="Struktur einer Solution im Source Control" src="http://devtyr.norberteder.com/image.axd?picture=image_161.png" width="204" height="149" /></p> <blockquote> <p><strong>Kurze Erklärung</strong>, soweit nicht selbstsprechend: <font face="Courier New">3rdPartyLibraries</font> beinhält alles von externen Anbietern (Node.js wäre in diesem Fall so jemand), <font face="Courier New">Build</font> alle Dateien, die für das Build (sowohl Client als auch Server) notwendig sind. Unter <font face="Courier New">Sources</font> ist die tatsächliche Solution zu finden.</p> </blockquote> <p>In meinem Falle würde also Node.js für Windows in ein Unterverzeichnis von 3rdPartyLibraries kopiert werden. In Node.js inkludiert ist der Package-Manager <strong>npm</strong>. Darüber muss nun JSLint installiert werden:</p> <p><font face="Courier New">npm install jslint</font></p> <p>Damit ist das Modul vorhanden und kann adaptiert bzw. verwendet werden.</p> <blockquote> <p><strong>Hinweis</strong>: Es stehen weitere Module zur Verfügung, in unterschiedlichen Ausprägungen, teilweise angepasst an das gewünschte Verhalten des jeweiligen Entwicklers. Hier muss man mitunter ein wenig experimentieren, um herauszufinden, welches Modul die eigenen Anforderungen am besten abdeckt. </p> </blockquote> <p>Wenn nun auch noch <strong>PowerShell</strong> zur Verfügung steht, sind alle Grundvoraussetzungen erfüllt.</p> <h2>Anpassungen für Visual Studio</h2> <p>Eine der Anforderungen für mich ist die Anzeige der gefundenen Fehler in der Error-Liste von Visual Studio, schließlich möchte ich diese auf einen Blick sehen. Im normalen Output-Fenster (der Build-Ergebnisse) würden diese mitunter untergehen bzw. nicht berücksichtigt werden. Dafür muss eine kleine Änderung im installierten Modul vorgenommen werden. Die Datei <font face="Courier New">reporter.js</font> für vom <font face="Courier New">jslint</font>-Modul für die Ausgabe der Fehler verwendet. Damit die Ausgabe jedoch von Visual Studio erkannt und in die Error-Liste eingetragen wird, muss diese speziell formatiert werden. Nachfolgend meine aktualisierte Variante.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 600px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #008000">/*jslint forin: true */</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> color = require(<span style="color: #006080">&quot;./color&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> log = console.log;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">exports.report = <span style="color: #0000ff">function</span> (file, lint, colorize) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">'use strict'</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> options = [], key, value, line,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> i, len, pad, e, fileMessage;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">for</span> (key <span style="color: #0000ff">in</span> lint.options) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> value = lint.options[key];</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> options.push(key + <span style="color: #006080">&quot;: &quot;</span> + value);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> fileMessage = <span style="color: #006080">&quot;\n&quot;</span> + ((colorize) ? color.bold(file) : file);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (!lint.ok) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> len = lint.errors.length;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">for</span> (i = 0; i &lt; len; i += 1) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> e = lint.errors[i];</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (e) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> log(file + <span style="color: #006080">'('</span> + e.line + <span style="color: #006080">','</span> + e.character + <span style="color: #006080">'): warning: '</span> + e.reason);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> } <span style="color: #0000ff">else</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> log(fileMessage + <span style="color: #006080">&quot; is &quot;</span> + ((colorize) ? color.green(<span style="color: #006080">'OK'</span>) : <span style="color: #006080">'OK'</span>) + <span style="color: #006080">&quot;.&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> lint.ok;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Von spezieller Bedeutung ist diese Zeile:</p> <p><font face="Courier New">log(file + '(' + e.line + ',' + e.character + '): warning: ' + e.reason);</font></p> <p>Hier wird die Ausgabe genau so formiert, dass Visual Studio die Meldung als <strong>Warning</strong> erkennt und in der Error-Liste zur Anzeige bringt. Zusätzlich wurden einige Zeilen entfernt, die für diesen Anwendungsfall nicht benötigt werden. Bei einer Aktualisierung des Modules ist jedoch darauf zu achten, dass die Änderungen wieder nachgezogen werden.</p> <blockquote> <p><strong>Tipp</strong>: Wer die JSLint-Meldungen lieber als tatsächlichen Fehler erhalten möchte, muss lediglich <font face="Courier New">warning</font> gegen <font face="Courier New">error </font>tauschen.</p> </blockquote> <p>Nun fehlt noch die Einbindung ins Build.</p> <h2>Einbindung Build</h2> <p>Auch diese Aufgabe lässt sich einfach bewältigen. Im einfachsten Fall wird ein kleines Powershell-Script geschrieben, welches ins Pre-build Event des Hauptprojektes eingebunden wird. Das Script kann in etwa so aussehen:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">$node_js_path = ($args[0]).Trim()</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">$js_files_path = ($args[1]).Trim()</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">$jslintmodule = <span style="color: #006080">&quot;$node_win_dir&quot;</span> + <span style="color: #006080">&quot;\node_modules\jslint\bin\jslint.js&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">$js_files = get-childitem $js_files_path -include *.js -recurse -force</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">Set-Location $node_win_dir</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">foreach</span> ($file <span style="color: #0000ff">in</span> $js_files)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> .\node.exe $jslintmodule <span style="color: #006080">&quot;--sloppy&quot;</span> <span style="color: #006080">&quot;--white&quot;</span> <span style="color: #006080">&quot;--undef&quot;</span> $file</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">popd</pre> <!--CRLF--></div> </div> <p>Das Script enthält<strong> zwei Parameter</strong>. Der erste Parameter legt fest, wo sich Node befindet, der zweite Parameter beschreibt, in welchem Pfad sämtliche JavaScripts zu finden sind. Das PowerShell-Script durchsucht diesen Pfad rekursiv und übergibt alle Files an Node unter Aufruf des entsprechenden Moduls.</p> <p>Fertig.&#160; Natürlich ist dieser Schritt an die Gegebenheiten der jeweiligen Umgebung anzupassen und stellt daher nur die Minimalumsetzung dar.</p> <h2>Fazit</h2> <p>Mit ein paar wenigen Handgriffen lässt sich JSLint mit Hilfe von Node.js und einen Schuss Powershell ins Visual Studio Client-Build einbinden. Läuft dies über ein Source Control funktioniert diese Variante für alle Team-Mitglieder ohne Installation und Konfiguration. Zusätzlich finden sich alle Meldungen übersichtlich in der Error-Liste von Visual Studio und sind dadurch mit Sprungmarken versehen, um direkt an die jeweilige Stelle springen zu können.</p> http://devtyr.norberteder.com/post/JavaScript-Validierung-im-Visual-Studio-Build-mit-Nodejs-und-JSLint.aspx Norbert Eder [MVP] 3630 2012-02-29T14:10:00 Buch - Justifiers 5: Sabotage - Boris Koch <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Justifiers 5 - Sabotage - Boris Koch" border="0" alt="Justifiers 5 - Sabotage - Boris Koch" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_158.png" width="109" height="151" /><em>Der Forschungsbeauftragte eines Großkonzerns verschwindet scheinbar spurlos und mit ihm ein mysteriöser schwarzer Koffer. Es beginnt ein Wettrennen zwischen den Mächtigen, jeder will der Erste sein, der den Verschwundenen aufspürt. Schließlich werden die Justifiers eingeschaltet, um das Problem zu lösen, doch die finden sich plötzlich auf einem abgelegenen Planeten wieder, wo sie es mit äußerst aggressivem Grünzeug, Mafiakillern und einem Verräter in den eigenen Reihen zu tun bekommen …</em></p> <p>Das neue Abenteuer der Justifiers wird eindrucksvoll und schnell erzählt. Kaum lange Pausen, schon gar keine Langatmigkeit. Alexeij, der Hauptprotagonist, ist der Lead des Justifier-Teams und wird vom Konzernchef abgesetzt. Er muss sich einem cholerischen Bisonbeta unterordnen. Kein leichtes Unterfangen, befinden sie sich - schneller als sie schauen können - auf einem verlassenen Planeten wieder, in den eigenen Reihen einen Verräter und kaum etwas zu tun. Man kann sich sehr schnell in seine Rolle versetzen, wenngleich die Gedankengänge in einigen Situationen nicht ganz nachvollziehbar sind. </p> <p>Die erzählte Geschichte ist gut und bis 20 Seiten vor dem Schluss geht es richtig dahin. Dann kommt ein - für meinen Geschmack - etwas sehr abruptes Ende, welches mir wenig durchdacht erscheint. Entweder wurde hier bereits eine vorgeschriebene Seitenanzahl erreicht, oder es wollte einfach kein besserer Schluss einfallen. Schade eigentlich, denn bis dahin war Spannung angesagt, auch wenn dieser Teil zur Gänze ohne Aliens auskommt.</p> <p><strong>Bewertung</strong>: 3/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Justifiers-5-Sabotage-Boris-Koch.aspx Norbert Eder [MVP] 3629 2012-02-29T11:56:42 Kostenloses E-Book zu Knockout.js - Zwischenstand <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Aktion 1 + 2 des kostenlosen E-Books zu Knockout.js abgeschlossen" border="0" alt="Aktion 1 + 2 des kostenlosen E-Books zu Knockout.js abgeschlossen" src="http://devtyr.norberteder.com/image.axd?picture=image_156.png" width="980" height="176" /></p> <p>Vergangenen Freitag wurden die Exemplare des <a title="Knockout.js E-Book" href="http://books.norberteder.com/books/knockoutjs.html" target="_blank">Knockout.js E-Books</a> für Aktion 1 und Aktion 2 versandt. Zeitgleich startete die 3. Aktion, zu der noch einige kostenlose Exemplare verfügbar sind. Wer also noch eines möchte, schnell handeln, sonst sind sie weg. Mit der Registrierung gab es auch eine Umfrage über interessante Themen, zu denen ein E-Book gerne gesehen würde. Damit die ersten beiden Aktionen nun aus meiner Sicht vollkommen abgeschlossen sind, wurden diese ausgewertet. Das bisherige Ergebnis möchte ich an dieser Stelle teilen.</p> <h2>Auswertung</h2> <p>Insgesamt stehen fünf Auswahlmöglichkeiten zur Verfügung:</p> <ul> <li>Backbone.js</li> <li>HTML5</li> <li>Bootstrap</li> <li>Node.js</li> <li>Microsoft LightSwitch</li> </ul> <p>Im Zuge von Aktion 1 und 2 haben <strong>78%</strong> aller Teilnehmer an der Umfrage teilgenommen und ihre Stimme abgegeben (Mehrfachnennungen möglich). Das Zwischenergebnis ist für mich wenig überraschend:</p> <p>&#160;</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_157.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Auswertung Aktion 1 + 2 (Knockout.js E-Book)" border="0" alt="Auswertung Aktion 1 + 2 (Knockout.js E-Book)" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_100.png" width="604" height="412" /></a></p> <p>Da Aktion 3 noch am Laufen ist, kann es noch zu gravierenderen Änderungen kommen. Ich bin auf jeden Fall gespannt, wie das Ergebnis aussehen wird und ob sich das eine oder andere Thema noch an <strong>HTML5</strong> vorbei schieben kann.</p> <p>Wer’s noch nicht hat: <a title="Für kurze Zeit: Knockout.js E-Book" href="http://books.norberteder.com/books/knockoutjs.html" target="_blank">Jetzt mitmachen!</a></p> http://devtyr.norberteder.com/post/Kostenloses-E-Book-zu-Knockoutjs-Zwischenstand.aspx Norbert Eder [MVP] 3625 2012-02-27T07:49:42 E-Books für Entwickler - Aktion <p><img style="margin: 0px 10px 10px 0px; display: inline; float: left" title="E-Book Knockout.js" alt="E-Book Knockout.js" align="left" src="http://books.norberteder.com/books/images/cover.png" width="105" height="140" />Ab sofort steht mein neuestes Projekt unter <a href="http://books.norberteder.com">http://books.norberteder.com</a> online zur Verfügung. Darüber werden zukünftig E-Books zu unterschiedlichsten Entwickler-Themen publiziert. Ziel ist es, ansprechende, gut aufbereitete, Literatur für Entwickler zu einem günstigen Preis zur Verfügung zu stellen. Dabei werden die einzelnen Themen sorgfältig aufbereitet und sowohl eine Einführung in die Thematik, als auch aussagekräftige Praxisbeispiele geboten. Eine mühsame Suche quer durch das Internet entfällt. Immer wieder dieselben Einführungsbeispiele ebenso. Auch das Wälzen von 700 Seiten starken Büchern. Auf das Thema fokussiert, übersichtlich und praxisorientiert ist die Devise. Das erhaltene Wissen soll sofort in einem realen Projekt einsetzbar sein.</p> <h2>Einführungsaktion</h2> <p>Den Startschuss macht das E-Book zu <strong>Knockout.js</strong> - und das gleich mit einer Aktion. Wer schnell genug ist, ergattert ein kostenloses Exemplar des knapp über 70 Seiten starken E-Books.</p> <h2>Wie funktioniert es?</h2> <p>Die Aktion ist in insgesamt 3 Stufen eingeteilt. Sobald eine Stufe erfüllt ist, gilt sie als abgeschlossen und die entsprechenden Registrierungen zählen. D.h. alle, die sich registriert haben, bekommen per E-Mail ein kostenloses Exemplar dieses E-Books zugesandt. Solange eine Stufe nicht erfüllt ist, kommt es zu keiner Aussendung. Die genauen Modalitäten sind <a title="Jetzt schnell kostenlos das Knockout.js E-Book beziehen." href="http://books.norberteder.com/books/knockoutjs.html" target="_blank">hier</a> zu finden.</p> <h2>Was ist zu tun?</h2> <p>Nicht viel. Es ist lediglich ein Tweet abzusetzen und das darauffolgende Registrierungsformular auszufüllen. Dieses erfordert die E-Mail-Adresse. Es müssen keine weiteren Angaben gemacht werden.</p> <blockquote> <p><strong>Hinweis</strong>: Mit den anzugebenden E-Mail-Adressen wird sehr behutsam umgegangen. Es werden lediglich Informationen zu neu erschienenen Büchern bzw. neuen Aktionen versendet. Die Daten werden <strong>niemals</strong> an Dritte weitergereicht.</p> </blockquote> <h2>Was bringt die Zukunft?</h2> <p>Die Entscheidung liegt nicht ausschließlich bei mir. Vorerst sind einige Themen in Planung. Im Zuge der Registrierung kann jedoch (auf freiwilliger Basis) an einer Abstimmung teilgenommen werden. Das Resultat wird in weitere Überlegungen einfließen. </p> <h2>Feedback</h2> <p>Hast du zu diesem Projekt oder zur Aktion Feedback, dann lasse es mich bitte wissen und hinterlasse einen Kommentar. Gerne kann auch bezüglich Kooperationen auf mich zugekommen werden.</p> http://devtyr.norberteder.com/post/E-Books-fur-Entwickler-Aktion.aspx Norbert Eder [MVP] 3616 2012-02-22T18:05:21 Basta Spring 2012 – Ticket für Kurzentschlossene Achtung, ich habe für den ersten Kurzentschlossenen eine Freikarte zur Hauptkonferenz. Dieses findet vom 28.02.-01.03. im Rhein-Main Hotel in Darmstadt statt . Wer ernsthaftes Interesse hat, hin zu fahren, sollte sich bitte bei mir melden. Checkt das aber vorher mit Eurem Arbeitgeber ab, nicht das ich das Ticket halte und dann klappt es nicht und [...] http://feedproxy.google.com/~r/BigglesBlog/~3/AGgTYZAt56Q/basta-spring-2012-ticket-fr-kurzentschlossene Mario Priebe 3615 2012-02-22T12:16:27 Buch - Kolyma - Tom Rob Smith <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Tom Rob Smith - Kolyma" border="0" alt="Tom Rob Smith - Kolyma" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_155.png" width="109" height="170" /><em>Als Leo Demidow ins Zimmer seiner beiden Adoptivkinder kommt, tut Soja so, als würde sie schlafen. Aber der ehemalige KGB-Polizist hat genug Erfahrung mit Gefangenen, um zu erkennen, dass Soja hellwach ist und auf jede seiner Bewegungen mit Anspannung lauscht. Kurz zuvor hatte sie, wie schon so viele Nächte vorher, ein Messer an seine Halsschlagader gehalten. Aber dann war sie durch einen Anruf aufgeschreckt und davon abgehalten worden, ihre Tat vielleicht zumindest dieses Mal durchzuführen.</em></p> <p><em>Der nächtliche Anruf ist für Leo Demidow mehr als unangenehm. Er kommt von einem betrunkenen Kollegen, der sich schuldig fühlt. Er hat eine Schuld auf sich geladen, an der auch Demidow seinen Anteil hat. Das ganze Lügengebäude einer heilen Familie scheint endgültig zusammenzubrechen. Dann wird auch noch Soja entführt und der Ex-KGB’ler und jetzige Leiter eines von der Sowjet-Regierung verschwiegenen Morddezernats auf perfide Art und Weise erpresst. Wenn ihm das Leben seiner Adoptivtochter lieb ist, so fordern die Entführer, solle er sich ins Gulag an den Rand Sibiriens einschleusen lassen und dort einen Priester befreien, für dessen Internierung vor sieben Jahren er selbst verantwortlich zeichnet. Demidow lässt sich auf den Handel ein – und wird im Strafgefangenenlager prompt enttarnt. Von diesem Zeitpunkt an scheint seine Ermordung nur noch eine Frage der Zeit zu sein...</em></p> <p>Der Roman spielt in der Post-Stalin-Ära und arbeitet recht gut das totalitäre System heraus. Gespickt um die langsame Aufweichung des Regimes und der damit verbundenen Gegenwehr. Ein interessanter Roman, der auch die Gegenseite beleuchtet. Die Geschichte an sich ist tragisch und unvorstellbar - wenn man ein derartiges Regime nicht kennt. Der Erzählfluss ist ein guter, die Charaktere sind klar definiert und nicht bloß kurz umschrieben. Der letzte Teil mutet dem Leser dann allerdings etwas zu viel zu, wird denn auch die Ungarische Revolution 1956 ins Spiel gebracht. Die Geschichte verliert dabei an Spannung und wird unnötig in die Länge gezogen. Schade eigentlich, weniger wäre hier durchaus mehr gewesen. </p> <p><strong>Bewertung</strong>: 3/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Kolyma-Tom-Rob-Smith.aspx Norbert Eder [MVP] 3611 2012-02-20T09:22:19 Diskussion und Integration von Disqus <p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Disqus" border="0" alt="Disqus" src="http://devtyr.norberteder.com/image.axd?picture=image_154.png" width="900" height="135" /></p> <p>In regelmäßigen Abständen würde ich gerne die Kommentarfunktion meines Blogs überarbeiten. Ich finde sie einfach unzureichend für die heutige Zeit und sie macht auch nicht wirklich große Lust, seine Meinung zu sagen. Aber gerade für mich hat Feedback einen hohen Stellenwert, erweitert es doch häufig den eigenen Horizont durch zusätzliche Informationen oder Gesichtspunkte. Nun bietet <a title="BlogEngine.NET" href="http://www.dotnetblogengine.net/" target="_blank">BlogEngine.NET</a> von Haus aus die Möglichkeit an, <a title="Disqus" href="http://disqus.com" target="_blank">Disqus</a> zu verwenden. Nachdem mich nun <a title="Michael Horkavy auf Twitter" href="twitter.com/michaelhorkavy" target="_blank">@michaelhorkavy</a> diesen Gedanken wieder aufgefrischt hat, werfe ich nochmals einen Blick darauf und versuche das Thema für mich zu Hinterfragen. Das Resultat ist nicht nur eine Grundsatzdiskussion, sondern auch ein How-To (und das nicht nur für Blogger auf Basis BlogEngine.NET).</p> <h2>Diskussionsgrundlage</h2> <p>Meine Beweggründe, die Kommentarfunktion immer wieder aufs Neue gedanklich zu diskutieren sind einfacher Natur. Aber sehen wir uns zuvor doch einmal an, wie die Kommentarfunktion zum Zeitpunkt des Schreibens dieses Posts aussieht (zur Dokumentation, sollte eine tatsächliche Umstellung geschehen):</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_147.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Kommentarfunktion devtyr.norberteder.com" border="0" alt="Kommentarfunktion devtyr.norberteder.com" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_93.png" width="602" height="244" /></a></p> <p>Klar, hier könnte man per Styling schon etwas nachhelfen, dass eine größere Lust zum Kommentieren aufkommt. Der <strong>Vorteil</strong> dieser Variante liegt ganz klar darin, dass ich als Besucher <strong>keinen Account </strong>besitzen muss, um meine Meinung zu sagen. Der <strong>Nachteil</strong> für mich als Betreiber ist hingegeben, dass so sehr viel <strong>Spam</strong> zu bereinigen ist (natürlich stehen hierfür zahlreiche Helferlein zur Verfügung, die sind aber manchmal weniger gründlich und manchmal mehr als einem lieb ist). Abgesehen davon, habe ich in vielen Fällen einfach <strong>keine Ahnung woher der Kommentar</strong> kommt. Ist das wichtig? Ich sage: ja! Manchmal tun sich durch einen Kommentar Fragen auf, die zu diskutieren es lohnt. Kann ich aber nicht, wenn ich den Schreiber nicht kontaktieren kann (siehe beispielsweise Mail-Adressen via <a href="http://10minutemail.com/">http://10minutemail.com/</a>).</p> <p>Eine weitere nette Funktionalität nennt sich <strong>Benachrichtige mich bei neuen Kommentaren</strong>. Wunderbar. Ich bekomme eine Email, wenn sich Neues bei den Kommentaren getan hat. Bin ich gar mitten in einer Diskussion, möchte ich aber unmittelbar antworten. Kann das aber nicht, da diese Funktionalität schlicht nicht unterstützt wird. Ich werde zu einem <strong>Medienbruch</strong> genötigt, da ich meine Mails verlassen und das Blog besuchen muss, um weiter zu diskutieren. Eine recht große Hürde - wie ich meine. Zumindest fällt mir das immer wieder sehr schwer, wodurch ich diesen “Task” auf später verschiebe. Nur dazu kommt es dann kaum.</p> <p>Hier braucht es eine bessere Lösung. Ein Ansatz über den ich schon lange nachdenke kommt von Disqus.</p> <h2>Disqus - Das bessere Kommentarsystem?</h2> <p>Vor längerer Zeit ging mal das Kommentarsystem von Facebook herum. Will ich schlicht nicht einsetzen, da zu einschränkend. Außerdem möchte ich Facebook nicht noch mehr Daten vermitteln, als dies ohnehin schon der Fall ist. Eine weitere Variante besteht durch Disqus (weil, wie bereits angesprochen, auch durch BlogEngine.NET unterstützt). Aber wie kann Disqus hier helfen?</p> <h3>Vorteile</h3> <p>Sehen wir uns vorerst einmal an, welche Vorteile ein Einsatz von Disqus bringen kann.</p> <blockquote> <p><strong>Wichtig</strong>: Ich gehe hier nur auf die kostenfreien Funktionen ein. Kostenpflichtig sehen weit mehr Möglichkeiten zur Verfügung, kommen für mich jedoch nicht in Frage. Wer einen Überblick haben möchte, sei auf die <a title="Disqus Addons / Features" href="http://disqus.com/addons/" target="_blank">Featureübersicht</a> verwiesen.</p> </blockquote> <ul> <li><strong>Benachrichtigungen und Antwortmöglichkeiten</strong>. Benachrichtigungen werden per Email zugestellt. Antworten sind ebenfalls per Email möglich, auch das Löschen, Freischalten und Markieren von Spam. Kein Medienbruch mehr notwendig - eine klare Minimierung einer großen Hürde. </li> <li><strong>Einbinden von multimedialen Inhalten</strong>. Derartige Inhalte sind meist deaktiviert, werden sie doch meist missbraucht. Wenn sauber implementiert können derartige Inhalte eine Diskussion durchaus bereichern. </li> <li><strong>Kompatibilität zu mobilen Geräten</strong>. In meinem Fall sollte dies nachrangig sein, scheint aber hin und wieder doch <a title="Kommentarabgabe iPad" href="https://twitter.com/#!/SchelianHP/status/169129264074067968" target="_blank">Probleme</a> zu bereiten. </li> <li><strong>Integration von sozialen Netzwerken</strong>. Die meisten Besucher sollten einen Account auf Disqus selbst, Google, Twitter, Facebook, Yahoo oder eine OpenID haben. Dem Verfassen von Kommentaren sollten keine Steine in den Weg gelegt sein. </li> <li><strong>Sharing</strong>.&#160; Besucher können mitteilen, ob ihnen ein Beitrag oder ein Kommentar gefällt und diesen teilen. Auf Facebook, Twitter und anderen Netzwerken. </li> <li><strong>Tweets und Reaktionen</strong>. Unterhaltungen oder Reaktionen auf Twitter werden gesammelt und ebenfalls angezeigt. Schön gesammelt beim ursprünglichen Beitrag. </li> </ul> <p>Und dann gibt es natürlich noch weitere Funktionen wie Statistiken, Blacklists, Whitelists, verbotenen Worten, Spamfilter bis hin zu <strong>Importen und Exporten</strong>.</p> <h3>Wo ist nun der Haken?</h3> <p>Bis jetzt klingt das doch positiv. Oder nicht? Irgendwo muss aber jetzt ein Haken sein. Klar. Die Kommentare liegen nicht auf meinem System, sondern auf einem Fremdsystem. Was bedeutet dies konkret?</p> <ul> <li>Ein Backup meines Systems umfasst keine Kommentare. Diese werden hoffentlich vom Fremdsystem, als Disqus, gesichert. Wovon auszugehen ist. </li> <li>Ein Umstieg auf ein anderes Blogsystem kann mitunter nicht so einfach werden. Disqus kann zwar grundsätzlich sehr einfach eingebunden werden, unterstützt werden jedoch nur die wirklich weit verbreiteten Systeme á la Wordpress, Blogger und Co. D.h. hier ist manuelle Arbeit notwendig. </li> <li>Disqus verwendet für Importe und Exporte das <strong>WordPress eXtended Rss</strong> (WXR) Format. BlogEngine.NET setzt beispielsweise auf <a title="BlogML" href="http://code.google.com/p/blogml/" target="_blank">BlogML</a>. Da hätten wir dann schon mal unterschiedliche Formate. </li> <li>Was tun sollte Disqus dicht machen? Ist ein Rückführen der Kommentare dann möglich? Ja, ist es. Allerdings wieder mit manuellem Aufwand verbunden. </li> </ul> <h2>Umstellung auf Disqus</h2> <p>Schrecken die erwähnten Nachteile nicht ab, kann eine Umstellung recht einfach erfolgen. Nachfolgend die notwendigen Schritte um das Blog (hier wird die Umstellung eines BlogEngine.NET Systems beschrieben, Hinweise auf andere Systeme aber ebenfalls gegeben).</p> <h3>Registrierung Blog / Benutzer</h3> <p>Notwendig ist hierzu eine Registrierung des Blogs und eines Benutzers (Verwaltungs-Account). Wichtig hierbei ist der anzugebende <strong>Shortname</strong>, der in allen Fällen des Zugriffs benötigt wird. Alle anderen Einstellungen können jederzeit geändert werden.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_148.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Blog bei Disqus registrieren" border="0" alt="Blog bei Disqus registrieren" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_94.png" width="600" height="382" /></a></p> <p>Wie im Screenshot zu sehen, habe ich bereits einen Benutzer. Ist keiner vorhanden, kann dieser im selben Schritt erstellt werden. Soweit ist diese Seite fertig. Damit wäre diese Sache erledigt.</p> <h3>Export der Kommentare</h3> <p>Ein bestehendes System (wie es meines ist) hat für gewöhnlich bestehende Kommentare. Diese würden bei einer Freischaltung von Disqus am Blogsystem zwar nicht verloren gehen, kämen allerdings nicht mehr zur Anzeige. Schade um die vielen Informationen, die unsere Besucher bisher bereichert haben. Also müssen bestehende Kommentare importiert werden. Weiter oben habe ich bereits angesprochen, dass die BlogEngine.NET das BlogML-Format unterstützt und damit nicht von Haus aus in Disqus importiert werden kann (Wordpress, Blogger und Co. sind hier natürlich schön im Vorteil).</p> <p>Um nun die eigenen Kommentare zu konvertieren, wird ein Tool namens <a title="Download BlogMLtoDisqus.exe" href="http://catfood.net/products/BlogMLtoDisqus.exe">BlogMLtoDisqus.exe</a> verwendet. Dieses setzt das <a title=".NET Framework 4.0" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992&amp;displaylang=en" target="_blank">.NET Framework 4.0</a> voraus. Zuvor müssen die Daten jedoch im benötigten Format exportiert werden. Dieser Schritt ist über die Administration auszuführen, erreichbar unter <strong>Einstellungen -&gt; Importiere &amp; Exportiere -&gt; Exportiere</strong>.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_149.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="BlogEngine.NET - Daten exportieren" border="0" alt="BlogEngine.NET - Daten exportieren" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_95.png" width="600" height="208" /></a></p> <p>Das Resultat kann nun einfach über die Konsolenanwendung konvertiert werden:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_150.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="BlogML nach WXR konvertieren" border="0" alt="BlogML nach WXR konvertieren" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_96.png" width="404" height="29" /></a></p> <blockquote> <p><strong>Wichtig</strong>: Das Konvertierungstool schreibt leider für jedes Post inkl. Kommentare keinen Wert für <font face="Courier New">dsq:thread_identifier</font> (dsq ist als XML-Namesapce auf <a href="http://www.disqus.com">http://www.disqus.com</a> einzubinden). Dies sollte (zumindest im Falle BlogEngine.NET) die eindeutige Post-Id sein. Dieser Wert wird von Disqus herangezogen, um den <font face="Courier New">disqus_identifier</font> zu bilden. Dies ist eine eindeutige Id mit der der Post-Thread angesprochen werden kann und wird benötigt, um die Kommentare und den Kommentarzähler auf das Posting zu mappen. Ist dieser Wert nicht gesetzt, vergibt Disqus einen eigenen Wert, der im eigenen Blogsystem natürlich nicht zur Verfügung steht. Der Entwickler des Konvertierungstools wurde von mir darauf hingewiesen. Sollte es ein Update geben, werde ich dies kund tun. Oder aber einen Blick auf <a title="ILSpy" href="http://wiki.sharpdevelop.net/ILSpy.ashx" target="_blank">ILSpy</a> werfen :).</p> </blockquote> <h3>Import der Kommentare</h3> <p>Wurde die Konvertierung erfolgreich durchgeführt, muss die resultierende Datei auf Disqus importiert werden, auch hier in der Administration, jedoch unter Tools, zu finden.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_151.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Disqus - WXR importieren" border="0" alt="Disqus - WXR importieren" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_97.png" width="600" height="320" /></a></p> <p>Der Import wird nicht sofort durchgeführt, sondern landet in einer Queue. Sobald diese abgearbeitet wurde, erhält man eine Benachrichtigung. Man kann also nur hoffen, dass zwischenzeitlich keine neuen Kommentare am alten System hinzukommen, oder beinhart sein, und umschalten.</p> <h3>Disqus unter BlogEngine.NET aktivieren</h3> <p>Wer denn nun auf Disqus umsteigen möchte, der muss nun wieder in die Administration von BlogEngine.NET wechseln. Unter <strong>Einstellungen -&gt; Kommentare</strong> findet sich ein entsprechender Disqus-Block:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_152.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Disqus unter BlogEngine.NET aktivieren" border="0" alt="Disqus unter BlogEngine.NET aktivieren" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_98.png" width="600" height="345" /></a></p> <p>Sobald die neuen Einstellungen gespeichert wurden, ändert sich bereits das Erscheinungsbild der Kommentare:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_153.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Erscheinungsbild Disqus Kommentare" border="0" alt="Erscheinungsbild Disqus Kommentare" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_99.png" width="600" height="222" /></a></p> <p>&#160;</p> <p>Das war es dann fast.</p> <h3>Kommentarzähler anpassen</h3> <p>Wer, wie ich, einen Kommentarzähler anzeigt mag jetzt vielleicht enttäuscht sein, oder sich in seiner Annahme bestätigt fühlen. Hierfür muss eine weitere Änderung durchgeführt werden. Dazu wird folgendes Script benötigt:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;script type=<span style="color: #006080">&quot;text/javascript&quot;</span>&gt; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> disqus_title = <span style="color: #006080">'&lt;%=Post.Title %&gt;'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> disqus_identifier = <span style="color: #006080">'&lt;%= Post.Id.ToString() %&gt;'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> disqus_url = <span style="color: #006080">'&lt;%= Post.AbsoluteLink %&gt;'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> disqus_developer = <span style="color: #006080">'&lt;%= BlogEngine.Core.BlogSettings.Instance.DisqusDevMode ? 1 : 0 %&gt;'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> (<span style="color: #0000ff">function</span>() { </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> dsq = document.createElement(<span style="color: #006080">'script'</span>); </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> dsq.type = <span style="color: #006080">'text/javascript'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> dsq.async = <span style="color: #0000ff">true</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> dsq.src = <span style="color: #006080">'http://&lt;%=BlogEngine.Core.BlogSettings.Instance.DisqusWebsiteName %&gt;.disqus.com/embed.js'</span>; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> (document.getElementsByTagName(<span style="color: #006080">'head'</span>)[0] || document.getElementsByTagName(<span style="color: #006080">'body'</span>)[0]).appendChild(dsq); </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> })();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/script&gt;</pre> <!--CRLF--></div> </div> <p>Über das Setzen der Post-Id als Identifier wird kein eigener von Disqus gesetzt, wodurch die Kommentare beispielsweise auch wieder rückgeführt werden könnten.</p> <blockquote> <p><strong>Hinweis</strong>: Diese Anpassung ist in der Datei <span style="font-family: &#39;Courier New&#39;">Post.aspx</span> durchzuführen (hierfür ist bereits ein entsprechender JS-Block vorhanden, der noch wie oben beschrieben zu erweitern ist).</p> </blockquote> <p>Der Kommentarzähler kann dann im Anschluss so bezogen werden:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;a rel=<span style="color: #006080">&quot;nofollow&quot;</span> href=<span style="color: #006080">&quot;&lt;%=Post.AbsoluteLink %&gt;#disqus_thread&quot;</span> identifier=<span style="color: #006080">&quot;&lt;%= Post.Id.ToString() %&gt;&quot;</span>&gt;&lt;%=Resources.labels.comments %&gt;&lt;/a&gt;</pre> <!--CRLF--></div> </div> <p>Fertig.</p> <h2>Fazit</h2> <p>Natürlich muss sich jeder selbst Gedanken machen, ob ein Abgaben der Kommentare an ein Fremdsystem gewünscht ist. Im Falle des Falles macht Disqus einen recht netten Eindruck, zumal die Funktionen in der Gratis-Variante durchaus ansprechend sind und auch die Referenzen für sich sprechen. Eine Einbindung kann recht flott durchgeführt werden, wenngleich auch im Falle BlogEngine.NET einige manuelle Schritte vorzunehmen sind. Mit der gezeigten Einbindung ist es allerdings auch wieder möglich, Kommentare zurück ins eigene System zu bringen, sollte man von dieser Entscheidung zurücktreten wollen.</p> http://devtyr.norberteder.com/post/Diskussion-und-Integration-von-Disqus.aspx Norbert Eder [MVP] 3601 2012-02-14T12:44:00 Mobile Developer Conference 2012 in Hamburg Für mich war die MDC 2012 eine Doppelpremiere: Zum einen war ich das erste Mal dort, zum anderen stand ich auch das erste Mal als Sprecher selber auf der Bühne. Für alle, welche die Folien, Link-Sammlungen und Beispiel-Projekte zu meinen Vorträgen haben möchten, stehen die Daten nun auch hier im Blog online zur Verfügung.<br /><br /><em>Lese den vollst&auml;ndigen Artikel von Gordon Breuer auf <a href="http://gordon-breuer.de/post/2012/02/14/Mobile-Developer-Conference-2012-in-Hamburg.aspx">anheledir.NET</a>&hellip;<br /> Read the complete article by Gordon Breuer at <a href="http://gordon-breuer.de/post/2012/02/14/Mobile-Developer-Conference-2012-in-Hamburg.aspx">anheledir.NET</a>&hellip;</em> http://gordon-breuer.de/post/2012/02/14/Mobile-Developer-Conference-2012-in-Hamburg.aspx Gordon Breuer 3600 2012-02-14T12:38:19 Der Weg zurück zu LaTeX <p><img title="" alt="LaTeX" src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/92/LaTeX_logo.svg/800px-LaTeX_logo.svg.png" width="900" height="375" /></p> <p>Vor vielen, vielen Jahren habe ich <a title="http://de.wikipedia.org/wiki/LaTeX" href="http://de.wikipedia.org/wiki/LaTeX" target="_blank">LaTeX</a> für mich entdeckt. Ein Paket, um das Textsatz-Tool TeX einfacher verwenden zu können. Der Grund lag damals in meiner anstehenden Diplomarbeit. Nach dem Schreiben dieser habe ich eigentlich (nach anfänglichen, kurzen Liaisonen) wieder den Weg zurück zu <a title="Microsoft Word" href="http://office.microsoft.com/word/" target="_blank">Microsoft Word</a> gefunden. Einfach, da in der Geschäftswelt kaum etwas anderes - hinsichtlich Dokumente - verwendet wird. Das galt sowohl für Mitschriften (die dann zwar teilweise per <a title="Microsoft OneNote" href="http://www.microsoft.com/office/onenote/" target="_blank">Microsoft OneNote</a> geschrieben wurden), als auch für größere Dokumente, Artikel und Dokumentationen. Da nun aber wieder etwas längere Artikel/Beiträge anstehen, habe ich meine uralte LaTeX-Umgebung wieder ausgegraben, aktualisiert und in Betrieb genommen. Warum eigentlich?</p> <p>Vielmals wird ja behauptet:</p> <blockquote> <p>Wäre Microsoft Word für das Schreiben von Büchern gedacht, dann würde man es Microsoft Book nennen.</p> </blockquote> <p>Darüber kann man nun streiten. Word hat schon seine Berechtigung. Vor allem die Verbreitung spricht für sich. Auch verlangen sehr viele Verlage (eigentlich alle, mit denen ich je zu tun hatte) sämtliche Beiträge, Artikel und Bücher im Word-Format. Dazu werden (mehr oder weniger gute) Vorlagen angeboten, die das Schreiberlebnis vereinfachen sollten. Naja, weniger das Schreiberlebnis, vielmehr die Übernahme in eine tatsächliche Textsatz-Software. Dem kann man sich auch kaum entziehen, was ich äußerst schade finde, da es einfachere und bessere Systeme gäbe.</p> <blockquote> <p>Eines vorweg: Ich möchte hier keine Grundsatzdiskussion über Word und Konsorten lostreten. Wenn ich hier Word schreibe, dann kann man getrost auch OpenOffice Writer, LibreOffice Writer und was es sonst noch so alles in diesem Genre gibt, einsetzen.</p> </blockquote> <p>Für die Fälle, die mich unabhängig von Verlagen machen und in denen massig Inhalt zusammen kommt, steht mit LaTeX (und TeX) ein vollwertes Textsatzsystem zur Verfügung, das es unheimlich einfach macht, Texte zu verfassen - ohne Stress. </p> <h2>Vorteile von LaTeX</h2> <p>Dann kommen wir zu den Vorteilen von LaTeX und warum ich persönlich dessen Einsatz befürworte.</p> <ul> <li><strong>Plain-Text</strong>: Alle Texte stehen in Plain-Text zur Verfügung. Keine proprietären Formate, keine Quasi-Standards und auch kein Gezippe. Ideal über mit jedem erdenklichen System damit zu arbeiten. Zum Schreiben wird nichts als ein einfacher Texteditor benötigt. </li> <li><strong>Source Control</strong>: Da nur mit Textdateien gearbeitet wird (abgesehen von eingebundenen Grafiken) eignet sich ein beliebiges Source Control System dazu, die Dateien darauf abzulegen und so eine Versionierung zu erreichen. Arbeiten mehrere Personen daran, greifen auch sämtliche Merge-Operationen.</li> <li><strong>Der Inhalt zählt!</strong> Beim Einsatz von Word und Co. muss erheblicher Aufwand geleistet werden, bis das Dokument so aussieht, wie man möchte. Ständig sind Umformatierungen notwendig, dann werden wieder Fußnoten nicht so angezeigt, wie sie sollten, Referenzen sind mit einem Mal ungültig usw. Je größer das Dokument wird, umso schwieriger die Verwaltung. Anders bei LaTeX. Hier zählt der Inhalt. Die Formatierung wird durch das Satzsystem vorgenommen. Während des Schreibens kann man sich voll und ganz auf das zu Schreibende konzentrieren. Es gibt kein Verrutschen einer Grafik, das einen aufhält. Keine Referenz, die nicht gesetzt werden will. Keine Seitenumbrüche, die den Kontext vernichten.</li> <li><strong>Styles / Formatierungen</strong>: Gerade bei aufwändigeren Formatierungen, beispielsweise der ordentlichen und übersichtlichen Formatierung von Sourcecodes und/oder Formeln) zeigt sich die Mächtigkeit von LaTeX gegenüber von Word und Konsorten. Einmal definiert, sieht das Ergebnis immer gleich aus, es gibt keine “externen” Einflüsse.</li> <li><strong>Erweiterungen</strong>: Für jeden Zweck stehen Erweiterungen (zB. via <a title="CTAN" href="http://www.ctan.org/" target="_blank">CTAN</a>) zur Verfügung. Damit kann wirklich alles konfiguriert und angepasst bzw. unterstützt werden. Und auch hier: Man bleibt von ungewollten Ablenkungen verschont. </li> <li><strong>Gleicher Output - überall</strong>! Schon einmal mühsam das Word so hingebogen, dass alle Seitenumbrüche an der richtigen Stelle sind, Tabellen und Grafiken korrekt positioniert sind und dann doch auf einem anderen Rechner gedruckt? Ja? Dann sollte man sich LaTeX genauer ansehen :)</li> </ul> <p>Schon eine Menge Vorteile und es ließen sich weitere finden …</p> <h2>Nachteile von LaTeX</h2> <p>Natürlich hat dieses System auch Nachteile, die hauptsächlich für Einsteiger eine große Hürde darstellen:</p> <ul> <li>Änderungen sind nicht sofort sichtbar. Das Dokument muss zuvor “kompiliert” werden.</li> <li>Word und Konsorten sind intuitiver</li> <li>Hohe Verbreitung</li> </ul> <p>Damit man versteht, was ich meine, hier ein Beispiel einer Tabelle unter LaTeX:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_144.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Beispiel einer Tabelle mit LaTeX" border="0" alt="Beispiel einer Tabelle mit LaTeX" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_91.png" width="402" height="209" /></a></p> <p>Die Ausgabe sieht dann in etwa so aus (je nach unterstützten Styles):</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_145.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_92.png" width="400" height="95" /></a></p> <p>Das sieht nun zwar etwas kompliziert aus, geht aber nach einer Eingewöhnungsphase recht gut von der Hand. Und der Vorteil: Alle Tabellen sehen auch wirklich gleich aus und werden korrekt gesetzt. D.h. es muss nicht jede Tabelle extra mit einer Vorlage oder einem Styling versehen werden (was gerade bei längeren Dokumenten in unterschiedlichen Formatierungen resultiert).</p> <h2>Weitere Hürden?</h2> <p>Die einzige Hürde, die es hier zu betonen gibt trifft beim Thema <strong>Kollaboration</strong> zu: Hier ist es so, dass gerade für die Businessanwendung (wenn mehrere Personen an den selben Dokumenten arbeiten) die Akzeptanz sehr gering ist, da eben Word und Co. einfacher zu bedienen und mit einem WYSIWYG-Editor ausgestattet sind. Als Standard kann das Dokument eben mal an einen Kollegen und/oder Kunden gesendet werden, der seine Kommentare dazu abgibt (was jedoch auch mit einem PDF funktionieren würde). Daher eignet sich LaTeX wohl eher hauptsächlich im wissenschaftlichen Bereich, oder wenn man alleine bzw. in einem eingeschworenen Team arbeitet (bzw. gemeinsam an einem Dokument schreibt). </p> <p>Gerade in letzterem Fall stellt sich LaTeX sehr schnell als Vorteil heraus. Zwar kann Word auch mit mehreren Dokumenten umgehen, die zu einem Hauptdokument&#160; zusammengefasst werden, jedoch sind mir dabei bis dato noch nie Probleme erspart geblieben.</p> <p>Es gilt also durchaus abzuwägen, wann dann doch lieber zu Word gegriffen wird …</p> <h2>Was wird unter Windows benötigt?</h2> <p>Wie schon eingangs erwähnt ist es bei LaTeX unerheblich, unter welchem System gearbeitet wird. Die wohl größte Anzahl an Tools etc. findet sich in der Linux-Welt, aber auch unter Windows lässt sich bequem damit arbeiten. Hier eine kurze Auflistung der eingesetzten Tools:</p> <ul> <li><a title="MiKTeX" href="http://miktex.org/" target="_blank">MiKTeX</a>: Eine aktuelle Implementierung von TeX für Windows inklusive aller notwendigen ausführbaren Dateien (um beispielsweise PDF, PS etc. zu erzeugen) und einem Package-Manager zum einfachen Nachinstallieren von gewünschten Erweiterungen.</li> <li><a title="TeXnicCenter" href="http://www.texniccenter.org/" target="_blank">TeXnicCenter</a>: Ich verwende als Editor für gewöhnlich TeXnicCenter. Darüber werden viele Dinge einfacher gemacht (das Erstellen der Ausgaben, Hilfe bei einschlägigen Befehlen etc.). Dies steht sowohl in einer stabilen Version 1.0 zur Verfügung, als auch einer Alpha-Version 2.0 (diese habe ich im Einsatz und zeigt sich recht stabil).</li> </ul> <p>Das war es schon an benötigten Tools. Wie gesagt, zum Schreiben selbst ist ein einfacher Editor ansich ausreichend (wer um all die notwendigen Befehle Bescheid weiß). Zur Erstellung der Ausgabe wird MiKTeX verwendet. Für die bequemeren dann eben eine entsprechende grafische Umgebung. Hier stehen neben TeXnicCenter noch Alternativen bereit, teilweise speziell für Windows, teilweise auch plattformunabhängige Lösungen, darunter unter anderem <a title="kile" href="http://kile.sourceforge.net/" target="_blank">Kile</a>, <a title="TeXstudio" href="http://texstudio.sourceforge.net/" target="_blank">TeXstudio</a> usw.</p> <h2>Ich möchte mehr Information!</h2> <p>Wer sich eingehender mit LaTeX beschäftigen möchte, dem sei das <a title="LaTeX-Kompendium" href="http://de.wikibooks.org/wiki/LaTeX-Kompendium" target="_blank">LaTeX-Kompendium</a> ans Herz gelegt. Es gibt einen wirklich guten Überblick über diese Materie und bringt die wichtigsten Eigenheiten/Befehle näher, um schnell loslegen zu können. Nachdem LaTeX gerade im wissenschaftlichen Bereich eine große Verbreitung hat, finden sich viele Informationen und Hilfen im Internet, einfach nach dem Gewünschten suchen. Es sollte kaum eine Frage offen bleiben.</p> http://devtyr.norberteder.com/post/Der-Weg-zuruck-zu-LaTeX.aspx Norbert Eder [MVP] 3598 2012-02-13T10:23:15 User Interfaces – Zukunftsvisionen Wie werden wohl Benutzeroberflächen künftig aussehen? Zwei sehr interessante Videos geben Eindrücke von User Interfaces von morgen. Die Firma Corning zeigt mit ihrem Video unterschiedliche Arten von Glas und den dazugehörigen UIs. A Day Made of Glass 2 Auch Microsoft zeigt in einem Video seine Zunkunftsvisionen.  Productivity Future Vision (2011)<img src="http://feeds.feedburner.com/~r/UxDevelopa/~4/r9SfFfmX0ik" height="1" width="1"/> http://feedproxy.google.com/~r/UxDevelopa/~3/r9SfFfmX0ik/ Kazim Bahar 3596 2012-02-12T23:43:05 .NET BlogBook: Over and out <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title=".NET BlogBook - das ultimative Nachschlagewerk für .NET" border="0" alt=".NET BlogBook - das ultimative Nachschlagewerk für .NET" src="http://devtyr.norberteder.com/image.axd?picture=image_143.png" width="960" height="264" /></p> <p>Am <strong>4. Januar 2007</strong> wurde das <a title=".NET BlogBook - das ultimative Nachschlagewerk für .NET" href="http://dotnet-blogbook.com" target="_blank">.NET BlogBook</a> von mir und <a title="Blog von Kai Gloth" href="http://blog.veloursnebel.de/" target="_blank">Kai Gloth</a> ins Leben gebracht. Dabei handelte es sich um eine Aufarbeitung der zum Thema .NET angefallenen Blogbeiträge unserer beider Blogs. Insgesamt sieben Ausgaben wurden veröffentlicht, die mehr als <strong>50.000 Mal</strong> herunter geladen wurden. Eine ordentliche Leistung - wie ich meine - mit entsprechend viel positiver Rückmeldung. Aber die Zeit dreht sich weiter und dieses Format verlor zunehmend an Berechtigung. Aus diesem Grund habe ich mich dazu entschlossen, dieses Projekt nun gänzlich einzustellen. Die Downloads werden bis auf Weiteres erhalten bleiben und auf einer neuen, aber einfacheren, Site präsentiert.</p> <h2>.NET BlogBook im Laufe der Zeit</h2> <p>Und so haben sich die einzelnen Ausgaben im Laufe der Zeit verändert, beginnend mit Ausgabe 1</p> <div> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_135.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 1" border="0" alt=".NET BlogBook - Ausgabe 1" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_84.png" width="174" height="244" /></a><a href="http://devtyr.norberteder.com/image.axd?picture=image_136.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 2" border="0" alt=".NET BlogBook - Ausgabe 2" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_85.png" width="174" height="244" /></a><a href="http://devtyr.norberteder.com/image.axd?picture=image_137.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 3" border="0" alt=".NET BlogBook - Ausgabe 3" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_86.png" width="174" height="244" /></a></p> </div> <div> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_138.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 4" border="0" alt=".NET BlogBook - Ausgabe 4" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_87.png" width="174" height="244" /></a><a href="http://devtyr.norberteder.com/image.axd?picture=image_139.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 5" border="0" alt=".NET BlogBook - Ausgabe 5" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_88.png" width="174" height="244" /></a><a href="http://devtyr.norberteder.com/image.axd?picture=image_140.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 6" border="0" alt=".NET BlogBook - Ausgabe 6" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_89.png" width="174" height="244" /></a></p> </div> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_141.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title=".NET BlogBook - Ausgabe 7" border="0" alt=".NET BlogBook - Ausgabe 7" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_90.png" width="174" height="244" /></a></p> <h2>Danke</h2> <p>An dieser Stelle ein herzliches Dankeschön an alle, die dieses Projekt unterstützt haben. Sei es <a title="Blog von Kai Gloth" href="http://blog.veloursnebel.de" target="_blank">Kai</a>, der fleißig mitgewirkt hat, sei es <a title="Thomas @ twitter" href="http://twitter.com/asp_net" target="_blank">Thomas</a>, der uns beim Cover-Design unterstützt hat, oder aber alle Leser mit ihren zahlreichen Rückmeldungen. Danke!</p> http://devtyr.norberteder.com/post/NET-BlogBook-Over-and-out.aspx Norbert Eder [MVP] 3592 2012-02-09T11:16:23 Multiple types were found that match the controller named ‘xxx’ Wenn man mit Areas innerhalb eines MVC Projektes arbeitet, dann wäre es ja sinnvoll beispielweise auch auch einen Controller namens Home zu verwenden. Das Problem ist nur, wenn man eben schon einen HomeController in der Anwendung hat, dass man vorerst die Fehlermeldung “Multiple types were found match the controller named “xxx” bekommt. Diese bekommt man [...] http://feedproxy.google.com/~r/BigglesBlog/~3/Gf0Tp4XzNGQ/multiple-types-were-found-that-match-the-controller-named-xxx Mario Priebe 3585 2012-02-07T14:06:05 Buch - Code Zero - Stel Pavlou <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Code Zero - Stel Pavlou" border="0" alt="Code Zero - Stel Pavlou" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_133.png" width="105" height="164" /></p> <p><em>8. März 2012. In der Antarktis, im Amazonas und unter der Sphinx stößt man auf mysteriöse kristallartige Artefakte mit hieroglyphenartigen Beschriftungen. Zwischen den drei Fundorten zirkuliert ein merkwürdiges Signal, dessen Botschaft ein Team internationaler Wissenschaftler verzweifelt zu entschlüsseln versucht. Doch es könnte bereits zu spät sein: Eine entsetzliche Prophezeiung droht sich zu erfüllen…</em></p> <p>Klingt interessant. Ist es grundsätzlich auch. Eine Geschichte über abenteuerlustige Wissenschaftler, einer Handvoll Marines und einer unglaublichen Bedrohung. Die Welt will gerettet werden, doch dazu ist ein 12.000 Jahre altes Geheimnis zu lüften. Rund um den Sprachwissenschaftler Scott wird versucht uralte Glypten zu entschlüsseln. Dabei geraten sie immer weiter in einen gefährlichen Strudel.</p> <p>Das Buch beginnt äußerst spannend, die Geschichte hinterlässt jedoch den Geschmack des Wiedergekauten. Schon oft hat man so ähnliche Stories gelesen, wenn auch vielleicht nicht mit diesem Grad an Aufarbeitung. Dennoch muss gesagt werden, dass der anfängliche Lesefluss recht stark nachlässt, da sich die Geschichte immer weiter verstrickt und leider in zu vielen Details und langatmigen Erklärungen untergeht. Kurzweilig stelle ich mir anders vor. Auch das Setting ist mittlerweile etwas langweilig, zu oft wurde man mit genau dieser Konstellation (Wissenschaftler werden zusammen gerufen, haben keine Zeit, müssen ein Problem lösen usw.) bereits konfrontiert. Das Ende selbst ist - kurz gesagt - für Hollywood geschrieben. Einfach too much. Es macht sich vielleicht auf einer Leinwand ganz gut, dennoch hätte ich mir einfach mehr erwartet.</p> <p>Im Großen und Ganzen kann ich dieses Buch nicht komplett empfehlen, lediglich die erste Hälfte. Das ist nicht nicht genug. Schade, hätte die Story selbst Potential.</p> <p><strong>Bewertung</strong>: 1/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Code-Zero-Stel-Pavlou.aspx Norbert Eder [MVP] 3582 2012-02-06T16:00:00 Jetzt Backbone.js lernen: JavaScript und Suchmaschinen <p>Der <a title="Jetzt Backbone.js lernen: Konzept WPF Blogger" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Konzept-WPF-Blogger.aspx">letzte Teil</a> der Serie <a title="Jetzt Backbone.js lernen: Die Serie" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Die-Serie.aspx">Jetzt Backbone.js lernen</a> beschäftigte sich mit dem Konzept des zu Grunde liegenden Projektes. Dieser Beitrag geht nun auf ein oftmals unterschätztes Thema der Webentwicklung ein, der Optimierung für Suchmaschinen in Verbindung mit JavaScript. Oder besser: Worauf sollte ich bezüglich Suchmaschinen aufpassen, wenn massig JavaScript eingesetzt wird. So soll ein stimmiges Bild entstehen, welches klar und deutlich hervorhebt, für welche Bereiche des Projektes JavaScript eingesetzt wird, und für welche nicht. Hierfür wird auch auf das Thema der Hashbangs eingegangen.</p> <h2>Abgrenzung</h2> <p>Wer sich in diesem Beitrag zahlreiche Tipps erwartet, wie sich denn das eigene Projekt für Suchmaschinen optimieren lässt, der wird an dieser Stelle nicht abgeholt. Hierzu findet sich bereits zahlreiches Material im <a title="Tipps zur Suchmaschinenoptimierung" href="http://www.bing.com/search?q=suchmachinenoptimierung+tipps" target="_blank">Internet</a>.&#160; Hier geht es darum festzustellen, welche Teile des Projektes sinnvoll über JavaScript abgewickelt werden und wie Content, der via AJAX bezogen wird, dennoch für Suchmaschinen zu finden ist. </p> <h2>Suchmaschinen und JavaScript</h2> <p>Um festlegen zu können, welche Teile einer Website statisch geliefert und welche dynamisch erzeugt werden, bedarf es zwei wichtiger Informationen. Zum Einen muss das Konzept der Website stehen. Dieses muss klar definieren, welche Inhalte vermittelt werden und worauf der Fokus gelegt wird. Zum Zweiten muss bekannt sein, wie Bots arbeiten. </p> <p>Fälschlicherweise wird oftmals angenommen, dass Googlebot und Co. die Website gleich “sehen”, wie das ein normaler Besucher via Browser tut. Dem ist aber natürlich nicht so. Ein Bot kann (noch) nicht mit dynamischen Inhalten umgehen, lediglich statischer Inhalt ist für ihn sichtbar und kann somit ausgewertet werden. Verwendet man nun beispielsweise JavaScript, um Daten vom Server zu laden, um diese dann per Template etc. anzuzeigen, dann sind dies Daten, die für einen Bot nicht zur Verfügung stehen.</p> <blockquote> <p>Ein gutes Beispiel hierfür findet sich in der Serie <a title="Jetzt Knockout.js lernen: Die Serie" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Die-Serie.aspx">Jetzt Knockout.js lernen</a>: In <a title="Jetzt Knockout.js lernen: Template verwenden" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">diesem Beispiel</a> werden Daten vom Server bezogen und via Template zur Anzeige gebracht. Sieht man sich den Quelltext der Seite an, erhält man ein Bild des Bots auf diese Seite. Herzlich wenig für eine Indizierung.</p> </blockquote> <p>Bei Interesse kann man sich Genaueres auch <a title="Rex Swain&#39;s HTTP Viewer" href="http://www.rexswain.com/httpview.html" target="_blank">hier</a> ansehen.</p> <h2>Hashbangs</h2> <p>Eine Möglichkeit dem ein wenig zu entgehen sind sogenannte <a title="Hashbang, Shebang auf Wikipedia" href="http://en.wikipedia.org/wiki/Hashbang" target="_blank">Hashbangs</a> (#!). Hierzu hat sich Google (schon vor langer Zeit) etwas einfallen lassen: <a title="Making AJAX Applications Crawlable" href="http://code.google.com/intl/de/web/ajaxcrawling/docs/specification.html" target="_blank">Making AJAX Applications Crawable</a>. Auch Bing kann damit mittlerweile <a title="Bing can AJAX Crawling" href="http://www.squidoo.com/ajax-crawling" target="_blank">umgehen</a>, wodurch diese Lösung durchaus in Betracht gezogen werden kann und sollte. Wer darin noch nicht so versiert ist, sollte einen Blick darauf werfen. </p> <h3>So funktioniert ein Hashbang</h3> <p>Historisch gesehen wird ein Hash (#) als <strong>Named Anchor</strong> verwendet, also ein benannter Anker innerhalb eines Dokumentes, an den per Link gesprungen werden kann. Alles was in einem URI nach dem Hash angegeben wird, wird daher nicht an den Server gesendet, sondern rein clientseitig verwendet/ausgewertet. Oftmals ist es nun aber so, dass der Ankerpunkt nicht vorhanden ist, sondern per AJAX-Call nachgeladen wird. Dies kann nun natürlich von keiner Suchmaschine ausgewertet werden.</p> <p>Der Ansatz von Google geht nun dahin, dass anstatt eines reinen Hashs ein Hashbang (#!) verwendet wird. Trifft der Googlebot auf einen derart aufgebauten Link, wird dieser umgewandelt. Aus</p> <blockquote> <p>http://devtyr.norberteder.com/#!/series</p> </blockquote> <p>wird dann </p> <blockquote> <p>http://devtyr.norberteder.com/?_escaped_fragment=/series</p> </blockquote> <p>Dieser URI wird vom Googlebot erneut aufgerufen und muss nun den dahinter verborgenen Content statisch zurückliefern. Somit kann der Inhalt indiziert werden. In der Anzeige von Suchergebnissen wird jedoch der “saubere” Link verwendet.</p> <p>Da Bing und Co. ebenfalls nachgezogen haben, stellt diese Lösung keine größere Problematik mehr da bzw. wird keine größere Suchmaschine ausgegrenzt.</p> <h2>Anwendungsgebiete Hashbangs</h2> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_132.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 10px 10px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Aktionen und Statistiken WPF-Blogger" border="0" alt="Aktionen und Statistiken WPF-Blogger" align="right" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_83.png" width="69" height="72" /></a>Für welche Bereiche des Projektes kann dies sinnvoll sein? Rufen wir uns das <a title="Jetzt Backbone.js lernen: Konzept WPF-Blogger" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Konzept-WPF-Blogger.aspx">Konzept</a> in Erinnerung. So werden in der Header-Leiste Aktionen angeboten, beispielsweise das Umschalten der Sprache, zu der Ergebnisse anzuzeigen sind. Auch diverse Statistiken auf der rechten Seite. Diese könnten nun so gestaltet werden, dass nicht die gesamte Seite durch den Server aufbereitet werden muss, sondern lediglich der Inhaltsbereich bezogen wird. Ein klassischer Fall für AJAX. Und somit auch für die Verwendung von Hashbangs, da somit auch der dahinter liegende Inhalt indiziert werden kann. </p> <p>Anregungen für weitere Anwendungsgebiete kann man sich unter anderem auch von <a title="Twitter" href="http://twitter.com" target="_blank">Twitter</a> holen.</p> <h2>Wo nun JavaScript verwenden?</h2> <p>Ein weiteres wichtiges Faktum ist, dass die geladene Seite Inhalte für die Indizierung bereit gestellt (nicht nur gefüllte META-Tags). Daher ist es anzuraten, die initiale Seite vollständig am Server aufzubereiten. Erst durch den Benutzer folgende Aktionen sollen nun via JavaScript und AJAX ausgewertet und verarbeitet werden. Dies betrifft daher unter anderem folgende Punkte:</p> <ul> <li>Aufgrund der Browsersprache wird anfänglich entschieden, aus welchem Pool Einträge anzuzeigen sind. Hier werden die ersten n Einträge fix ausgeliefert. Per JavaScript kann es nun allerdings möglich sein, auf das Scrollverhalten des Benutzers zu reagieren und ein <strong>Infinite Scroll</strong> zu implementieren. </li> <li>Das <strong>Wechseln der Sprache</strong> (und dem damit verbundenen Austausch des Inhaltsbereiches) kann am Client passieren. Durch entsprechendes Anbieten von Hashbangs können Suchmaschinen alle angebotenen Sprachen durchforsten und indizieren. </li> <li>Etwaige <strong>Verlinkungen der Statistiken</strong> werden ebenfalls am Client gehandhabt. Die Statistiken selbst werden jedoch bereits am Server zusammengebaut. Hier sollte es völlig ausreichend sein, diese nur bei jedem erneuten Laden der Seite zu aktualisieren. </li> <li>Im <strong>Bereich für angemeldete Benutzer</strong> ist eine Indizierung durch Suchmaschinen wenig zielführend, ja sogar gänzlich unerwünscht. Sämtliche Eingabeformulare, Übersichten, Statistiken etc. können komplett via JavaScript und AJAX-Calls abgewickelt werden. </li> </ul> <p>Diese Punkte geben den grundsätzlichen Rahmen vor, der auch auf andere Stellen angewandt werden kann. Es sollte so jedoch durchaus gut vermittelt werden, welche Bereiche durch JavaScript (und in weiterer Folge <a title="Backbone.js" href="http://backbonejs.org/" target="_blank">Backbone.js</a>) abgedeckt werden.</p> <h2>Fazit</h2> <p>Wer eine Website implementiert möchte natürlich auch, dass diese gefunden wird. Die Auswahl der einzusetzenden Technologien ist hierbei allerdings nur die halbe Miete. Beste Technologie verschafft noch immer keine Besucher. Daher ist auf das Thema der Suchmaschinen unbedingt Rücksicht zu nehmen und sollte ihnen die Chance geben, die Website zu indizieren. Dieser Beitrag hat einige grundlegende Informationen vermittelt, um auch Seiten mit starker JavaScript-Verwendung für Suchmaschinen zu optimieren. Auf weitere Optimierungen ist bewusst nicht eingegangen worden, da es hierzu zahlreiche Inhalte im Internet gibt.</p> <p>Nachdem nun viele wichtige Fragen geklärt wurden (das Konzept steht, wir wissen, wann wir JavaScript einsetzen sollten und wann nicht), kann es ab dem nächsten Teil dieser Serie ans Eingemachte gehen. Es folgt eine Einführung in Backbone.js.</p> http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-JavaScript-und-Suchmaschinen.aspx Norbert Eder [MVP] 3580 2012-02-06T12:00:00 Jetzt Backbone.js lernen: Konzept WPF-Blogger <p>Bevor es so richtig mit <a title="Backbone.js" href="http://backbonejs.org/" target="_blank">Backbone.js</a> los geht, möchte ich das neue Konzept von <a title="WPF-Blogger" href="http://wpf-blogger.com" target="_blank">WPF-Blogger</a> vorstellen, die grundlegenden Features beschreiben und über den generellen Aufbau als solchen berichten. Es sind zahlreiche Änderungen angedacht. Aus dem Feed-Aggregat soll eine Site mit weit mehr Benutzer-Interaktion entstehen. Einige Funktionalitäten stellen jedoch auch lediglich Überlegungen dar, die ich gerne zur Diskussion freigeben möchte. Aber mehr in dieser Vorstellung.</p> <h2>Status Quo</h2> <p><a title="WPF-Blogger" href="http://wpf-blogger.com" target="_blank">WPF-Blogger</a> war ursprünglich als reines Feed-Aggregat konzipiert. Ziel war es, Feeds zum Thema WPF zu bündeln und Interessierten gesammelt zur Verfügung zu stellen. Folgende Features wurden in der ersten Version inkludiert:</p> <ul> <li>Feed-Aggregation von ausgesuchten Blog-Feeds </li> <li>Mehrsprachigkeit </li> <li>Registrierung von neuen Feeds </li> <li>Übersicht aller registrierten Feeds </li> <li>Archiv inklusive Suche </li> <li>Gesamtfeed und Sprachfeeds </li> <li>Statistiken </li> </ul> <p>Umgesetzt wurde die Website mit ASP.NET und WebForms und ganz, ganz wenig JavaScript.</p> <p><a title="WPF-Blogger" href="http://wpf-blogger.com" target="_blank"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://devtyr.norberteder.com/image.axd?picture=image_127.png" width="604" height="329" /></a></p> <h3>Feed-Aggregat</h3> <p>Für das Aggregieren der Feeds läuft ein eigener Job, der zeitgesteuert sämtliche Feeds hin auf Neuigkeiten prüft bzw. bereits importierte Artikel aktualisiert. Dieser bleibt durch die Neuentwicklung der Website unberührt, da alle wesentlichen Funktionen enthalten sind.</p> <h2>Quo vadis?</h2> <p>Das ursprüngliche “Konzept” war hauptsächlich auf mich persönlich zugeschnitten. Es sollte eine Stelle sein, an der ich alle interessanten Blogs zum Thema WPF sammeln kann. Da dies auch für andere von Interesse sein konnte, hatte ich mich damals kurzer Hand entschlossen, eine eigene Website online zu stellen.</p> <p>Im Laufe der Zeit hat sich gezeigt, dass das Interesse für diese Site da ist, jedoch fehlt vielen (auch mir) die Möglichkeit selbst Informationen einzustellen bzw. gute Inhalte zu teilen - kennt man schließlich auch von anderen Webangeboten. So das Feedback.</p> <p>Nun gut, aber wie sieht es um den geplanten Funktionen aus?</p> <ul> <li><strong>Login über Drittanbieter</strong>. In der ersten Implementierungsphase wird Twitter implementiert. Als Erweiterung sollen Facebook und Google Plus ebenfalls angeboten werden, um möglichst wenige auszuschließen. Gewisse Funktionalitäten sind nur im eingeloggten Zustand möglich. </li> <li><strong>Suche</strong>. Eine Suche war bis dato über das Archiv bereits möglich. Dies wird weiterhin möglich sein, soll aber präsenter platziert werden. </li> <li><strong>Sprachauswahl</strong>. Wie bisher soll auch die Sprachauswahl weiter bestehen bleiben. Durch diese wird bestimmt, aus welcher Sprache Ergebnisse anzuzeigen sind. Die generelle Sprache der Website ergibt sich durch die Browsersprache. </li> <li><strong>Sharing Content</strong>. Es soll möglich sein, einzelne Artikel über unterschiedliche Kanäle zu verteilen, um guten Content bestmöglich verteilen zu können. Angeboten sollen Twitter, Facebook und Google Plus werden. Zusätzlich soll es möglich sein, Artikel für das spätere Lesen zu markieren. Dies kann wahlweise in der Applikation selbst (man muss angemeldet sein) oder über die Anbindung von Drittanbietern (Read It Later etc.) geschehen. </li> <li><strong>Statistiken</strong>. Diese sollen helfen, gute und interessante Inhalte schnell aufzufinden. Diese beziehen sich auf Topics, Autor und Aufrufen. </li> </ul> <p>Nachfolgend findet sich ein Screen-Mock, der den Aufbau im ausgeloggten Zustand näher beschreibt.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_128.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_80.png" width="604" height="322" /></a></p> <p>Loggt sich der Benutzer ein, erhält er neue Möglichkeiten. Im ersten Schritt ist angedacht, ein Blog bzw. einen neuen Artikel einzustellen. Unter den Aktionen (rechts oben) können dann benutzerspezifische Einstellungen vorgenommen werden. Der Rest der Seite bleibt unverändert.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_129.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_81.png" width="604" height="322" /></a></p> <h3>Allgemeine Verwendbarkeit</h3> <p>Eines der Ziele dieser Umsetzung ist, dass die entstehende Anwendung breiter eingesetzt werden kann. Sie soll den Grundstock für Feed-Aggregationen bieten, jedoch nicht auf diesen speziellen Anwendungsfall beschränkt bleiben.</p> <h3>Eingestellte Blogs und Artikel</h3> <p>Sämtlicher eingestellter Inhalt, der nicht aus einer vertrauenswürdigen Quelle stammt wird geprüft. D.h.<strong> ein neu eingestelltes Blog wird nicht automatisch aggregiert</strong>, sondern landet auf einer Liste von zu prüfenden Quellen. Damit soll zum Einen vermieden werden, dass Spam in der Auswahl landet, zum Anderen ist es durchaus sinnvoll, sich zuerst die Erlaubnis des Blogbetreibers einzuholen (wenn dies im Internet offensichtlich auch kaum üblich ist).</p> <p>Neue eingestellte Artikel werden ebenfalls geprüft und freigeschalten. Auch hier soll es vermieden werden, dass Spam publiziert wird. Beiträge von Benutzern, die bereits 2 (oder eine andere zu konfigurierende Anzahl) freigeschaltete Artikel eingestellt haben, werden automatisch publiziert, da diese als vertrauenswürdig eingestuft werden. Dies kann über die Administration jederzeit rückgängig gemacht werden.</p> <h3>Administration</h3> <p>Die Administration soll im Wesentlichen folgende Funktionen bieten:</p> <ul> <li>Benutzerverwaltung </li> <li>Verwaltung der Blogs </li> <li>Verwaltung der eingestellten Beiträge (Beiträge via Blog-Feeds werden in dieser Liste nicht behandelt) </li> <li>Verfügbare Sprachen </li> <li>Diverse Einstellungen </li> </ul> <p>Die Administrationsseite wird Benutzern mit entsprechender Rolle über die Aktionen angeboten.</p> <h2>Nichtziel</h2> <p style="background-color: #eee">Es ist kein Ziel von <a title="WPF-Blogger" href="http://wpf-blogger.com" target="_blank">WPF-Blogger</a>, die gesamten Inhalte anzuzeigen. Der Autor soll honoriert werden. Aus diesem Grund werden auch weiterhin nicht die gesamten Beiträge angezeigt, sondern lediglich ein Teaser.</p> <h2>Offene Fragen / Feedback erwünscht</h2> <p>Es gibt meinerseits einige Überlegungen, die grundsätzlich gut zur Neuentwicklung von <a title="WPF-Blogger" href="http://wpf-blogger.com" target="_blank">WPF-Blogger</a> passen würden, bei denen ich mir allerdings nicht zu 100% sicher bin. Ich möchte sie an dieser Stelle zur Diskussion stellen, in der Hoffnung auf Feedback.</p> <h3>Bewertung</h3> <p>Von einschlägigen Seiten (siehe beispielsweise <a title="DotNetKicks" href="http://dotnetkicks.com/default.aspx" target="_blank">DotNetKicks</a> oder der <a title="dotnet-kicks.de" href="http://dotnet-kicks.de/" target="_blank">deutschsprachigen Umsetzung</a>) ist man es gewohnt, Beiträge bewerten zu können, um so die Spreu vom Weizen zu trennen. Das ist grundsätzlich eine gute Sache. Im Endeffekt ist mein Ansatz aber der Aktualität gewidmet. Der Benutzer soll einen schnellen Überblick erlangen, was sich in den abgedeckten Bereichen tut. Nichts desto trotz sollte er - meiner Meinung nach - doch auch eine Rückmeldung erhalten, welcher Inhalt von anderen empfohlen wird. Anstatt einer direkten Bewertung kann dies aber auch durch die eigentliche Statistik-Auswertung geschehen. Links, die häufig geklickt werden, scheinen grundlegend interessanter zu sein, als solche mit wenigen Aufrufen. Daraus könnte eine Bewertung abgeleitet werden, ohne den Benutzer zu einer Bewertung zu nötigen.</p> <h3>Kommentare</h3> <p>Wünschenswert wäre eine Möglichkeit Kommentare zu hinterlassen. Die Ideallösung wäre, dass sämtliche Kommentare an das eigentliche Blog zurückfließen und dem Verfasser des Artikels zu Gute kommen. Allerdings habe ich hierfür noch keine zufriedenstellende Lösung gefunden, wodurch ich die gesamte Funktionalität in Frage stelle. Meinungen?</p> <h2>Ausblick</h2> <p>Der nächste Artikel der <a title="Jetzt Backbone.js lernen" href="http://devtyr.norberteder.com/?tag=/Backbone.js">Serie über Backbone.js</a> beschäftigt sich mit dem Thema der Suchmaschinen. Darin wird hinterfragt, für welche Teile der Website der Einsatz von Backbone.js tatsächlich geeignet ist. Soll heißen, welche Inhalte werden statisch ausgeliefert und welche erst durch den Client erstellt.</p> http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Konzept-WPF-Blogger.aspx Norbert Eder [MVP] 3567 2012-01-31T12:00:00 Jetzt Backbone.js lernen: Die Serie <p><a title="Backbone.js" href="http://documentcloud.github.com/backbone/" target="_blank"><img style="margin: 0px 10px 10px 0px; display: inline; float: left" title="Backbone.js" alt="Backbone.js" align="left" src="http://documentcloud.github.com/backbone/docs/images/backbone.png" width="209" height="37" /></a></p> <p>Nach der erfolgreichen <a title="Jetzt Knockout.js lernen: Die Serie" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie über Knockout.js</a> und dem durchwegs positiven Feedback, möchte ich - wie bereits angekündigt - eine neue Serie starten. Diese beschäftigt sich mit <a title="Backbone.js" href="http://documentcloud.github.com/backbone/" target="_blank">Backbone.js</a>. In dieser Vorabinformation möchte ich kurz darauf eingehen, was der Leser erwarten darf. Und das ist eine ganze Menge, da diese Serie einen gänzlich anderen Weg einschlagen wird.</p> <h2>Praxisbeispiel</h2> <p>Im Rahmen der Knockout.js-Serie wurden unterschiedliche Beispiele behandelt. Diese wurden möglichst nahe an der Realität gehalten, aber es mussten auch Teile konstruiert werden. Dies soll in dieser Serie anders sein.</p> <p><a title="WPF-Blogger.com - Entwickler-Informationen zu WPF, Silverlight und Windows Phone" href="http://wpf-blogger.com" target="_blank"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WPF-Blogger.com - Entwickler-Informationen zu WPF, Silverlight und Windows Phone" border="0" alt="WPF-Blogger.com - Entwickler-Informationen zu WPF, Silverlight und Windows Phone" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_126.png" width="97" height="60" /></a>Im Rahmen der Backbone.js-Serie wird ein bereits bestehendes Projekt neu implementiert. Konkret geht es um meine Website <a title="WPF-Blogger.com - Entwickler-Informationen zu WPF, Silverlight und Windows Phone" href="http://wpf-blogger.com" target="_blank">http://wpf-blogger.com</a>. Diese aggregiert Feeds von Bloggern zu WPF, Silverlight und Windows Phone in mehreren Sprachen. Damit soll einschlägigen Entwicklern eine zentrale Anlaufstelle für aktuelle Tipps, Tricks und Techniken auf Basis der genannten Technologien geboten werden.</p> <p>Diese Entscheidung hat mehrere Hintergründe: So besteht die aktuelle <a title="WPF-Blogger.com - Entwickler-Informationen zu WPF, Silverlight und Windows Phone" href="http://wpf-blogger.com" target="_blank">WPF-Blogger</a> bereits unverändert seit mehreren Jahren und bedarf zahlreicher Neuerungen. Da mir eine Weiterentwicklung auf der aktuellen Basis wenig zielführend erscheint, habe ich mich dazu entschieden, auf aktuelle Technologien und Techniken zu setzen, auch wenn manches davon als Hype angesehen werden kann.</p> <h2>Was kann der Leser nun erwarten?</h2> <p>Da ein konkretes Projekt zur Umsetzung gelangt, wird die Backbone.js-Serie einen hohen Grad an <strong>Praxiswissen</strong> und - im Rahmen der Umsetzung gemachten - Erfahrungen aufweisen. Ideal, um sich ein Bild über diese Bibliothek zu machen und einen etwaigen eigenen Einsatz besser abschätzen zu können. </p> <p>Ein weiterer Mehrwert besteht sicherlich darin, dass ich - als der Autor dieser Serie - Backbone.js gerade erst lerne. Daher sind zahlreiche <strong>Hinweise auf Fallen und Tücken</strong> zu erwarten, in die ich getreten bin - oder noch treten werde.</p> <p>Großes Augenmerk werde ich auch auf die Themen <strong>Konzept</strong> und <strong>Testing</strong> legen.</p> <h2>Eingesetzte Technologien und Bibliotheken</h2> <p>Das Projekt soll aus aktueller Sicht folgende (Quasi-)Standards, Technologien und Bibliotheken umfassen:</p> <ul> <li>HTML5 </li> <li>CSS3 </li> <li>jQuery </li> <li>Backbone.js </li> <li>.NET </li> </ul> <p>Sollte sich die Notwendigkeit ergeben, weitere Bibliotheken zu verwenden, wird diese Liste entsprechend erweitert.</p> <blockquote> <p><strong>Hinweis</strong>: Die obige Liste setzt auf weit mehr als nur Backbone.js. Auch diese werden in dieser Serie teilweise besprochen/diskutiert. Das Hauptaugenmerk wird jedoch auf Backbone.js gelenkt.</p> </blockquote> <h2>Sourcecode / Sharing</h2> <p>Jeder soll sich den aktuellen Sourcecode ansehen, aber auch für eigene Projekte verwenden können. In der <a title="Jetzt Knockout.js lernen: Die Serie" href="http://devtyr.norberteder.com/?tag=/Knockout.js" target="_blank">Knockout.js-Serie</a> habe ich hierfür teilweise <a title="JSFiddle" href="http://jsfiddle.net/" target="_blank">JSFiddle</a> verwendet, ist aber in diesem Rahmen nicht sehr zielführend. Aus diesem Grund habe ich mich entschieden, das gesamte Projekt auf <a title="WPF-Blogger.com auf GitHub" href="https://github.com/devtyr/wpfblogger" target="_blank">github</a> zu hosten.</p> <h2>Inhalt</h2> <p>Die einzelnen Teile dieser Serie sind nicht im Vorab festgelegt, sondern ergeben sich aus der laufenden Entwicklung des Projektes. Die untenstehende Liste ist daher als flexibel anzusehen und wird ständig erweitert bzw. auf dem aktuellen Stand gehalten.</p> <ul> <li><a title="Jetzt Backbone.js lernen: Die Serie" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Die-Serie.aspx">Jetzt Backbone.js lernen: Die Serie</a> (dieser Beitrag) </li> <li><a title="Jetzt Backbone.js lernen: Konzept WPF-Blogger" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Konzept-WPF-Blogger.aspx">Jetzt Backbone.js lernen: Konzept WPF-Blogger</a> </li> <li><a title="Jetzt Backbone.js lernen: JavaScript und Suchmaschinen" href="http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-JavaScript-und-Suchmaschinen.aspx">Jetzt Backbone.js lernen: JavaScript und Suchmaschinen</a>&#160;</li> <li>Jetzt Backbone.js lernen: Grundlagen Backbone.js </li> <li>Weitere Teile: TBD </li> </ul> <p>Auf neue Teile wird zusätzlich über <a title="Norbert Eder auf Twitter" href="http://twitter.com/norberteder" target="_blank">Twitter</a> hingewiesen.</p> <h2>Feedback</h2> <p>JavaScript, HTML5 und CSS3 waren bis dato nicht mein Hauptscope. Daher ist es sehr wahrscheinlich, dass jede Menge meines Codes einfacher, schöner und besser geschrieben werden kann. Damit die Leser, die, so wie ich, ebenfalls keine Gurus auf diesem Gebiet sind, sich weiterentwickeln, hoffe ich auf zahlreiches Feedback. Darum bitte ich schon jetzt die Gurus unter meinen Lesern, mit ihrer Meinung nicht hinter den Berg zu halten.</p> http://devtyr.norberteder.com/post/Jetzt-Backbonejs-lernen-Die-Serie.aspx Norbert Eder [MVP] 3563 2012-01-28T14:36:24 Jetzt Knockout.js lernen: Mapping <p>Im letzten Teil meiner <a title="Serie zu Knockout.js" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie zu Knockout.js</a> beschäftigen wir uns mit dem Mapping Plugin. In einigen der letzten Beispiele wurde mit JSON gearbeitet und so Daten simuliert, die vom Server stammen. Damit diese an eine View gebunden wurde, musste das ViewModel (welches Observables enthält) manuell aufgefüllt werden. Das Mapping Plugin bietet hier eine Unterstützung, die in diesem Anwendungsfall sehr viel Aufwand spart. Dieser Artikel zeigt wie es funktioniert.</p> <h2>Voraussetzungen</h2> <p>Damit das Mapping-Plugin verwendet werden kann, muss es via <a title="knockout.mapping auf github" href="https://github.com/SteveSanderson/knockout.mapping/tree/master/build/output" target="_blank">github</a> bezogen werden. Hier der <a title="knockout.mapping.js" href="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js" target="_blank">Direktlink</a> zur aktuellsten Version. Das Script ist dann natürlich entsprechend einzubinden.</p> <h2>Grundlagen / Wiederholung</h2> <p>In den letzten Teilen dieser Serie wurden alle ViewModels manuell erstellt und sahen - mehr oder weniger - so aus:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 400px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> MyViewModel = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title = ko.observable(); </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.author = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.pages = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Die Daten wurden dann so gesetzt:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 400px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">myViewModel.title(<span style="color: #006080">'Ein Buch'</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">myViewModel.author(<span style="color: #006080">'Ein Autor'</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">myViewModel.pages(500);</pre> <!--CRLF--></div> </div> <p>So musste das für jede Variable vorgenommen werden. Ein recht großer Aufwand, vor allem, wenn die Struktur komplexer wird. </p> <p>Knockout.mapping kann diesen Aufwand für uns stark minimieren.</p> <h2>Beispiel</h2> <p>Nun aber zu einem Beispiel an Hand dessen wir uns ansehen, wie knockout.mapping funktioniert. Dazu benötigen wir eine View, die mit einer Schaltfläche ausgestattet ist. Bei einem Klick darauf werden JSON-Daten vom Server geladen und an die View gebunden. Hier vorerst die View:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;control&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">=&quot;button&quot;</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;click: loadData&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;Load data&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;data&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>Loaded Data<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: userName&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;&lt;</span><span style="color: #800000">br</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: tweetCount&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Soweit noch nichts Neues, aber wenden wir uns der JavaScript-Seite zu.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">$(<span style="color: #0000ff">function</span>(){</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> OverallViewModel = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.loadData = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.getJSON(<span style="color: #006080">'http://dl.dropbox.com/u/30654117/Demos/JavaScript/Knockout.js/Mapping/data/data.json'</span>, <span style="color: #0000ff">function</span>(data) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> viewModel = ko.mapping.fromJS(data);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ko.applyBindings(viewModel, document.getElementById(<span style="color: #006080">'data'</span>));</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> firstViewModel = <span style="color: #0000ff">new</span> OverallViewModel();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.applyBindings(firstViewModel, document.getElementById(<span style="color: #006080">'control'</span>));</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">});</pre> <!--CRLF--></div> </div> <p>Hier wird ein ViewModel namens <font face="Courier New">OverallViewModel</font> definiert und an das DIV mit der Id <font face="Courier New">control</font> gebunden. Darin enthalten ist die Funktion <font face="Courier New">loadData</font>, welche bei einem Klick auf die Schaltfläche ausgelöst wird.</p> <p>Darin wird im ersten Schritt das JSON vom Server bezogen. Im Anschluss wird <font face="Courier New">ko.mapping.fromJS</font> mit den Daten als Parameter aufgerufen. Das Ergebnis ist ein ViewModel, welches die entsprechenden Eigenschaften, welche im JSON definiert sind (als Observables) besitzt.</p> <p>Der Vollständigkeit halber hier das JSON:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;userName&quot;</span>: <span style="color: #006080">&quot;Norbert Eder&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;tweetCount&quot;</span>: 10000</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Das resultierende ViewModel wird nun via <font face="Courier New">ko.applyBindings</font> an das DIV mit der Id <font face="Courier New">data</font> gebunden und die Daten kommen sofort zur Anzeige. Das einfache Beispiel ist fertig. Aber das Plugin kann noch mehr.</p> <h2>Ins Mapping eingreifen</h2> <p>Meine erste Frage - und das wird vermutlich jedem so gehen, war: </p> <blockquote> <p>So ein einfaches ViewModel ist ganz nett, aber was, wenn ich Funktionen, berechnete Eigenschaften etc. benötige?</p> </blockquote> <p>Aber auch hierfür gibt es eine entsprechende Lösung.</p> <p>Erweitern wir obiges Beispiel ein wenig. Zu den rudimentären Tweet-Informationen sollen nun einzelne Tweets hinzugefügt und angezeigt werden. Jeder Eintrag soll mit einer Schaltfläche bestückt werden, mit deren Hilfe ein Retweet durchgeführt werden kann. Auch das sollte nun recht einfach gehen, haben wir uns doch bereits mit <a title="Jetzt Knockout.js lernen: Templates" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Templates</a> beschäftigt. Die Herausforderung ist jedoch, die Tweets mit einem eigenen ViewModel zu versehen, welches eine entsprechende Funktion <font face="Courier New">retweet</font> anbietet, um eben diese Aktion ausführen zu können.</p> <p>Zuerst aber ein Blick auf die Daten, zwecks Übersicht der durchgeführten Änderungen:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;userName&quot;</span>: <span style="color: #006080">&quot;Norbert Eder&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;tweetCount&quot;</span>: 10000,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;tweets&quot;</span>: [</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;content&quot;</span>: <span style="color: #006080">&quot;Ein Testtweet der mit Sicherheit 140 Zeichen nicht überschreitet.&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> },</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;content&quot;</span>: <span style="color: #006080">&quot;Knockout.js ist schon eine sehr feine Sache!&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> },</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">&quot;content&quot;</span>: <span style="color: #006080">&quot;Bin schon gespannt auf Backbone.js. Soll auch nett sein.&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ]</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Nun muss die View umgebaut und mit einem Template versehen werden, auch noch nicht spektakulär:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;div id=<span style="color: #006080">&quot;control2&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;input type=<span style="color: #006080">&quot;button&quot;</span> data-bind=<span style="color: #006080">&quot;click: loadData&quot;</span> value=<span style="color: #006080">&quot;Load data&quot;</span>&gt;&lt;/input&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;div id=<span style="color: #006080">&quot;data2&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;h2&gt;Loaded Data&lt;/h2&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;span data-bind=<span style="color: #006080">&quot;text: userName&quot;</span>&gt;&lt;/span&gt;&lt;br/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;span data-bind=<span style="color: #006080">&quot;text: tweetCount&quot;</span>&gt;&lt;/span&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div data-bind=<span style="color: #006080">&quot;template: { name: 'tweet-template', foreach: tweets }&quot;</span>&gt;&lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/div&gt; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;script type=<span style="color: #006080">&quot;text/html&quot;</span> id=<span style="color: #006080">&quot;tweet-template&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;p data-bind=<span style="color: #006080">&quot;text: content&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;input type=<span style="color: #006080">&quot;button&quot;</span> value=<span style="color: #006080">&quot;Retweet&quot;</span> data-bind=<span style="color: #006080">&quot;click: retweet&quot;</span>/&gt;&lt;/input&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/script&gt;</pre> <!--CRLF--></div> </div> <p>Interessant ist das ViewModel, oder besser gesagt, sind die beiden ViewModels, da für die Anzeige eines einzelnen Tweets ein weiteres ViewModel (nennen wir es <font face="Courier New">TweetViewModel</font>) definiert werden muss. Immerhin möchten wir eine Funktion unterbringen. Darin sehen wir nun auch bereits den ersten Trick:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> TweetViewModel = <span style="color: #0000ff">function</span>(data) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ko.mapping.fromJS(data, {}, <span style="color: #0000ff">this</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.retweet = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> alert(<span style="color: #006080">&quot;retweeted&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Die Funktion <font face="Courier New">retweet</font> ist einfach und zeigt hier lediglich einen Alert an. Zumindest kann so die Funktionalität getestet werden. Interessanter ist, dass das ViewModel Daten als Parameter übergeben bekommt und diese via <font face="Courier New">ko.mapping.fromJS</font> auf sich selbst appliziert. Damit werden für die in den Daten enthaltenen Eigenschaften korrespondierende Observables am ViewModel erzeugt. Erster Teil erledigt.</p> <p>Nun muss noch ein Weg gefunden werden, eine Instanz von <font face="Courier New">TweetViewModel</font> pro Item zu erzeugen. Dazu muss das Haupt-ViewModel ein wenig adaptiert werden. </p> <blockquote> <p><strong>Hinweis</strong>: Dieses wurde mit einem anderen Namen als im einfachen Beispiel zu sehen, da es im gleichen Beispiel zu finden ist, Download siehe weiter unten.</p> </blockquote> <p>Sehen wir es uns an:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> AnotherViewModel = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.loadData = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.getJSON(<span style="color: #006080">'http://dl.dropbox.com/u/30654117/Demos/JavaScript/Knockout.js/Mapping/data/data2.json'</span>, <span style="color: #0000ff">function</span>(data) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> viewModel = ko.mapping.fromJS(data, mapping);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ko.applyBindings(viewModel, document.getElementById(<span style="color: #006080">'data2'</span>));</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Abgesehen davon, dass die Daten nun von einer anderen Quelle bezogen werden, sticht diese Änderung ins Auge:</p> <p><font face="Courier New">var viewModel = ko.mapping.fromJS(data, mapping);</font></p> <p>Es wird ein neuer Parameter übergeben. Eine Konfiguration für das Mapping.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> mapping = {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #006080">'tweets'</span>: {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> create: <span style="color: #0000ff">function</span>(options) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> TweetViewModel(options.data);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Darin wird ein <font face="Courier New">create</font>-Callback definiert, der sich auf das Array <font face="Courier New">tweets</font> bezieht (siehe Daten weiter oben) und für alle Einträge aus dem <font face="Courier New">tweets</font>-Array (siehe Daten) aufgerufen. Als Parameter werden <font face="Courier New">options</font> übergeben. Diese enthalten:</p> <ul> <li><strong>data</strong>: Ein JavaScript-Objekt mit den Daten </li> <li><strong>parent</strong>: Das Eltern-Objekt oder das Array zu dem die Daten gehören </li> </ul> <p>Schlussendlich definiert die Zeile</p> <p><font face="Courier New">return new TweetViewModel(options.data);</font></p> <p>dass eine neue Instanz von <font face="Courier New">TweetViewModel </font>instanziiert werden soll. Die Daten werden als Parameter übergeben und innerhalb des ViewModel weiterverarbeitet (siehe weiter oben). </p> <p>Das wunderschön gestaltete Ergebnis:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_125.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js Mapping Plugin Demo" border="0" alt="Knockout.js Mapping Plugin Demo" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_79.png" width="604" height="316" /></a></p> <h2>Fazit</h2> <p>Diese beiden Beispiele zeigen sehr schön, dass man sich mit Hilfe des Mapping Plugins jede Menge Schreibarbeit - und damit durchaus auch Fehler - sparen kann. Durch das mögliche Eingreifen in die Erstellung der ViewModels sind alle notwendigen Szenarien vorstellbar und keine Grenzen gesetzt.</p> <h2>Download / Showcase</h2> <p>Getestet werden können die beschriebenen Beispiele <a title="Knockout.js Mapping Online Demo" href="http://dl.dropbox.com/u/30654117/Demos/JavaScript/Knockout.js/Mapping/index.html" target="_blank">hier</a>. Gleich untenstehend der Download des gesamten Paketes:</p> <p><iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; padding-right: 0px; padding-top: 0px" title="Preview" height="120" marginheight="0" src="https://skydrive.live.com/embed?cid=C8D8CB313DB8E795&amp;resid=C8D8CB313DB8E795%21490&amp;authkey=ABZ1KqPCN4Md7f4" frameborder="0" width="98" marginwidth="0" scrolling="no"></iframe></p> <h2>Feedback</h2> <p>Gerne nehme ich jegliches Feedback zu diesem Beitrag, als auch zur gesamten <a title="Serie zu Knockout.js" href="http://knockoutjs.com/">Serie zu Knockout.js</a> entgegen. Hat dir die Serie geholfen? Hast du Anmerkungen, Anregungen? Fehlt ein Teil, sprich, wurde ein wichtiges Thema nicht besprochen? Teile es mir doch einfach mit und verfasse gleich einen Kommentar.</p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> </li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a> (dieser Teil)</li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx Norbert Eder [MVP] 3560 2012-01-27T12:30:00 MVC / Razor Style-Switcher – Quicky Heute möchte ich zeigen, wie man sich einen einfachen Style-Switcher mittels jQuery in einem MVC / Razor Projekt einbauen kann. Den Basis-Style setzen wir zu Beginn, wenn die Seite zum ersten Mal geöffnet wird. Wichtig ist, das wir eine Id setzen, um in unserer jQuery Funktion dieses Element wieder zu finden. &#60;link id=&#34;jQ&#34; href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; [...] http://feedproxy.google.com/~r/BigglesBlog/~3/IRGH_QW2X14/mvc-razor-style-switcher-quicky Mario Priebe 3558 2012-01-26T13:25:17 Jetzt Knockout.js lernen: Formularvalidierung mit Undo <p>In <a title="Jetzt Knockout.js lernen: Observables erweitern" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a> der <a title="Serie zu Knockout.js" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie zu Knockout.js</a> wurde gezeigt, wie Observables erweitert werden können. Als Beispiel diente eine Validierung auf Basis von einzelnen Observables. Nun hängen diese in der Regel aber in einem Formular zusammen, wodurch eine Gesamtvalidierung und eine damit verbundene Freischaltung von Schaltflächen bzw. weiteren Interaktionsmöglichkeiten einhergeht. Dieser Beitrag greift das Validierungsbeispiel auf und erweitert es im Rahmen dieser Anforderung.</p> <h2>Ausgangspunkt</h2> <p>Den Ausgangspunkt dieses Beitrags bietet dieses <a title="Beispiel zu Knockout.js - Observables erweitern" href="http://jsfiddle.net/zHFEU/" target="_blank">Beispiel</a>, zu dem Florian einen sinnvollen <a title="Erweiterungswunsch zur Validierung unter Knockout.js" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx#id_ec633037-a724-451b-96c2-0ce6a98d6b1b" target="_blank">Erweiterungswunsch</a> hinterlassen hat:</p> <blockquote> <p>Interessant wäre noch ein Save-Button, der nur aktiv ist, wenn es keine Fehler auf dem gesamten Formular mehr gibt, sowie ein Cancel- bzw. Undo-Button der bei eventuellen Fehlern, die Werte zurücksetzt auf den ursprünglichen Wert.</p> </blockquote> <p>Aus meiner Sicht handelt es sich hierbei um eine gängige Anforderung, die ich natürlich aufgegriffen habe. Wer den Hintergrund des Beispiels erfahren möchte, kann dies <a title="Jetzt Knockout.js lernen: Observables erweitern" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx" target="_blank">hier</a> vollständig nachlesen. Als Zusammenfassung: Das Beispiel zeigt, wie ein eigener Extender für Observables unter <a title="Knockout.js" href="http://knockoutjs.com/" target="_blank">Knockout.js</a> geschrieben werden kann, um einzelne Observables zu validieren. Als Validierung wurde eine Erweiterung hinsichtlich Pflichtfelder implementiert. Eine Gesamtvalidierung war nicht vorgesehen.</p> <h2>Gesamtvalidierung</h2> <p>Aktuell wird jedes Observable einzeln validiert. Entsprechend der Anforderung sollen nun zwei Schaltflächen für das Speichern, als auch das Zurückstellen auf die zuletzt gültigen Werte (im Fehlerfalle) hinzugekommen. Damit diese auch entsprechend freigeschalten sind, muss das ViewModel bekannt geben, in welchem Status es sich gesamt befindet. Dieser ergibt sich aus den Status jedes einzelnen Observables. Dies können wir uns berechnen lassen (<font face="Courier New">ko.computed</font>) und nennen wir <font face="Courier New">hasErrors</font>.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">self.hasErrors = ko.computed(<span style="color: #0000ff">function</span>() </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">{ </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> self.title.hasError() || </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.author.hasError() || </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.pages.hasError(); </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">});</pre> <!--CRLF--></div> </div> <blockquote> <p><strong>Hinweis</strong>: <font face="Courier New">self</font> ist eine Referenz auf <font face="Courier New">this</font> und wurde im Vergleich zum originalen Beispiel hinzugefügt, um innerhalb der anonymen Funktion auf die Eigenschaften und Funktionen des ViewModels zugreifen zu können.</p> </blockquote> <p>Damit könnten nun auch bereits die beiden neuen Schaltflächen gesteuert werden:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">=&quot;button&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;Save&quot;</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;disable: hasErrors&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">=&quot;button&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;Undo&quot;</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;enable: hasErrors&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Auf die Speichern-Schaltfläche möchte ich an dieser Stelle nicht weiter eingehen, viel spannender ist hier der Undo-Button. Dieser soll ja - im Fehlerfalle - die zuletzt gültigen Werte hinterlegen. Dies bedeutet, dass diese erfasst werden müssen.</p> <p>Nun ist es so, dass die einzelnen Eingabefelder eine <font face="Courier New">value</font>-Bindung besitzen und das Durchschreiben der Werte via <font face="Courier New">valueUpdate</font> auf den Wert <font face="Courier New">afterkeydown</font> gesetzt wurde. Das ViewModel wird also in Echtzeit aktualisiert. Darauf können wir also nicht aufbauen, da der Benutzer beispielsweise per Backspace alle Zeichen von “Beispiel” löschen könnte, durch die Echtzeit-Aktualisierung würde der zuletzt valide Wert durch “B” repräsentiert. Worauf wir uns jedoch hängen können ist das Verlassen des Fokus, also dem <font face="Courier New">OnBlur</font>-Ereignis.</p> <p>Dazu brauchen wir eine Funktion, die uns den beim Verlassen vorhandenen - gültigen - Wert übernimmt:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">self.updateLastValidValue = <span style="color: #0000ff">function</span>(observable) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (!observable.hasError()) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> observable.lastValidValue(observable());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> Als Parameter wird das an das Eingabefeld gebundene Observable übergeben. So kann auch auf die durch den Extender geschriebenen Eigenschaften (siehe <font face="Courier New">hasError</font>) zugegriffen werden. Läuft die Validierung ohne Fehler, dann ist ein entsprechender Wert vorhanden und kann übernommen werden. Hierzu wird eine neue Eigenschaft namens <font face="Courier New">lastValidValue</font> mit dem Wert gesetzt. <p>Damit dies nun bei allen Eingabefeldern berücksichtigt wird, ist deren Bindung zu aktualisieren, hier an Hand der Titel-Eingabe:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;input data-bind=<span style="color: #006080">'value: title, valueUpdate: &quot;afterkeydown&quot;, event: { blur: function() { updateLastValidValue(title); }}'</span> /&gt;</pre> <!--CRLF--></div> </div> <p>So werden die Werte nun weiterhin in Echtzeit übernommen und zusätzlich beim Verlassen des Feldes die Funktion <font face="Courier New">updateLastValidValue</font> des ViewModels aufgerufen. Das ist allerdings noch nicht alles, denn ein etwaiger initial gesetzter Wert würde nicht berücksichtig werden. An dieser Stelle bietet es sich an, den bereits existierenden Extender (<font face="Courier New">requireField</font>) zu erweitern:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.extenders.requiredField = <span style="color: #0000ff">function</span>(target, message) { </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.hasError = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.validationMessage = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.lastValidValue = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">function</span> validate(newValue) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.hasError(newValue ? <span style="color: #0000ff">false</span> : <span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.validationMessage(newValue ? <span style="color: #006080">&quot;&quot;</span> : message || <span style="color: #006080">&quot;* required&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">function</span> setInitialValueIfValid() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (!target.hasError()) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.lastValidValue(target());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> } </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> validate(target());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> setInitialValueIfValid();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.subscribe(validate);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> target;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Neu ist die Funktion <font face="Courier New">setInitialValueIfValid()</font>. Diese wird beim Erstellen von <font face="Courier New">requiredField</font> durchlaufen (siehe den Aufruf direkt nach der initialen Validierung) und, wenn ein Wert vorhanden ist, <font face="Courier New">lastValidValue</font> mit dem entsprechenden Wert beschrieben.</p> <p>Zu guter Letzt fehlt noch das tatsächliche Zurückschreiben der Werte, wenn die Undo-Schaltfläche geklickt wird. Dazu benötigen wir eine Funktion, nennen wir sie <font face="Courier New">resetToValidValues</font>:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">self.resetToValidValues = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.title(self.title.lastValidValue());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.author(self.author.lastValidValue());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.pages(self.pages.lastValidValue());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Außerdem muss die <font face="Courier New">click</font>-Bindung auf der Schaltfläche gesetzt werden:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">=&quot;button&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;Undo&quot;</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;enable: hasErrors, click: resetToValidValues&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Fertig ist die Gesamtvalidierung des Formulars, inklusive der Möglichkeit, die zuletzt gültigen Werte zurück zu schreiben.</p> <h2>Ergebnis</h2> <p>An dieser Stelle nun zwei Screenshots, die die Implementierung visuell veranschaulichen. Der erste Screenshot zeigt das gesamte Formular ohne Validierungsfehler:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_123.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js: Erfolgreiche Validierung eines Formulars" border="0" alt="Knockout.js: Erfolgreiche Validierung eines Formulars" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_77.png" width="604" height="309" /></a></p> <p>Und hier nun im Fehlerfalle:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_124.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js: Validierungsfehler eines Formulars" border="0" alt="Knockout.js: Validierungsfehler eines Formulars" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_78.png" width="604" height="306" /></a></p> <h2>Download / Showcase</h2> <p>Wie immer gibt es auch dieses Beispiel vollständig für eigene Tests. Unter <a href="http://jsfiddle.net/VgvuK/" target="_blank">http://jsfiddle.net/VgvuK/</a> findet sich die entsprechende Spielwiese. Wer möchte, kann sich dies auch unterhalb ansehen, sollte hierbei allerdings auf die Nutzung eines IE verzichten:</p> <p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/nitronic/VgvuK/embedded/" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p> <h2>Fazit</h2> <p>Die notwendigen Erweiterungen der “Feld-Validierung” konnte in meinen Augen mit sehr wenig Aufwand auf eine Gesamtvalidierung erweitert werden, wodurch für den Benutzer sehr schnell ersichtlich ist, welche Aktionen zur Verfügung stellen. Ein äußerst sauberer Weg, durch die mögliche Auftrennung.</p> <h2>Feedback</h2> <p>Gerne nehme ich - wie immer - konstruktive Kritik, Anregungen und Anmerkungen entgegen. Einfach einen kurzen Kommentar hinterlassen, es findet sich sicherlich die eine oder andere Verbesserungsmöglichkeit.</p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> </li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx Norbert Eder [MVP] 3556 2012-01-25T11:30:00 Google API jQuery UI 1.7.2 Theme Übersicht + Razor-Layout Im folgenden eine kleine Übersicht von Google API jQuery UI 1.7.2 Designs, so vorbereitet, dass diese schnell im Header eines Razor Layouts eingefügt werden können. base &#60;link href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; type=&#34;text/css&#34; /&#62; blitzer &#60;link href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/blitzer/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; type=&#34;text/css&#34; /&#62; dark-hive &#60;link href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/dark-hive/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; type=&#34;text/css&#34; /&#62; eggplant &#60;link href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/eggplant/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; type=&#34;text/css&#34; /&#62; flick &#60;link href=&#34;@Url.Content(&#34;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/flick/jquery-ui.css&#34;)&#34; rel=&#34;Stylesheet&#34; type=&#34;text/css&#34; /&#62; [...] http://feedproxy.google.com/~r/BigglesBlog/~3/Trqwqv7QzS8/google-api-jquery-ui-1-7-2-theme-bersicht-razor-layout Mario Priebe 3554 2012-01-24T15:02:13 Jetzt Knockout.js lernen: Observables erweitern <p>Im vergangenen Teil der <a title="Jetzt Knockout.js lernen" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie zu Knockout.js</a> wurden <a title="Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">benutzerdefinierte Bindungen</a> behandelt. Dieser Teil beschäftigt sich nun damit, wie Observables auf eigene Bedürfnisse hin erweitert werden können. <a title="Knockout.js" href="http://knockoutjs.com/" target="_blank">Knockout.js</a> unterstützt das Lesen und Schreiben von Werten, als auch Benachrichtigungen bei Wertänderungen. In zahlreichen Fällen (zum Beispiel Validierung) möchte man dieses Verhalten jedoch erweitern. Dieser Beitrag zeigt, wie dies umgesetzt werden kann.</p> <h2>Extender zur Validierung erstellen</h2> <p>Knockout.js bietet mit Extendern eine Erweiterungsmöglichkeit an, sich an Observables zu hängen. Das nachfolgende Beispiel erweitert Observables durch die Möglichkeit einer Validierung.</p> <p>Im ersten Schritt erstellen wir ein einfaches ViewModel, welches an eine View gebunden wird. Hier das ViewModel:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">function</span> BookViewModel(title, author, pages) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title = ko.observable(title).extend({ requiredField: <span style="color: #006080">&quot;Please enter a title&quot;</span> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.author = ko.observable(author).extend({ requiredField: <span style="color: #006080">&quot;Please enter an author&quot;</span> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.pages = ko.observable(pages).extend({ requiredField: <span style="color: #006080">&quot;&quot;</span> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> viewModel = <span style="color: #0000ff">new</span> BookViewModel(<span style="color: #006080">&quot;Windows Presentation Foundation 4.5 - Einführung und Praxis&quot;</span>, <span style="color: #006080">&quot;Norbert Eder&quot;</span>, 400);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.applyBindings(viewModel);</pre> <!--CRLF--></div> </div> <p>Und passend dazu die View:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 300px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;bookform&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Title<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: title'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Author<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: author'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Pages<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: pages'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Soweit nichts Neues. Nun möchten wir aber, dass eingegebene Werte validiert werden. In diesem Fall beschränke ich mich darauf, Felder als benötigt zu definieren. Ein Extender wird daher benötigt. Um einen Extender zu schreiben muss <font face="Courier New">ko.extenders</font> um eine Funktion erweitert werden, nennen wir sie <font face="Courier New">requiredField</font>. Diese enthält als Parameter das Ziel der Erweiterung und eine Nachricht (die für die Anzeige einer Meldung verwendet werden kann). </p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 300px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.extenders.requiredField = <span style="color: #0000ff">function</span>(target, message) { </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.hasError = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.validationMessage = ko.observable();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">function</span> validate(newValue) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.hasError(newValue ? <span style="color: #0000ff">false</span> : <span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.validationMessage(newValue ? <span style="color: #006080">&quot;&quot;</span> : message || <span style="color: #006080">&quot;* required&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> validate(target());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> target.subscribe(validate);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> target;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Der Extender hängt dem Ziel zwei Eigenschaften <font face="Courier New">hasError</font> und <font face="Courier New">validationMessage</font> um. Die erste beschreibt, ob ein Validierungsfehler vorliegt, die zweite, welcher Fehler dies genau ist. Zusätzlich wird eine Funktion <font face="Courier New">validate</font> benötigt, welche die Validierung schlussendlich durchführt. Dies ist in diesem Beispiel recht einfach. So muss lediglich auf Vorhandensein eines Wertes geprüft werden. Ist dies nicht der Fall wird die über den Parameter <font face="Courier New">message</font> übergegebene Meldung angezeigt - wurde keine eigene Meldung übergeben, wird ein Fallback auf eine Standardmeldung verwendet.</p> <p>Via<font face="Courier New"> validate(target());</font> wird eine initiale Validierung durchgeführt. Per <font face="Courier New">target.subscribe(validate);</font> wird ein Abonnement hinsichtlich Wertänderungen hinzugefügt, damit auch in diesen Fällen die Validierung durchgeführt wird.</p> <p>Anschließend wird das ursprüngliche Observable zurück geliefert. Das war alles, was auf JavaScript-Seite zu implementieren war. Nun ist noch die View anzupassen, um etwaige Meldungen sichtbar zu machen.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 300px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;bookform&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Title<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;css: { error: title.hasError }&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: title, valueUpdate: &quot;afterkeydown&quot;'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='visible: title.hasError, text: title.validationMessage'</span><span style="color: #0000ff">&gt;</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Author<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;css: { error: author.hasError }&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: author, valueUpdate: &quot;afterkeydown&quot;'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='visible: author.hasError, text: author.validationMessage'</span><span style="color: #0000ff">&gt;</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span>Pages<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h3</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">p</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;css: { error: pages.hasError }&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='value: pages, valueUpdate: &quot;afterkeydown&quot;'</span> <span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='visible: pages.hasError, text: pages.validationMessage'</span><span style="color: #0000ff">&gt;</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">p</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Für die Erweiterung der View wurden insgesamt drei Schritte unternommen:</p> <ol> <li>Für die <font face="Courier New">input</font>-Felder wird die Aktualisierung des Wertes im ViewModel durch <font face="Courier New">valueUpdate</font> auf <font face="Courier New">afterkeydown</font> geändert, damit jede Änderung sofort im ViewModel wirksam wird und so schon zur Eingabe eine Validierung stattfinden kann. </li> <li>Es wird ein <font face="Courier New">span</font>-Element eingeführt. Dieses enthält eine <font face="Courier New">visible</font>-Bindung auf die Eigenschaft <font face="Courier New">hasError</font> - ist also nur sichtbar, wenn ein Validierungsfehler aufgetreten ist. Der anzuzeigende Wert des span-Elementes wird auf die <font face="Courier New">validationMessage</font> gebunden. </li> <li>Die umschließenden <font face="Courier New">p</font>-Tags wurden um eine <font face="Courier New">css</font>-Bindung erweitert. Dadurch wird bei Vorhandensein eines Validierungsfehlers eine CSS-Klasse <font face="Courier New">error</font> auf das Element gehängt, wodurch ein Styling einfach gemacht wird. So sieht es aus: </li> </ol> <a href="http://devtyr.norberteder.com/image.axd?picture=image_122.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js: Validierung per Extender" border="0" alt="Knockout.js: Validierung per Extender" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_76.png" width="604" height="152" /></a> <ol></ol> <h2>Download / Showcase</h2> <p>Das Beispiel kann unter <a href="http://jsfiddle.net/zHFEU/">http://jsfiddle.net/zHFEU/</a> getestet und bezogen werden. Untenstehend findet sich das JSFiddle in eingebundener Form, benötigt aber einen Browser ungleich IE.</p> <p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/nitronic/zHFEU/embedded/" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p> <h2>Fazit</h2> <p>Dieses Beispiel hat gezeigt, wie einfach es möglich ist, ein Verhalten á la Validierung per Knockout.js und Extender zu realisieren. Auch hier gilt wieder, dass die Zuständigkeiten sauber getrennt sind und einfach gewartet werden. </p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx Norbert Eder [MVP] 3553 2012-01-24T10:00:00 Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen <p>In den vorangegangenen drei Teilen der <a title="Jetzt Knockout.js lernen" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie über Knockout.js</a> haben wir uns mit einer generellen Einführung, einer beispielhaften Bindung an Formulare und Listen als auch der Verwendung von Vorlagen beschäftigt. Dieser Teil beschäftigt sich nun mit der Möglichkeit der benutzerdefinierten Bindungen. So wird gezeigt, wann diese sinnvoll verwendet werden und wie sie denn überhaupt funktionieren.</p> <h2>Bindungen im Allgemeinen</h2> <p>Vordefinierte Bindungen stehen für die unterschiedlichsten Bereiche zur Verfügung. Abgedeckt werden Bindungen um Text und Darstellung zu kontrollieren (z.B. <font face="Courier New">visible</font>, <font face="Courier New">text</font>, <font face="Courier New">html</font>, <font face="Courier New">css</font> usw.), um mit Formular-Feldern zu arbeiten (<font face="Courier New">submit</font>, <font face="Courier New">checked</font>, <font face="Courier New">value</font>, etc.) und zur Ablaufsteuerung (<font face="Courier New">foreach</font>, <font face="Courier New">if</font>, <font face="Courier New">ifnot</font>, <font face="Courier New">with</font>). </p> <blockquote> <p>Eine vollständige Übersicht findet sich in den <a title="Jetzt Knockout.js lernen: Slides und Beispiele" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Slides</a> des ersten Teils.</p> </blockquote> <p>Trotz der mannigfaltigen Möglichkeiten, besteht der Bedarf an eigenen Bindungen, gerade dann, wenn Werteänderungen spezielle Auswirkungen auf DOM Elemente haben sollen. Äußerst hilfreich sind benutzerdefinierte Bindungen auch dann, wenn Steuerelemente von Drittanbietern zum Einsatz kommen und so spezielle oder zusätzliche Attribute/Verhalten bedient werden sollen.</p> <h2>Grundlagen</h2> <p>Eine benutzerdefinierte Bindung wird durch folgenden Code erstellt, wobei <font face="Courier New">myBindingName</font> mit dem tatsächlichen Namen der Bindung zu ersetzen ist:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.bindingHandlers.myBindingName = {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> init: <span style="color: #0000ff">function</span>(element, valueAccessor, allBindingsAccessor, viewModel) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> },</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> update: <span style="color: #0000ff">function</span>(element, valueAccessor, allBindingsAccessor, viewModel) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Von Bedeutung sind die beiden Funktionen <font face="Courier New">init</font> und <font face="Courier New">update</font>:</p> <ul> <li><strong>init</strong>: Wird nur beim ersten Auswerten der Bindung aufgerufen. Ideal für die Initialisierung, beispielsweise dem Setzen von Eventhandlern. </li> <li><strong>update</strong>: Hier kann darauf reagiert werden, wenn sich gebundene Werte verändern. Der Aufruf erfolgt, wenn die Bindung das erste Mal angewandt wird und bei jeder Änderung des gebundenen Wertes. Sollte verwendet werden, um DOM Elemente auf Basis des geänderten Wertes zu manipulieren/aktualisieren. </li> </ul> <p>Beide Funktionen sind mit insgesamt vier Parametern ausgestattet:</p> <ul> <li><strong>element</strong>: Das DOM Element der Bindung. Dadurch ist es nicht notwendig, dem Element eine Id oder Ähnliches zuzuweisen. </li> <li><strong>valueAccessor</strong>: Dahinter verbirgt sich eine Funktion, die Zugriff zum gebundenen Wert gibt. Die Funktion liefert ein Observable zurück, nicht den tatsächlichen Wert. Wird ein Ausdruck für die Bindung verwendet, dann wird dieser zurück geliefert. </li> <li><strong>allBindingsAccessor</strong>: Eine Funktion, die alle Bindungen auf dieses DOM Element zurück liefert. </li> <li><strong>viewModel</strong>: Das ViewModel-Objekt, das via <font face="Courier New">ko.applyBindings</font> gebunden wurde. Bei einer verschachtelten Bindung wird das gebundene Datenelement zurückgeliefert. </li> </ul> <p>Doch sehen wir uns ein einfaches Beispiel an.</p> <h2>Beispiel</h2> <p>Sehen wir uns die benutzerdefinierte Bindung anhand eines kleinen Beispiels an. Es soll ein Eingabeformular geben. Hier können sowohl der Vor- als auch der Nachname erfasst werden. Die Daten werden darüber als Zusammenfassung angezeigt. Wird ein Wert in der Eingabe verändert, soll die Wertänderung in der Zusammenfassung mit Hilfe eines Fade-In-Effekts angezeigt werden.</p> <p>Dazu ist ein einfaches ViewModel notwendig, welches an das User Interface gebunden wird:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> viewModel = {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> firstName: ko.observable(<span style="color: #006080">&quot;Norbert&quot;</span>),</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> lastName: ko.observable(<span style="color: #006080">&quot;Eder&quot;</span>)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.applyBindings(viewModel);</pre> <!--CRLF--></div> </div> <p>Die View selbst sieht dann so aus:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;overview&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>First name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: firstName&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>Last name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: lastName&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;data&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>First name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: firstName&quot;</span> <span style="color: #0000ff">/&gt;&lt;</span><span style="color: #800000">br</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>Last name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: lastName&quot;</span> <span style="color: #0000ff">/&gt;&lt;</span><span style="color: #800000">br</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Soweit noch nichts aufregendes. Bei einer Werteveränderung, wird dies sofort in der Zusammenfassung nachgezogen. Nun soll aber noch der Einblendeffekt hinzukommen. Dazu erstellen wir eine benutzerdefinierte Bindung, die auf eine Wertänderung reagiert (<font face="Courier New">update</font>-Funktion).</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.bindingHandlers.fade= {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> update: <span style="color: #0000ff">function</span>(element, valueAccessor) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $(element).hide().fadeIn(1000);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> } </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Da lediglich auf die Wertänderung, ohne Berücksichtigung des tatsächlichen Wertes, reagiert werden muss, ist die update-Funktion ausreichend. Auch muss auf den Wert selbst nicht zugegriffen werden. Stattdessen wird lediglich das Element versteckt und via <font face="Courier New">fadeIn</font> eingeblendet.</p> <blockquote> <p><strong>Hinweis</strong>: Müsste auf den Wert reagiert werden, kann dieser via <font face="Courier New">ko.utils.unwrapObservable(valueAccessor())</font> bezogen werden.</p> </blockquote> <p>Damit dies auch tatsächlich funktioniert, muss die benutzerdefinierte Bindung noch in der View gesetzt werden:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;overview&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>First name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: firstName, fade: firstName&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>Last name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: lastName, fade: lastName&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">span</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;data&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>First name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: firstName&quot;</span> <span style="color: #0000ff">/&gt;&lt;</span><span style="color: #800000">br</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span>Last name<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h2</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: lastName&quot;</span> <span style="color: #0000ff">/&gt;&lt;</span><span style="color: #800000">br</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Fertig ist eine einfache Verwendung.</p> <h2>Download / Showcase</h2> <p>Das Bespiel kann unter <a title="http://jsfiddle.net/SvAHr/" href="http://jsfiddle.net/SvAHr/">http://jsfiddle.net/SvAHr/</a> getestet und bezogen werden. Oder aber auch untenstehend (IE streikt hier leider):</p> <p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/nitronic/SvAHr/embedded/" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p> <h2>Fazit</h2> <p>Auch wenn das gezeigte Beispiel ein sehr einfaches ist, können benutzerdefinierte Bindungen sehr gut eingesetzt werden, um komplexe Verhalten zu steuern. Der Vorteil liegt darin, dass so wiederverwendbare Bindungen erstellt werden können. Im einfachsten Fall können darüber Standardverhalten/-einstellungen gesetzt werden, die jedoch nur an einer einzelnen Stelle zu implementieren/verwalten sind.</p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> </li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx Norbert Eder [MVP] 3550 2012-01-23T06:50:32 Suche der BlogEngine.NET mittels Knockout.js verbessern - ein Praxisbeispiel <p>In meiner <a title="Serie zu Knockout.js" href="http://devtyr.norberteder.com/?tag=/Knockout.js">Serie zu Knockout.js</a> habe ich bereits gezeigt, was diese Bibliothek leisten kann. Nichts liegt also näher, als das eigene Blog ein wenig auf Vordermann zu bekommen. Stein des Anstoßes ist die Suche, die bei <a title="BlogEngine .NET" href="http://www.dotnetblogengine.net/" target="_blank">BlogEngine.NET</a> sehr altertümlich wirkt und in meinem neuen Design daher bis dato nicht berücksichtigt wurde. Mit Knockout.js sollte eine verbesserte Variante schnell implementiert sein. Da die Suchergebnisse durch diverse Bots auch nicht indiziert werden müssen, kann Knockout.js bedenkenlos eingesetzt werden. Hier mein Erfahrungsbericht.</p> <h1>Kontext</h1> <p>Um den Kontext für diejenigen zu setzen, die sich weder mit der BlogEngine.NET beschäftigt haben, noch dies wollen, ein kurze Einführung wie die Zusammensetzung hinsichtlich der Suche ist und was alles benötigt wird. Wenn Erfahrungen mit eben diesem System bestehen, kann dieser Abschnitt übersprungen werden.</p> <p>Die Suche der BlogEngine.NET besteht aus folgenden Teilen:</p> <ul> <li>Klasse <font face="Courier New">Search</font>, welche die Suche übernimmt und Ergebnisse zurück liefert. </li> <li>Ein Steuerelement <font face="Courier New">SearchBox</font>, welches ein Input-Feld, eine Schaltfläche und noch ein paar andere Dinge rendert. Das Input-Feld selbst reagiert auf ein Enter und leitet eigentlich nur auf die Suchseite weiter. </li> <li>Ein Widget, welches das Steuerelement verwendet </li> <li>Eine Suchseite (<font face="Courier New">search.aspx</font>), welche ebenfalls das angesprochene Steuerelement verwendet. </li> </ul> <p>Das ist grob alles. Um das gesamte User Interface der Suche ersetzen zu können, ist es also notwendig, ein einzelnes Steuerelement (zum Einbinden im Header etc.), ein Widget und eine dedizierte Suchseite anzubieten.</p> <h1>Suche via AJAX ermöglichen</h1> <p>Die Suchfunktionalität besteht bereits (durch die Klasse <font face="Courier New">Search</font>). Diese sollte soweit bestehen bleiben, um auch mit zukünftigen Versionen kompatibel zu sein. </p> <p>Was allerdings fehlt, ist ein Service, um dies nutzen zu können. Damit das Ergebnis am Client gut verarbeitet werden kann, liefert dieses JSON zurück. Zusätzlich werden auf Einstellungen des Blogsystems zurück gegriffen, um die Beschreibungen der Posts für die Ergebnisliste entsprechend zu kürzen. Der Code hierfür kann man sich dann im Download-Package ansehen.</p> <h1>Knockout.js ViewModel</h1> <p>Damit in der UI die notwendigen Bindungen gesetzt werden können, ist ein entsprechendes ViewModel notwendig, nennen wir es <font face="Courier New">FastSearchViewModel</font>. Welche Möglichkeiten soll es bieten?</p> <ol> <li>Es muss der Suchbegriff abgefasst werden. </li> <li>Der Benutzer kann wählen, ob Kommentare durchsucht werden sollen. Diese Information ist ebenfalls durch das ViewModel zu halten. </li> <li>Die AJAX-Suche muss unter Angabe des Suchbegriffs durchgeführt werden. </li> <li>Eine Liste der Ergebnisse ist zur Verfügung zu stellen. </li> <li>Der Benutzer möchte Rückmeldungen á la “Keine Suchergebnisse” erhalten. Diese müssen angeboten werden. </li> <li>Die Suche kann theoretisch dreimal auf einer Seite vorkommen (Suchfeld, Widget und Suchseite). Dieser Umstand ist zu berücksichtigen (wichtig für die Datenbindung auf einen bestimmten Bereich, da sonst alle Suchmöglichkeiten mit derselben Bindung ausgestattet werden). </li> <li>Schlussendlich bedarf es noch Kleinigkeiten, wie das Zurücksetzen des Eingabefeldes bei einem Klick bzw. dem Auslösen der Suche bei Betätigen der Enter-Taste. </li> </ol> <p>All diese Dinge wurden im nachfolgenden ViewModel berücksichtigt.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 600px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> FastSearchViewModel = <span style="color: #0000ff">function</span> (containerElement) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> self = <span style="color: #0000ff">this</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.container = containerElement;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.searchValue = ko.observable(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.includeComments = ko.observable(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.foundItems = ko.observableArray();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.showNoItemsFound = ko.observable(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasSearchValue = ko.computed(<span style="color: #0000ff">function</span> () { <span style="color: #0000ff">return</span> self.searchValue().length &gt; 0; }, self);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasResult = ko.observable(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.notExecuted = ko.observable(<span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.search = <span style="color: #0000ff">function</span> () {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> dto = { <span style="color: #006080">&quot;searchTerm&quot;</span>: self.searchValue(), <span style="color: #006080">&quot;includeComments&quot;</span>: self.includeComments() };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.ajax({</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> url: <span style="color: #006080">&quot;uri/to/searchmethod&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> data: JSON.stringify(dto),</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> type: <span style="color: #006080">&quot;POST&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> contentType: <span style="color: #006080">&quot;application/json; charset=utf-8&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> dataType: <span style="color: #006080">&quot;json&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> success: <span style="color: #0000ff">function</span> (result) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.foundItems = ko.observableArray();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (result.d.Posts &amp;&amp; result.d.Posts.length &gt; 0) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">for</span> (<span style="color: #0000ff">var</span> i = 0; i &lt; result.d.Posts.length; i++) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.foundItems().push(<span style="color: #0000ff">new</span> ResultViewModel(result.d.Posts[i].Title, result.d.Posts[i].Content, result.d.Posts[i].Link));</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.showNoItemsFound(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasResult(<span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> } <span style="color: #0000ff">else</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.showNoItemsFound(<span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasResult(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.notExecuted(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ko.applyBindings(self, self.container);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.inputChanged = <span style="color: #0000ff">function</span> (sender, <span style="color: #0000ff">event</span>) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (<span style="color: #0000ff">event</span>.keyCode === 13 &amp;&amp; self.hasSearchValue()) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.search();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.clear = <span style="color: #0000ff">function</span> (sender, <span style="color: #0000ff">event</span>) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.searchValue(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasResult(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.showNoItemsFound(<span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.notExecuted(<span style="color: #0000ff">true</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.closePopup = <span style="color: #0000ff">function</span> () {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.hasResult(<span style="color: #0000ff">false</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Zu beachten ist, dass die Ergebnisse aus dem AJAX-Aufruf in ein weiteres ViewModel geschrieben werden (<font face="Courier New">ResultViewModel</font>). Dies ist notwendig, damit die Bindungen greifen, die in einem Template für die einzelnen Einträge festgelegt sind. Hier der entsprechende Code:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> ResultViewModel = <span style="color: #0000ff">function</span> (postTitle, postContent, postLink) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title = ko.observable(postTitle);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.content = ko.observable(postContent);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.link = ko.observable(postLink);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <h1>User-Interface</h1> <p>Das User-Interface muss nun die für die Suche notwendigen Elemente zur Verfügung stellen und die Bindungen festlegen. Hier das auf die Suchseite vereinfachte Markup:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 600px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;div id=<span style="color: #006080">&quot;fastsearchpage&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;input id=<span style="color: #006080">&quot;fastsearchbox&quot;</span> data-bind=<span style="color: #006080">&quot;value: searchValue, valueUpdate: 'afterkeydown', event: { keyup: inputChanged, click: clear }&quot;</span> placeholder=<span style="color: #006080">&quot;Suche&quot;</span> onkeypress=<span style="color: #006080">&quot;return noenter()&quot;</span>&gt;&lt;/input&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;input id=<span style="color: #006080">&quot;fastsearchcomment&quot;</span> type=<span style="color: #006080">&quot;checkbox&quot;</span> data-bind=<span style="color: #006080">&quot;checked: includeComments&quot;</span>&gt;Kommentare inkludieren&lt;/input&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;input type=<span style="color: #006080">&quot;button&quot;</span> id=<span style="color: #006080">&quot;fastsearchbutton&quot;</span> data-bind=<span style="color: #006080">&quot;click: search, enable: hasSearchValue&quot;</span> value=<span style="color: #006080">&quot;Durchsuchen&quot;</span>&gt;&lt;/input&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div id=<span style="color: #006080">&quot;fastsearchresult&quot;</span> data-bind=<span style="color: #006080">&quot;template: { name: 'searchresult-template', foreach: foundItems }&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div id=<span style="color: #006080">&quot;nofastsearchresult&quot;</span> data-bind=<span style="color: #006080">&quot;visible: showNoItemsFound&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> Keine Suchergebnisse.</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div id=<span style="color: #006080">&quot;nofastsearchexecuted&quot;</span> data-bind=<span style="color: #006080">&quot;visible: notExecuted&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> Geben Sie einen Suchbegriff ein und drücken Sie Enter oder die Suchen-Schaltfläche.</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;script type=<span style="color: #006080">&quot;text/html&quot;</span> id=<span style="color: #006080">&quot;searchresult-template&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div <span style="color: #0000ff">class</span>=<span style="color: #006080">&quot;searchitem&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;a data-bind=<span style="color: #006080">&quot;attr: { href: link, title: title }&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;span&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;strong data-bind=<span style="color: #006080">&quot;text: title&quot;</span>&gt;&lt;/strong&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/span&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/a&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div data-bind=<span style="color: #006080">&quot;text: content&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/script&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;script type=<span style="color: #006080">&quot;text/javascript&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">function</span> noenter() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> !(window.<span style="color: #0000ff">event</span> &amp;&amp; window.<span style="color: #0000ff">event</span>.keyCode == 13);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/script&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/div&gt;</pre> <!--CRLF--></div> </div> <p>Der Großteil der darin verwendeten Bindungen bringen zur <a title="Serie zu Knockout.js" href="http://devtyr.norberteder.com/?tag=/Knockout.js" target="_blank">Knockout.js-Serie</a> nichts Neues. Interessant ist das Eingabefeld selbst:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;input id=<span style="color: #006080">&quot;fastsearchbox&quot;</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> data-bind=<span style="color: #006080">&quot;value: searchValue, valueUpdate: 'afterkeydown', event: { keyup: inputChanged, click: clear }&quot;</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> placeholder=<span style="color: #006080">&quot;Suche&quot;</span> onkeypress=<span style="color: #006080">&quot;return noenter()&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/input&gt;</pre> <!--CRLF--></div> </div> <p>Dieses selbst hat eine Bindung auf <font face="Courier New">searchValue</font> um den eingegebenen Suchbegriff in das ViewModel durchzuschreiben. Ebenfalls wird das Ereignis <font face="Courier New">OnKeyUp</font> abonniert um auf das Betätigen der Enter-Taste hin zu prüfen, da in diesem Fall die Suche ausgelöst werden sollte. Beim Standardverhalten der <font face="Courier New">value</font>-Bindung ist es nun aber so, dass zum Zeitpunkt des Auslösens des Ereignisses (und des Verarbeitens in der Funktion des ViewModels) der eingegebene Wert noch nicht bekannt ist. Das liegt daran, dass die <font face="Courier New">value</font>-Bindung erst beim Verlassen des Fokus die Bindung selbst aktualisiert.</p> <p>Um aber derartige Anforderungen abzudecken, steht der zusätzliche Parameter <font face="Courier New">valueUpdate</font> bereit. Darüber lässt sich konfigurieren, zu welchem Zeitpunkt die gebundene Eigenschaft des ViewModels aktualisiert werden soll. Folgende Möglichkeiten stehen zur Verfügung:</p> <ul> <li><strong>change</strong>: Das ist die Standardeinstellung und aktualisiert das ViewModel wenn der Fokus zu einem anderen Element geht. </li> <li><strong>keyup</strong>: Die Aktualisierung findet beim Loslassen des Tastendrucks statt. </li> <li><strong>keypress</strong>: Das ViewModel wird aktualisiert, wenn eine Taste gedrückt wurde. Hier ist anzumerken, dass dieses Ereignis mehrfach ausgelöst wird, wenn der Benutzer auf der Taste bleibt. </li> <li><strong>afterkeydown</strong>: Hier wird das ViewModel aktualisiert, sobald der Benutzer beginnt, ein Zeichen einzugeben. Diese Auswahl eignet sich bestens dazu, wenn das ViewModel in Echtzeit aktualisiert werden soll. </li> </ul> <p>Stellen wir also <font face="Courier New">valueUpdate</font> auf <font face="Courier New">afterkeydown</font>, steht beim Auslösen der Suche der durch den Benutzer eingegebene Suchbegriff bereit.</p> <blockquote> <p><strong>Hinweis</strong>: Zusätzlich wird beim <font face="Courier New">OnKeyPress</font> noch die Funktion <font face="Courier New">noenter()</font> aufgerufen. Diese dient lediglich dazu, ein Submit eines eventuell vorhandenen Formulars zu verhindern.</p> </blockquote> <h1>Binden des ViewModels</h1> <p>Damit die Bindungen angezogen werden, muss <font face="Courier New">ko.applyBindings</font> aufgerufen werden. Wie bereits oben angesprochen, kann die Suche selbst mehrfach auf der Seite vorkommen. Damit nicht alle an dasselbe ViewModel gebunden werden (und dadurch anspringen, sobald es in einem der Felder eine Aktion gibt), sollte überprüft werden, wie viele Vorkommen vorhanden sind und an jedes eine eigene Instanz des ViewModels gebunden werden.</p> <h1>Das Ergebnis</h1> <p>Für die Verwendung unter BlogEngine.NET ist nun nicht mehr viel zu tun und weniger relevant, da lediglich Widget-Control (als Host) implementiert werden muss etc. Dies kann sich der interessierte Leser im Download genauer ansehen.</p> <p>Das Resultat kann sich jeder hier im Blog ansehen, da alle Suchmöglichkeiten auf dieser Implementierung beruhen.</p> <p>So sieht die Einbindung des Suchfeldes aus:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_120.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="FastSearch für BlogEngine.NET Searchbox" border="0" alt="FastSearch für BlogEngine.NET Searchbox" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_74.png" width="604" height="329" /></a></p> <p>Und hier noch die Suchseite:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_121.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="FastSearch für BlogEngine.NET Search Page" border="0" alt="FastSearch für BlogEngine.NET Search Page" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_75.png" width="604" height="389" /></a></p> <h1>Download / BlogEngine.NET Package</h1> <p>Der Download ist über die <a title="Download FastSearch BlogEngine.NET package" href="http://dnbegallery.org/cms/List/Extensions/FastSearch" target="_blank">BlogEngine.NET Gallery</a> verfügbar. Darin befindet sich die Erweiterung zur BlogEngine.NET selbst, als auch die gesamte Implementierung. Wer diese Erweiterung für sein Blogsystem basierend auf BlogEngine.NET einsetzen möchte, findet weitere Informationen unter <a title="FastSearch for BlogEngine.NET" href="http://devtyr.com/fastsearch.html" target="_blank">http://devtyr.com/fastsearch.html</a>.</p> <h1>Feedback</h1> <p>Wie immer freue ich mich über jegliches Feedback. Sowohl zum Code selbst, als auch grundsätzlich zur Funktionalität der BlogEngine.NET-Erweiterung.</p> http://devtyr.norberteder.com/post/Suche-der-BlogEngineNET-mittels-Knockoutjs-verbessern-ein-Praxisbeispiel.aspx Norbert Eder [MVP] 3546 2012-01-19T15:25:52 Asynchrones Befüllen einer ObservableCollection<T> in einem ViewModel Die Aufgabenstellung beschreibt, das innerhalb eine ViewModels Daten aus einer Datenbank ausgelesen und über der Netzwerkverbindung noch weiter verarbeitet werden müssen. Hier liegt es auf der Hand, dass eine asynchrone Lösung her muss, sprich es muss unter allen Umständen verhindert werden, dass die UI blockiert. Wie man das machen kann, zeige ich wie folgt: Ich [...] http://feedproxy.google.com/~r/BigglesBlog/~3/yprHmfxg2Zk/asynchrones-befllen-einer-observablecollectiont-in-einem-viewmodel Mario Priebe 3537 2012-01-14T18:46:21 Automatisiertes Ein- und Auschecken im Buildprozess Möchte man nach einem Build, die Assembly in ein dafür bereitgestelltes Verzeichnis kopieren, kann man das recht einfach im Prä- und Postbuild-Ereignis im Visual Studio definieren. Hat man die DLL jedoch im TFS eingecheckt, muss man vor dem Kopieren dafür Sorge tragen, dass die Datei ausgecheckt wurde, ansonsten kann die eben wegen dem Schreibschutz nicht [...] http://feedproxy.google.com/~r/BigglesBlog/~3/hIEYDDEivoM/automatisiertes-ein-und-auschecken-im-buildprozess Mario Priebe 3535 2012-01-12T13:36:58 Jetzt Knockout.js lernen: Template verwenden <p>Weiter geht es mit <a title="Knockout.js" href="http://knockoutjs.com/" target="_blank">Knockout.js</a>. Nachdem ich nun über den <a title="Jetzt Knockout.js lernen: Slides und Beispiele" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Einstieg</a> gebloggt, als auch ein Beispiel bezüglich <a title="Jetzt Knockout.js lernen: Formulare und Listen binden" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Formulare und Listen</a> gezeigt habe, möchte ich mich mit diesem Beitrag mit dem Thema <strong>Templates</strong> beschäftigen und ein Beispiel implementieren, welches den Umgang damit aufzeigt. Vorlagen sind gerade bei wiederkehrenden Darstellungen (Listen etc.) eine hervorragende Sache, gibt es doch nur eine Stelle diese zu pflegen/ändern.</p> <h2>Aufgabenstellung</h2> <p>Konstruierte Beispiele sind immer so eine Sache, da oft der praxistaugliche Nutzen fehlt. Daher habe ich mich dazu entschieden, einen Teil meines Blogs mit Knockout.js nachzubilden. Konkret geht es um den Bereich <a title="Norbert Eder&#39;s Lesestoff" href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>. </p> <p>Wie nachfolgend abgebildet, setzt sich diese Liste aus zwei zusammengehörigen Teilen zusammen:</p> <ul> <li>Die Jahresangabe und der dazugehörigen Statistik über die Anzahl der gelesenen Bücher und Seiten. </li> <li>Die Liste der Bücher, die im entsprechenden Jahr gelesen wurden. </li> </ul> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_118.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Nobert Eder&#39;s Lesestoff" border="0" alt="Nobert Eder&#39;s Lesestoff" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_72.png" width="502" height="462" /></a></p> <p>Wie man bereits vermuten kann, bietet sich diese Darstellung wunderbar für die Verwendung von Vorlagen an. Die Umsetzung dieser Liste mittels Knockout.js unter Verwendung von Vorlagen, ist nun das Ziel des nachfolgenden Beispiels.</p> <h2>Templates / View</h2> <p>Bevor ich mich den ViewModels zuwende, muss ein Plan bezüglich der Vorlagen her, da sich daraus der weitere Aufbau ergibt. Wie bereits oben erwähnt, setzt sich die Seite aus zwei Teilen zusammen, dem Jahr (sowie der dazugehörigen Statistik) und der Buchliste zum Jahr. Es bietet sich daher an, eine Vorlage für das Jahr selbst und eine weitere für die Buchliste zu erstellen.</p> <p>Nun zur Vorlage für die Jahresdarstellung, welcher wir den Namen <font face="Courier New">year-template</font> geben. Dieses besteht aus einem <font face="Courier New">h3</font>-Tag für die Anzeige des Jahres. Hier erfolgt eine Datenbindung auf eine Eigenschaft <font face="Courier New">year</font>, die durch das ViewModel geliefert werden muss. Die Auflistung der Bücher selbst findet über eine unsortierte Liste statt. Diese bekommt über eine <font face="Courier New">template</font>-Bindung nun ein Template für die Darstellung eines einzelnen Buches gesetzt und durchläuft mittels <font face="Courier New">foreach</font> alle Einträge der Auflistung <font face="Courier New">books</font>. </p> <p>Damit die Anzahl der Bücher und der Seiten dargestellt werden kann, muss da ViewModel diese Werte berechnen und zur Verfügung stellen. Dies soll durch <font face="Courier New">booksCount</font> und <font face="Courier New">pages</font> passieren.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;script type=<span style="color: #006080">&quot;text/html&quot;</span> id=<span style="color: #006080">&quot;year-template&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;h3 data-bind=<span style="color: #006080">&quot;text: year&quot;</span>&gt;&lt;/h3&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;ul <span style="color: #0000ff">class</span>=<span style="color: #006080">&quot;kastenlightul&quot;</span> data-bind=<span style="color: #006080">&quot;template: { name: 'book-template', foreach: books }&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/ul&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;strong data-bind=<span style="color: #006080">&quot;text: booksCount&quot;</span>/&gt; B&amp;uuml;cher&lt;br/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;strong data-bind=<span style="color: #006080">&quot;text: pages&quot;</span>/&gt; Seiten&lt;br/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/p&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/script&gt;</pre> <!--CRLF--></div> </div> <p>Im nächsten Schritt wird die Vorlage <font face="Courier New">book-template</font> definiert. Diese definiert nun, wie ein einzelnes Buch dargestellt wird. Die Darstellung erfolgt durch das <font face="Courier New">year-template</font> in einer unsortierten Liste, wodurch <font face="Courier New">li</font>-Elemente gerendert werden müssen.</p> <p>Ein <font face="Courier New">li</font>-Elemente enthält nun die notwendigen Elemente zur Darstellung des Buches selbst, das ist nicht weiter aufregend. Interessant ist hier die <font face="Courier New">attr</font>-Bindung. Darüber können jegliche Attribute des betreffenden DOM-Elementes gesetzt werden. Dies ist besonders interessant für Link- und Image-Elemente, zumal hier zusätzlich meist mehrere Attribute zu setzen sind.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;script type=<span style="color: #006080">&quot;text/html&quot;</span> id=<span style="color: #006080">&quot;book-template&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;li <span style="color: #0000ff">class</span>=<span style="color: #006080">&quot;kastenlight&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;img data-bind=<span style="color: #006080">&quot;attr: { src: coverlink, alt: title }&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;a data-bind=<span style="color: #006080">&quot;attr: { href: titlelink, title: title }&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;span&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;strong data-bind=<span style="color: #006080">&quot;text: title&quot;</span>&gt;&lt;/strong&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/span&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/a&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;br /&gt; &lt;span data-bind=<span style="color: #006080">&quot;text: author&quot;</span>/&gt;&lt;br /&gt; &lt;span data-bind=<span style="color: #006080">&quot;text: pages&quot;</span>/&gt; Seiten&lt;br /&gt;&lt;strong&gt;Bewertung&lt;/strong&gt;: &lt;span data-bind=<span style="color: #006080">&quot;text: rating&quot;</span>/&gt;/5</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;div <span style="color: #0000ff">class</span>=<span style="color: #006080">&quot;buy&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;a data-bind=<span style="color: #006080">&quot;attr: { href: amazonlink }&quot;</span> target=<span style="color: #006080">&quot;_blank&quot;</span>&gt;Auf Amazon kaufen&lt;/a&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/div&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> &lt;/li&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&lt;/script&gt;</pre> <!--CRLF--></div> </div> <p>Was nun noch fehlt ist die Stelle, die den Stein nun tatsächlich ins Rollen bringt. Eine Stelle, die beim Öffnen gerendert wird und auf das erste Template verweist.</p> <p>Dazu wird ein einfaches <font face="Courier New">div</font>-Element erstellt und die dafür notwendige Bindung gesetzt:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;template: { name: 'year-template', foreach: years }&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Über die <font face="Courier New">template</font>-Bindung wird nun die Vorlage <font face="Courier New">year-template</font> für jedes Vorkommen in <font face="Courier New">years</font> angewandt.</p> <blockquote> <p><strong>Hinweis</strong>: Für dieses Beispiel wurden die bereits vorhandenen Styles verwendet. Diese befinden sich natürlich im Download, der ganz unten zu finden ist.</p> </blockquote> <h2>ViewModels</h2> <p>Auf JavaScript-Seite müssen nun die obigen Anforderungen abgedeckt werden. Für das <font face="Courier New">book-template</font> wird eine Repräsentation eines Buches mit den angegebenen Eigenschaften benötigt.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> BookViewModel = <span style="color: #0000ff">function</span>(item) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title = ko.observable(item.title);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.titlelink = ko.observable(item.titlelink);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.coverlink = ko.observable(item.coverlink);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.author = ko.observable(item.author);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.pages = ko.observable(item.pages);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.rating = ko.observable(item.rating);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.amazonlink = ko.observable(item.amazonlink);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Als Parameter wird ein Objekt übergeben, welches alle notwendigen Informationen hat und das <font face="Courier New">BookViewModel</font> auffüllt.</p> <blockquote> <p><strong>Hinweis</strong>: Die Daten werden in diesem Beispiel via JSON gehalten und könnten an einigen Stellen direkt verwendet werden, habe ich aber hinsichtlich der Übersichtlichkeit und der möglichen Erweiterungen nicht getan.</p> </blockquote> <p>Zur Darstellung eines Jahres, wie in <font face="Courier New">year-template</font> gefordert, wird nachfolgendes ViewModel verwendet:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> YearViewModel = <span style="color: #0000ff">function</span>(initYear, initBooks) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> self = <span style="color: #0000ff">this</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.year = ko.observable(initYear);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.books = ko.observableArray();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.each(initBooks, <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> item = <span style="color: #0000ff">new</span> BookViewModel(<span style="color: #0000ff">this</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.books().push(item);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.booksCount = ko.computed(<span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> self.books().length;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.pages = ko.computed(<span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> pagesCount = 0;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.each(self.books(), <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> pagesCount += <span style="color: #0000ff">this</span>.pages();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> pagesCount;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--></div> </div> <p>Dieses ist nun schon ein weniger interessanter, als dass es ein Array der Bücher für dieses Jahr enthält, als auch zwei berechnete Eigenschaften <font face="Courier New">booksCount</font> und <font face="Courier New">pages</font>.</p> <p>Nun fehlt noch das ViewModel, welches als “Einstieg” dient und an das <font face="Courier New">div</font>-Element der View gebunden wird, sowie eine Auflistung der in den Daten enthaltenen Jahre enthält:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> BooksViewModel = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> self = <span style="color: #0000ff">this</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.years = ko.observableArray();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.init = <span style="color: #0000ff">function</span>(initialItems) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> $.each(initialItems, <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">var</span> year = <span style="color: #0000ff">new</span> YearViewModel(<span style="color: #0000ff">this</span>.year, <span style="color: #0000ff">this</span>.books);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> self.years().push(year);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Diesem ViewModel wird über die Funktion <font face="Courier New">init</font> das JSON übergeben, wodurch sich in weiterer Folge die gesamte Struktur aufbaut.</p> <p>Nun noch die Instanziierung und das Anwenden der Bindungen via:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> firstViewModel = <span style="color: #0000ff">new</span> BooksViewModel();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">firstViewModel.init(jsonBooklist.years);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.applyBindings(firstViewModel, $(<span style="color: #006080">'booksCollection'</span>).get(0));</pre> <!--CRLF--></div> </div> <p>Fertig.</p> <h2>So sieht’s aus</h2> <p>Wenig überraschend sieht das Ergebnis dem Original sehr ähnlich :)</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_119.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Lesestoff via Knockout.js" border="0" alt="Lesestoff via Knockout.js" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_73.png" width="502" height="462" /></a></p> <h2>Fazit</h2> <p>In diesem Beispiel wurde der Umgang mit benannten Vorlagen gezeigt. Natürlich gibt es auch noch die Möglichkeit, Vorlagen dynamisch zu wählen oder überhaupt eine externe Template Engine zu verwenden.</p> <p>Mir gefällt die einfache Art und Weise wie eine Problemstellung wie diese umgesetzt werden kann. </p> <h2>Download/Showcase</h2> <p>Dieses Beispiel kann nachfolgend herunter geladen werden. Wer möchte kann auch einen Blick auf die <a title="Knockout.js - Template verwenden - Online Demo" href="http://dl.dropbox.com/u/30654117/Demos/JavaScript/Knockout.js/Lesestoff/index.html">Online-Demo</a> werfen.</p> <p><iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; padding-right: 0px; padding-top: 0px" title="Preview" height="120" marginheight="0" src="https://skydrive.live.com/embed?cid=C8D8CB313DB8E795&amp;resid=C8D8CB313DB8E795%21489&amp;authkey=ALY_bEOD1IQnttI" frameborder="0" width="98" marginwidth="0" scrolling="no"></iframe></p> <h2>Feedback</h2> <p>Wie immer freue ich mich natürlich auch hierzu über Feedback, schließlich kann man nie auslernen und es gibt immer etwas, das verbessert werden kann.</p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> </li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx Norbert Eder [MVP] 3534 2012-01-12T07:00:00 Jetzt Knockout.js lernen: Formulare und Listen binden <p>Aus der WPF-Welt kommend ist gerade das Thema MVVM und Datenbindung sehr interessant für mich (weil dadurch auch etwas verwöhnt). Mit <a title="Knockout.js" href="http://knockoutjs.com/" target="_blank">Knockout.js</a> ist dies nun auch in JavaScript komfortabel möglich. Aufbauend auf den <a title="Jetzt Knockout.js lernen: Slides und Beispiele" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">einführenden Beispielen</a> und den von mir bereitgestellten <a title="Jetzt Knockout.js lernen: Slides und Beispiele" href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Slides</a> habe ich mich gefragt, wie nun der Umgang mit Listen und Formularen stattfinden kann und gleich in die Tasten gegriffen, um dies zu testen. Das Resultat ist ein Beispiel und ein paar Erkenntnisse, die ich teilen möchte.</p> <h2>Aufgabenstellung</h2> <p>Als Zielsetzung soll eine HTML-Seite ein Eingabeformular für die Eingabe von Buchinformationen anbieten und die eingegebenen Bücher in einer Liste darstellen. Zudem soll eine einfache Validierung stattfinden. Zu lösen ist die Problemstellung durch Datenbindung und somit einer sauberen Trennung zwischen ViewModel und View. Eine Serverkommunikation ist nicht angedacht.</p> <h2>ViewModels</h2> <p>Für die Umsetzung dieses Beispiels dachte ich an zwei verschiedene ViewModels. Eines, nennen wir es <font face="Courier New">BookViewModel</font> dient der Bindung an das Eingabeformular. Es kann sich selbst validieren und auf den ursprünglichen Stand zurücksetzen. Dieses ist nachfolgend abgebildet.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> BookViewModel = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title = ko.observable(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.author = ko.observable(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.pages = ko.observable(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.errorMessage = ko.observable(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.hasErrors = ko.computed(<span style="color: #0000ff">function</span>() { <span style="color: #0000ff">return</span> (<span style="color: #0000ff">this</span>.errorMessage() != <span style="color: #006080">''</span>); }, <span style="color: #0000ff">this</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.reset = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.title(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.author(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.pages(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.errorMessage(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.validate = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.errorMessage(<span style="color: #006080">''</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (<span style="color: #0000ff">this</span>.title().length === 0 || <span style="color: #0000ff">this</span>.author().length === 0 || <span style="color: #0000ff">this</span>.pages().length === 0) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.errorMessage(<span style="color: #006080">'All fields are required'</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Die einzelnen Eigenschaften sind Observables (<font face="Courier New">ko.observable</font>), wodurch Benachrichtigungen über Änderungen an den Abonnenten (in Falle dieses Beispiels nur das UI) versendet werden und die dargestellten Werte (in der UI) immer aktuell sind.</p> <p>Mit <font face="Courier New">hasErrors</font> soll zudem gesteuert werden, ob eine Fehlermeldung anzuzeigen ist. Die tatsächliche Meldung ist in <font face="Courier New">errorMessage</font> zu finden. Beides wird über die Funktion <font face="Courier New">validate</font> gesetzt.</p> <blockquote> <p><strong>Wichtig</strong>: Bezüglich der observierten Eigenschaften ist mir aufgefallen (und das verhält sich auch unter <a href="http://devtyr.norberteder.com/category/WPF.aspx">WPF</a>/<a href="http://devtyr.norberteder.com/category/Silverlight.aspx" target="_blank">Silverlight</a> so), dass das direkte Zuweisen von Werten zu Observables (diese sind als Funktionen abgebildet), diese natürlich überschreiben und somit keine Überwachung mehr stattfindet. Daher immer so darauf zugreifen: <font face="Courier New">this.title('Der neue Wert')</font>; Andernfalls kann die Suche nach dem Fehler schon mal etwas länger dauern …</p> </blockquote> <p>Ein zweites ViewModel, <font face="Courier New">BooksViewModel</font>, beinhält eine Auflistung aller “gespeicherten” Bücher und stellt eine Instanz des ersten ViewModels via <font face="Courier New">currentBook</font> zur Verfügung. Damit neue Elemente hinzugefügt werden können, wird <font face="Courier New">addItem</font> angeboten. Hier wird im ersten Schritt die Validierung ausgeführt. Ist diese erfolgreich, wird das neue Buch in die Auflistung übernommen. Zusätzlich gibt es noch die Funktion <font face="Courier New">clear</font>. Diese setzt lediglich die Liste zurück.</p> <blockquote> <p><strong>Hinweis</strong>: Für die Darstellung der Liste habe ich auf das <a title="knockout.simpleGrid" href="https://github.com/SteveSanderson/knockout/tree/gh-pages/examples/resources" target="_blank">knockout.simpleGrid</a> zurück gegriffen.</p> </blockquote> <p>Und das ist das <font face="Courier New">BooksViewModel</font>:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> BooksViewModel = <span style="color: #0000ff">function</span>(items) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.items = ko.observableArray(items);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.currentBook = <span style="color: #0000ff">new</span> BookViewModel();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.addItem = <span style="color: #0000ff">function</span>(formData) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.currentBook.validate();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (!<span style="color: #0000ff">this</span>.currentBook.hasErrors()) {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.items.push({</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> title: formData[0].value,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> author: formData[1].value,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> pages: formData[2].value</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.currentBook.reset();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.clear = <span style="color: #0000ff">function</span>() {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.items.removeAll();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> };</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">this</span>.gridViewModel = <span style="color: #0000ff">new</span> ko.simpleGrid.viewModel({</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> data: <span style="color: #0000ff">this</span>.items,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> columns: [</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> headerText: <span style="color: #006080">&quot;Title&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> rowText: <span style="color: #006080">&quot;title&quot;</span>},</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> headerText: <span style="color: #006080">&quot;Author&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> rowText: <span style="color: #006080">&quot;author&quot;</span>},</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> headerText: <span style="color: #006080">&quot;Pages&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> rowText: <span style="color: #006080">&quot;pages&quot;</span>}</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ],</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> pageSize: 5</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> });</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">};</pre> <!--CRLF--></div> </div> <p>Zu beachten ist hier, dass die Auflistung der Elemente via <font face="Courier New">ko.observableArray(items)</font> erledigt wird. Also auch überwachbare Arrays sind möglich.</p> <p>Das <font face="Courier New">BooksViewModel</font> enthält zusätzlich Initialdaten; die Erstellung und Übergabe ist weiter unten zu sehen.</p> <h2>View</h2> <p>Die View selbst ist nun nicht mehr besonders aufregend. Im Endeffekt werden ein paar <font face="Courier New">div</font>-Elemente verwendet und eine <font face="Courier New">form</font>, die zur Eingabe der Daten dient.</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 500px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;booksCollection&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">form</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;submit: addItem&quot;</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;newEntryForm&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;formArea&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h1</span><span style="color: #0000ff">&gt;</span>Add new Entry<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h1</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;errorBox&quot;</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;visible: currentBook.hasErrors&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> ERROR: <span style="color: #0000ff">&lt;</span><span style="color: #800000">span</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;text: currentBook.errorMessage&quot;</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;row&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> Title</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: currentBook.title&quot;</span> <span style="color: #ff0000">placeholder</span><span style="color: #0000ff">=&quot;Enter new book title&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;row&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> Author</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: currentBook.author&quot;</span> <span style="color: #ff0000">placeholder</span><span style="color: #0000ff">=&quot;Enter new author&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;row&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> Pages</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;col&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;value: currentBook.pages&quot;</span> <span style="color: #ff0000">placeholder</span><span style="color: #0000ff">=&quot;Enter new pages count&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">input</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">button</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">=&quot;submit&quot;</span><span style="color: #0000ff">&gt;</span>Add book<span style="color: #0000ff">&lt;/</span><span style="color: #800000">button</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">form</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">=&quot;collectionArea&quot;</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">h1</span><span style="color: #0000ff">&gt;</span>Books<span style="color: #0000ff">&lt;/</span><span style="color: #800000">h1</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">='simpleGrid: gridViewModel'</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">button</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;click: clear&quot;</span><span style="color: #0000ff">&gt;</span>Clear books<span style="color: #0000ff">&lt;/</span><span style="color: #800000">button</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Eine interessante Geschichte ist die <font face="Courier New">action</font> des Formulares. Hier wird eine <font face="Courier New">submit</font>-Bindung auf die Funktion <font face="Courier New">addItem</font> erstellt. Wird nun der Submit-Button betätigt, werden die Daten aus dem Formular an diese Funktion übergeben. </p> <blockquote> <p><strong>Hinweis</strong>: Dies könnte auch ohne Formular und mit einer <font face="Courier New">click</font>-Bindung implementiert werden, da <font face="Courier New">currentBook</font> ohnehin die eingegebenen Daten enthält.</p> </blockquote> <p>Das <font face="Courier New">div</font>-Element, das zur Anzeige der Auflistung herangezogen wird, enthält eine <font face="Courier New">simpleGrid</font>-Bindung auf <font face="Courier New">gridViewModel</font> (dieses wird über das SimpleGrid zur Verfügung gestellt und enthält die Auflistung aller Bücher).</p> <p>Damit die angezeigte Liste zurückgesetzt werden kann, wird über das ViewModel die Funktion <font face="Courier New">clear</font> angeboten. Damit diese aufgerufen wird, reicht es, eine Schaltfläche mit einem <font face="Courier New">click</font>-Binding auf diese Funktion zu erstellen:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">&lt;</span><span style="color: #800000">button</span> <span style="color: #ff0000">data-bind</span><span style="color: #0000ff">=&quot;click: clear&quot;</span><span style="color: #0000ff">&gt;</span>Clear books<span style="color: #0000ff">&lt;/</span><span style="color: #800000">button</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--></div> </div> <p>Um die <strong>Bindungen zu aktivieren</strong>, muss noch ein wenig JavaScript hinzugefügt werden:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> initialData = [</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> title: <span style="color: #006080">&quot;Windows Presentation Foundation 4.5&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> author: <span style="color: #006080">&quot;Norbert Eder&quot;</span>,</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"> pages: 400}</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">];</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #0000ff">var</span> firstViewModel = <span style="color: #0000ff">new</span> BooksViewModel(initialData);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">&#160;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">ko.applyBindings(firstViewModel, $(<span style="color: #006080">'booksCollection'</span>).get(0));</pre> <!--CRLF--></div> </div> <p>Hier werden lediglich Demodaten angelegt und bei der Erstellung des <font face="Courier New">BooksViewModel</font>-Objektes übergeben. <strong>Weit wichtiger</strong> an dieser Stelle ist der Aufruf <font face="Courier New">ko.applyBindings</font>. Damit wird das ViewModel an das Element gebunden, das durch den zweiten Parameter gefunden wird. </p> <blockquote> <p><strong>Hinweis</strong>: Wahlweise könnte der zweite Parameter auch weggelassen werden. In diesem Fall würde das gesamte Dokument nach dem Attribut <font face="Courier New">data-bind</font> durchsucht werden.</p> </blockquote> <p>Ab diesem Zeitpunkt ist das Binding aktiv und die Werte werden synchronisiert.</p> <h2>So sieht’s aus</h2> <p>Hier nun die einzelnen Darstellungen der Website. Nachfolgend die Darstellung nach Öffnen der Seite:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_116.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js - Anfängliche Darstellung" border="0" alt="Knockout.js - Anfängliche Darstellung" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_70.png" width="502" height="325" /></a></p> <p>Durch die Validierung wurde festgelegt, dass alle Eingabefelder einen zugewiesenen Wert besitzen müssen. Ist dem nicht der Fall, wird ein Fehlerhinweis angezeigt:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_117.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Knockout.js - Validierung" border="0" alt="Knockout.js - Validierung" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_71.png" width="502" height="367" /></a></p> <h2>Download</h2> <p>Wer sich mit diesem Beispiel ein wenig spielen möchte, findet unterhalb die Möglichkeit dieses herunter zu laden, auch steht es auf <a title="Knockout.js - Form und List Demo" href="http://jsfiddle.net/PVunQ/" target="_blank">JSFiddle</a> zur Verfügung (wer den Internet Explorer verwendet, sollte sich das Beispiel herunter laden).</p> <p><iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; padding-right: 0px; padding-top: 0px" title="Preview" height="120" marginheight="0" src="https://skydrive.live.com/embed?cid=C8D8CB313DB8E795&amp;resid=C8D8CB313DB8E795%21488&amp;authkey=AMZAoi7ZCoq1Bdk" frameborder="0" width="98" marginwidth="0" scrolling="no"></iframe></p> <h2>Fazit</h2> <p>Ein wenig HTML-Markup, ein wenig JavaScript-Code, Bindungen und ein paar Styles, fertig ist die Eingabemaske und die entsprechende Liste. Die einzelnen Teile lassen sich schön voneinander trennen und somit gut pflegen. Kein Code der Felder, Werte etc. aktualisiert. Auf das Wesentliche reduziert. Eine feine Sache, die Lust auf mehr macht.</p> <h2>Feedback</h2> <p>Was kann man schöner, eleganter, einfacher lösen? Hast du hierzu Feedback? Lasse es mich bitte wissen!</p> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> </li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx Norbert Eder [MVP] 3529 2012-01-11T07:00:00 Jetzt Knockout.js lernen: Slides und Beispiele <p><img style="margin: 0px 10px 10px 0px; display: inline; float: left" align="left" src="http://knockoutjs.com/img/ko-logo.png" width="113" height="33" /><a title="Knockout.js" href="http://knockoutjs.com/" target="_blank">Knockout.js</a> ist eine JavaScript Bibliothek, die es ermöglicht, Datenbindungen durchzuführen. Dadurch ist eine saubere Trennung zwischen ViewModel und View (als auch Model) möglich. Wer Erfahrung mit <a href="http://devtyr.norberteder.com/category/WPF.aspx">WPF</a> und/oder <a href="http://devtyr.norberteder.com/category/Silverlight.aspx" target="_blank">Silverlight</a> hat, der kennt die Vorteile bereits, wird auch hier das Pattern <strong>Model-View-ViewModel</strong> (oder kurz MVVM) verfolgt. Um mir selbst einen Überblick zu Knockout zu verschaffen, habe ich grundlegende Informationen und kleinere Beispiele in einer Präsentation zusammen gefasst, die ich an dieser Stelle teilen möchte.</p> <iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; padding-right: 0px; padding-top: 0px" title="Preview" height="327" marginheight="0" src="https://r.office.microsoft.com/r/rlidPowerPointEmbed?p1=1&amp;p2=1&amp;p3=SDC8D8CB313DB8E795!459&amp;p4=&amp;ak=!AMbGmPy_KAttuLU&amp;kip=1&amp;authkey=!AMbGmPy_KAttuLU" frameborder="0" width="402" marginwidth="0" scrolling="no"></iframe> <p>Die Links zu den Beispielen sind zwar in den Slides vorhanden (können im Vollbildmodus geklickt werden), dennoch nochmals außerhalb: <a title="Knockout.js Simple Demo" href="http://jsfiddle.net/GSNAj/" target="_blank">hier</a> und <a title="Knockout.js Observable Demo" href="http://jsfiddle.net/eLmaN/" target="_blank">hier</a>. Sie sind auf <a title="JSFiddle" href="http://jsfiddle.net" target="_blank">JSFiddle</a> gehostet (idealerweise nicht den Internet Explorer verwenden, da dieser offensichtlich beim Beziehen der eingebundenen JavaScripts daneben greift), dadurch kann gleich im Browser getestet und probiert werden.</p> <blockquote> <p>Habe ich etwas Essentielles in der Präsentation vergessen oder kann man die Beispiele (den Code selbst) weiter verbessern? Ich freue mich über Feedback, bin ich doch selbst erst beim Erlernen.</p> </blockquote> <h2>Jetzt Knockout.js lernen: Die Serie</h2> <ul> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx">Jetzt Knockout.js lernen: Slides und Beispiele</a> (dieser Teil)</li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formulare-und-Listen-binden.aspx">Jetzt Knockout.js lernen: Formulare und Listen binden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Template-verwenden.aspx">Jetzt Knockout.js lernen: Template verwenden</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Benutzerdefinierte-Bindungen.aspx">Jetzt Knockout.js lernen: Benutzerdefinierte Bindungen</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Observables-erweitern.aspx">Jetzt Knockout.js lernen: Observables erweitern</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Formularvalidierung-mit-Undo.aspx">Jetzt Knockout.js lernen: Formularvalidierung mit Undo</a></li> <li><a href="http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Mapping.aspx">Jetzt Knockout.js lernen: Mapping</a></li> </ul> http://devtyr.norberteder.com/post/Jetzt-Knockoutjs-lernen-Slides-und-Beispiele.aspx Norbert Eder [MVP] 3526 2012-01-10T09:14:55 Buch: vier minus drei - Barbara Pachl-Eberhart <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="vier minus drei - Barbara Pachl-Eberhart" border="0" alt="vier minus drei - Barbara Pachl-Eberhart" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_115.png" width="113" height="176" /><em>Ein Schicksal, das erschüttert. Ein Buch, das Mut macht. Es gibt wohl nichts Tragischeres, als von einem Moment auf den anderen seine Familie zu verlieren. Barbara Pachl-Eberhart hat es erlebt: Im März 2008 starben ihr Mann und ihre beiden kleinen Kinder durch einen Verkehrsunfall. In diesem Buch schildert die Autorin, wie sie sich ihrem Schicksal stellte. Wie sie mit Mut und bedingungsloser Offenheit den Weg in ein neues Leben fand. Und wie das starke innere Band zu ihren verstorbenen Lieben ihr dazu die Kraft gab. Ihr ergreifender Bericht zeugt von menschlicher Größe und einem unerschütterlichen Glauben an den Sinn des Lebens.</em></p> <p>Manche haben es in ihrem Leben wahrlich nicht einfach. Meist denkt man selbst “Es erwischt ja eh nur die anderen”. In diesem Fall schlug das Schicksal gar nicht so weit entfernt zu. Über Jahre hinweg bin ich knapp an der Unglücksstelle, welche die Familie von Barbara Pachl-Eberhart zerriss, vorbei gefahren. Kenne die Gegend, kenne den besagten Bahnübergang. Sehr dramatisch und “nahe” genug, um auch mal darüber nachzudenken, wie man selbst mit einem derartigen Ereignis umgehen würde. Wie Barbara Pachl-Eberhart damit umgegangen ist und wie es geschafft hat, wieder einen Sinn im Leben zu finden, das beschreibt sie in diesem Buch. <strong>Aber Achtung</strong>: Es geht wirklich nahe und zeitweise muss man eine Pause einlegen, um das Erzählte und eigene Gedanken zu sortieren und ein wenig Abstand zu bekommen. Das erklärt auch, warum ich fast ein Jahr an diesem Buch gelesen habe.</p> <p>Dennoch, das Buch handelt nicht nur von Traurigkeit, einer Tragödie, nein, es gibt auch all denjenigen, die ähnliches erfahren mussten, Trost und Hoffnung auf ein gutes Ende. Wem nichts dergleichen widerfahren ist, dem wird gezeigt, dass ein kurzer Moment der Unachtsamkeit, eine Familie/ein Leben nachhaltig ändern kann.</p> <p>Für dieses Buch möchte ich <strong>keine Bewertung</strong> geben, zu heikel ist mir das besprochene Thema. Doch möchte ich eine <strong>klare Empfehlung</strong> aussprechen. Unbedingt lesen!</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-vier-minus-drei-Barbara-Pachl-Eberhart.aspx Norbert Eder [MVP] 3522 2012-01-09T10:39:00 Neues Jahr, neues Blogdesign. Warum eigentlich? <p>Ich muss ja gestehen, dass ich nicht unbedingt der begabteste Designer bin. Vielleicht gefallen mir aber auch deswegen schlichte Designs wesentlich besser als aufwändige. Da mir von Zeit zu Zeit das Aussehen meines Blogs auf die Nerven geht, hatte ich mir für 2012 vorgenommen, daran zu schrauben. Schneller als gedacht fand der erste Schwung der Umstellung statt. Aber was genau hat mich gestört und warum habe ich mich für eine bestimmte Lösung entschieden?</p> <h1>Inhalt zählt</h1> <p><strong>Für mich zählt der Inhalt</strong>, ohne Schnörkel. Lese ich online Inhalte, dann möchte ich mich ganz darauf konzentrieren und so wenig als möglich abgelenkt werden. Dies ist schwierig, wenn zahlreiche Widgets, Sidebars und Co. durch die Gegend schwirren und mich an eine andere Stelle (ver)leiten möchten. Ich als Leser möchte das aber nicht. Ich will den Inhalt, diesen eventuell kommentieren oder teilen. Mehr interessiert mich dann aber auch schon nicht mehr. Und mehr möchte ich meinen Lesern auch nicht zumuten.</p> <p>Also weg mit all dem das stört. Den Rest an Stellen positionieren, die gefunden werden, aber nicht störend sind (wie in meinem Fall eine Platzierung am Ende der Seite). So geschehen mit meiner Sidebar und einer Box, die direkt unter dem Menü ihr Dasein fristete. Allerdings ist dabei Vorsicht walten zu lassen, mehr unter <strong>Analyse</strong>.</p> <blockquote> <p>Meist wird auch eine Leserschaft vergessen: Diejenigen, die nicht <a title="Read It Later" href="http://readitlaterlist.com/" target="_blank">Read It Later</a> oder <a title="InstaPaper" href="http://www.instapaper.com" target="_blank">InstaPaper</a> verwenden um etwas später zu lesen, sondern es schlicht und einfach <strong>ausdrucken</strong>. Kaum jemandes Blog verwendet für das Medium <strong>Print</strong> eigene Stylesheets, wodurch sämtliches unnötige Zeugs auf dem Ausdruck zu sehen ist. Unzumutbar. Abspecken und unbedingt auf den Inhalt reduzieren. So kann sich auch der Offline-Leser auf den Inhalt konzentrieren, mal davon abgesehen, dass seine Navigationsmöglichkeiten ohnehin anderer Natur sind.</p> </blockquote> <p>Das Ergebnis ist nun eine Konzentration auf den angebotenen Inhalt. Ohne viel drum rum. So wie ich es mir oft auf anderen Seiten wünschen würde.</p> <h1>Lesbarkeit</h1> <p>Zum Thema Lesbarkeit fallen mir auf die Schnelle folgende Punkte ein:</p> <ul> <li>Schriftfamilie/Schrift</li> <li>Schriftgröße</li> <li>Kontrast</li> </ul> <p>Zur <strong>Schriftfamilie</strong> und <strong>Schrift</strong> lassen sich die unterschiedlichsten Meinungen und Auswertungen finden. Wichtig für mich war die Verwendung einer Web-Schriftart (siehe auch <a title="Google Web Fonts" href="http://www.google.com/webfonts" target="_blank">Google Web Fonts</a>), da das Lesen am Bildschirm dadurch eindeutig erleichtert wird. Bei der Wahl der Schriftfamilie und der Schrift selbst habe ich mich jedoch auf meinen ganz persönlichen Geschmack verlassen.</p> <p>Das Thema der <strong>Schriftgröße</strong> erachte ich mittlerweile als weniger wichtig (wobei ich auch hier auf Basis des erhaltenen Feedbacks nachjustiert habe), da per Browser-Zoom mal schnell korrigiert werden kann - durch den Benutzer.</p> <p>Gestehen muss ich, dass ich auf das Thema <strong>Kontrast</strong> eindeutig zu wenig Rücksicht genommen haben. <a href="http://twitter.com/#!/sven_s" target="_blank">Sven</a> hat mich darauf (nach einer ersten Version) <a href="http://twitter.com/#!/sven_s/status/154176753638707200" target="_blank">aufmerksam gemacht</a> und auch gleich einen passenden Link geliefert: <a href="http://contrastrebellion.com/">http://contrastrebellion.com/</a> (unbedingt ansehen!). Wieder etwas gelernt und auch gleich umgesetzt.</p> <p>Werden nun aber Sidebar und Co entfernt, verbreitert sich der Inhaltsbereich oft wesentlich. Gut, um viel Inhalt darzustellen. Schlecht für die Lesbarkeit, meint <a href="http://twitter.com/#!/asp_net/" target="_blank">Thomas</a> in <a href="http://twitter.com/#!/asp_net/status/154168162307424256" target="_blank">seinem Feedback</a>. Und recht hat er. Wie aber entgegen wirken?</p> <p>Für die Darstellung von <strong>Fließtext</strong> (siehe sämtliche News-Seiten) kann dann gerne mal ein mehrspaltiges Layout herhalten. Das eignet sich allerdings so gar nicht für das Anzeigen von Sourcecode. Das heißt, an dieser Stelle muss man wohl einen Kompromiss eingehen. Gefällt mir nicht, muss ich aber mangels Alternativen. </p> <blockquote> <p>Hast du eine Alternative? Dann lass es mich bitte wissen!</p> </blockquote> <p>Ein weiterer Schritt die Lesbarkeit weiter zu erhöhen ist das Auflockern der Beiträge selbst. Definitiv ein Punkt der in Zukunft mehr Beachtung benötigt.</p> <h1>Inhalt finden</h1> <p>Was bringt der beste Inhalt, wenn er nicht gefunden werden kann. Mit aller Aufräumerei sollte bedacht werden, dass der werte Besucher auch noch das findet, das ihn interessiert. Und das ist in der Regel nicht die erste Handvoll an Beiträgen. Dies passiert in der Regel über drei Varianten (direkt auf einer Site):</p> <ul> <li>Kategorien</li> <li>Tags</li> <li>Suche</li> </ul> <p><strong>Kategorien</strong> sind eine nette Variante den gezeigten Inhalt zu filtern. Mehr aber auch nicht. Vor allem auf News-Sites stellt die Hauptnavigation eben diese Filterung dar. In den meisten Blogsystemen sind Hauptnavigation und Kategorien jedoch getrennt.</p> <p>Durch das Verschwinden der Sidebar fand diese Auflistung ein jähes Ende. Eigentlich wollte ich sie auch nicht, da sie von lediglich 0,2% der Besucher benutzt wurde. Doch das Feedback ließ nicht lange auf sich warten (<a href="http://twitter.com/#!/Cayas_Software" target="_blank">Sebastian</a> ist einer dieser 0,2% wie er <a href="http://twitter.com/#!/Cayas_Software/status/154180160051101696" target="_blank">meint</a>). Also dann doch wieder rauf damit. Allerdings in einer platzsparenden Version, die sich aufklappen lässt, wenn tatsächlich benötigt. Zusätzlich empfinde ich einfache Icons als auflockernd und hilfreich beim erneuten Finden. Hier in aufgeklappter Form:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_112.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Darstellung von Kategorien" border="0" alt="Darstellung von Kategorien" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_67.png" width="650" height="192" /></a></p> <p>Für mich besonders interessant sind <strong>Tags</strong>. Eigentlich werden diese in den meisten Fällen sehr stiefmütterlich behandelt. Tags werden vergeben, finden sich in einer Auflistung oder einer Tag-Wolke wieder. Das war’s. Für meinen Geschmack nicht ausreichend. </p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_113.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Darstellung von Tags" border="0" alt="Darstellung von Tags" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_68.png" width="650" height="35" /></a></p> <p>Dennoch bedurften die Tags einer Verschönerung, vor allem, um auch eindeutig als solche erkannt zu werden, ohne notwendiger Weise “Tags” davor zu schreiben.</p> <blockquote> <p><strong>Exkurs</strong>: Eigentlich könnte eine Auswertung der Tags Kategorien ersetzen. Aus meiner Sicht müssten die Tags hinsichtlich ihres gemeinsamen Vorkommens ausgewertet werden. Tags, die nicht (oder nur selten) zusammen vorkommen (und eine bestimmte Relevanz haben) könnten als Kategorien angesehen werden. Durch das Schaffen von Verbindungen könnte darüber eine Navigation erfolgen/angeboten werden. Die Navigation würde sich aus den Inhalten ergeben und bietet zudem die Möglichkeit eine tiefgreifende Filterung durchzuführen. Allerdings erst geeignet, wenn sich die “Master-Tags” ermitteln lassen.</p> </blockquote> <p>Bleibt schließlich noch die <strong>Suche</strong>. Ich weiß nicht wie es dir, werter Leser, damit geht. Die Statistik meines Blogs besagt, dass so gut wie niemand diese Funktionalität verwendet. Suchende kommen über Suchmaschinen. Alle anderen sehen sich in der Regel die letzten Einträge an, oder browsen via Tags, noch weniger über Kategorien. Aus diesem Grund habe ich mich entschlossen, das Suchfeld vorerst zu entfernen und zukünftig ein wenig Effort in ein besseres Tag-System zu stecken.</p> <h1>Analyse</h1> <p>Es ist sinnvoll darüber Gedanken zu machen, ob etwas aktuell Vorhandenes auch weiterhin benötigt wird, oder entfernt werden kann. Das ist aber noch nicht ausreichend. Die eigene Meinung muss nicht zwangsweise die der Leser entsprechen. Es empfiehlt sich also zu analysieren, ob das entsprechende Teil durch die Besucher verwendet wird. Ist dem nicht so, verhält sich der Fall recht einfach - entfernen. Findet jedoch eine Verwendung statt, sollte man seinen Entschluss nochmals überdenken (dies ist natürlich auch von der Intensität der Nutzung abhängig).</p> <blockquote> <p>Eine Analyse des Klickverhaltens bringt einen guten Überblick, welche Teile der Site vom Besucher genutzt/als interessant empfunden werden. Eine gute Basis für zukünftige Entscheidungen.</p> </blockquote> <p>Eine entsprechende Analyse kann beispielsweise via <a title="Google Analytics" href="http://www.google.com/analytics/" target="_blank">Google Analytics</a> erfolgen, sofern eingesetzt. Sehr hilfreich an dieser Stelle ist die <strong>In-Page-Analyse</strong>, gibt sie doch sehr schnell einen Überblick darüber, welche Links geklickt werden und welche nicht. Entsprechende Auswertungsmöglichkeiten bringen aber auch die meisten Log Analyzer (wie <a title="AWStats" href="http://awstats.sourceforge.net/" target="_blank">AWStats</a> und Co.) mit.</p> <h1>Feedback</h1> <p>Das Einbinden der Leser ist ein wichtiger Prozess um Rückmeldungen zu den bereits durchgeführten oder angedachten Neuerungen zu erhalten. Schließlich gestaltet man seinen Webauftritt nicht nur für sich alleine. Möglichkeiten hierzu finden sich viele, man wähle einfach aus den Social Networks, ziehe Designer, Kollegen, Freunde hinzu. Dennoch: Ohne ein klares Rahmenwerk helfen auch Feedbacks nicht.</p> <p>Zum Schluss noch ein herzliches Dankeschön an: <a href="http://twitter.com/#!/michaelhorkavy" target="_blank">Michael</a>, <a href="http://twitter.com/#!/sven_s" target="_blank">Sven</a>, <a href="http://twitter.com/#!/AlexZeitler" target="_blank">Alex</a>, <a href="http://twitter.com/#!/Cayas_Software" target="_blank">Sebastian</a>, <a href="http://twitter.com/#!/asp_net" target="_blank">Thomas</a>, <a href="http://twitter.com/#!/MarioPriebe" target="_blank">Mario</a>, <a href="http://twitter.com/#!/ThorstenHans" target="_blank">Thorsten</a>, <a href="http://twitter.com/#!/anheledir" target="_blank">Gordon</a> und <a href="http://twitter.com/#!/PeNoWiMo" target="_blank">Peter</a>. Die Reihenfolge wurde zufällig gewählt und hoffentlich wurde niemand vergessen.</p> <blockquote> <p>Wenn auch du noch konstruktive Anregungen und/oder Anmerkungen hast, bitte einfach einen Kommentar hinterlassen. Ich freue mich natürlich auch über ein <em><strong>Gefällt mir</strong></em>.</p></blockquote> http://devtyr.norberteder.com/post/Neues-Jahr-neues-Blogdesign-Warum-eigentlich.aspx Norbert Eder [MVP] 3516 2012-01-05T14:54:53 Buch: Justifiers 4 - Zero Gravity - Nicole Schuhmacher <p><img style="margin: 0px 10px 10px 0px; display: inline; float: left" title="Justifiers 4 - Zero Gravity - Nicole Schuhmacher" alt="Justifiers 4 - Zero Gravity - Nicole Schuhmacher" align="left" src="http://www.randomhouse.de/content/edition/covervoila/351_52804_108034_xl.jpg" width="109" height="173" /><em>Auf das Team der Justifiers wartet einer ihrer bis dahin gefährlichsten Aufträge. Sie sollen auf einem einsamen Vorposten eines Konzerns nach dem Rechten sehen, denn die Station hat jeden Kontakt eingestellt. Zwar sind sie bereits auf einiges gefasst – aber was den Justifiers auf Holloway II tatsächlich begegnet, übertrifft ihre schlimmsten Alpträume …</em></p> <p>Im vierten Teil der Justifiers-Serie erzählt Nicole Schuhmacher die Geschichte eines zusammengewürfelten Justifiers-Team der United Industries. Dieses soll von einem entfernten System Informationen beschaffen, die zum Stichtag nicht geliefert wurden, zumal auch kein Kontakt mehr möglich ist. Doch was sie dort finden lässt den ursprünglichen Kurier-Auftrag sehr schnell in ein äußerst gefährliches Spektakel ausarten. Währenddessen findet sich die Auftraggeberin selbst in großer Gefahr wieder. Ein Anschlag auf sie und ihrem Forschungschef zeigt sehr schnell, dass die Anzahl der Feinde groß und der eingeschlagene Weg für den Konzern vielversprechend ist …</p> <p>Das Gute vorweg: Die erzählte Geschichte ist sehr spannend und gut erzählt. Leider ist der Anfang ein wenig holprig und bedarf ein wenig Überwindung, sich da wirklich durchzukämpfen. Nach den ersten Kapiteln wird man jedoch wirklich belohnt und findet sich mitten im Justifiers-Universum wieder. Grundsätzlich sehr empfehlenswert, durch den schwachen Start wirkt sich dies jedoch negativ auf die Beurteilung aus.</p> <p><strong>Bewertung</strong>: 3/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Justifiers-4-Zero-Gravity-Nicole-Schuhmacher.aspx Norbert Eder [MVP] 3508 2012-01-02T09:54:15 2011 Top 10 Posts Das Jahr ist wieder vorbei, deshalb wird es Zeit ein Resümee zu ziehen und die Top 10 der meistgeklickten Posts zu betrachten. Model-View-ViewModel (MVVM) – 868 Silverlight 2.0 Crashkurs Teil 2 – Textbox, Textblock, Button und Controlls – 392 Silverlight: Glass Button – 193 “Metro” design guide v1.00 – 161 WP 7 Update – 140 [...] http://www.ebnerj.at/blog/?p=1203 Jürgen Ebner 3507 2012-01-01T13:40:25 Windows Presentation Foundation 4.5 - Bindung an statische Eigenschaften <p>Im dritten Teil <a href="http://devtyr.norberteder.com/post/Windows-Presentation-Foundation-45-Die-Serie.aspx">Windows Presentation Foundation 4.5 Serie</a> beschäftigen wir uns mit der Bindung an statischen Eigenschaften. Dies war - ohne Umwege - bis inklusive WPF 4.0 nicht möglich. Da es jedoch immer wieder eine entsprechende Anforderung gibt, wurde dies mit Version 4.5 erweitert und diese Möglichkeit zur Verfügung gestellt.</p> <p>Um statische Eigenschaften mit einem Two-Way-Binding zu versehen, können statische Ereignisse verwendet werden. Diese müssen sich an eine von zwei Signaturen halten. Die erste Signatur ist wie folgt:</p> <p><font face="Courier New">public static event EventHandler MyPropertyChanged;</font></p> <p>Dabei ist “MyProperty” mit dem Namen der tatsächlichen Eigenschaft zu ersetzen. Die zweite Möglichkeit besteht in einem generischen Ansatz (der an das Ereignis <font face="Courier New">PropertyChanged</font> aus <font face="Courier New">INotifyPropertyChanged</font> angelehnt ist):</p> <p><font face="Courier New">public static event EventHandler&lt;PropertyChangedEventArgs&gt; StaticPropertyChanged;</font></p> <blockquote> <p><strong>Wichtig</strong>: Zu beachten ist, dass die beiden Möglichkeiten mit unterschiedlichen Ereignis-Argumenten arbeiten. Die erste Variante setzt auf die Klasse <font face="Courier New">EventArgs</font>, Variante 2 auf <font face="Courier New">PropertyChangedEventArgs</font>. Dies ist für eine erfolgreiche Implementierung zu berücksichtigen.</p> </blockquote> <p>Sehen wir uns die Implementierung einer statischen Klasse <font face="Courier New">StaticSettings</font> mit zwei statischen Eigenschaften <font face="Courier New">Value1</font> und <font face="Courier New">Value2</font> an:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> StaticSettings</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> value1;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> value2;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> Value1</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> get { <span style="color: #0000ff">return</span> value1; }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> set</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #0000ff">if</span> (value1 == <span style="color: #0000ff">value</span>)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> <span style="color: #0000ff">return</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> value1 = <span style="color: #0000ff">value</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> RaiseValue1Changed();</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">event</span> EventHandler Value1Changed;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> RaiseValue1Changed()</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> EventHandler handler = Value1Changed;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> <span style="color: #0000ff">if</span> (handler != <span style="color: #0000ff">null</span>)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> handler(<span style="color: #0000ff">null</span>, <span style="color: #0000ff">new</span> EventArgs());</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> Value2</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> get { <span style="color: #0000ff">return</span> value2; }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span> set</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> <span style="color: #0000ff">if</span> (value2 == <span style="color: #0000ff">value</span>)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> <span style="color: #0000ff">return</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> value2 = <span style="color: #0000ff">value</span>;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> RaiseStaticPropertyChanged(<span style="color: #006080">&quot;Value2&quot;</span>);</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum38"> 38:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum39"> 39:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">event</span> EventHandler&lt;PropertyChangedEventArgs&gt; StaticPropertyChanged;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum40"> 40:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum41"> 41:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> RaiseStaticPropertyChanged(<span style="color: #0000ff">string</span> propertyName)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum42"> 42:</span> {</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum43"> 43:</span> EventHandler&lt;PropertyChangedEventArgs&gt; handler = StaticPropertyChanged;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum44"> 44:</span> <span style="color: #0000ff">if</span> (handler != <span style="color: #0000ff">null</span>)</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum45"> 45:</span> handler(<span style="color: #0000ff">null</span>, <span style="color: #0000ff">new</span> PropertyChangedEventArgs(propertyName));</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum46"> 46:</span> }</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum47"> 47:</span> }</pre> <!--CRLF--></div> </div> <p>Dabei wird die Update-Notification der Eigenschaft <font face="Courier New">Value1</font> nach der ersten Variante, die der Eigenschaft <font face="Courier New">Value2</font> nach der zweiten Variante implementiert. Welche Variante eingesetzt wird, hängt von der Anzahl der Eigenschaften ab. Variante 1 wird bei mehreren Eigenschaften schnell unübersichtlich, wodurch der generische Ansatz zu bevorzugen ist.</p> <p>Anschließend erfolgt die Deklaration der View:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; height: 450px; max-height: 450px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> &lt;Window x:Class=<span style="color: #006080">&quot;DevTyr.Wpf45.StaticPropertyBinding.MainWindow&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> xmlns=<span style="color: #006080">&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> xmlns:x=<span style="color: #006080">&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> xmlns:local=<span style="color: #006080">&quot;clr-namespace:DevTyr.Wpf45.StaticPropertyBinding&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> Title=<span style="color: #006080">&quot;DevTyr - WPF 4.5 - Static Property Binding&quot;</span> Height=<span style="color: #006080">&quot;350&quot;</span> Width=<span style="color: #006080">&quot;525&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> &lt;Grid&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> &lt;Grid.ColumnDefinitions&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> &lt;ColumnDefinition Width=<span style="color: #006080">&quot;Auto&quot;</span> MaxWidth=<span style="color: #006080">&quot;250&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> &lt;ColumnDefinition Width=<span style="color: #006080">&quot;*&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> &lt;/Grid.ColumnDefinitions&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> &lt;Grid.RowDefinitions&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> &lt;RowDefinition Height=<span style="color: #006080">&quot;Auto&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> &lt;RowDefinition Height=<span style="color: #006080">&quot;Auto&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> &lt;RowDefinition Height=<span style="color: #006080">&quot;Auto&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> &lt;RowDefinition Height=<span style="color: #006080">&quot;*&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> &lt;RowDefinition Height=<span style="color: #006080">&quot;Auto&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> &lt;/Grid.RowDefinitions&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> &lt;TextBlock Text=<span style="color: #006080">&quot;PropertyNameChanged&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> TextWrapping=<span style="color: #006080">&quot;Wrap&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> &lt;TextBox Text=<span style="color: #006080">&quot;{Binding Path=(local:StaticSettings.Value1)}&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> Grid.Column=<span style="color: #006080">&quot;1&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> &lt;TextBlock Text=<span style="color: #006080">&quot;StaticPropertyChanged&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> TextWrapping=<span style="color: #006080">&quot;Wrap&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> Grid.Row=<span style="color: #006080">&quot;1&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> &lt;TextBox Text=<span style="color: #006080">&quot;{Binding Path=(local:StaticSettings.Value2)}&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span> Grid.Column=<span style="color: #006080">&quot;1&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> Grid.Row=<span style="color: #006080">&quot;1&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span>&#160; </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> &lt;StackPanel Grid.Row=<span style="color: #006080">&quot;4&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> Grid.ColumnSpan=<span style="color: #006080">&quot;2&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> Orientation=<span style="color: #006080">&quot;Horizontal&quot;</span>&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span> &lt;Button Content=<span style="color: #006080">&quot;Update property values&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span> Click=<span style="color: #006080">&quot;OnRefreshClick&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum38"> 38:</span> &lt;Button Content=<span style="color: #006080">&quot;Reset&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum39"> 39:</span> Click=<span style="color: #006080">&quot;OnResetClick&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum40"> 40:</span> &lt;Button Content=<span style="color: #006080">&quot;Show current source data&quot;</span></pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum41"> 41:</span> Click=<span style="color: #006080">&quot;OnShowDataClick&quot;</span>/&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum42"> 42:</span> &lt;/StackPanel&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum43"> 43:</span> </pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum44"> 44:</span> &lt;/Grid&gt;</pre> <!--CRLF--> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum45"> 45:</span> &lt;/Window&gt;</pre> <!--CRLF--></div> </div> <p>Im Endeffekt wird hier nicht mehr gemacht, als zwei Textfelder (diese haben per Default eine Two-Way-Bindung) mit einer Bindung auf die beiden Eigenschaften der in den Ressourcen definierten Klasse zu versehen.</p> <blockquote> <p><strong>Wichtig</strong>: Zu beachten sind die runden Klammern, die für die Pfadangabe der Bindung verwendet werden. Durch diese “weiß” das Bindungssystem, dass nach dem Schema <font face="Courier New">Klassenname.Eigenschaftsname</font> geparst werden soll. Ohne runde Klammern wird nach dem Schema <font face="Courier New">Eigenschaftsname.Eigenschaftsname </font>verfahren.</p> </blockquote> <p>Nicht verschrecken sollten folgende beiden Eigenheiten der Developer Preview:</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_107.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Windows Presentation Foundation 4.5 - Probleme Rendering" border="0" alt="Windows Presentation Foundation 4.5 - Probleme Rendering" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_62.png" width="492" height="250" /></a></p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_108.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Windows Presentation Foundation 4.5 - Probleme Rendering" border="0" alt="Windows Presentation Foundation 4.5 - Probleme Rendering" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_63.png" width="492" height="85" /></a></p> <blockquote> <p>Trotz der angezeigten Fehler kann die Anwendung trotzdem gestartet werden. Offensichtlich wird die neue Bindungs-Syntax noch nicht erkannt. In den weiteren Versionen wird es hierfür wohl einen entsprechenden Fix bzw. eine Erweiterung geben.</p> </blockquote> <p>Um das Verhalten testen zu können, finden sich auch einige Schaltflächen auf der Oberfläche (auf die Verwendung von MVVM wird der Einfachheit halber verzichtet).</p> <p>Hier die Eventhandler:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; max-height: 400px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnRefreshClick(<span style="color: #0000ff">object</span> sender, RoutedEventArgs e)<br />{<br /> StaticSettings.Value1 = <span style="color: #006080">&quot;Updated&quot;</span>;<br /> StaticSettings.Value2 = <span style="color: #006080">&quot;Updated&quot;</span>;<br />}<br /><br /><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnResetClick(<span style="color: #0000ff">object</span> sender, RoutedEventArgs e)<br />{<br /> StaticSettings.Value1 = <span style="color: #006080">&quot;&quot;</span>;<br /> StaticSettings.Value2 = <span style="color: #006080">&quot;&quot;</span>;<br />}<br /><br /><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnShowDataClick(<span style="color: #0000ff">object</span> sender, RoutedEventArgs e)<br />{<br /> StringBuilder sb = <span style="color: #0000ff">new</span> StringBuilder();<br /> sb.AppendFormat(<span style="color: #006080">&quot;Value1: {0}\n&quot;</span>, StaticSettings.Value1);<br /> sb.AppendFormat(<span style="color: #006080">&quot;Value2: {0}\n&quot;</span>, StaticSettings.Value2);<br /> MessageBox.Show(sb.ToString());<br />}</pre> <br /></div> <p>Nach einem Start der Anwendung können über die erste Schaltfläche im Hintergrund die Werte der beiden Eigenschaften verändert werden. Wie nachfolgend zu sehen, spiegeln sich diese in der Oberfläche wider. Test bestanden.</p> <p><a href="http://devtyr.norberteder.com/image.axd?picture=image_109.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Windows Presentation Foundation 4.5 - Binding to static properties" border="0" alt="Windows Presentation Foundation 4.5 - Binding to static properties" src="http://devtyr.norberteder.com/image.axd?picture=image_thumb_64.png" width="492" height="159" /></a></p> <blockquote> <p><strong>Hinweis</strong>: Wer mit der Erweiterung <font face="Courier New">x:Static</font> arbeiten wollte, wird eine Enttäuschung erleben. Hier verhält es sich so, dass die Ereignisse bei der Änderung der Source nicht ausgewertet werden. Dies ist das Standardverhalten und wird auch in WPF 4.5 nicht geändert.</p> </blockquote> <p>Das hier besprochene Beispiel kann nachfolgend herunter geladen werden.</p> <p><iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; padding-right: 0px; padding-top: 0px" title="Preview" height="120" marginheight="0" src="https://skydrive.live.com/embed?cid=C8D8CB313DB8E795&amp;resid=C8D8CB313DB8E795%21457&amp;authkey=AJIi96Tfo1gz8X0" frameborder="0" width="98" marginwidth="0" scrolling="no"></iframe></p> <p><a href="http://dotnet-kicks.de/kick/?url=http%3a%2f%2fdevtyr.norberteder.com%2fpost%2fWindows-Presentation-Foundation-45-Bindung-an-statische-Eigenschaften.aspx"><img border="0" alt="kick it on dotnet-kicks.de" src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fdevtyr.norberteder.com%2fpost%2fWindows-Presentation-Foundation-45-Bindung-an-statische-Eigenschaften.aspx" /></a></p> http://devtyr.norberteder.com/post/Windows-Presentation-Foundation-45-Bindung-an-statische-Eigenschaften.aspx Norbert Eder [MVP] 3503 2011-12-29T21:33:53 WebSequenceDiagrams API mit .NET Heute bin ich durch einen Tweet auf websequencediagrams aufmerksam geworden. Mit websequencediagrams kann man sich über eine einfache Textnotation ein SequenzDiagramm in verschiedenen Styles erstellen lassen. Die Applikation bietet aber auch eine Schnittstelle die es einem ermöglicht mit .NET ein solches Diagramm zu erstellen. Folgendes CodeSnippet soll zeigen wie: 1 public void SaveSequenceDiagram(string data, string [...] http://feedproxy.google.com/~r/BigglesBlog/~3/D1Ak4traZyE/websequencediagrams-api-mit-net Mario Priebe 3498 2011-12-28T21:06:47 Buch - Die Versuchung - David Baldacci <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Die Versuchung - David Baldacci" border="0" alt="Die Versuchung - David Baldacci" align="left" src="http://devtyr.norberteder.com/image.axd?picture=image_105.png" width="112" height="164" /></p> <p><em>LuAnn lebt mit ihrer Tochter und ihrem arbeitsscheuen Lebensgefährten in einem alten Wohnwagen. Sie schlägt sich mit Gelegenheitsjobs durch, bis sie ein mysteriöses Angebot erhält: Ein Fremder will sie zur Hauptgewinnerin in der staatlichen Lotterie machen. Dafür soll sie genau das tun, was er ihr befiehlt. Zu spät erkennt LuAnn, dass das Spiel mit dem Glück tödlicher Ernst ist ..</em></p> <p>Die Story ist spannend, keine Frage. LuAnn ist sehr jung, hat ein Baby und einen Nichtsnutz als Freund, der nicht arbeiten will, und wenn, sich mit illegalen Geschäften über Wasser hält. Eines Tages erhält sie von einem Unbekannten, Jackson, ein Angebot, das sie kaum abschlagen kann. Hundert Millionen Dollar. Zu gewinnen über die staatliche Lotterie, die Jackson jederzeit manipulieren kann, wie er ihr auch vorführt. Daran gebunden sind jedoch unbekannte Forderungen, die erst nach einer Zusage bekannt gemacht werden. Nachdem ihr Freund umgebracht wird, ist sie mehr oder weniger gezwungen, das Angebot anzunehmen. Sie bekommt Charlie an ihre Seite gestellt, der sie bei allen “Formalitäten” unterstützt. Schnell fasst sie Vertrauen zu ihm. Nachdem sie aufgrund wegen des mysteriösen Todes ihres Freundes lange Jahre auf der Flucht ist, zieht sie mit Charlie (der bei ihr geblieben ist) in den Heimatsort ihrer Mutter zurück. Ein Schritt, den sie unter keinen Umständen machen hätte dürfen und unter Strafe durch Jackson verboten wurde.</p> <p>Es beginnt ein Katz und Mausspiel. Jackson - ein Meister der Tarnung und Verkleidung - unternimmt alles, um sämtliche Spuren zu verwischen, zudem auch noch ein Reporter der gesamten Geschichte auf die Schliche kommt …</p> <p>Die Handlung ist eines Thrillers würdig, wenn er es sich an einigen Stellen auch etwas zu einfach macht. Dennoch, das Buch geht runter wie Öl und findet ein sehr interessantes Ende. Es gibt kaum Phasen, die sich wirklich hinziehen, dem Leser wird es in keiner Weise langweilig. Zugegeben, ich bin ein Fan von <a href="http://davidbaldacci.com/" target="_blank">David Baldacci</a>, da er es versteht, den Leser zu fesseln und interessante Bücher zu liefern. Mir fehlt aber doch das gewisse Etwas, um die volle Punkteanzahl geben zu können. Ein solides Werk und empfehlenswert ist es aber allemal.</p> <p><strong>Bewertung</strong>: 4/5</p> <blockquote> <p>Weitere von mir gelesene und bewertete Bücher finden sich unter <a href="http://devtyr.norberteder.com/page/books.aspx">Lesestoff</a>.</p></blockquote> http://devtyr.norberteder.com/post/Buch-Die-Versuchung-David-Baldacci.aspx Norbert Eder [MVP] 3492 2011-12-26T20:09:47 Iconset-Sammlung – Minimalistische Icons Für die Entwicklung von ansprechenden Applikationen sind die visuellen Elemente essentiell. Dazu gehören die kleinen Bildchen &#8211; oder auch Icons genannt &#8211; die dem Anwender auf einem Blick klar machen sollen, welche Funktion sich dahinter verbirgt. Wir Entwickler haben meist nicht so das Händchen dafür, solche Icons zu erstellen. Wir sollten aber wissen, wo man [...] http://feedproxy.google.com/~r/BigglesBlog/~3/twf4-NvS23c/iconset-sammlung-minimalistische-icons Mario Priebe 3490 2011-12-25T14:08:30