how to use hogan template with backbone?

757 Views Asked by At

How to use hogan templates with backbone code?How to combine the values of a model into the Hogan templates?

My HTML page:

<!doctype html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">  
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Backbone.js • TodoMVC</title>
<link rel="stylesheet" href="js/assets/base.css">
</head>
<body>
    <section id="todoapp">
      <header id="header">
      <h1>todos</h1>
      <input id="new-todo" placeholder="What needs to be done?" autofocus>
    </header>
    <section id="main">
      <input id="toggle-all" type="checkbox">
      <label for="toggle-all">Mark all as complete</label>
      <ul id="todo-list"></ul>
    </section>
    <footer id="footer"></footer>
  </section>
  <div id="info">
    <p>Double-click to edit a todo</p>
    <p>Written by <a href="https://github.com/addyosmani">Addy Osmani</a></p>
    <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
  </div>

  <script type="text/template" id="item-template">
    <div class="view">
      <input class="toggle" type="checkbox" {{ completed ? 'checked' : '' }}>
      <label>{{ title }}</label>
      <button class="destroy"></button>
    </div>
    <input class="edit" value="{{ title }}">
  </script>

   <script type="text/template" id="stats-template">
    <span id="todo-count"><strong>{{ remaining }}</strong> {{ remaining === 1 ? 'item' : 'items' }} left</span>
    <ul id="filters">
      <li>
        <a class="selected" href="#/">All</a>
      </li>
      <li>
        <a href="#/active">Active</a>
      </li>
      <li>
        <a href="#/completed">Completed</a>
      </li>
    </ul>
 {[ if (completed) { ]}
    <button id="clear-completed">Clear completed ({{ completed }})</button>
    {[ } ]}
  </script>

  <script src="js/assets/base.js"></script>
  <script src="js/lib/jquery.js"></script>
  <script src="js/lib/underscore.js"></script>
  <script src="js/lib/backbone.js"></script>
  <script src="js/lib/backbone.localStorage.js"></script>
  <script src="js/models/todo.js"></script>
  <script src="js/collections/todos.js"></script>
  <script src="js/views/todos.js"></script>
  <script src="js/views/app.js"></script>
  <script src="js/routers/router.js"></script>
  <script src="js/app.js"></script>
</body>
</html>

My js code

/*global Backbone, jQuery, _, ENTER_KEY */
var app = app || {};

(function ($) {
    'use strict';



    _.templateSettings = {
              evaluate : /\{\[([\s\S]+?)\]\}/g,
              interpolate : /\{\{([\s\S]+?)\}\}/g
            };
    // The Application
    // ---------------

    // Our overall **AppView** is the top-level piece of UI.
    app.AppView = Backbone.View.extend({

        // Instead of generating a new element, bind to the existing skeleton of
        // the App already present in the HTML.

        el: '#todoapp',

        // Our template for the line of statistics at the bottom of the app.

        statsTemplate: _.template($('#stats-template').html()),

        // Delegated events for creating new items, and clearing completed ones.
        events: {
            'keypress #new-todo': 'createOnEnter',
            'click #clear-completed': 'clearCompleted',
            'click #toggle-all': 'toggleAllComplete'
        },

        // At initialization we bind to the relevant events on the `Todos`
        // collection, when items are added or changed. Kick things off by
        // loading any preexisting todos that might be saved in *localStorage*.
        initialize: function () {
            this.allCheckbox = this.$('#toggle-all')[0];
            this.$input = this.$('#new-todo');
            this.$footer = this.$('#footer');
            this.$main = this.$('#main');
            this.$list = $('#todo-list');

            this.listenTo(app.todos, 'add', this.addOne);
            this.listenTo(app.todos, 'reset', this.addAll);
            this.listenTo(app.todos, 'change:completed', this.filterOne);
            this.listenTo(app.todos, 'filter', this.filterAll);
            this.listenTo(app.todos, 'all', this.render);

            // Suppresses 'add' events with {reset: true} and prevents the app view
            // from being re-rendered for every model. Only renders when the 'reset'
            // event is triggered at the end of the fetch.
            app.todos.fetch({reset: true});
        },

        // Re-rendering the App just means refreshing the statistics -- the rest
        // of the app doesn't change.
        render: function () {
            var completed = app.todos.completed().length;
            var remaining = app.todos.remaining().length;

            if (app.todos.length) {
                this.$main.show();
                this.$footer.show();

                this.$footer.html(this.statsTemplate({
                    completed: completed,
                    remaining: remaining
                }));

                this.$('#filters li a')
                    .removeClass('selected')
                    .filter('[href="#/' + (app.TodoFilter || '') + '"]')
                    .addClass('selected');
            } else {
                this.$main.hide();
                this.$footer.hide();
            }

            this.allCheckbox.checked = !remaining;
        },

        // Add a single todo item to the list by creating a view for it, and
        // appending its element to the `<ul>`.
        addOne: function (todo) {
            var view = new app.TodoView({ model: todo });
            this.$list.append(view.render().el);
        },

        // Add all items in the **Todos** collection at once.
        addAll: function () {
            this.$list.html('');
            app.todos.each(this.addOne, this);
        },

        filterOne: function (todo) {
            todo.trigger('visible');
        },

        filterAll: function () {
            app.todos.each(this.filterOne, this);
        },

        // Generate the attributes for a new Todo item.
        newAttributes: function () {
            return {
                title: this.$input.val().trim(),
                order: app.todos.nextOrder(),
                completed: false
            };
        },

        // If you hit return in the main input field, create new **Todo** model,
        // persisting it to *localStorage*.
        createOnEnter: function (e) {
            if (e.which !== ENTER_KEY || !this.$input.val().trim()) {
                return;
            }

            app.todos.create(this.newAttributes());
            this.$input.val('');
        },

        // Clear all completed todo items, destroying their models.
        clearCompleted: function () {
            _.invoke(app.todos.completed(), 'destroy');
            return false;
        },

        toggleAllComplete: function () {
            var completed = this.allCheckbox.checked;

            app.todos.each(function (todo) {
                todo.save({
                    'completed': completed
                });
            });
        }
    });
})(jQuery);

it is from the ToDo example. I used Mustache templates here by changing the template settings. But i want to convert the template into Hogan.

my Edited js:

/*global Backbone, jQuery, _, ENTER_KEY, ESC_KEY */
var app = app || {};

(function ($) {
    'use strict';
    // Todo Item View
    // --------------
    _.templateSettings = {
              evaluate : /\{\[([\s\S]+?)\]\}/g,
              interpolate : /\{\{([\s\S]+?)\}\}/g
            };
    // The DOM element for a todo item...
    app.TodoView = Backbone.View.extend({
        tagName:  'li',
        // Cache the template function for a single item.
        template1: _.template($('#item-template').html()),
        template:Hogan.compile(template1),
        // The DOM events specific to an item.
        events: {
            'click .toggle': 'toggleCompleted',
            'dblclick label': 'edit',
            'click .destroy': 'clear',
            'keypress .edit': 'updateOnEnter',
            'keydown .edit': 'revertOnEscape',
            'blur .edit': 'close'
        },
        initialize: function () {
            this.listenTo(this.model, 'change', this.render);
            this.listenTo(this.model, 'destroy', this.remove);
            this.listenTo(this.model, 'visible', this.toggleVisible);
        },
        render: function () {
            // Backbone LocalStorage is adding `id` attribute instantly after creating a model.
            // This causes our TodoView to render twice. Once after creating a model and once on `id` change.
            // We want to filter out the second redundant render, which is caused by this `id` change.
            // It's known Backbone LocalStorage bug, therefore we've to create a workaround.
            // https://github.com/tastejs/todomvc/issues/469
            if (this.model.changed.id !== undefined) {
                return;
            }
            console.log(this.template);
            this.$el.html(this.template(this.model.toJSON()));
            this.$el.toggleClass('completed', this.model.get('completed'));
            this.toggleVisible();
            this.$input = this.$('.edit');
            return this;
        },
        toggleVisible: function () {
            this.$el.toggleClass('hidden', this.isHidden());
        },
        isHidden: function () {
            var isCompleted = this.model.get('completed');
            return (// hidden cases only
                (!isCompleted && app.TodoFilter === 'completed') ||
                (isCompleted && app.TodoFilter === 'active')
            );
        },
        toggleCompleted: function () {
            this.model.toggle();
        },
        edit: function () {
            this.$el.addClass('editing');
            this.$input.focus();
        },
        close: function () {
            var value = this.$input.val();
            var trimmedValue = value.trim();        
            if (!this.$el.hasClass('editing')) {
                return;
            }
            if (trimmedValue) {
                this.model.save({ title: trimmedValue });
                if (value !== trimmedValue) {               
                    this.model.trigger('change');
                }
            } else {
                this.clear();
            }
            this.$el.removeClass('editing');
        },
        updateOnEnter: function (e) {
            if (e.which === ENTER_KEY) {
                this.close();
            }
        },
        revertOnEscape: function (e) {
            if (e.which === ESC_KEY) {
                this.$el.removeClass('editing');
            }
        },
        clear: function () {
            this.model.destroy();
        }
    });
})(jQuery);
0

There are 0 best solutions below