Interaktive Ansicht
Jetzt wird die Backbone.js-Ansicht aus der Einführung so erweitert, dass die typischen Aktionen Hinzufügen, Bearbeiten und Löschen möglich sind.
tl;dr
Es kommt die Ereignisbehandlung im Browser/Frontend/GUI hinzu. Direkt ausprobieren geht unter JSFIDDLE Demo.
Anpassungen und Vorbereitung
- Zur Sicherheit lege ich die Kodierung auf UTF-8 fest (Zeile 4).
- Die einfachen Liste ändere ich ab in eine Tabelle. Dazu werden die jeweiligen
tagName
-Eigenschaften angepasst (Zeile 13 und 25). - Damit der
View
eines Elements als Tabellenzeileninhalt funktioniert, passe ich das Template an (Zeile 27). - Auf der Seite wird noch ein Aufruf zum Hinzufügen platziert (Zeile 22).
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Backbone Tutorial</title> <script src="/jquery-1.11.0.min.js" type="text/javascript"></script> <script src="/underscore-min.js" type="text/javascript"></script><!-- Version 1.6.0 --> <script src="/backbone-min.js" type="text/javascript"></script><!-- Version 1.1.1 --> </head> <body> <script type="text/javascript"> var MasterView = Backbone.View.extend({ tagName: "table", className: "masterview", addOne: function(element) { var itemview = new ItemView({ data: element }); this.$el.append(itemview.render().el); } }); var masterview = new MasterView(); jQuery('body').append(masterview.$el).append('<a href="javascript:bbadd();">+</a>'); var ItemView = Backbone.View.extend({ tagName: "tr", className: "backboneitem", template: _.template('<td><span class="show"><%= title %></span></td>'), initialize: function(options) { if (options.data) { this.data = options.data; this.listenTo(this.data, "remove", this.remove); this.listenTo(this.data, "change:title", this.render); } }, render: function() { this.$el.html(this.template(this.data.toJSON())); return this; } }); var Items = Backbone.Collection.extend(); var items = new Items(); masterview.listenTo(items, "add", masterview.addOne); items.add({ id: 17, title: 'Apfel' }); items.add({ id: 23, title: 'Birne' }); items.add({ id: 42, title: 'Orange' }); </script> </body> </html>
Alle Anpassungen sind in der Datei file1000.html festgehalten
Hinzufügen
Um Elemente zu ergänzen, soll beim Klick auf den Link der Titel des neuen Elements abgefragt werden. Anschließend wird das Element erzeugt und der Collection
hinzugefügt. Die folgende Funktion ist dafür ausreichend:
var bbadd = function() { var title = prompt("Neuer Titel?"); if (title != "" && title != null) { items.add({title: title}); } }
Der Zustand ist in der Datei file1010.html festgehalten.
Löschen
Um Elemente aus der Collection
zu löschen, fügen wir dem ItemView
einen Bereich hinzu, der unsere Löschfunktion auslöst. Dazu schreiben wir als erstes etwas CSS in das HTML-Grundgerüst:
.delete { cursor: pointer; }
Danach tausche ich das Template des ItemView
gegen folgenden Text aus. Damit erreiche ich, dass in jeder Zeile eine weitere Zelle entsteht, die den Löschlink enthält. Der »Link« ist ein einfaches SPAN
-Element, das für sich genommen noch keine Funktion hat. Selbstverständlich wäre auch die Nutzung eines A
-Elements möglich.
template: _.template('<td><span class="show"><%= title %></span></td><td><span class="delete">✗</span></td>'),
Damit nun beim Klick auch eine Funktion ausgelöst wird, kommt ein Sonderfall der Events
zum Einsatz. Bei der Definition eines Views
ist es möglich, direkt die zu verarbeitenden Ereignisse anzugeben. Dies ist in folgendem Code in den Zeilen 6 bis 8 dargestellt. Die ereignisverarbeitende Funktion (ab Zeile 14) wird als Zeichenkette hinter dem jQuery-Selektor angegeben (in Zeile 7).
var ItemView = Backbone.View.extend({ tagName: "tr", className: "backboneitem", template: _.template( "" /* gekürzt */ ), events: { "click .delete": "clickOnDelete" }, initialize: function(options) { /* gekürzt */ }, render: function() { /* gekürzt */ }, clickOnDelete: function() { if (confirm(this.data.get("title") + " löschen?")) { this.data.collection.remove(this.data); } } });
In der Ereignisverarbeitung (Zeile 14 – 18) wird eine Sicherheitsabfrage ausgelöst.
Bestätigt der Benutzer den Dialog, wird das Element gelöscht. Weil die Collection
nur im Browser vorhanden ist, reicht es aus, das Element aus der Collection
zu entfernen.
Der Zustand ist in der Datei file1020.html festgehalten.
Bearbeiten
Die letzte Aufgabe besteht darin, die vorhandenen Elemente bearbeiten zu können. Die Umsetzung erfolgt analog zum Löschen:
- Anpassung der CSS-Anweisung:
.edit, .delete { cursor: pointer; }
- Erweiterung des Templates um eine weitere Zelle:
template: _.template('<td><span class="edit">✏</span></td><td><span class="show"><%= title %></span></td><td><span class="delete">✗</span></td>'),
- Ergänzung der Zeile 38 in den
events
desItemView
:events: { "click .delete": "clickOnDelete", "click .edit" : "clickOnEdit" },
- Ergänzung der Funktion zur Ereignisbehandlung:
clickOnEdit: function() { var newtitle = prompt("Neuer Titel", this.data.get("title")); if (newtitle != null && newtitle != "") { this.data.set("title", newtitle); } }
Der Zustand ist in der Datei file1030.html festgehalten.
Zusammenfassung
Der Quellcode der Seite sieht nun so aus:
<!DOCTYPE html> <html> <head> <!-- http://jsfiddle.net/ErikWegner/hnLkk/ --> <meta charset="utf-8"> <title>Backbone Tutorial</title> <script src="/jquery-1.11.0.min.js" type="text/javascript"></script> <script src="/underscore-min.js" type="text/javascript"></script><!-- Version 1.6.0 --> <script src="/backbone-min.js" type="text/javascript"></script><!-- Version 1.1.1 --> <style type="text/css"> .edit, .delete { cursor: pointer; } </style> </head> <body> <script type="text/javascript"> var MasterView = Backbone.View.extend({ tagName: "table", className: "masterview", addOne: function(element) { var itemview = new ItemView({ data: element }); this.$el.append(itemview.render().el); } }); var masterview = new MasterView(); jQuery('body').append(masterview.$el).append('<a href="javascript:bbadd();">+</a>'); var ItemView = Backbone.View.extend({ tagName: "tr", className: "backboneitem", template: _.template('<td><span class="edit">✏</span></td><td><span class="show"><%= title %></span></td><td><span class="delete">✗</span></td>'), events: { "click .delete": "clickOnDelete", "click .edit" : "clickOnEdit" }, initialize: function(options) { if (options.data) { this.data = options.data; this.listenTo(this.data, "remove", this.remove); this.listenTo(this.data, "change:title", this.render); } }, render: function() { this.$el.html(this.template(this.data.toJSON())); return this; }, clickOnDelete: function() { if (confirm(this.data.get("title") + " löschen?")) { this.data.collection.remove(this.data); } }, clickOnEdit: function() { var newtitle = prompt("Neuer Titel", this.data.get("title")); if (newtitle != null && newtitle != "") { this.data.set("title", newtitle); } } }); var Items = Backbone.Collection.extend(); var items = new Items(); masterview.listenTo(items, "add", masterview.addOne); items.add({ id: 17, title: 'Apfel' }); items.add({ id: 23, title: 'Birne' }); items.add({ id: 42, title: 'Orange' }); var bbadd = function() { var title = prompt("Neuer Titel?"); if (title != "" && title != null) { items.add({title: title}); } } </script> </body> </html>
Darin implementiert sind die typischen CRUD-Operationen: der Benutzer kann im Browser zur Laufzeit dynamisch Elemente anzeigen lassen, ergänzen, bearbeiten und löschen.
Als neue Technik kommt hier die Ereignisbehandlung in den Backbone.Views
zum Einsatz.
Der gesamte Code kann auch unter JSFIDDLE Demo direkt im Browser ausprobiert werden.