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

Ähnliche Dokumente
Geister, Gurken und Halbmetalle. Tools für Web-UI-Acceptance-Tests. Malte Clasen

Knockout MVVM für Javascript und HTML5. W3L AG

NEWSLETTER. FileDirector Version 2.5 Novelties. Filing system designer. Filing system in WinClient

Order Ansicht Inhalt


Spiel, Spaß, Spannung mit ember js

Exercise (Part V) Anastasia Mochalova, Lehrstuhl für ABWL und Wirtschaftsinformatik, Kath. Universität Eichstätt-Ingolstadt 1

p^db=`oj===pìééçêíáåñçêã~íáçå=

Erweiterte Interaktion mit Trees und Charts in APEX

Mul$media im Netz Wintersemester 2012/13. Übung 06

Word-CRM-Upload-Button. User manual

Exercise (Part VIII) Anastasia Mochalova, Lehrstuhl für ABWL und Wirtschaftsinformatik, Kath. Universität Eichstätt-Ingolstadt 1

NotesSession.GetPropertyBroker( )

!! Um!in!ADITION!ein!HTML51Werbemittel!anzulegen,!erstellen!Sie!zunächst!ein!neues! Werbemittel!des!Typs!RichMedia.!!!!!!

Spiel, Spaß, Spannung mit ember js

VGM. VGM information. HAMBURG SÜD VGM WEB PORTAL USER GUIDE June 2016

Webanwendungen mit Java und JavaServerPages

Version 1.2 belboon GmbH /78

(0911) BLZ:

Doppelklick auf eine Klasse verzweigt in den Class Builder (Transaktion SE24).

Dexatek's Alexa Smart Home Skills Instruction Guide

ADF steht für Application Developer Framework, BC für Business Components.

Brot & Brötchen. Paco s Genusskiste. Rezept gefunden bei resoe.de

VGM. VGM information. HAMBURG SÜD VGM WEB PORTAL - USER GUIDE June 2016

VON MVC ZU MODEL-VIEW-VIEWMODEL

Exercise (Part XI) Anastasia Mochalova, Lehrstuhl für ABWL und Wirtschaftsinformatik, Kath. Universität Eichstätt-Ingolstadt 1

Funktionen. Überblick über Stored Functions. Syntax zum Schreiben einer Funktion. Schreiben einer Funktion

<body> <h1>testseite für HTML-Parameter-Übergabe<br>50 Parameter werden übergeben</h1>

Java Tools JDK. IDEs. Downloads. Eclipse. IntelliJ. NetBeans. Java SE 8 Java SE 8 Documentation

Dynamisches Anzeigen von Informationen mit jqueryui Dialogs und Tabs

ENTERPRISEY ANGULAR.JS

PHP JavaScript Kapitel 9. Java-Script-Objekte und das Event-Modell

Web 2. Gang. Python User Group Köln Christopher Arndt

Einschätzung

Exercise (Part II) Anastasia Mochalova, Lehrstuhl für ABWL und Wirtschaftsinformatik, Kath. Universität Eichstätt-Ingolstadt 1

Wählt man einen Wert aus, so wird dieser in das Selektionsbild übernommen und der Docking- Container wird wieder verkleinert.

SAP-Daten per HTML anzeigen

1. General information Login Home Current applications... 3

Apfelkuchen mit Streusel vom Blech

Tragfähige Frontend-Architekturen

ColdFusion 8 PDF-Integration

Knockout für den Rivalen

DataTables LDAP Service usage Guide

WebApp mit Node und Express

Oracle9i Designer. Rainer Willems. Page 1. Leitender Systemberater Server Technology Competence Center Frankfurt Oracle Deutschland GmbH

Umzug. ASP.NET-WebForms-Elemente in MVC weiterverwenden. Dr. Malte Clasen adesso AG

MVVM (Model View ViewModel) in JavaFX

p^db=`oj===pìééçêíáåñçêã~íáçå=

APEX Plugins: Alles, was Sie darüber wissen müssen. Denes Kubicek

The app the crashes, before the breakpoint is reached: Code to the event:

hotelanfrage_sample <td align = "center"> <select name=dy0 size=1 class="smalltext"> <option selected value="0"><< kein Erwachsener

Exercise (Part I) Anastasia Mochalova, Lehrstuhl für ABWL und Wirtschaftsinformatik, Kath. Universität Eichstätt-Ingolstadt 1

Legacy Web-Apps mit AngularJS pimpen

Vorteil. Einfach zu realisieren performant. Übersichtlich performant. "Vererbung" von Änderungen an vererbender Tabelle

White-paper: Jäger zwischen zwei Welten

Quick Installation Guide

Dynamisches Anzeigen von Informationen in APEX mit jquery UI Dialogs und Tabs

Informationen zur Verwendung des TFE-Portals / Information for Using the TFE portal

APEX 5.0: Page Designer. Tobias Strohmeyer Berlin,

EINFÜHRUNG IN REACT.JS UND REDUX

11. Webautomatisierung HTTP Protokoll Tabellen Formulare und Parameter Templates, Graphik Ajax Zustandsinformationen

USB -> Seriell Adapterkabel Benutzerhandbuch

Fakultät für Informatik & Wirtschaftsinformatik DB & IS II SS 2015 PHP MVC. Dr. Christian Senger. PHP MVC 1 von 21

Design Patterns I. Observer, Listener & MVC

NVR Mobile Viewer for iphone/ipad/ipod Touch

Kuchen-Kategorie. Obstkuchen vom Blech. Teig:

Automatisierte Akzeptanztests für ios-apps. Sven Günther it-agile GmbH

BDD UND GHERKIN IN DER PRAXIS VON DER ANFORDERUNG ZUR UMSETZUNG

Web-Anwendungen, SS17 - Fragentypen

PeakTech Zeitprogramm erstellen über Excel - Beispiel / Timed programs with Excel Example

Titelmasterformat Object Generator durch Klicken bearbeiten

tempela Eine Template Engine für WordPress wildbits.de Jenseits des täglichen Wahnsinns

GEBÄCK. Cranberry-Muffins. Cranberry-Muffins mit Honig (ca Stück)

ORM & OLAP. Object-oriented Enterprise Application Programming Model for In-Memory Databases. Sebastian Oergel

USER MANUAL pdfprint for Magento 2

2. HTML. Vorlesung und Übung Dr. Peter Pfahler Institut für Informatik Universität Paderborn. Das Umfeld dynamischer Web-Anwendungen 2-2

Mindbreeze Web Parts. für Microsoft SharePoint. Version 2016 Fall Release

Zwetschgenkuchen nach Omas Rezept mit Mandelzimtstreuseln

Cross-Platform Mobile Apps

Realtime Anbindung an SAP ERP

Schokobrownies. 15 Min Min. backen Brownie (ca. 25 g) 3 Eier 250 g Puder Eier, Puderzucker und Vanillezucker schaumig rühren.

THEMA: GUT VORBEREITET IST HALB ZERTIFIZIERT ANTWORTEN ZUR SAS VISUAL ANALYTICS-ZERTIFIZIERUNG" THOMAS WENDE

Baguette (lange Teigführung/48 Stunden)

2.2 Spezifikation abstrakter Datentypen. 2.3 Implementierung und Anwendung von ADT. 2.4 Datenabstraktion und Objektorientierung

Quick Installation Guide for 4 and 7-Port Broadband Router

Exporting ALV to Memory2

Informatik 2 für Regenerative Energien

Digitale Medien. Übung zur Vorlesung. Vorlesung: Heinrich Hußmann Übung: Renate Häuslschmid

Übung zur Vorlesung. Digitale Medien. Vorlesung: Heinrich Hußmann Übung: Renate Häuslschmid, Hanna Schneider

Trigger Based Mass Reversal

NoSQL The SQL Way. PostgreSQL JSON Features. PGConf.de 2018 Stefanie Janine Stölting PostgreSQL

Vue.js eine Einführung

Schriftliche Reifeprüfung aus INFORMATIK: Klasse 8D Haupttermin 2002/03

BRÖTCHEN. Startrampe ZUBEREITUNG

Multimedia im Netz Wintersemester 2013/14. Übung 05 (Nebenfach)

Rezepte für Hefezopf. Vanille-Mandel-Zopf

Transkript:

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

Problem: Rezepteditor

Problem: Rezepteditor

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

HTML-Ansicht <h1>streuselkuchen</h1> <img class="photo" alt="recipe" src="/content/images/streuselkuchen.jpg"> <div>foto von Malte</div> <h2>zubereitung</h2> <h3>teig</h3> <div>mehl in eine Schüssel geben und eine Kuhle hineindrücken. Zucker, Hefe und <emph>lauwarmen</emph> Soja-Reis-Drink hineingeben. Mit einem Küchentuch zudecken und 15 Minuten lang gehen lassen. Margarine zerlassen und ebenfalls in die Kuhle geben. Von innenheraus mit dem restlichen Mehl verkneten. Nochmals 15 Minuten lang zugedeckt gehen lassen. Auf einem mit Backpapier ausgelegten Blech ausrollen und wieder 15 Minuten lang gehen lassen.</div> <h3>streusel</h3> <div>mehl, Zucker und Zimt vermischen, 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> <h3>kategorien</h3> <ul> <li><a href="/kuchenundtorten"> Kuchen und Torten</a></li> <li>kleingebäck</li> </ul> <h2>zutaten</h2> <h3>teig</h3> <table> <tbody> <tr class="ingredient"> <td class="amount">400</td> <td class="unit">g</td> <td class="name"><a href="/mehl"> Mehl</a></td> </tr> </tbody> </table> <h3>streusel</h3> <table> </table>

ASP.NET-Editor veränderbare Anzahl in Listen neue Kategorie zwei Code- Pfade, Postback, 6

Knockout: Prinzip JSON ViewModel Template HTML 7

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

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

Observable function QuantityModel(data) { this.amount = ko.observable(data.amount); this.unit = ko.observable(data.unit); 10

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

Binding: Text <h1 data-bind="text: Title"></h1> ergibt zur Laufzeit <h1 data-bind="text: Title">Streuselkuchen</h1> 12

Binding: With function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); ; ko.applybindings(recipeviewmodel); <form action="#" id="recipeeditor" data-bind="with: data"> </form> <h1 data-bind="text: Title"></h1> 13

Binding: Attr <ul data-bind="foreach: Categories"> <li><a data-bind="text:name, attr: {href:url"></a></li> </ul> 14

Virtual Elements <img class="photo" alt="recipe" data-bind="attr: {src: Image.Url" /> <div> Foto von <!--ko text: Image.Author--> <!--/ko--> </div> 15

Binding: Foreach <ul data-bind="foreach: Categories"> <li><a data-bind="text:name, attr: {href:url"></a></li> </ul> 16

Binding: If 17 <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);

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

Mapping, automatisch 19 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));

Mapping, zu JSON 20 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);

HTML-Editor <h1 contenteditable="true">streuselkuchen</h1> <img class="photo" alt="recipe" src="/content/images/streuselkuchen.jpg"> <div>foto von Malte</div> <h2>zubereitung</h2> <h3 contenteditable="true">teig</h3> <div contenteditable="true">mehl in eine Schüssel geben und eine Kuhle hineindrücken. Zucker, Hefe und <emph>lauwarmen</emph> Soja-Reis-Drink hineingeben. Mit einem Küchentuch zudecken und 15 Minuten lang gehen lassen. Margarine zerlassen und ebenfalls in die Kuhle geben. Von innenheraus mit dem restlichen Mehl verkneten. Nochmals 15 Minuten lang zugedeckt gehen lassen. Auf einem mit Backpapier ausgelegten Blech ausrollen und wieder 15 Minuten lang gehen lassen.</div> <h3 contenteditable="true">streusel</h3> <div contenteditable="true">mehl, Zucker und Zimt vermischen, 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> <h3>kategorien</h3> <ul> <li><input type="text"></li> <li><input type="text"></li> </ul> <h2>zutaten</h2> <div class="toolbar edit"> <button type="button"> <img src="/list-remove.png"> </button> </div> <h3 contenteditable="true">teig</h3> <table> <tbody> <tr class="ingredient"> <td class="amount"><input type="number"></td> <td class="unit"><input type= text"></td></td> <td class="name"><input type= text"></td> </tr> </tbody> </table> <h3 contenteditable="true">streusel</h3> <table> </table>

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

Event: Click <button type="button" data-bind="event: { click: $root.onremovecomponent "> </button> <img alt="list-remove" src="list-remove.png" /> function RecipeViewModel(initialData) { var self = this; self.data = ko.observable(); this.onremovecomponent = function (model, event) { self.data().components.remove(model); 23

Binding: Value <ul data-bind="foreach: Categories"> </ul> <li><input type="text" data-bind="value:name"/></li> function CategoryModel(data) { var self = this; this.name = ko.observable(data.name); 24

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

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

Subscribe 27 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(); ); );

Rahmenwerk @Scripts.Render("~/Scripts/recipe") <script type="text/javascript"> InitRecipeViewModel(@Html.Raw(Model.Json)); </script> 28 var recipeviewmodel; function InitRecipeViewModel(initialData) { recipeviewmodel = new RecipeViewModel(initialData); function InitRecipeEditor() { ko.applybindings(recipeviewmodel); ShowRecipeEditor();

Übersicht Grundlage: HTML-Ansicht Knockout: Model: Service View: Template ViewModel: Script Observable, ObservableArray, Compute, Subscribe Binding Inhalte: Text, Attr Struktur: With, Foreach, If Events: Click 29

Vielen Dank für Ihre Aufmerksamkeit. info@adesso.de www.adesso.de malteclasen.de/blog