smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

Todo-App: 5. Restliche Views implementieren

6. Dezember 2012
Stephan
Todo-App mit backbone.js und CoffeeScript entwickeln

In diesem vorletzten Teil des Todo-App Tutorials geht es um die Implementierung der uns noch fehlenden drei Views.

Als erstes werden wir die TodoListView und dann die TodoStatsView umsetzen. Abschließend widmen wir uns der Hauptview, der sogenannten TodoView.

Falls ihr nicht mehr genau wissen solltet, wozu die einzelnen Views gedacht sind bzw, welche Aufgaben die Views haben, schaut ihr euch am besten noch einmal die Abbildung zur View-Struktur im letzten Teil an.

Teile der Artikel-Serie

Zur Übersicht eine Auflistung aller erschienenen Artikel der Artikel-Serie „Tutorial: Todo-App mit backbone.js & CoffeeScript erstellen“:

  1. Vorbereitungen vornehmen (Projektverzeichnis anlegen etc.)
  2. Model erstellen
  3. Collection – Liste von Models
  4. View-Struktur & Grundlagen einer backbone.js View
  5. Restliche Views implementieren
  6. Controller implementieren & App fertigstellen
  7. Daten mit Ruby on Rails per REST-API serverseitig speichern

TodoListView implementieren

Für die Erstellung der TodoListView legen wir als erstes eine Datei mit dem Namen TodoListView.coffee im Verzeichnis app/views an. Als nächstes erstellen wir uns wieder unser Klassengerüst

class TodoApp.Views.TodoListView extends Backbone.View
    el: '#todoList'

    initialize: (args) ->
        @todos = args.todos

JavaScript:

TodoApp.Views.TodoListView = Backbone.View.extend({
    el: '#todoList',

    initialize: function(arguments)
    {
        this.todos = arguments.todos;
    }
});

Im Gegensatz zur TodoListItemView haben wir in diesem Fall keinen tagName definiert, sondern direkt unser el-Element. Unsere TodoListView repräsentiert in diesem Fall das div mit der ID #todoList.

In der initialize-Methode (Konstruktor) erhalten wir als Parameter zudem alle Todo-Models.

Als nächstes wollen wir wieder eine render-Methode für unsere View schreiben. Diese Methode soll für alle Models eine TodoListViewItem-Instanz erstellen, rendern und anzeigen:

class TodoApp.Views.TodoListView extends Backbone.View
    # Konstruktor etc.

    render: ->
        @todos.each((todo) =>
            todoListItemView = new TodoApp.Views.TodoListItemView(todo: todo)
            @$el.append(todoListItemView.render().el)
        )

JavaScript:

TodoApp.Views.TodoListView = Backbone.View.extend({
    // Konstruktor etc.

    render: function()
    {
        this.todos.each(function(todo)
        {
            var todoListItemView = new TodoApp.Views.TodoListItemView({todo: todo});
            this.$el.append(todoListItemView.render().el);
        }.bind(this));
    }
});

Wir iterieren hier einfach über alle Models, die sich innerhalb unserer todos-Liste (eine Instanz der von uns bereits implementierten TodoCollection) befinden. Für jedes Model instanziieren wir eine entsprechende TodoListItemView und rendern die jeweilige View. Anschließend fügen wir den gerenderten HTML-Inhalt dem #todoList-Element hinzu. Bei der Instanziierung der TodoListItemView seht ihr jetzt auch, wie wir dem Konstruktor ein Argument/Parameter mit übergeben.

Als nächstes benötige wir nur noch eine Methode zum dynamischen Hinzufügen einer Aufgabe zur Liste:

class TodoApp.Views.TodoListView extends Backbone.View
    # Konstruktor etc.

    addItem: (todo) ->
        todoListItemView = new TodoApp.Views.TodoListItemView(todo: todo)
        @$el.append(todoListItemView.render().el)

JavaScript:

TodoApp.Views.TodoListView = Backbone.View.extend({
    // Konstruktor etc.

    addItem: function(todo)
    {
        var todoListItemView = new TodoApp.Views.TodoListItemView({todo: todo});
        this.$el.append(todoListItemView.render().el);
    }
});

Wie ihr seht, macht diese Methode im Prinzip nichts anderes wie die render-Methode.

TodoStatsView implementieren

Auch für diese View legen wir uns eine entsprechende Datei namens TodoStatsView.coffee im Verzeichnis app/views an.

Da diese Klasse bzw. View nur aus einem Konstruktor (initialize) und einer render-Methode besteht, findet ihr im Folgenden gleich den kompletten Code für diese View:

class TodoApp.Views.TodoStatsView extends Backbone.View
    el: '#todoStats'

    initialize: (args) ->
        @todos = args.todos

    render: ->
        @$el.html(
            'Alle: ' + @todos.length + '  -  ' +
                'Erledigt: ' + @todos.done().length + '  -  ' +
                'Verbleibend: ' + @todos.remaining().length
        )

JavaScript:

TodoApp.Views.TodoStatsView = Backbone.View.extend({
    el: '#todoStats',

    initialize: function(arguments)
    {
        this.todos = arguments.todos;
    },

    render: function()
    {
        this.$el.html(
            'Alle: ' + this.todos.length + '  -  ' +
                'Erledigt: ' + this.todos.done().length + '  -  ' +
                'Verbleibend: ' + this.todos.remaining().length
        );
    }
});

Analog zum Konstruktor der TodoListView erhält auch diese View im Konstruktor eine TodoCollection als Argument mit allen Todo-Models.

Die render-Methode dient in diesem Fall dazu unsere Statistik anzuzeigen. Zur Ermittlung der Anzahl der erledigten bzw. verbleibenden Aufgaben, rufen wir dazu einfach die entsprechenden Filter-Methoden der TodoCollection auf. Für die zurückgelieferten Liste erhalten wir dann mittels length die konkrete Anzahl.

TodoView implementieren

Fehlt nun nur noch unsere Hauptview. Dazu legen wir in unseren View-Verzeichnis die Datei TodoView.coffee an und legen ein Grundgerüst an:

class TodoApp.Views.TodoView extends Backbone.View
    el: '#todoWrap'

    events:
        'keypress #createItemInput': 'createItem'

    initialize: (args) ->
        @todos = args.todos
        @todoListView = args.todoListView
        @todoStatsView = args.todoStatsView

        @createItemInput = $('#createItemInput')

        @todos.bind('add', @todoListView.addItem, @todoListView)
        @todos.bind('change', @todoStatsView.render, @todoStatsView)
        @todos.bind('destroy', @todoStatsView.render, @todoStatsView)

JavaScript:

TodoApp.Views.TodoView = Backbone.View.extend({
    el: '#todoWrap',

    events: {
        'keypress #createItemInput': 'createItem'
    },

    initialize: function(arguments)
    {
        this.todos = arguments.todos;
        this.todoListView = arguments.todoListView;
        this.todoStatsView = arguments.todoStatsView;

        this.createItemInput = $('#createItemInput');

        this.todos.bind('add', this.todoListView.addItem, this.todoListView);
        this.todos.bind('change', this.todoStatsView.render, this.todoStatsView);
        this.todos.bind('destroy', this.todoStatsView.render, this.todoStatsView);
    }
});

Die TodoView soll in unserem Fall die Methode createItem feuern, sobald ein keypress-Event des createItemInput-Felds aufgetreten ist.

Im Konstruktor holen wir uns als erstes einmal die TodoCollection, also unsere Liste mit allen Models. Weiterhin erhalte wir als übergebenes Argument eine Instanz der TodoListView als auch der TodoStatsView.

Interessant sind die letzten drei Zeilen im Konstruktor. Hier nutzen wir die internen backbone.js Events, die unter bestimmten Bedingungen ausgelöst werden.

Dabei wird z.B. ein add-Event ausgelöst, sobald mittels der create-Methode der TodoCollction ein neues Model erstellt und der Liste hinzugefügt wird. Wenn dieses Event nun also ausgelöst wird, dann wollen wir, dass die addItem-Methode der TodoListView ausgeführt wird.

Der dritte Parameter gibt immer den jeweiligen Kontext an. Das bedeutet, dass die addItem-Methode im Kontext der TodoListView-Instanz ausgeführt wird. Mittels @ bzw this greifen wir also auf die TodoListView-Instanz zu. Geneuer gesagt referenziert @ bzw this diese Instanz.

Analog dazu reagieren wir auf ein change-Event, sobald eine Aufgabe (also ein Todo-Model) aktualisiert/bearbeitet wurde. Wenn das der Fall ist, wollen wir unsere Statistik aktualisieren. Das gleiche gilt, wenn eine Aufgabe gelöscht wird.

Jetzt wollen wir wieder eine render-Methode implementieren, die in diesem Fall nichts weiter macht, als die entsprechende TodoListView und TodoStatsView zu rendern:

class TodoApp.Views.TodoView extends Backbone.View
    # Konstruktor etc. 

    render: ->
        @todoListView.render()
        @todoStatsView.render()

JavaScript:

TodoApp.Views.TodoView = Backbone.View.extend({
    // Konstruktor etc. 

    render: function()
    {
        this.todoListView.render();
        this.todoStatsView.render();
    }
});

Abschließend benötigen wir noch unsere createItem-Methode, die eine neue Aufhabe erstellt:

class TodoApp.Views.TodoView extends Backbone.View
    # Konstruktor etc. 

    createItem: (event) ->
        if event.keyCode is 13 && @createItemInput.val()
            @todos.create(title: @createItemInput.val())
            @todoStatsView.render()

JavaScript:

TodoApp.Views.TodoView = Backbone.View.extend({
    // Konstruktor etc. 

    createItem: function(event)
    {
        if(event.keyCode === 13 && this.createItemInput.val())
        {
            this.todos.create({title: this.createItemInput.val()});
            this.todoStatsView.render();
        }
    }
});

Wir prüfen hierbei, ob die Enter-Taste (die Zahl 13 steht für Enter) gedrückt wurde und ob ein Titel eingegeben wurde. Falls dem so ist, erstellen wir eine neue Model-Instanz und aktualisieren die Statistik.

Fazit / Wie gehts weiter?

Nachdem wir nun alle Views für die Todo-App erstellt haben, fehlt uns nun nur noch alle Einzelteile zu einem Ganzen zusammenzufügen. Im nächsten und letzten Teil erstellen wir uns dafür einen Controller, der die App bzw. den Ablauf der App regelt.

Kommentare  
0 Kommentare vorhanden
0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!