jQuery Mobile с Backbone.js JQM initializePage () не работает должным образом - PullRequest
3 голосов
/ 05 февраля 2012

Я работаю над простым проектом, пытающимся изучить jQuery Mobile и Backbone.js, и столкнулся с проблемой. Проект представляет собой простое приложение для создания заметок, которое сохраняет заметки, используя локальное хранилище HTML5.

Программа создает страницы на стороне клиента, и я пытаюсь использовать $ .mobile.initializePage (), чтобы заставить полученные страницы работать должным образом с JQM. Вместо этого происходит то, что initializePage () никогда не завершается, и получающийся загрузочный счетчик никогда не исчезает.

Я проверил HTML, созданный на стороне клиента, и все правильно, насколько я могу судить. Я также попытался использовать trigger ('create') и createPage () из консоли в chrome, чтобы увидеть, не создаются ли страницы, но это не решает проблему. Это не приводит к ошибкам, и я не смог найти решение этой проблемы за последние 2 дня. Мой код выглядит следующим образом.

HTML-страница

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Local Notes</title>
    <link rel="stylesheet" href="css/jquery.mobile-1.0.1.css" media="screen" title="jquery mobile" charset="UTF-8"/>
</head>
<body>
    <!-- Home Page -->
    <div id="home" data-role="page">
        <div data-role="header">
            <h1>Local Notes</h1>
        </div>
        <div data-role="content">
            <a href="#new" data-rel="dialog" data-transition="pop" data-role="button" data-icon="plus" data-theme="b">New</a>
            <ul data-role="listview" data-inset="true">
                <li><a href="#all">All Notes</a></li>
                <li><a href="#nearest">Nearest Notes</a></li>
            </ul>
        </div>
    </div>

    <!-- New Note Form-->
    <div id="new" data-role="page">
        <div data-role="header">
            <h1>New Note</h1>
        </div>
        <div data-role="content">
            <form action="#" method="post">
                <div data-role="fieldcontain">
                    <label for="title">Title</label>
                    <input id="title" name="title" value="" />
                </div>
                <div data-role="fieldcontain">
                    <label for="body">Body</label>
                    <textarea id="body" name="body" value=""></textarea>
                </div>
                <button data-icon="check" data-theme="b">Save</button>
            </form>
        </div>
    </div>

    <!-- List of Notes -->
    <div id="all" data-role="page">
        <div data-role="header">
            <a href="#home" data-role="button" data-icon="arrow-l" data-rel="back">Back</a>
            <h1>All Notes</h1>
        </div>
        <div data-role="content">
            <ul data-role="listview" id="all_notes">
            </ul>
        </div>
    </div>

    <!-- List of Note detail pages -->
    <div id="note-detail-list"></div>   

    <!-- Note list template -->
    <script type="text/template" id="note-list-item-template">
        <a href="#note_<%= note.id %>"><%= note.get('title') %></a>
    </script>

    <!-- Note detail template -->
    <script type="text/template" id="note-detail-template">
        <div data-role="header">
            <a href="#home" data-role="button" data-icon="arrow-l" data-rel="back">Back</a>
            <h1><%= note.get('title') %></h1>
        </div>
        <div data-role="content"><%= note.get('body') %></div>
    </script>

    <script src="js/jquery-1.7.1.js"></script>
    <script src="js/underscore.js"></script>
    <script src="js/backbone.js"></script>
    <script src="js/backbone.localStorage.js"></script>
    <script src="js/jquery.mobile-1.0.1.js"></script>
    <script src="js/application.js"></script>
</body>
</html>

1010 * Javascript *

var NotesApp = (function(){

var App = {
    stores: {},
    views:{},
    collections:{}
}

// Initialize localStorage Data Store
App.stores.notes = new Store('notes');

// Note model
var Note = Backbone.Model.extend({
    // Use localStorage datastore
    localStorage: App.stores.notes,

    initialize: function(){
        if(!this.get('title')){
            this.set({title: "Note @ " + Date() })
        };

        if(!this.get('body')){
            this.set({body: "No Content"})
        };
    }
})

// Collections
var NoteList = Backbone.Collection.extend({
    // This collection is composed of Note objects
    model: Note,

    // Set the localStorage datastore
    localStorage: App.stores.notes,

    initialize: function(){
        var collection = this;

        this.localStorage.bind('update', function(){
            collection.fetch();
        })
    }
})

// Views
var NewFormView = Backbone.View.extend({
    events: {
        "submit form": "createNote"
    },

    createNote: function(e){
        var attrs = this.getAttributes(),
        note = new Note();

        note.set(attrs);
        note.save();

        // Stop browser from actually submitting the form
        e.preventDefault();
        // Stop jQuery mobile from doing its form magic
        e.stopPropagation();

        // Close dialog
        $('.ui-dialog').dialog('close');
        this.reset();
    },

    getAttributes: function(){
        return {
            title: this.$('form [name=title]').val(),
            body: this.$('form [name=body]').val()
        }
    },

    reset: function(){
        this.$('input, textarea').val('');
    }
});

var NoteListView = Backbone.View.extend({
    initialize: function(){

        _.bindAll(this, 'addOne', 'addAll');

        this.collection.bind('add', this.addOne);
        this.collection.bind('reset', this.addAll);

        this.collection.fetch();
    },

    addOne: function(note){
        var view = new NoteListItemView({model: note});
        $(this.el).append(view.render().el);

        if(this.el.hasClass('ui-listview')){
            $(this.el).listview('refresh');
        }
    },

    addAll: function(){
        $(this.el).empty();
        this.collection.each(this.addOne);
    }
});

var NoteListItemView = Backbone.View.extend({
    tagName: 'LI',
    template: _.template($('#note-list-item-template').html()),

    initialize: function(){
        _.bindAll(this, 'render')
        this.model.bind('change', this.render)
    },

    render: function(){
        $(this.el).html(this.template({ note: this.model }))
        return this;
    }
});

var NoteDetailView = Backbone.View.extend({
    tagName: "DIV",
    template: _.template($('#note-detail-template').html()),

    initialize: function(){
        _.bindAll(this, 'render');

        $(this.el).attr({
            'data-role': 'page',
            'id': "note_" + this.model.id
        });

        this.model.bind('change', this.render);
    },

    render: function(){
        $(this.el).html(this.template({note: this.model}));
        return this;
    }
});

var NoteDetailList = Backbone.View.extend({
    el: $('#note-detail-list'),

    initialize: function(){
        _.bindAll(this, 'addOne', 'addAll', 'render');

        this.collection.bind('add', this.addOne);
        this.collection.bind('reset', this.addAll);

        this.collection.fetch();
    },

    addOne: function(note){
        var view = new NoteDetailView({model: note});

        $(this.el).append(view.render().el);

        if($.mobile){
            $.mobile.initializePage();
        }
    },

    addAll: function(){
        $(this.el).empty();
        this.collection.each(this.addOne);
    }
});

App.collections.all_notes = new NoteList()

App.views.new_form = new NewFormView({
    el: $('#new')
});

App.views.list_alphabetical = new NoteListView({
    el: $('#all_notes'),
    collection: App.collections.all_notes
})

App.views.notes = new NoteDetailList({
    collection: App.collections.all_notes
})

return App;
})()

UPDATE:

После более подробного изучения у меня появятся некоторые подробности об этой ошибке. Код правильно генерирует динамически созданные страницы, к которым просто невозможно добраться по ссылкам в просмотре списка. Ссылки ссылаются на хеш с идентификатором DIV, который я пытаюсь достичь. DIV имеет data-role = page и data-url = # ID. Эти же страницы могут быть доступны с помощью следующего кода через консоль в Chrome и Firefox.

$.mobile.changePage($('#DIV ID'))

Это прекрасно работает, и страница отформатирована правильно. В соответствии с документацией JQM существовала проблема, из-за которой ссылки не работали, если в них отсутствовал атрибут data-url, но он предположительно был исправлен в выпуске JQM 1.0.

...