Я работаю над простым проектом, пытающимся изучить 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.