Backbone.js

Backbone.js

Basisdaten

Entwickler Jeremy Ashkenas
Erscheinungsjahr 13. Oktober 2010[1]
Aktuelle Version 1.5.0
(28. July 2023)
Betriebssystem plattformunabhängig
Programmier­sprache JavaScript
Kategorie JavaScript-Bibliothek
Lizenz MIT-Lizenz (Freie Software)
deutschsprachig nein
backbonejs.org

Backbone.js ist eine JavaScript-Bibliothek mit RESTful-JSON-Schnittstelle. Backbone basiert auf dem Model-View-Controller-Muster (MVC). Backbone ist für seine geringe Größe bekannt und nur von der JavaScript-Bibliothek[2] Underscore.js abhängig. Backbone wird zur Programmierung von Single-Page-Webanwendungen und zur Synchronität von Webanwendungen (z. B. verschiedene Clients und Server) verwendet. Backbone wurde von Jeremy Ashkenas geschaffen, der ebenso der initiale Autor von CoffeeScript ist.

Architekturvorgaben

Arbeitsweise von Backbone.js

Eine Backbone-Anwendung besteht aus den Elementen Model, Collection, View und Router. Das Interaktionsmuster von Backbone kann dem MVC-Muster zugeordnet werden. Model und View werden gemäß dem MVC-Muster umgesetzt. Allerdings fehlen konkrete Controller-Instanzen bei der Umsetzung. Dies hat folgende Gründe:

  • Der Router übernimmt die Aufgaben eines „Front Controllers“. Ein solcher Controller dient als Ereignissenke und Einstiegspunkt für alle eingehenden Anfragen an eine Webseite. Der Front Controller adressiert bei Backbone unmittelbar die jeweils verantwortliche View.
  • Die View einer Backbone-SPA übernimmt neben der Darstellung ebenfalls die Aufgabe der Ereignisbehandlung. Bei einem traditionellen MVC-Muster werden alle Aktionen im Rahmen der View zum jeweils verantwortlichen Controller weitergeleitet. Auf diese View/Controller-Separation wird bei Backbone-Anwendungen verzichtet. Der klassische Grund für die View/Controller-Separation liegt darin, dass die jeweiligen Verhaltensstrategien über verschiedene Controller ausgetauscht werden können. Ein Beispiel hierfür kann ein editierbares und nicht editierbares Verhalten sein. Durch den Verzicht auf explizite Controller-Instanzen wird der Implementierungsaufwand reduziert.

Konzept

Backbone gibt vier verschiedene Strukturierungselemente zur Realisierung einer Single-Page-Webanwendung vor. Das Fachmodell wird clientseitig durch Model und Collection-Klassen abgebildet. Bei Backbone beinhalten die Model-Objekte die Fachkonzeptdaten sowie Programmlogiken, welche direkt auf eine Model-Instanz operieren. Dies kann beispielsweise eine Datenvalidierung des Modells, die Definition von abgeleiteten Attributen, Zugriffskontrollen oder eine andere fachliche Funktionalität sein. Der nachfolgende Codeausschnitt zeigt die Implementierung eines Modells. Backbone bietet hierzu die Oberklasse Backbone.Model an. Über die Methode extend kann eine Unterklassendefinition erzeugt werden.

Modelldefinition in Backbone:

var Person = Backbone.Model.extend({
    urlRoot: '/persons',
    defaults: {
        firstname: '',
        name: '',
        isReadonly: false
    },
    initialize: function() {
        console.log('Konstruktur-Code');
    },
    validate: function(attribs) {
        if (attribs.name === undefined || attribs.name === '') {
            return 'Bitte einen Namen angeben.';
        }
    },
    allowedToEdit: function() {
        return !this.get('isReadonly');
   }
});

Diese Oberklasse liefert verschiedene Basisoperationen zum Umgang mit einem Model. Hierzu gehören beispielsweise die Methoden get und set zum Abrufen und Setzen von Attributen. Die Oberklasse definiert ebenfalls ein ID-Attribut zur Adressierung der Objekte. Bei clientseitig neu erfassten Objekten erfolgt eine temporäre Vergabe einer Client-ID. Über die urlRoot-Angabe kann definiert werden, unter welcher URL das Modell serverseitig verwaltet wird. Wenn der verwendete Webdienst eine REST-konforme API besitzt, so kann die komplette Client-Server-Kommunikation selbstständig von Backbone durchgeführt werden. Durch einen Aufruf der save-Methode auf dem Model wird die Synchronisation gestartet.

Collections sind ein weiteres Strukturierungselement zur Abbildung des Fachkonzepts. Eine Collection verwaltet eine Menge von Model-Instanzen. Die logische Typisierung einer Collection erfolgt über das model-Attribut. Hierdurch kann Backbone erkennen, welche Art von Model-Instanz verwaltet wird. Wie bei der Model-Oberklasse werden verschiedene Basisfunktionalitäten von der Backbone.Collection-Klasse geerbt. Hierzu gehören beispielsweise die Funktionen add, remove und sort zur Verwaltung der Listenelemente. Für die Definition einer Standardsortierung innerhalb einer Collection kann die Methode comparator implementiert werden. Ebenfalls angeboten wird die filter-Methode zur Filterung von Listenelementen.

Collection-Definition in Backbone:

var PersonCollection = Backbone.Collection.extend({
    url: '/persons',
    model: Person,
    onlyEditable: function() {
        return this.filter(function(person) {
            return person.allowedToEdit();
        });
    },
    comparator: function(person) {
        return person.get('name');
    }
});

Ebenfalls möglich ist die Angabe einer URL zum serverseitigen Abruf der Daten. Ausgeführt wird der Abruf der Listenelemente einer Collection durch die fetch-Methode der Basisklasse. Als drittes Element in einer Backbone-Anwendung ist der Router aufzuführen. Der Router ist für die clientseitige Navigation innerhalb der SPA verantwortlich. Für eine SPA-Anwendung wird eine Router-Instanz erzeugt. Diese Instanz verwaltet sämtliche Linkaktionen innerhalb der Anwendung. Hierdurch ist ebenfalls eine Navigation über die Webbrowser-Schaltflächen möglich. Als Nebenprodukt entstehen zusätzlich bookmarkfähige Links. Der nachfolgende Codeausschnitt veranschaulicht die Implementierung eines Routers mit Backbone. Hierbei wird von der Oberklasse Backbone.Router geerbt. Zu erkennen ist, dass über das interne routes-Objekt des Routers die verschiedenen URLs festgelegt werden. Diese internen Adressen können ebenfalls GET-Parameter beinhalten, um einen parametrisieren Webseitenaufruf im Rahmen der SPA nachzubilden. Die Einträge im routes-Objekt werden von Backbone nach dem First-Match-Verfahren abgearbeitet.

Beispiel einer Router-Definition mit Backbone:

var Router = Backbone.Router.extend({
    routes: {
       "": "home",
       "edit/:id": "edit",
       "new": "edit"
    },
    // Aktionsdefinition bei der home-Navigation
    home: function() {
        userListView.render();
    },
    // Aktionsdefinition bei der new- und edit-Navigation
    edit: function(id) {
        userEditView.render({id: id});
    }
});
// Aktivierung der globalen Linkbehandlung mit Backbone + History API
Backbone.history.start({pushState: true});

Die View in einer Backbone-Anwendung beinhaltet keinen HTML-Code. Sie beinhaltet Präsentationslogik zur Reaktion auf Benutzereingaben und ist für DOM-Manipulationen verantwortlich. Die eigentliche Darstellung erfolgt durch die HTML-View. Die HTML-View wird allerdings häufig bei einer SPA von der View aus mit Inhalten aus dem clientseitigen Model befüllt. Hierbei kommt die Template-Technik von Underscore zum Einsatz. Die Ausdrücke der Templatesprache erlauben eine einfache clientseitige Generierung von HTML-Inhalten auf Basis von Modellinformationen. Diese Templates können Bestandteile der Bootstrapper-Seite der SPA sein oder mittels der Text-Erweiterung von RequireJS asynchron nachgeladen werden. Backbone gibt im Rahmen der View drei Konventionen vor. Die erste Konvention bezieht sich auf das Haupt-DOM-Element, welches im Rahmen der aktuellen View verwaltet wird. Der CSS-Selektor für dieses DOM-Element soll in der Variable el abgelegt werden. Falls jQuery verwendet wird, so legt die Backbone-Infrastruktur automatisch einen Cache für das DOM-Objekt mit dem Namen $el an. Dies reduziert ständige DOM-Selektionen über jQuery und erhöht so die Performance. Für den Fall, dass das Haupt-DOM-Element für den aktuellen View-Bereich noch nicht existiert, kann die Variable tagName verwendet werden. In diesem Fall erzeugt die Backbone-Infrastruktur selbstständig ein neues DOM-Element. Diese Variante wird häufig verwendet, wenn die aktuelle Ansicht von verschiedenen partiellen View-Instanzen verwaltet wird. Dieses Vorgehen wird beispielsweise bei Auflistungen gewählt. In diesem Fall repräsentiert eine View die Liste. Zusätzlich werden für jeden Eintrag in der Liste partielle Views erzeugt. Auf diese Weise können die Funktionalitäten, die ein Listeneintrag anbietet, von den Funktionalitäten der kompletten Liste abgekapselt werden. Ein Listeneintrag kann z. B. ein direktes Löschen oder eine Bearbeitung des Eintrags anbieten.

Beispiel für eine View-Implementierung:

var UserListView = Backbone.View.extend({
    el: '.page',
    template: _.template($('#user-list-template').html()),
    events: {
       'click .refresh': 'loadAndDisplayData' // Click-Aktion auf $('.refresh')
    },
    loadAndDisplayData: function() {
        userCollection.fetch(); // Impliziert ein reset-Event auf der Collection
    },
    initialize: function() {
        // Registrierung für Events der “userCollection”
        this.listenTo(userCollection, 'add', this.addOneItem);
        this.listenTo(userCollection, 'reset', this.addAllItems);
    },
    addOneItem: function(user) {
        var view = new UserListItemView({model: user }); // Partielle View erzeugen
        $('#userListBody').append(view.render().el); // Eintrag der Liste hinzufügen
    },
    addAllItems: function() {
        this.$el.find('#userListBody').html(''); // Liste leeren
        userCollection.each(this.addOneItem, this); // Alle Elemente neu hinzufügen
    },
    render: function() {
        this.$el.html(this.template); // Haupt-Template der Seite hinzufügen
        if (!userCollection.length) {
            this.loadAndDisplayData(); // Einträge laden und anzeigen
        } else {
            this.addAllItems();
        };
        return this;
    }
});

Die zweite Konvention besagt, dass ein verwendetes HTML-Template in der Variable template abgelegt werden soll. Auf diese Weise kann verhindert werden, dass ein Template zum wiederholten Mal geladen wird. Die dritte Konvention sieht das Vorhandensein einer Methode mit dem Namen render vor. Diese Methode soll Basis-DOM-Manipulationen durchführen. Im oben aufgeführten Beispiel wird in der render-Methode die initiale Darstellung einer Listenansicht durch ein Template geladen. Ebenfalls wird das Laden der Listeneinträge veranlasst, falls diese nicht schon auf dem Client vorhanden sind. Die Registrierung von DOM-Events im Rahmen von Backbone-Views erfolgt über das events-Dictionary. Hierbei werden ein DOM-Selektor für das Event und eine Callback-Methode angegeben. Sobald das selektierte Event eintritt, erfolgt automatisch ein Aufruf der Callback-Methode. Die Eventbehandlung bezieht sich immer auf den DOM-Teilbaum des el-Elements.

Vorkommen

Folgende Webanwendungen wurden mit Backbone.js erstellt:[3]

Siehe auch

JavaScript MVC Frameworks

Literatur

  • Addy Osmani: Developing Backbone.js applications. 1. Auflage. O’Reilly Media, Beijing 2012, ISBN 978-1-4493-2825-2, S. 150 (englisch).

Einzelnachweise

  1. Change Log
  2. Alex MacCaw: JavaScript Web Applications. O’Reilly Media, Inc., 2001, ISBN 978-1-4493-0351-8, S. 165 (eingeschränkte Vorschau in der Google-Buchsuche).
  3. builtwithbackbonejs.com: Showcase of apps and websites using Backbone.js (Memento vom 13. Mai 2015 im Internet Archive)
  4. Backbonification: migrating a large JavaScript project from DOM spaghetti to Backbone.js, Samuel Clay (NewsBlur) 13th November 2012