Your SlideShare is downloading. ×
0
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Wartbare Web-Anwendungen mit Knockout.js und Model-View-ViewModel (MVVM)

502

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
502
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Wartbare Web-Anwendungenmit Knockout.js undModel-View-ViewModel (MVVM)Malte Clasen
  • 2. Problem: Rezepteditor
  • 3. Problem: Rezepteditor
  • 4. Acceptance Tests Feature: RecipeEditor In order to edit a recipe As a registered user I want to be able to modify all properties of a recipe Scenario: Add Category Given I am on the "Streuselkuchen" recipe page And I am in edit mode When I click on the empty category field And I type "Blechkuchen" Then there should be 3 categories And the title of the third category should be "Blechkuchen"4
  • 5. HTML-Ansicht <h1>Streuselkuchen</h1> <img class="photo" alt="recipe" <h3>Kategorien</h3> src="/Content/Images/streuselkuchen.jpg"> <ul> <div>Foto von Malte</div> <li><a href="/KuchenUndTorten"> Kuchen und Torten</a></li> <h2>Zubereitung</h2> <li>Kleingebäck</li> </ul> <h3>Teig</h3> <h2>Zutaten</h2> <div>Mehl in eine Schüssel geben und eine Kuhle hineindrücken. Zucker, Hefe und <h3>Teig</h3> <emph>lauwarmen</emph> <table> Soja-Reis-Drink hineingeben. Mit einem <tbody> Küchentuch zudecken und 15 Minuten lang <tr class="ingredient"> gehen lassen. Margarine zerlassen und <td class="amount">400</td> ebenfalls in die Kuhle geben. Von innenheraus <td class="unit">g</td> mit dem restlichen Mehl verkneten. Nochmals <td class="name"><a href="/Mehl"> 15 Minuten lang zugedeckt gehen lassen. Auf Mehl</a></td> einem mit Backpapier ausgelegten Blech </tr> ausrollen und wieder 15 Minuten lang gehen … lassen.</div> </tbody> </table> <h3>Streusel</h3> <h3>Streusel</h3> <div>Mehl, Zucker und Zimt vermischen, <table>…</table> Margarine zerlassen und alles verkneten. Streusel auf dem ausgerollten, gegangenen Teig <strong>gleichmäßig</strong> verteilen und ca. 20 Minuten bei 180°C Umluft backen.</div>
  • 6. ASP.NET-Editor zwei Code- veränderbare „neue Pfade, Anzahl in Listen Kategorie“ Postback, …6
  • 7. Knockout: Prinzip JSON ViewModel Template HTML7
  • 8. JSON [AcceptVerbs(HttpVerbs.Get)] public ActionResult Get() { return Json(_model, JsonRequestBehavior.AllowGet); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(RecipeModel model) { return Json("gespeichert um " + DateTime.Now.ToShortTimeString()); }8
  • 9. ViewModel function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); … this.onSave = function () { … }; this.onRemoveComponent = function (model, event) { self.data().Components.remove(model); } … var mapping = { … }; self.data(ko.mapping.fromJS(initialData, mapping)); };9
  • 10. Observable function QuantityModel(data) { this.Amount = ko.observable(data.Amount); this.Unit = ko.observable(data.Unit); }10
  • 11. ObservableArray function ComponentModel(data) { var self = this; this.Title = ko.observable(data.Title); this.Preparation = ko.observable(data.Preparation); this.Ingredients = ko.observableArray(); this.Ingredients($.map(data.Ingredients, function (item) { return new RecipeIngredientModel(item); })); … }11
  • 12. Binding: Text <h1 data-bind="text: Title"></h1> ergibt zur Laufzeit <h1 data-bind="text: Title">Streuselkuchen</h1>12
  • 13. Binding: With function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); … }; … ko.applyBindings(recipeViewModel); <form action="#" id="RecipeEditor" data-bind="with: data"> <h1 data-bind="text: Title"></h1> … </form>13
  • 14. Binding: Attr <ul data-bind="foreach: Categories"> <li><a data-bind="text:Name, attr: {href:Url}"></a></li> </ul>14
  • 15. Virtual Elements <img class="photo" alt="recipe" data-bind="attr: {src: Image.Url}" /> <div> Foto von <!--ko text: Image.Author--> <!--/ko--> </div>15
  • 16. Binding: Foreach <ul data-bind="foreach: Categories"> <li><a data-bind="text:Name, attr: {href:Url}"></a></li> </ul>16
  • 17. Binding: If <ul data-bind="foreach: Categories"> <!-- ko if:!IsEmpty() --> <li><a data-bind="text:Name, attr: {href:Url}"></a></li> <!-- /ko --> </ul> function CategoryModel(data) { var self = this; this.Name = ko.observable(data.Name); this.Url = ko.observable(data.Url); this.IsEmpty = ko.computed(function () { return (!self.Name()) && (!self.Url()); }, this); }17
  • 18. Mapping, manuell function ComponentModel(data) { var self = this; this.Title = ko.observable(data.Title); this.Preparation = ko.observable(data.Preparation); this.Ingredients = ko.observableArray(); this.Ingredients($.map(data.Ingredients, function (item) { return new RecipeIngredientModel(item); })); }18
  • 19. Mapping, automatisch function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); var mapping = { Components: { create: function (options) { return new ComponentModel(options.data); } } }; self.data(ko.mapping.fromJS(initialData, mapping)); }19
  • 20. Mapping, zu JSON this.onSave = function () { $.ajax("/Recipe/Edit", { data: ko.mapping.toJSON(self.data), type: "post", contentType: "application/json", dataType: "json", success: function (result) { ShowLogMessage(result); } }) .error(function (e, jqxhr, settings, exception) { console.log(exception); }); };20
  • 21. HTML-Editor <h1 contenteditable="true">Streuselkuchen</h1> <img class="photo" alt="recipe" <h3>Kategorien</h3> src="/Content/Images/streuselkuchen.jpg"> <ul> <div>Foto von Malte</div> <li><input type="text"></li> <li><input type="text"></li> <h2>Zubereitung</h2> </ul> <h3 contenteditable="true">Teig</h3> <h2>Zutaten</h2> <div contenteditable="true">Mehl in eine <div class="toolbar edit"> Schüssel geben und eine Kuhle <button type="button"> hineindrücken. Zucker, Hefe und <img src="/list-remove.png"> <emph>lauwarmen</emph> </button> Soja-Reis-Drink hineingeben. Mit einem </div> Küchentuch zudecken und 15 Minuten lang <h3 contenteditable="true">Teig</h3> gehen lassen. Margarine zerlassen und <table> ebenfalls in die Kuhle geben. Von innenheraus <tbody> mit dem restlichen Mehl verkneten. Nochmals <tr class="ingredient"> 15 Minuten lang zugedeckt gehen lassen. Auf <td class="amount"><input einem mit Backpapier ausgelegten Blech type="number"></td> ausrollen und wieder 15 Minuten lang gehen <td class="unit"><input lassen.</div> type=“text"></td></td> <td class="name"><input <h3 contenteditable="true">Streusel</h3> type=“text"></td> </tr> <div contenteditable="true">Mehl, Zucker … und Zimt vermischen, Margarine zerlassen </tbody> und alles verkneten. Streusel auf dem </table> ausgerollten, gegangenen Teig <strong>gleichmäßig</strong> verteilen und <h3 contenteditable="true">Streusel</h3> ca. 20 Minuten bei 180°C Umluft <table>…</table> backen.</div>
  • 22. HTML-Editor <div contenteditable="true" data-bind="html: Preparation, event: {change: onUpdatePreparation}">Mehl in eine Schüssel geben … function ComponentModel(data) { var self = this; this.Preparation = ko.observable(data.Preparation); this.onUpdatePreparation = function(model, event) { self.Preparation($(event.target).html()); }; }22
  • 23. Event: Click <button type="button" data-bind="event: { click: $root.onRemoveComponent }"> <img alt="list-remove" src="list-remove.png" /> </button> function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); this.onRemoveComponent = function (model, event) { self.data().Components.remove(model); } }23
  • 24. Binding: Value <ul data-bind="foreach: Categories"> <li><input type="text" data-bind="value:Name"/></li> </ul> function CategoryModel(data) { var self = this; this.Name = ko.observable(data.Name); }24
  • 25. Event: Change <ul data-bind="foreach: Categories"> <li><input type="text" data-bind="value:Name, event:{change: $root.onChangeCategory}" /></li> </ul> this.onChangeCategory = function (model, event) { if (model.Name()) { … } else { self.data().Categories.remove(model); } }25
  • 26. Computed function ComponentModel(data) { var self = this; this.Ingredients = ko.observableArray(); this.LastIngredient = ko.computed(function () { if (self.Ingredients().length === 0) return null; return self.Ingredients()[self.Ingredients().length-1]; }, this); }26
  • 27. Subscribe this.LastIngredientSubscription = null; this.LastIngredient.subscribe(function (newValue) { if (self.LastIngredientSubscription !== null) { self.LastIngredientSubscription.dispose(); } var currentLastIngredient = newValue; if (currentLastIngredient === null) currentLastIngredient = self.AddEmptyIngredient(); if (!currentLastIngredient.IsEmpty()) currentLastIngredient = self.AddEmptyIngredient(); self.LastIngredientSubscription = currentLastIngredient.IsEmpty.subscribe( function (newValue) { if (!newValue) { self.AddEmptyIngredient(); } }); });27
  • 28. Rahmenwerk @Scripts.Render("~/Scripts/recipe") <script type="text/javascript"> InitRecipeViewModel(@Html.Raw(Model.Json)); </script> var recipeViewModel; function InitRecipeViewModel(initialData) { recipeViewModel = new RecipeViewModel(initialData); } function InitRecipeEditor() { ko.applyBindings(recipeViewModel); ShowRecipeEditor(); }28
  • 29. Übersicht • Grundlage: HTML-Ansicht • Knockout: – Model: Service – View: Template – ViewModel: Script • Observable, ObservableArray, Compute, Subscribe • Binding – Inhalte: Text, Attr – Struktur: With, Foreach, If – Events: Click29
  • 30. Vielen Dank für Ihre Aufmerksamkeit.info@adesso.dewww.adesso.de | malteclasen.de/blog

×