Fixed a bug with the updater.
This commit is contained in:
parent
e7625991a1
commit
58c3d50bce
2
Makefile
2
Makefile
|
@ -39,7 +39,7 @@ store.js: backbonestore.nw
|
||||||
rm $*.nw-tmp; \
|
rm $*.nw-tmp; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
index.html:
|
index.html: backbonestore.nw
|
||||||
@ $(ECHO) $(NOTANGLE) -c -R$@ $<
|
@ $(ECHO) $(NOTANGLE) -c -R$@ $<
|
||||||
@ - $(NOTANGLE) -c -R$@ $< > $*.nw-html-tmp
|
@ - $(NOTANGLE) -c -R$@ $< > $*.nw-html-tmp
|
||||||
@ if [ -s "$*.nw-html-tmp" ]; then \
|
@ if [ -s "$*.nw-html-tmp" ]; then \
|
||||||
|
|
116
backbonestore.nw
116
backbonestore.nw
|
@ -144,9 +144,11 @@ Also, it would be nice to know the total price of the Item.
|
||||||
<<cart models>>=
|
<<cart models>>=
|
||||||
var Item = Backbone.Model.extend({
|
var Item = Backbone.Model.extend({
|
||||||
update: function(amount) {
|
update: function(amount) {
|
||||||
this.set({'quantity': amount});
|
this.set({'quantity': amount}, {silent: true});
|
||||||
|
this.collection.trigger('change', this);
|
||||||
},
|
},
|
||||||
price: function() {
|
price: function() {
|
||||||
|
console.log(this.get('product').get('title'), this.get('quantity'));
|
||||||
return this.get('product').get('price') * this.get('quantity');
|
return this.get('product').get('price') * this.get('quantity');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -236,7 +238,7 @@ and remove tabs from the top of the viewport as needed.
|
||||||
|
|
||||||
<<base view>>=
|
<<base view>>=
|
||||||
var _BaseView = Backbone.View.extend({
|
var _BaseView = Backbone.View.extend({
|
||||||
parent: '#main',
|
parent: $('#main'),
|
||||||
className: 'viewport',
|
className: 'viewport',
|
||||||
|
|
||||||
@
|
@
|
||||||
|
@ -313,8 +315,8 @@ for our one-page application:
|
||||||
</title>
|
</title>
|
||||||
<link rel="stylesheet" href="jsonstore.css" type="text/css">
|
<link rel="stylesheet" href="jsonstore.css" type="text/css">
|
||||||
<<product list template>>
|
<<product list template>>
|
||||||
<<product template>>
|
<<product detail template>>
|
||||||
<<checkout template>>
|
<<cart template>>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
|
@ -388,23 +390,23 @@ you should understand this fairly easily.
|
||||||
And here is the HTML:
|
And here is the HTML:
|
||||||
|
|
||||||
<<product list template>>=
|
<<product list template>>=
|
||||||
<script id="store_index_template" type="text/x-underscore-tmplate">
|
<script id="store_index_template" type="text/x-underscore-tmplate">
|
||||||
<h1>Product Catalog</h1>
|
<h1>Product Catalog</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<% for(i=0,l=products.length;i<l;++i) { p = products[i]; %>
|
<% for(i=0,l=products.length;i<l;++i) { p = products[i]; %>
|
||||||
<li class="item">
|
<li class="item">
|
||||||
<div class="item-image">
|
<div class="item-image">
|
||||||
<a href="#item/<%= p.id %>">
|
<a href="#item/<%= p.id %>">
|
||||||
<img alt="<%= p.title %>" src="<%= p.image %>" />
|
<img alt="<%= p.title %>" src="<%= p.image %>" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<div class="item-artist"><%= p.artist %></div>
|
||||||
<div class="item-artist"><%= p.artist %></div>
|
<div class="item-title"><%= p.title %></div>
|
||||||
<div class="item-title"><%= p.title %></div>
|
<div class="item-price">$<%= p.price %></div>
|
||||||
<div class="item-price">$<%= p.price %></div>
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
</script>
|
</script>
|
||||||
@
|
@
|
||||||
%$
|
%$
|
||||||
|
|
||||||
|
@ -467,12 +469,20 @@ get its id and so forth. All of that has been put into the shopping
|
||||||
cart model, which is where it belongs: \textit{knowledge about items
|
cart model, which is where it belongs: \textit{knowledge about items
|
||||||
and each item's relationship to its collection belongs in the
|
and each item's relationship to its collection belongs in the
|
||||||
collection}.
|
collection}.
|
||||||
|
|
||||||
|
Look closely at the [[update()]] method. The reference [[this.\$]] is
|
||||||
|
a special Backbone object that limits selectors to objects inside the
|
||||||
|
element of the view. Without it, jQuery would have found the first
|
||||||
|
input field of class 'uqf' in the DOM, not the one for this specific
|
||||||
|
view. [[this.\$('.uqf')]] is shorthand for [[$('uqf', this.el)]], and
|
||||||
|
helps clarify what it is you're looking for.
|
||||||
|
|
||||||
%'
|
%'
|
||||||
|
|
||||||
<<product detail view>>=
|
<<product detail view>>=
|
||||||
update: function(e) {
|
update: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.item.update(parseInt($('.uqf').val()));
|
this.item.update(parseInt(this.$('.uqf').val()));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
|
@ -499,33 +509,33 @@ The product detail template is fairly straightforward. There is no
|
||||||
[[underscore]] magic because there are no loops.
|
[[underscore]] magic because there are no loops.
|
||||||
|
|
||||||
<<product detail template>>=
|
<<product detail template>>=
|
||||||
<script id="store_item_template" type="text/x-underscore-template">
|
<script id="store_item_template" type="text/x-underscore-template">
|
||||||
<div class="item-detail">
|
<div class="item-detail">
|
||||||
<div class="item-image">
|
<div class="item-image">
|
||||||
<img alt="<%= title %>" src="<%= large_image %>" />
|
<img alt="<%= title %>" src="<%= large_image %>" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-info">
|
<div class="item-info">
|
||||||
<div class="item-artist"><%= artist %></div>
|
<div class="item-artist"><%= artist %></div>
|
||||||
<div class="item-title"><%= title %></div>
|
<div class="item-title"><%= title %></div>
|
||||||
<div class="item-price">$<%= price %></div>
|
<div class="item-price">$<%= price %></div>
|
||||||
<form action="#/cart" method="post">
|
<form action="#/cart" method="post">
|
||||||
<p>
|
<p>
|
||||||
<label>Quantity:</label>
|
<label>Quantity:</label>
|
||||||
<input class="uqf" name="quantity" size="2" type="text" value="1" />
|
<input class="uqf" name="quantity" size="2" type="text" value="1" />
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input class="uq" type="submit" value="Add to Cart" />
|
<input class="uq" type="submit" value="Add to Cart" />
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
<div class="item-link">
|
<div class="item-link">
|
||||||
<a href="<%= url %>">Buy this item on Amazon</a>
|
<a href="<%= url %>">Buy this item on Amazon</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="back-link">
|
<div class="back-link">
|
||||||
<a href="#">« Back to Items</a>
|
<a href="#">« Back to Items</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
@
|
@
|
||||||
|
|
||||||
So, let's talk about that shopping cart thing. We've been making the
|
So, let's talk about that shopping cart thing. We've been making the
|
||||||
|
@ -570,9 +580,9 @@ show that it did changed:
|
||||||
And the HTML for the template is dead simple:
|
And the HTML for the template is dead simple:
|
||||||
|
|
||||||
<<cart template>>=
|
<<cart template>>=
|
||||||
<script id="store_cart_template" type="text/x-underscore-template">
|
<script id="store_cart_template" type="text/x-underscore-template">
|
||||||
<p>Items: <%= count %> ($<%= cost %>)</p>
|
<p>Items: <%= count %> ($<%= cost %>)</p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@
|
@
|
||||||
%$
|
%$
|
||||||
|
@ -722,6 +732,8 @@ Here's the entirety of the program:
|
||||||
|
|
||||||
<<product detail view>>
|
<<product detail view>>
|
||||||
|
|
||||||
|
<<cart widget>>
|
||||||
|
|
||||||
<<router>>
|
<<router>>
|
||||||
|
|
||||||
<<initialization>>
|
<<initialization>>
|
||||||
|
|
134
index.html
134
index.html
|
@ -1,73 +1,75 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<title>The Backbone Store</title>
|
<title>
|
||||||
<link charset="utf-8" href="jsonstore.css" rel="stylesheet" type="text/css" />
|
The Backbone Store
|
||||||
|
</title>
|
||||||
<script id="store_index_template" type="text/x-underscore-tmplate">
|
<link rel="stylesheet" href="jsonstore.css" type="text/css">
|
||||||
<h1>Product Catalog</h1>
|
<script id="store_index_template" type="text/x-underscore-tmplate">
|
||||||
<ul>
|
<h1>Product Catalog</h1>
|
||||||
<% for(i=0,l=products.length;i<l;++i) { p = products[i]; %>
|
<ul>
|
||||||
<li class="item">
|
<% for(i=0,l=products.length;i<l;++i) { p = products[i]; %>
|
||||||
<div class="item-image">
|
<li class="item">
|
||||||
<a href="#item/<%= p.id %>">
|
<div class="item-image">
|
||||||
<img alt="<%= p.title %>" src="<%= p.image %>" />
|
<a href="#item/<%= p.id %>">
|
||||||
</a>
|
<img alt="<%= p.title %>" src="<%= p.image %>" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="item-artist"><%= p.artist %></div>
|
||||||
|
<div class="item-title"><%= p.title %></div>
|
||||||
|
<div class="item-price">$<%= p.price %></div>
|
||||||
|
</li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
</script>
|
||||||
|
<script id="store_item_template" type="text/x-underscore-template">
|
||||||
|
<div class="item-detail">
|
||||||
|
<div class="item-image">
|
||||||
|
<img alt="<%= title %>" src="<%= large_image %>" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<div class="item-info">
|
||||||
<div class="item-artist"><%= p.artist %></div>
|
<div class="item-artist"><%= artist %></div>
|
||||||
<div class="item-title"><%= p.title %></div>
|
<div class="item-title"><%= title %></div>
|
||||||
<div class="item-price">$<%= p.price %></div>
|
<div class="item-price">$<%= price %></div>
|
||||||
<% } %>
|
<form action="#/cart" method="post">
|
||||||
</ul>
|
<p>
|
||||||
</script>
|
<label>Quantity:</label>
|
||||||
|
<input class="uqf" name="quantity" size="2" type="text" value="1" />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input class="uq" type="submit" value="Add to Cart" />
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<div class="item-link">
|
||||||
|
<a href="<%= url %>">Buy this item on Amazon</a>
|
||||||
|
</div>
|
||||||
|
<div class="back-link">
|
||||||
|
<a href="#">« Back to Items</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script id="store_cart_template" type="text/x-underscore-template">
|
||||||
|
<p>Items: <%= count %> ($<%= cost %>)</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script id="store_item_template" type="text/x-underscore-template">
|
</head>
|
||||||
<div class="item-detail"></div>
|
<body>
|
||||||
<div class="item-image">
|
<div id="container">
|
||||||
<img alt="<%= title %>" src="<%= large_image %>" />
|
<div id="header">
|
||||||
</div>
|
<h1>
|
||||||
<div class="item-info"></div>
|
The Backbone Store
|
||||||
<div class="item-artist"><%= artist %></div>
|
</h1>
|
||||||
<div class="item-title"><%= title %></div>
|
|
||||||
<div class="item-price">$<%= price %></div>
|
|
||||||
<div class="item-form"></div>
|
|
||||||
<form action="#/cart" method="post">
|
|
||||||
<p>
|
|
||||||
<label>Quantity:</label>
|
|
||||||
<input class="uqf" name="quantity" size="2" type="text" value="1" />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<input class="uq" type="submit" value="Add to Cart" />
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
<div class="item-link">
|
|
||||||
<a href="<%= url %>">Buy this item on Amazon</a>
|
|
||||||
</div>
|
|
||||||
<div class="back-link">
|
|
||||||
<a href="#">« Back to Items</a>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script id="store_cart_template" type="text/x-underscore-template">
|
<div class="cart-info">
|
||||||
<p>Items: <%= count %> ($<%= cost %>)</p>
|
</div>
|
||||||
</script>
|
</div>
|
||||||
|
|
||||||
</head>
|
<div id="main"> </div>
|
||||||
|
</div>
|
||||||
<body>
|
<script src="jquery-1.6.2.min.js" type="text/javascript"></script>
|
||||||
<div id="container">
|
<script src="underscore.js" type="text/javascript"></script>
|
||||||
<div id="header">
|
<script src="backbone.js" type="text/javascript"></script>
|
||||||
<h1>
|
<script src="store.js" type="text/javascript"></script>
|
||||||
The Backbone Store
|
</body>
|
||||||
</h1>
|
|
||||||
<div class="cart-info"></div>
|
|
||||||
</div>
|
|
||||||
<div id="main"></div>
|
|
||||||
</div>
|
|
||||||
<script src="jquery-1.6.2.min.js" type="text/javascript"></script>
|
|
||||||
<script src="underscore.js" type="text/javascript"></script>
|
|
||||||
<script src="backbone.js" type="text/javascript"></script>
|
|
||||||
<script src="store.js" type="text/javascript"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -33,12 +33,17 @@ body {
|
||||||
img {
|
img {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
#productlistview ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
display: border;
|
||||||
float:left;
|
float:left;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin-right: 3px;
|
margin-right: 10px;
|
||||||
padding: 2px;
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
34
store.js
34
store.js
|
@ -16,12 +16,18 @@
|
||||||
|
|
||||||
var Item = Backbone.Model.extend({
|
var Item = Backbone.Model.extend({
|
||||||
update: function(amount) {
|
update: function(amount) {
|
||||||
this.set({'quantity': this.get('quantity') + amount});
|
this.set({'quantity': amount}, {silent: true});
|
||||||
|
this.collection.trigger('change', this);
|
||||||
|
},
|
||||||
|
price: function() {
|
||||||
|
console.log(this.get('product').get('title'), this.get('quantity'));
|
||||||
|
return this.get('product').get('price') * this.get('quantity');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ItemCollection = Backbone.Collection.extend({
|
var ItemCollection = Backbone.Collection.extend({
|
||||||
model: Item,
|
model: Item,
|
||||||
|
|
||||||
getOrCreateItemForProduct: function(product) {
|
getOrCreateItemForProduct: function(product) {
|
||||||
var i,
|
var i,
|
||||||
pid = product.get('id'),
|
pid = product.get('id'),
|
||||||
|
@ -35,18 +41,19 @@
|
||||||
this.add(i, {silent: true})
|
this.add(i, {silent: true})
|
||||||
return i;
|
return i;
|
||||||
},
|
},
|
||||||
|
|
||||||
getTotalCount: function() {
|
getTotalCount: function() {
|
||||||
return this.reduce(function(memo, obj) {
|
return this.reduce(function(memo, obj) {
|
||||||
return obj.get('quantity') + memo; }, 0);
|
return obj.get('quantity') + memo; }, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
getTotalCost: function() {
|
getTotalCost: function() {
|
||||||
return this.reduce(function(memo, obj) {
|
return this.reduce(function(memo, obj) {
|
||||||
return (obj.get('product').get('price') *
|
return obj.price() + memo; }, 0);
|
||||||
obj.get('quantity')) + memo; }, 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var _BaseView = Backbone.View.extend({
|
var _BaseView = Backbone.View.extend({
|
||||||
parent: $('#main'),
|
parent: $('#main'),
|
||||||
className: 'viewport',
|
className: 'viewport',
|
||||||
|
@ -63,9 +70,8 @@
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
promise = $.Deferred(_.bind(function(dfd) {
|
promise = $.Deferred(_.bind(function(dfd) {
|
||||||
this.el.fadeOut('fast', dfd.resolve)}, this)).promise();
|
this.el.fadeOut('fast', dfd.resolve)}, this));
|
||||||
this.trigger('hide', this);
|
return promise.promise();
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
|
@ -73,13 +79,12 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise = $.Deferred(_.bind(function(dfd) {
|
promise = $.Deferred(_.bind(function(dfd) {
|
||||||
this.el.fadeIn('fast', dfd.resolve) }, this)).promise();
|
this.el.fadeIn('fast', dfd.resolve) }, this))
|
||||||
|
return promise.promise();
|
||||||
this.trigger('show', this);
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var ProductListView = _BaseView.extend({
|
var ProductListView = _BaseView.extend({
|
||||||
id: 'productlistview',
|
id: 'productlistview',
|
||||||
template: $("#store_index_template").html(),
|
template: $("#store_index_template").html(),
|
||||||
|
@ -96,6 +101,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var ProductView = _BaseView.extend({
|
var ProductView = _BaseView.extend({
|
||||||
id: 'productitemview',
|
id: 'productitemview',
|
||||||
template: $("#store_item_template").html(),
|
template: $("#store_item_template").html(),
|
||||||
|
@ -113,7 +119,7 @@
|
||||||
|
|
||||||
update: function(e) {
|
update: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.item.update(parseInt($('.uqf').val()));
|
this.item.update(parseInt(this.$('.uqf').val()));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
|
@ -128,6 +134,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var CartWidget = Backbone.View.extend({
|
var CartWidget = Backbone.View.extend({
|
||||||
el: $('.cart-info'),
|
el: $('.cart-info'),
|
||||||
template: $('#store_cart_template').html(),
|
template: $('#store_cart_template').html(),
|
||||||
|
@ -137,7 +144,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
console.log(arguments);
|
|
||||||
this.el.html(
|
this.el.html(
|
||||||
_.template(this.template, {
|
_.template(this.template, {
|
||||||
'count': this.collection.getTotalCount(),
|
'count': this.collection.getTotalCount(),
|
||||||
|
@ -147,6 +153,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var BackboneStore = Backbone.Router.extend({
|
var BackboneStore = Backbone.Router.extend({
|
||||||
views: {},
|
views: {},
|
||||||
products: null,
|
products: null,
|
||||||
|
@ -200,4 +207,5 @@
|
||||||
new BackboneStore();
|
new BackboneStore();
|
||||||
Backbone.history.start();
|
Backbone.history.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
Loading…
Reference in New Issue