Use bootstrap popover with MeteorJS and have trouble
I Can't assign some value that coming from collection to input value (where
{{title}} is some string like wwww). In html of form POPOVER doesnt exist value="///" ,but in my form I see this value="some title"
<template name="one">
<div class="popover-markup">
<div class=" trigger ">
Edit
</div>
</div>
<div class="content-popover hide">
<form class="form">
<input name="title" id="post_edit_title" value="{{title}}" />
</form>
</div>
</template>
Template.one.onRendered(function(){
$('.popover-markup > .trigger').popover({
html : true,
content: function() {
return $('.content-popover').html();
},
container: 'body',
placement: 'right'
});
EDIT:
Meteor.publish("posts_levels", function(){
return Posts.find();
});
<template name="www">
{{#each level}}
{{> one}}
{{/each}}
</template>
Template.www.onCreated(function(){
var self = this;
self.autorun(function() {
self.subscribe('posts_levels');
});
});
Create a Template Helper which exposes title to your template. docs
Template.one.helpers({
title: function() {
return Collection.findOne({/* select your data*/}).prop;
}
});
App.FolderListItemView = Ember.View.extend({
templateName: 'folder-list-item',
tagName: 'li',
classNames: ['folder'],
classNameBindings: ['opened'],
opened: false,
click: function (e) {
this.set('opened', !this.get('opened'));
}
});
<script type="text/x-handlebars" data-template-name="folder-list-item">
<i {{bind-attr class="opened:icon-content-plus:icon-content-minus"}}></i>
...
</script>
I would like to change the icon (plus/minus) according to the value of 'opened' of the view.
The bind-attr does not work. How should I deal with this?
You need to use view.opened property in your template
<script type="text/x-handlebars" data-template-name="folder-list-item">
<i {{bind-attr class="view.opened:icon-content-plus:icon-content-minus"}}></i>
...
</script>
I'm currently learning how to deal with backbone.js.
Currently I have the problem that the model isnt updating when the view does through user input.
When I change the input of the textarea and I click the button, I send the old data since the view didnt notify the model that a change happened.
What do I do wrong?
PostView
define([
'jquery',
'underscore',
'backbone',
'postModel'
], function($, _, Backbone, PostModel){
var PostView = Backbone.View.extend({
timer: null,
el: $('.admin__wrapper'),
template: $('#post_template'),
initialize: function () {
console.log('Initializing Post View');
this.model = new PostModel({id: this.id});
this.listenTo(this.model, 'change', this.render);
this.model.fetch();
},
events: {
'keyup textarea': 'keyup',
'click button': 'submit'
},
submit: function(event) {
this.model.save();
},
render: function(){
var template = _.template(this.template.html(), { post: this.model });
this.$el.html(template);
return this;
}
});
return PostView;
});
PostTemplate
<script type="text/template" id="post_template">
<div class="post__title">
<div class="entry">
<input class="input--less" name="title" type="text" value="<%= post.get('title') %>" placeholder="Post title">
</div>
</div>
<div class="entry post__panel post__markdown">
<header class="entry__header post__panel__header">
<span><small>markdown</small></span>
</header>
<div class="post__boundary">
<textarea name="content" id="editor" class="input--less post__editor" rows="5"><%= post.get('content') %></textarea>
</div>
</div>
<div class="entry post__panel post__html">
<header class="entry__header post__panel__header">
<span><small>preview</small></span>
<span id="reading-time" class="float--right" style="text-align: right"></span>
</header>
<div class="post__boundary">
<div class="post__preview" id="preview"><%= post.get('content_compiled') %></div>
</div>
</div>
<div class="post__footer">
<span class="batch--tag-4 post__icon"></span>
<button class="button button--blue post__button">Publish</button>
</div>
</script>
When the user clicks submit your not getting the data from the view you are simply saving the model with defaults, therefor not firing any change events, you will have to do something like this in keyup method which is triggered by the keyup event.
keyup: function(e)
{
this.model.set(e.target.name, e.target.value, {silent: true});
}
Assuming you correctly named your textarea, the correct model attribute will be updated. So now when this.model.save is called by submit these attributes will be saved triggering the change event and re-rendering the view.
When you change the form in your page, this change is not automatically set in your model, you have to set it by yourself.
Backbone does not provide 2 way data binding like Angular Js, you need to set the model yourself and then sync the model.
Try Backbone Mutators for 2 way data binding in Bakcbone.
Also as a follow up read this article
Hope someone can help me with,
I have a Backbone view, that is basically a skeleton of HTML, the HTML builds a tabbed interface, each tab obviously has a link and content area. What I am wanting to is for each content render an individual Backbone template specific to that tab.
So for example in the tab #briefs I would want to render app.projectBriefsView. I cannot for the life of figure how I would go about doing this, here is my "base/master" view that I want to load everything else into.
app.ProjectsTabsView = Backbone.View.extend({
el: "header.project",
template: _.template($("#tpl-projects-tabs").html()),
events: {
'click .js-tab-link': 'showTab',
},
initialize: function() {
this.render();
var briefView = new app.projectBriefView;
briefView.render().el;
},
render: function() {
this.$el.append(this.template());
return this;
},
showTab: function(el) {
var tabRequired = $(el.currentTarget).attr("href");
console.log(tabRequired);
$(".tab-content.active").css("display", "none").removeClass("active");
$(".tab-content"+tabRequired).addClass("active").css("display", "block");
el.preventDefault();
}
});
Template
<script type="text/template" id="tpl-projects-tabs">
<div class="tabs">
<ul>
<li>Brief + Notes</li>
<li>Dates</li>
<li>Files</li>
<li>Tasks</li>
<li>Messages</li>
<li>Comments</li>
</ul>
<div class="tab-content js-tab-content active" id="brief">Briefs</div>
<div class="tab-content js-tab-content" id="dates">Dates</div>
<div class="tab-content js-tab-content" id="files">Files</div>
<div class="tab-content js-tab-content" id="tasks">Tasks</div>
<div class="tab-content js-tab-content" id="messages">Messages</div>
<div class="tab-content js-tab-content" id="comments">Comments</div>
</div>
</script>
and here is the view I am wanting to load into the .tab-content#brief area.
app.projectBriefView = Backbone.View.extend({
el: ".tab-content",
template: _.template($("#tpl-brief-notes").html()),
events: {
},
initialize: function() {
this.render();
},
render: function() {
this.$el.append(this.template({
p: app.project.toJSON()
}));
return this;
}
});
Template
<script type="text/template" id="tpl-brief-notes">
<div class="project_info_content">
<!-- New brief form -->
<div class="brief">
<h4>Brief</h4>
<% if (p.is_owner) { %>
<div class="js-brief-text">
<% if (p.brief == undefined || p.brief == '') { %>
<p class="add-text">No Brief, Click to add</p>
<% }
} else { %>
<div>
<% }
if (p.brief != undefined || p.brief != '') { %>
<% //p.brief %>
<?= nl2br(str_replace(' ', ' ', htmlspecialchars($project['brief']))); ?>
<% } %>
</div>
<div class="inline-edit">
<% if (p.is_owner) { %>
<form action="<?= base_url(); ?>projects/edit_brief/<%= p.id %>" method="post" accept-charset="utf-8" class="inline_edit edit_brief" novalidate="novalidate">
<p>
<textarea name="brief" class="brief_edit"><%= p.brief %></textarea>
<input type="submit" name="submit" value="Update"><a class="cancel" href="#">Cancel</a>
</p>
</form>
<% } %>
</div>
</div>
<!-- End of new brief form -->
<!-- New additional notes form -->
<div class="additional_notes">
<h4>Additional notes <span class="instructions">(Editable by other users)</span></h4>
<div class="js-notes-text">
<%
if (p.additional_info == undefined || p.additional_info == '') { %>
<p class="add-text">No Notes, Click to add</p>
<% } else { %>
<% // p.additional_info %>
<?= nl2br(str_replace(' ', ' ', htmlspecialchars($project['additional_info']))); ?>
<% } %>
</div>
<div class="inline-edit">
<form action="<?= base_url(); ?>projects/edit_additional_info/<%= p.id %>" method="post" accept-charset="utf-8" class="inline_edit edit_notes" novalidate="novalidate"> <p>
<textarea name="text_details" class="notes_edit"><%= p.additional_info %></textarea>
<input type="submit" name="submit" value="Update"> <a class="cancel" href="#">Cancel</a>
</p>
</form>
</div>
</div>
</div>
<!-- End of new additional notes form -->
</div>
</script>
I thought that in the app.ProjectTabsView in the render function I would be able to do something like,
var brief = new app.projectBriefView();
brief.render().el();
to throw the output to the browser but this does not seem to work. Is there a better way to work with what I would call partial views in Backbone? How can I get my partial to the browser?
Since Backbone views can populate the browser with html dynamically, you only need to have one div element for content. This div element will then serve as a placeholder for the nested view generated by the view managing the tabs.
I had to solve a very similar problem and here is what I did:
First, define a control structure to bind a tab title to a view constructor:
var Tab = function( title, viewConstructor ) {
this.title = title;
this.viewConstructor = viewConstructor;
};
_.extend( Module.prototype, {
render : function( options ) {
this.view = new this.viewConstructor( options );
return this.view.render();
},
close : function() {
if( this.view ) {
this.view.close();
}
}
});
Then, define all your tabs in an array:
var tabs = [
new Tab('brief', app.projectBriefView),
new Tab('dates', app.projectDatesView),
//...
]
You need to clean up a little bit your template:
<script type="text/template" id="tpl-projects-tabs">
<div class="tabs">
<ul>
<li>Brief + Notes</li>
<li>Dates</li>
<li>Files</li>
<li>Tasks</li>
<li>Messages</li>
<li>Comments</li>
</ul>
<div class="tab-content js-tab-content" id="tab-content">Briefs</div>
</div>
</script>
Finally, you just have to use them in your events:
//...
showTabs : function( event ) {
event.preventDefault();
var clicked = $(el.currentTarget),
title = clicked.attr("href").replace("#", ""),
tab = _.findWhere( tabs, { title : title });
// always cleanup the preceding tab.
if ( this.activeTab ) {
this.activeTab.close();
}
this.activeTab = tab;
this.$('ul > li > .active').removeClass('active');
this.$('#tab-content').html( tab.render().el );
clicked.addClass('active');
}
I'm learning JQM and Backbone.js and I have a few problems. Im making a recipe app following the TODO list example trying to blend them both.
Anyway I can't refresh any page besides the first one, I'm getting undefined variables. I believe it has to do with the DOM and many views I have. Secondly Upon entering the recipe to search for to query the API, it displays the results first as plain links!
If I got forward a page or back a page and return to the results page it display the links as they should be the JQM style. This is because I couldn't figure how or what to append to in the JS, so I did it in the HTML.
I know this is a long shot but can anyone give me guidance as to what the hell I'm doing wrong, general advice, anything?
var Todo = Backbone.Model.extend({
defaults: function() {
return {
id: 0,
title: 'defaultname',
imgUrl: 'defaultimageurl',
order: searchTemp.nextOrder(),
rating: 0,
timeToMake: '',
salty: 0,
sour: 0,
sweet: 0,
bitter: 0,
isPerm: false,
taggedForList: false
};
},
initialize: function(){
if( !this.get('ingrs') ){
this.set({ingrs: new Array()});
}
},
saveModel: function() {
this.set({isPerm: true});
this.save();
}
});
var TodoList = Backbone.Collection.extend({
model: Todo,
localStorage: new Backbone.LocalStorage("searchTemp"),
initialize: function() {
},
nextOrder: function() {
if (!this.length) return 1;
return this.last().get('order') + 1;
},
comparator: 'order',
taggedForList: function() {
return this.where({taggedForList: true});
},
remaining: function() {
return this.without.apply(this, this.taggedForList);
},
findRecipes: function(theQuery) {
console.log("findRecipes called");
searchTemp.each(function (model) {
if (!model.isPerm) {
model.destroy();
}
});
$.ajax({
url: 'http://api.yummly.com/v1/api/recipes?_app_id=d8087d51&_app_key=005af5a16f1a8abf63660c2c784ab65f&maxResult=5&q='+theQuery,
dataType: 'jsonp',
success: function(apiStuff){
var result = new Array();
result = apiStuff; //saves the API's response as a new array
result = result.matches; //trims extra information from the json object, now only has information on the various recipes
$.each(result, function(i, item) {
var anotherRecipe= new Todo(); // makes a new model for each result
anotherRecipe.set({
id: result[i].id, //then sets the attributes
title: result[i].recipeName,
ingrs: result[i].ingredients,
imgUrl: result[i].smallImageUrls,
rating: result[i].rating,
timeToMake: result[i].totalTimeInSeconds,
});
//not all recipes support flavor ratings, so error catching must be used to avoid setting null values
try { anotherRecipe.set({ salty : result[i].flavors.salty }); } catch(e) {anotherRecipe.set({salty : "?"});} //maybe replace the error condition to setting the flavor to '?'
try { anotherRecipe.set({ sour: result[i].flavors.sour }); } catch(e) {anotherRecipe.set({sour : "?"});}
try { anotherRecipe.set({ sweet: result[i].flavors.sweet }); } catch(e) {anotherRecipe.set({sweet : "?"});}
try { anotherRecipe.set({ bitter: result[i].flavors.bitter }); } catch(e) {anotherRecipe.set({bitter : "?"});}
searchTemp.add(anotherRecipe); //adds the model to the temporary
});
} //eventually, should add something that checks for an empty search result, appending some warning if that happens
});
// console.log("search done");
}
});
var ShopItem = Backbone.Model.extend({
defaults: function() {
return {
ingr : 'ingredient',
done : false
}
},
toggle: function() {
this.save({taggedForList: !this.get("taggedForList")});
}
});
var ShopList = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage("grocery-list"),
generate: function() {
console.log("SHOP LIST! ASSSSSEMMMMBLLLLLLE!");
searchTemp.fetch();
var ingrList = searchTemp.pluck('ingrs'); //this returns an array of arrays
console.log(ingrList);
ingrList = _.union(ingrList); //this needs to get a series of arrays ( _.union(array1, array 2); )
console.log(ingrList);
},
getList: function() {
var list = new Array();
list = this.toJSON();
return list;
}
});
var Todos = new TodoList; //I am afraid to move this, 95% sure its obsolete, though
/*
var savedRecipesView = Backbone.View.extend({
tagName: "li",
initialize: function() {
this.render();
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
},
render: function() {
var template = _.template( $("#list_item").html(), {} );
this.$el.html( template );
//this.$el.html(this.template(this.model.toJSON()));
//this.$el.toggleClass('done', this.model.get('done'));
//this.input = this.$('.edit');
//return this;
},
events: {
"click input[type=button]": "sendToGroceries"
},
sendToGroceries: function() {
var temp = new Array();
temp = this.toJSON();
$.each(temp, function(i, item) {
var shopItem = new ShopItem();
shopItem.set({ name: temp[i].title });
shoppingList.add(shopItem); //use pluck [ingrs]
shopItem.save();
});
}
});
*/
window.HomeView = Backbone.View.extend({
template:_.template($('#home').html()),
render:function (eventName) {
$(this.el).html(this.template());
return this;
}
});
window.newSearchView = Backbone.View.extend({
template:_.template($('#newSearch').html()),
//this VAGUELY works, but causes visual chaos the first run through,
//still relies on the appending for that
initialize: function() {
console.log(searchTemp);
//searchTemp.bind('searchDone', this.render, this);
searchTemp.bind('add', this.render, this);
},
render:function (eventName) {
var temp = new Array(); // I think this line isnt doing anyting
results = searchTemp.toJSON();
// console.log(results);
var variables = {
recipes: results
};
$(this.el).html(this.template());
return this;
},
events: {
"keypress #recipe-search": "searchOnEnter",
//add a listener to newSearch to change what's displaye don this list
},
searchOnEnter: function(e) { //the search bar's functionality
if (e.keyCode != 13) return;
var searchin = $("input[id='recipe-search']").val();
console.log("searched for - "+ searchin);
//this function is in todoList, does an API call and
//adds a new model for each result (there will almost always be 5 results)
searchTemp.findRecipes(searchin);
}
});
window.newListView = Backbone.View.extend({
template : _.template($('#newList').html()),
initialize: function() {
},
render:function (eventName) {
recipe = this.model.toJSON(); ///INCOMPLETE, modify newlist to accept straight from JSON
var variables = {
recipe_name : this.model.get("title"),
img_url : this.model.get("imgUrl"),
timetomake: this.model.get("timeToMake"),
ingrs : this.model.get("ingrs"),
rating : this.model.get("rating"),
salty : this.model.get("salty"),
sour : this.model.get("sour"),
sweet : this.model.get("sweet"),
bitter : this.model.get("bitter")
};
$(this.el).html(this.template(variables));
return this;
},
events: {
"click #save-this": "saveModel"
},
saveModel: function() {
console.log("saveModel() called");
//console.log(permStorage.taggedForList());
//shift the model over to permStorage
//searchTemp.remove(this.model);
//console.log(this.model);
this.model.saveModel();
//console.log(this.model)
//now save permStorage to local storage
searchTemp.each(function (model) {
if(model.isPerm) {
model.save();
}
});
}
});
window.savedRecipesView = Backbone.View.extend({
template:_.template($('#savedRecipes').html()),
initialize: function() {
console.log("about to fetch from local storage...");
searchTemp.fetch();
console.log("...fetched!");
},
render:function (data) {
results = searchTemp.toJSON();
//results = results.models;
//console.log(results);
var variables = {
results: results
};
_.each(data, function(task) {
console.log("meow");
this.addOne(task);
}, this);
$(this.el).html(this.template(variables));
return this;
},
addOne: function(task) {
var view = new listItemView({ model:task });
$(this.el).append( view.render().el );
}
});
window.listItemView = Backbone.View.extend({
tagName: 'li',
template:_.template($('#list-item').html()),
initialize: function() {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.model.view = this;
},
events: {
"click input[type=button]" : "onClick"
},
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
this.setContent();
return this;
},
onClick: function(){
searchTemp.add(this.model);
console.log("model added to searchTemp, current state of searchTemp:");
console.log(searchTemp);
}
});
window.oldListView = Backbone.View.extend({
template:_.template($('#oldList').html()),
render: function (eventName) {
$(this.el).html(this.template());
return this;
}
});
window.deleteOldView = Backbone.View.extend({
template:_.template($('#deleteOld').html()),
render: function (eventName) {
$(this.el).html(this.template());
return this;
}
});
window.shoppingListView = Backbone.View.extend({
template:_.template($('#shoppingList').html()),
initialize: function() {
shopList.generate();
},
render: function (eventName) {
var variables = {
};
$(this.el).html(this.template(variables));
return this;
}
});
var AppRouter = Backbone.Router.extend({
routes:{
"":"home",
"newSearch":"newSearch",
"newList/:id":"newList",
"savedRecipes":"savedRecipes",
"oldList":"oldList",
"deleteOld":"deleteOld",
"shoppingList":"shoppingList"
},
initialize:function () {
// Handle back button throughout the application
$('.back').live('click', function(event) {
window.history.back();
return false;
});
this.firstPage = true;
},
home:function () {
this.changePage(new HomeView());
},
newSearch:function () {
this.changePage(new newSearchView());
},
newList:function (theID) {
var tempModel = searchTemp.get(theID);
this.changePage(new newListView({
model: tempModel,
id: theID
}));
//console.log(permStorage.taggedForList());
},
savedRecipes:function () {
this.changePage(new savedRecipesView());
},
oldList:function () {
this.changePage(new oldListView());
},
deleteOld:function () {
this.changePage(new deleteOldView());
},
shoppingList:function () {
this.changePage(new shoppingListView());
},
changePage:function (page) {
$(page.el).attr('data-role', 'page');
page.render();
$('body').append($(page.el));
var transition = $.mobile.defaultPageTransition;
// We don't want to slide the first page
if (this.firstPage) {
transition = 'none';
this.firstPage = false;
}
$.mobile.changePage($(page.el), {changeHash:false, transition: transition});
}
});
$(document).ready(function () {
console.log('document ready');
app = new AppRouter();
Backbone.history.start();
searchTemp = new TodoList(); //this stores searched recipes, rename to myRecipes
shopList = new ShopList();
});
<!DOCTYPE html>
<html class="ui-mobile-rendering">
<head>
<title>RECILIST</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/jquery.mobile-1.0.1.min.css"/>
<!-- The Templates -->
<script type="text/template" id="home">
<div data-role="header" >
<h1 style="color:black">Recilist Home</h1>
</div>
<img src="store.jpg" id="vege">
<div data-role="content" style="color:red">
<!-- <h3>recilist home page</h3>
<p>Welcome to Recilist!</p>
<p>This is the Home page. </p>
-->
<h1>Save Recipes & <br/>
Create Shopping <br/>
Lists Anywhere</h1>
<p class="blurb">Create and manage your grocery shopping list, FIND and <br/>SAVE your favorite recipes from across the web,<br/> get great SAVINGS and share with your entire family - for FREEEE!!!!</p>
<ul data-role="listview" id="choices" data-inset="true">
<li><a style="color:red" href="#newSearch">Search for new Recipes</a></li>
<li><a style="color:red" href="#savedRecipes">View saved Recipes</a></li>
</ul>
</div>
<div data-role="footer" class="ui-bar" id ="footer">
<h5 style="color:black"> powered by <img src="http://static.yummly.com/api-logo.png"> </h5>
</div>
</script>
<script type="text/template" id="newSearch">
<div data-role="header">
<h1 style="color:black">Search for a new Recipe</h1>
</div>
<div data-role="content">
<input name= "recipe-search" id="recipe-search" data-icon="search" type="text" placeholder="What do you want to cook?">
<ul id="search-list" data-role="listview" data-inset="true">
<% for(var i in results) { %>
<li> <img src="<%= results[i].imgUrl %>"> <%= results[i].title %> </li>
<% } %>
</ul>
</div>
<img src="list.png" id="list">
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="newList">
<div data-role="header">
<h1 style="color:black"> <%=recipe_name%> </h1>
</div>
<div>
<div data-role="content">
<img src= <%=img_url%> >
<h4>Recipe Rating: <%= rating %> </h4>
<h4>Total time to Prepare: <%= timetomake %> </h4>
<h4>Flavor Ratings</h4>
<div class="ui-block-a"> <div class="ui-bar ui-bar-e"> <h4>saltiness</h4> <%= salty %> </div> </div>
<div class="ui-block-b"> <div class="ui-bar ui-bar-e"> <h4>sourness</h4> <%= sour %> </div> </div>
<div class="ui-block-c"> <div class="ui-bar ui-bar-e"> <h4>sweetness</h4> <%= sweet %> </div> </div>
<div class="ui-block-d"> <div class="ui-bar ui-bar-e"> <h4>bitterness</h4> <%= bitter %> </div> </div>
</div>
<div data-role="collapsible" data-collapsed="true">
<h3>Ingredients</h3>
<ul id="ingr-list" data-role="listview" data-inset="true">
<% for(var i in ingrs) { %>
<li><%= ingrs[i] %></li>
<% } %>
</ul>
</div>
<div data-role="content">
<input type="button" id="save-this" data-icon="check" value="save to My Recipies">
<div>
<img src="store3.jpg" id="aisle">
</div>
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="savedRecipes">
<div data-role="header">
<h1>My Recipes</h1>
</div>
<div data-role="content">
<p>list of saved recipes, retrieved from local storage</p>
<p>Saved Recipes:</p>
<ul id="search-list" data-role="listview" data-inset="true">
<% for(var i in results) { %>
<li> <img src="<%= results[i].imgUrl %>"> <%= results[i].title %> </li>
<% } %>
</ul>
manage saved recipes
generate shopping list
</div>
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="deleteOld">
<div data-role="header">
<h1>Delete Recipes</h1>
</div>
<div data-role="content">
<p>select which recipes you wish to delete from local storage</p>
<p>recipes:</p>
<p>(currently lacks functionality to populate this list)</p>
<ul data-role="listview" data-inset="true" id="recipe-list">
</ul>
<input type="button" data-icon="delete" value="delete selected" />
</div>
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="oldList">
<div data-role="header">
<h1>---NAME OF THE RECIPE----</h1>
</div>
<div data-role="content">
<p>This is a list of all the ingredients in this recipe</p>
<p>Ingredients:</p>
<ul data-role="listview" data-inset="true">
<li>ingredient 1</li>
<li>ingredient 2</li>
<li>ingredient 3</li>
<li>ingredient 4</li>
</ul>
<p> (button to view the recipe) </p>
</div>
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="shoppingList">
<div data-role="header">
<h1>shopping list</h1>
</div>
<div data-role="content">
<ul id="search-list" data-role="listview" data-inset="true">
<% for(var i in results) { %>
<li> <input type="checkbox" name=i id=i class="custom" /></li> <!-- these checkboxes are HIDEOUSLY DEFORMED-->
<label for=i> <%= results[i].title %> </label>
<% } %>
</ul>
</div>
<div data-role="footer" class="ui-bar">
Back
Home
</div>
</script>
<script type="text/template" id="list-item">
<li>cheese</li>
</script>
<!-- <li> <img src= <%=img_url%> > <a href="#newList/"+ <%=model_id%> +"' class='ui-link-inherit'>" + <%=model_title%> + "</a> </li> -->
<!-- The Scripts -->
<script src="lib/jquery-1.7.1.min.js"></script>
<script src="js/jqm-config.js"></script>
<script src="lib/jquery.mobile-1.0.1.min.js"></script>
<script src="js/underscore.js"></script>
<script src="lib/backbone-min.js"></script>
<script src="js/backbone.localStorage.js"</script>
<script src="js/json2.js"></script>
<script src="js/main.js"></script>
</head>
<body></body>
</html>
To enhance dynamically created list view, you need to refresh the markup using the below.
$('[data-role=listview]').listview('refresh');