Skip to content

Commit 036e11c

Browse files
committed
more backbone fixes
1 parent b4c0661 commit 036e11c

File tree

5 files changed

+52
-226
lines changed

5 files changed

+52
-226
lines changed

examples/todomvc-backbone/css/base.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ body {
383383
color: inherit;
384384
}
385385

386+
.submitButton {
387+
display: none;
388+
}
389+
386390
/*
387391
Hack to remove background from Mobile Safari.
388392
Can't use it globally since it destroys checkboxes in Firefox and Opera

examples/todomvc-backbone/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<script type="text/javascript" src="../shared/thirdparty/jquery.min.js" charset="utf-8"></script>
1717
<script type="text/javascript" src="thirdparty/lodash.min.js" charset="utf-8"></script>
1818
<script type="text/javascript" src="thirdparty/backbone-min.js" charset="utf-8"></script>
19-
<script type="text/javascript" src="thirdparty/backbone.localStorage.js" charset="utf-8"></script>
19+
<script type="text/javascript" src="thirdparty/backbone.localStorage-min.js" charset="utf-8"></script>
2020
<script type="text/jsx" src="js/app.js"></script>
2121
</body>
2222
</html>

examples/todomvc-backbone/js/app.js

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var TodoList = Backbone.Collection.extend({
3737
model: Todo,
3838

3939
// Save all of the todo items under the `"todos"` namespace.
40-
localStorage: new Store('todos-backbone'),
40+
localStorage: new Store('todos-react-backbone'),
4141

4242
// Filter down the list of all todo items that are finished.
4343
completed: function() {
@@ -46,39 +46,24 @@ var TodoList = Backbone.Collection.extend({
4646
});
4747
},
4848

49-
// Filter down the list to only todo items that are still not finished.
50-
remaining: function() {
51-
return this.without.apply( this, this.completed() );
52-
},
53-
5449
// We keep the Todos in sequential order, despite being saved by unordered
5550
// GUID in the database. This generates the next order number for new items.
56-
nextOrder: function() {
57-
if ( !this.length ) {
51+
nextOrder: function () {
52+
if (!this.length) {
5853
return 1;
5954
}
6055
return this.last().get('order') + 1;
6156
},
6257

6358
// Todos are sorted by their original insertion order.
64-
comparator: function( todo ) {
59+
comparator: function (todo) {
6560
return todo.get('order');
6661
}
6762
});
6863

6964
var Utils = {
70-
// https://gist.github.com/1308368
71-
uuid: function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b},
7265
pluralize: function( count, word ) {
7366
return count === 1 ? word : word + 's';
74-
},
75-
store: function( namespace, data ) {
76-
if ( arguments.length > 1 ) {
77-
return localStorage.setItem( namespace, JSON.stringify( data ) );
78-
} else {
79-
var store = localStorage.getItem( namespace );
80-
return ( store && JSON.parse( store ) ) || [];
81-
}
8267
}
8368
};
8469

@@ -87,24 +72,20 @@ var Utils = {
8772
var ENTER_KEY = 13;
8873

8974
var TodoItem = React.createClass({
90-
getInitialState: function() {
91-
return {editValue: this.props.todo.get('title')};
92-
},
93-
onKeyUp: React.autoBind(function(event) {
94-
this.setState({editValue: event.target.value});
95-
var val = event.target.value.trim();
96-
if (event.nativeEvent.keyCode !== ENTER_KEY || !val) {
97-
return;
75+
handleSubmit: React.autoBind(function(event) {
76+
var val = this.refs.editField.getDOMNode().value;
77+
if (val) {
78+
this.props.onSave(val);
9879
}
99-
this.props.onSave(val);
80+
return false;
10081
}),
10182
onEdit: React.autoBind(function() {
10283
this.props.onEdit();
10384
this.refs.editField.getDOMNode().focus();
10485
}),
10586
render: function() {
10687
return (
107-
<li class={cx({completed: this.props.todo.get('completed'), editing: this.props.editing})}>
88+
<li class={cx({completed: this.props.todo.get('completed'), editing: this.props.editing})}>
10889
<div class="view">
10990
<input
11091
class="toggle"
@@ -115,7 +96,9 @@ var TodoItem = React.createClass({
11596
<label onDoubleClick={this.onEdit}>{this.props.todo.get('title')}</label>
11697
<button class="destroy" onClick={this.props.onDestroy} />
11798
</div>
118-
<input ref="editField" class="edit" value={this.state.editValue} onKeyUp={this.onKeyUp} />
99+
<form onSubmit={this.handleSubmit}>
100+
<input ref="editField" class="edit" value={this.props.todo.get('title')} />
101+
</form>
119102
</li>
120103
);
121104
}
@@ -143,57 +126,62 @@ var TodoFooter = React.createClass({
143126

144127
var TodoApp = React.createClass({
145128
getInitialState: function() {
146-
return {newTodoValue: '', editing: {}};
129+
return {editing: null};
147130
},
148131
// Here is "the backbone integration." Just tell React whenever there *might* be a change
149132
// and we'll reconcile.
150-
componentWillMount: function() {
133+
componentDidMount: function() {
151134
this.props.todos.on('add change remove', this.forceUpdate, this);
135+
this.props.todos.fetch();
136+
},
137+
componentDidUpdate: function() {
138+
// If saving were expensive we'd listen for mutation events on Backbone and do this manually.
139+
// however, since saving isn't expensive this is an elegant way to keep it reactively up-to-date.
140+
this.props.todos.map(function(todo) {
141+
todo.save();
142+
});
152143
},
153144
componentWillUnmount: function() {
154145
this.props.todos.off(null, null, this);
155146
},
156-
handleKeyUp: React.autoBind(function(event) {
157-
this.setState({newTodoValue: event.target.value});
158-
var val = event.target.value.trim();
159-
if (event.nativeEvent.keyCode !== ENTER_KEY || !val) {
160-
return;
147+
handleSubmit: React.autoBind(function() {
148+
var val = this.refs.newField.getDOMNode().value.trim();
149+
if (val) {
150+
this.props.todos.create({
151+
title: val,
152+
completed: false,
153+
order: this.props.todos.nextOrder()
154+
});
155+
this.refs.newField.getDOMNode().value = '';
161156
}
162-
this.props.todos.add(new Todo({id: Utils.uuid(), title: val, completed: false}));
163-
this.setState({newTodoValue: ''});
157+
return false;
164158
}),
165159
toggleAll: function(event) {
166160
var checked = event.nativeEvent.target.checked;
167161
this.props.todos.map(function(todo) {
168162
todo.set('completed', checked);
169163
});
170164
},
171-
toggle: function(todo) {
172-
todo.set('completed', !todo.get('completed'));
173-
},
174165
destroy: function(todo) {
175166
this.props.todos.remove(todo);
176167
},
177168
edit: function(todo) {
178-
var editing = {};
179-
editing[todo.get('id')] = true;
180-
this.setState({editing: editing});
169+
this.setState({editing: todo.get('id')});
181170
},
182171
save: function(todo, text) {
183172
todo.set('title', text);
184-
this.setState({editing: {}});
173+
this.setState({editing: null});
185174
},
186175
clearCompleted: function() {
187-
this.props.todos.completed().map(this.props.todos.remove.bind(this.props.todos));
188-
},
189-
componentDidUpdate: function() {
190-
Utils.store('todos-react', this.props.todos);
176+
this.props.todos.completed().map(function(todo) {
177+
todo.destroy();
178+
});
191179
},
192180
render: function() {
193181
var footer = null;
194182
var main = null;
195183
var todoItems = this.props.todos.map(function(todo) {
196-
return <TodoItem todo={todo} onToggle={this.toggle.bind(this, todo)} onDestroy={this.destroy.bind(this, todo)} onEdit={this.edit.bind(this, todo)} editing={this.state.editing[todo.get('id')]} onSave={this.save.bind(this, todo)} />;
184+
return <TodoItem todo={todo} onToggle={todo.toggle.bind(todo)} onDestroy={this.destroy.bind(this, todo)} onEdit={this.edit.bind(this, todo)} editing={this.state.editing === todo.get('id')} onSave={this.save.bind(this, todo)} />;
197185
}.bind(this));
198186

199187
var activeTodoCount = this.props.todos.filter(function(todo) { return !todo.get('completed') }).length;
@@ -219,7 +207,9 @@ var TodoApp = React.createClass({
219207
<section class="todoapp">
220208
<header class="header">
221209
<h1>todos</h1>
222-
<input class="new-todo" placeholder="What needs to be done?" autofocus="autofocus" onKeyUp={this.handleKeyUp} value={this.state.newTodoValue} />
210+
<form onSubmit={this.handleSubmit}>
211+
<input ref="newField" class="new-todo" placeholder="What needs to be done?" autofocus="autofocus" />
212+
</form>
223213
</header>
224214
{main}
225215
{footer}
@@ -233,4 +223,4 @@ var TodoApp = React.createClass({
233223
);
234224
}
235225
});
236-
React.renderComponent(<TodoApp todos={new TodoList(Utils.store('todos-react'))} />, document.getElementById('todoapp'));
226+
React.renderComponent(<TodoApp todos={new TodoList()} />, document.getElementById('todoapp'));

0 commit comments

Comments
 (0)