@@ -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
6964var 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 = {
8772var ENTER_KEY = 13 ;
8873
8974var 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
144127var 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