jQuery Plugins

Keep them warm and toasty

By @johnkpaul

Rate this talk

Who?

John K. Paul

I work for Conde Nast

I ♥ JavaScript


@johnkpaul

john@johnkpaul.com

johnkpaul.com

Invention

Some start from nothing

Some start with something

jQuery plugins

write less, do more

Actually using plugins

To Each Their Own

  • A lightweight start
  • Widget factory
  • Widget factory + RequireJS
  • Namespaced pattern
  • Custom events (Publish/Subscribe)
  • Extend pattern
  • Non Widget-factory widget
  • Prototypal inheritance pattern
  • Universal Module Definition pattern
  • ...

on their own...

Backbone Views

  • widget initialization
  • event binding
  • ORGANIZATION

1.  var CenterPhotoCarouselView = Backbone.View.extend({
2.    el: '.center-carousel',
3.    events:{
4.      'click .left-arrow': 'moveCarouselLeft'
5.      'click .right-arrow': 'moveCarouselRight'
6.    },
7.    initialize: function(){
8.      var photoCount = this.$el.find('li').length;
9.    },
10.   moveCarouselLeft: function(event){}
11. });                                    
                                    

Backbone + Plugin?

Throw it all into initialize or render!


1. var CenterPhotoCarouselView = Backbone.View.extend({
2.   el: '.center-carousel',
3.   initialize: function() {
4.     this.$el.find('ul').jcarousel({
5.       jcarouselNext: '.next',
6.       jcarouselPrev: '.prev',
7.       auto: 2,
8.       vertical: false,
9.       scroll: 1,
10.      btnNextEvent: 'click',
11.      btnPrevEvent: 'click',
12. 
13. 
14. 
15. 
16. 
17.     });
18.   }
19. });                                    
                                    

What's wrong?

  • Duplication

Fix?

  • Don't Repeat Yourself
  • Separate details from specific views

duplication--


1.  var CarouselView = Backbone.View.extend({
2.   initialize: function(options){
3.     this.carouselOptions = _.defaults(options, {
4.       jcarouselNext: '.next',
5.       jcarouselPrev: '.prev',
6.       auto: true
7.       //required jQuery plugin initialization 
8.       //spaghetti goes here
9.     });
10.    this.$el.find('ul').jcarousel(this.carouselOptions);
11.  }
12. });
13.
14.  var centerCarouselView = new CarouselView({
15.    el: '.photos-boston',
16.    jcarouselNext: '.next-boston',
17.    jcarouselPrev: '.prev-boston'
18.  });
                                    

What's wrong?

Rigidity

Something new will always come along

What to do?

Design Patterns

Facade

We use facades all the time

  • Backbone.Model.prototype.save
  • Backbone.History
  • $(document).ready(func);
  • $.ajax(options);
  • $('input').val(newVal);

let's build a facade

Facade

How to find important pieces?

Which parts differ?

  • Need external config?
  • Need external control?
  • Need proxied events?

Need external config?

  • next element selector
  • prev element selector
  • auto start


1. var CarouselView = Backbone.View.extend({
2.   initialize: function(options){
3.      var carouselOptions = _.defaults(options, {
4.        nextButtonSelector: '.next',
5.        prevButtonSelector: '.prev',
6.        autoStart: false
7.       //required jQuery plugin initialization 
8.       //spaghetti goes here
9.      });
10.     this.$el.find('ul').jcarousel({
11.       jcarouselNext: carouselOptions.nextButtonSelector,
12.       jcarouselPrev: carouselOptions.prevButtonSelector,
13.       auto: carouselOptions.autoStart
14.     });  
15.  }
16. });                                    
17.
18. //no jCarousel anywhere
19. var bostonView = new CarouselView({
20.   el: $('.photos-boston'),
21.   nextButtonSelector: '.next',
22.   prevButtonSelector: '.prev',
23.   autoStart: true //your own name if you want
24. });
                                    

Need external control?

  • carouselView.moveLeft(2)
  • carouselView.start()
  • carouselView.stop()


1. var CarouselView = Backbone.View.extend({
2.   moveRight: function(){
3.      this.$el.data('jcarousel')('move')(1)
4.   },
5.   moveLeft: function(){
6.      this.$el.data('jcarousel')('move')(-1)
7.   },
8.   start: function(){
9.      this.$el.data('jcarousel')('startAuto');  
10.  },
11.  stop: function(){
12.     this.$el.data('jcarousel')('stopAuto');
13.  }
14. });                                    
15.
16. bostonView.start();
                                    

Need proxied events?

  • slideStart
  • slideEnd


var CarouselView = Backbone.View.extend({
  initialize: function(){
     if(this.onSlideStart) { 
       this.$el.data('jcarousel')
               .on('slide', _.bind(this.slideStart, this));
     }
     if(this.onSlideEnd) { 
       this.$el.data('jcarousel')
               .on('slide', _.bind(this.slideEnd, this));
     }
  }
});                                    

var BostonView = CarouselView.extend({
  initialize: function(){
    CarouselView.prototype.initialize.apply(this, arguments);
  },
  onSlideStart: function(){
    // update carousel progression counter
  }
});

                                    

Sensitivity


  • complexity is hidden
  • changes are much easier

Law of Demeter


Principle of Least Knowledge

My Goal

Takeaways

  • jQuery plugins are a necessity
  • Find what you need to customize
    • Configuration
    • Control
    • Events

Resources

Thank You

By @johnkpaul

john@johnkpaul.com