WPF-Blogger.com [Language: de] http://www.wpf-blogger.com All news and information about Windows Presentation Foundation and Silverlight at one place. Montag, 6. Februar 2012 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>Jetzt Backbone.js lernen: Überlegungen zum Thema Suchmaschinen </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