Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Introducing Backbone.js

Introducing Backbone.js

Backbone.js fundamentals with models, collections, views and their interaction (change event - rendering), to really understand what's going and how it helps you manage JavaScript application complexity.

Demo code for this talk can be found at: https://github.com/toonketels/backbone-presentation-demo

Presented at:
* DrupalCampLeuven - 2013.09.15 - Leuven, Belgium
* Drupal User Group @ Wunderkraut - 2013.07.11 - Antwerp, Belgium
* DrupalJam - 2013.05.17 - Rotterdam, the Netherlands.

Toon Ketels

July 11, 2013
Tweet

More Decks by Toon Ketels

Other Decks in Programming

Transcript

  1. Backbone.js gives structure to web applications by providing models with

    key- value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface. backbonejs.org
  2. Let's focus on understanding the fundamentals, so we can hack

    existing apps, know were everything goes and don't curse backbone.js for all the complexity it adds, 'cause... it is making our lives easier.
  3. n e w B a c k b o n

    e . M o d e l ( )
  4. Models are the heart of any JavaScript application, containing the

    interactive data as well as a large part of the logic surrounding it: conversions, validation, computed properties, and access control. backbonejs.org/#Model
  5. v a r t o o n = n e

    w B a c k b o n e . M o d e l ( { n a m e : " T o o n K e t e l s " , a g e : 3 0 , j o b : " D e v e l o p e r " , b i o : " < p > S c r u m m a s t e r , b a c k e n d D r u p a l d e v e l o p e r . < / p > " , u i d : 7 5 4 4 } ) ;
  6. { _ c h a n g i n g

    : f a l s e , _ p e n d i n g : f a l s e , _ p r e v i o u s A t t r i b u t e s : { / * . . . * / } , _ a t t r i b u t e s : { / * . . . * / } , c h a n g e d : { / * . . . * / } , c i d : " c i d " } ;
  7. t o o n . h a s ( '

    a g e ' ) ; t o o n . g e t ( ' a g e ' ) ; t o o n . e s c a p e ( ' b i o ' ) ;
  8. t o o n . s e t ( '

    a g e ' , 3 1 ) ; t o o n . c h a n g e d ; t o o n . p r e v i o u s A t t r i b u t e s ( ) ;
  9. t o o n . o n ( ' c

    h a n g e ' , f u n c t i o n ( m o d e l ) { c o n s o l e . l o g ( ' c h a n g e d ' ) ; c o n s o l e . l o g ( m o d e l ) ; } ) ;
  10. t o o n . o n ( ' c

    h a n g e : a g e ' , f u n c t i o n ( m o d e l , v a l u e ) { c o n s o l e . l o g ( ' A g e h a s h a n g e d ' ) ; c o n s o l e . l o g ( m o d e l ) ; c o n s o l e . l o g ( v a l u e ) ; } ) ;
  11. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { / / C u s t o m m e t h o d s } ) ; v a r t o o n = n e w P e r s o n ( { . . . } ) ;
  12. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { i n i t i a l i z e : f u n c t i o n ( ) { c o n s o l e . l o g ( ' I r u n o n s t a r t u p ' ) ; } } ) ;
  13. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { d e f a u l t s : { c o u n t r y : " B e l g i u m " , p r o f e s s i o n : " A n a l y s t " } } ) ;
  14. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { v a l i d a t e : f u n c t i o n ( a t t r i b u t e s , o p t i o n s ) { i f ( t y p e o f a t t r i b u t e s . a g e ! = = " n u m b e r " ) { r e t u r n " A g e s h o u l d b e a n u m b e r " ; } } } ) ;
  15. t o o n . s e t ( '

    a g e ' , ' n o n e ' ) ; t o o n . i s V a l i d ( ) ; / / f a l s e t o o n . v a l i d a t i o n E r r o r ; / / " A g e s h o u l d b e a n u m b e r " t o o n . s e t ( ' a g e ' , ' n o n e ' , { v a l i d a t e : t r u e } ) ;
  16. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { i d A t t r i b u t e : ' u i d ' } ) ;
  17. v a r P e r s o n =

    B a c k b o n e . M o d e l . e x t e n d ( { i d A t t r i b u t e : ' u i d ' , u r l R o o t : ' u s e r ' } ) ;
  18. v a r t o o n = n e

    w P e r s o n ( { u i d : 1 } ) ; t o o n . f e t c h ( ) ; t o o n . s e t ( ' a g e ' , 3 1 ) ; t o o n . s a v e ( ) ;
  19. Separation data/functionality Tie data related functions related together with the

    data No polling, get alerted on changes (events) Easy communication with server
  20. n e w B a c k b o n

    e . C o l l e c t i o n ( )
  21. v a r C o w o r k e

    r s = B a c k b o n e . C o l l e c t i o n . e x t e n d ( { m o d e l : P e r s o n } ) ;
  22. v a r s o u r c e =

    [ { n a m e : " T o o n K e t e l s " , a g e : 3 0 , j o b : " D e v e l o p e r " , b i o : " < p > S c r u m m a s t e r , b a c k e n d D r u p a l d e v e l o p e r . < / p > " , u i d : 7 5 4 4 , i d : ' t k - 7 5 4 4 - c o r l ' } , { n a m e : " A n K a t r i e n " , a g e : 2 3 , c o u n t r y : " t h e N e t h e r l a n d s " , b i o : " < p > W o r k s i n G e r m a n y . L o v e s t o g a m b l e . < / p > " , u i d : 3 4 0 0 , i d : ' a k - 3 4 0 0 - c o r l ' } ,
  23. v a r c o w o r k e

    r s = n e w C o w o r k e r s ( s o u r c e ) ;
  24. { _ b y I d : O b j

    e c t , l e n g t h : 3 , m o d e l s : A r r a y [ 3 ] }
  25. c o w o r k e r s .

    a t ( 1 ) ; c o w o r k e r s . g e t ( 4 1 0 ) ; c o w o r k e r s . w h e r e ( { c o u n t r y : " t h e N e t h e r l a n d s " } ) ;
  26. v a r s o m e o n e

    = c o w o r k e r s . a t ( 1 ) ; c o w o r k e r s . r e m o v e ( s o m e o n e ) ;
  27. v a r n o o b = n e

    w P e r s o n ( { n a m e : " D r i e s G a a s t r a " , a g e : 1 9 , c o u n t r y : " t h e N e t h e r l a n d s " , j o b : " T h e m e r " , b i o : " < p > P l a y s w i t h c s s a n d j a v a s c r i p t a l l d a y l o n g . < / p > " , u i d : 9 0 1 6 , i d : ' d g - 9 0 1 6 - c o r l ' } ) ; c o w o r k e r s . a d d ( n o o b ) ;
  28. v a r C o w o r k e

    r s = B a c k b o n e . C o l l e c t i o n . e x t e n d ( { m o d e l : P e r s o n , c o m p a r a t o r : ' a g e ' } ) ;
  29. c o w o r k e r s .

    c o m p a r a t o r = f u n c t i o n ( m o d e l ) { r e t u r n m o d e l . g e t ( ' n a m e ' ) ; } c o w o r k e r s . s o r t ( ) ; c o w o r k e r s . c o m p a r a t o r = ' c o u n t r y ' ; c o w o r k e r s . s o r t ( ) ;
  30. c o w o r k e r s .

    o n ( ' s o r t ' , f u n c t i o n ( m o d e l , v a l u e ) { / / . . . } ) ;
  31. c o w o r k e r s .

    o n ( ' c h a n g e : a g e ' , f u n c t i o n ( m o d e l , v a l u e ) { / / . . . } ) ;
  32. c o w o r k e r s .

    o n ( ' a l l ' , f u n c t i o n ( ) { c o n s o l e . l o g ( ' e v e n t e m i t t e d ' ) ; c o n s o l e . l o g ( a r g u m e n t s ) ; } ) ;
  33. v a r C o w o r k e

    r s = B a c k b o n e . C o l l e c t i o n . e x t e n d ( { m o d e l : P e r s o n , u r l : ' u s e r ' } ) ; v a r c o w o r k e r s = n e w C o w o r k e r s ( ) ; c o w o r k e r s . f e t c h ( { d a t a : { p a g e : 1 } } ) ;
  34. Organize sets of models into groups Tie collection related functions

    together with the collection Emit events and aggregate events of models. We no longer need pointers to all the models Easy communication with server
  35. n e w B a c k b o n

    e . V i e w ( )
  36. Views are objects which do two things: 1) display data

    (most of the time models) and 2) capture user interaction to trigger code.
  37. root DOM element node v a r v i e

    w = n e w B a c k b o n e . V i e w ( { e l : $ ( ' # m a i n ' ) } ) ;
  38. v a r P e r s o n V

    i e w = B a c k b o n e . V i e w . e x t e n d ( { c l a s s N a m e : ' p e r s o n - v i e w ' , } ) ; v a r v i e w = n e w P e r s o n V i e w ( ) ;
  39. v a r P e r s o n V

    i e w = B a c k b o n e . V i e w . e x t e n d ( { c l a s s N a m e : ' p e r s o n - v i e w ' , r e n d e r : f u n c t i o n ( ) { t h i s . $ e l . h t m l ( ' < h 2 > T o o n K e t e l s < / h 2 > ' ) ; r e t u r n t h i s ; } } ) ;
  40. v a r v i e w = n e

    w P e r s o n V i e w ( ) ; $ ( ' # m a i n ' ) . a p p e n d ( v i e w . r e n d e r ( ) . e l ) ;
  41. v a r t o o n = n e

    w P e r s o n ( { n a m e : " T o o n K e t e l s " , a g e : 3 0 , j o b : " D e v e l o p e r " , b i o : " < p > S c r u m m a s t e r , b a c k e n d D r u p a l d e v e l o p e r . < / p > " , u i d : 7 5 4 4 , i d : ' t k - 7 5 4 4 - c o r l ' } ) ; v a r v i e w = n e w P e r s o n V i e w ( { m o d e l : t o o n } ) ;
  42. v a r P e r s o n V

    i e w = B a c k b o n e . V i e w . e x t e n d ( { ' c l a s s N a m e ' : ' p e r s o n - v i e w ' , r e n d e r : f u n c t i o n ( ) { v a r c o n t e n t = ' < h 2 > ' + t h i s . m o d e l . g e t ( ' n a m e ' ) + ' < / h 2 > ' ; t h i s . $ e l . h t m l ( c o n t e n t ) ; r e t u r n t h i s ; } } ) ;
  43. v a r P e r s o n v

    i e w = B a c k b o n e . V i e w . e x t e n d ( { ' c l a s s N a m e ' : ' p e r s o n - v i e w ' , i n i t i a l i z e : f u n c t i o n ( ) { t h i s . m o d e l . o n ( ' c h a n g e ' , t h i s . r e n d e r ) ; } , r e n d e r : f u n c t i o n ( ) { v a r c o n t e n t = ' < h 2 > ' + t h i s . m o d e l . g e t ( ' n a m e ' ) + ' < / h 2 > ' ; t h i s . $ e l . h t m l ( c o n t e n t ) ; r e t u r n t h i s ; } } ) ;
  44. t h i s . m o d e l

    . o n ( ' c h a n g e ' , t h i s . r e n d e r ) ; t h i s . l i s t e n T o ( t h i s . m o d e l , ' c h a n g e ' , t h i s . r e n d e r ) ;
  45. < s c r i p t t y p

    e = " t e x t / t e m p l a t e " i d = " p e r s o n - v i e w " > < / s c r i p t > < h 2 > < % = n a m e % > < / h 2 > < p > < s p a n c l a s s = " j o b " > < % = j o b % > < / s p a n > | < s p a n c l a s s = " c o u n t r y " < d i v c l a s s = " c o n t r o l s " > < s p a n c l a s s = ' m o r e ' > M o r e < / s p a n > < s p a n c l a s s < d i v c l a s s = " b i o h i d e " > < % = b i o % > < / d i v >
  46. v a r P e r s o n v

    i e w = B a c k b o n e . V i e w . e x t e n d ( { ' c l a s s N a m e ' : ' p e r s o n - v i e w ' , i n i t i a l i z e : f u n c t i o n ( ) { t h i s . l i s t e n T o ( t h i s . m o d e l , ' c h a n g e ' , t h i s . r e n d e r ) ; } , t e m p l a t e : _ . t e m p l a t e ( $ ( ' # p e r s o n - v i e w ' ) . h t m l ( ) ) , r e n d e r : f u n c t i o n ( ) { v a r c o n t e n t = t h i s . t e m p l a t e ( t h i s . m o d e l . t o J S O N ( ) ) ; t h i s . $ e l . h t m l ( c o n t e n t ) ; r e t u r n t h i s ; } } ) ;
  47. t e m p l a t e : _

    . t e m p l a t e ( $ ( ' # p e r s o n - v i e w ' ) . h t m l ( ) ) , v a r c o n t e n t = t h i s . t e m p l a t e ( t h i s . m o d e l . t o J S O N ( ) ) ;
  48. v a r P e r s o n V

    i e w = B a c k b o n e . V i e w . e x t e n d ( { / / . . . e v e n t s : { ' c l i c k . m o r e ' : ' s h o w M o r e ' , ' c l i c k . l e s s ' : ' s h o w L e s s ' , ' c l i c k h 2 ' : ' g o T o D e t a i l ' , ' m o u s e o v e r ' : ' s t a r t H i g h l i g h t ' , ' m o u s e o u t ' : ' s t o p H i g h l i g h t ' } , s h o w M o r e : f u n c t i o n ( e v e n t ) { / / . . . } , s h o w L e s s : f u n c t i o n ( e v e n t ) {
  49. v a r P e r s o n V

    i e w = B a c k b o n e . V i e w . e x t e n d ( { / / . . . e v e n t s : { ' c l i c k h 2 ' : ' s e l e c t P e r s o n ' , / / . . . } , s e l e c t P e r s o n : f u n c t i o n ( e v e n t ) { i f ( t h i s . m o d e l . g e t ( ' s e l e c t e d ' ) ) { t h i s . m o d e l . s e t ( ' s e l e c t e d ' , f a l s e ) ; } e l s e { t h i s . m o d e l . s e t ( ' s e l e c t e d ' , t r u e ) ; } } ,
  50. User clicks `h2` title View calls `selectPerson` Function will toggle

    the `selected` attribute of the model Model emits `change` event Since the view's render function is tied to this event, `render` get's called Render takes the model's attributes (some of them were just updated) and displays itself with the updated values.
  51. < s c r i p t t y p

    e = " t e x t / t e m p l a t e " i d = " l i s t - v i e w " > < / s c r i p t > < t d > < % - t i t l e % > < t d > < t d > < s p a n c l a s s = " l a b e l l a b e l - i n f o " < % - s e l e c t e d % > < / s p a n > < / t d
  52. v a r T a b l e R o

    w V i e w = B a c k b o n e . V i e w . e x t e n d ( { t a g N a m e : ' t r ' , i n i t i a l i z e : f u n c t i o n ( ) { t h i s . l i s t e n T o ( t h i s . m o d e l , ' c h a n g e : s e l e c t e d ' , t h i s . r e n d e r ) ; t h i s . l i s t e n T o ( t h i s . m o d e l , ' c h a n g e : n a m e ' , t h i s . r e n d e r ) ; } , t e m p l a t e : _ . t e m p l a t e ( $ ( ' # t a b l e - r o w - v i e w ' ) . h t m l ( ) ) , r e n d e r : f u n c t i o n ( ) { v a r c o n t e n t = { s e l e c t e d : t h i s . m o d e l . g e t ( ' s e l e c t e d ' ) ? ' s e l e c t e d ' : ' ' , t i t l e : t h i s . m o d e l . g e t ( ' n a m e ' ) } ; t h i s . $ e l . h t m l ( t h i s . t e m p l a t e ( c o n t e n t ) ) ;
  53. 1. one model, two views 2. view updates itself 3.

    a different view updates the model
  54. Create a view Set its contents Insert it into the

    DOM Pass models so the content is dynamic Auto update its display when model changes Use templates Catch user interaction with "events" property
  55. All user interaction goes via Views, in its events hash

    Separate data (model) from display (view) allows us to have multiple displays Templates keep the views code tidy By binding to model change event, the view automatically gets updated.
  56. By binding to model change event, a view automatically gets

    updated. A view does not care who updates the model or how. One view can update the display of another view via a model, without even knowing it.
  57. By binding to model change event, the view automatically gets

    updated. The view does not care who updates the model or how.
  58. A view binds to the collections change event to automatically

    updated itself. A view does not care who updates the collection or how. One view can update the display of another view via a collection, without even knowing it.