JavaScript Modularity with Plugins & Widgets

Modular JavaScript with Plugins & Widgets

Don Smith

Senior Program Manager

Microsoft patterns & practices

Use arrow keys to navigate and Ctrl/Cmd -/+ to adjust text and positioning

Agenda

Project Silk
Client-side Web
Development for
Modern Browsers

http://silk.codeplex.com

http://tinyurl.com/projectsilk

Consequences

A Delicious Example

Unit Testing

Assertions in QUnit:

 
            var ok = function ok(value, msg, results) {
                var result = value ? 'pass' : 'fail';
                $('<div class="test-result">').text(msg)
                    .addClass(result)
                    .appendTo(results);
            };
        
 
            ok(true, 'ok');
            ok('100' == 100, 'equal');
            ok('100' === 100, 'not equal');
        
ok(true, 'ok', '#test-result'); ok('100' == 100, 'equal', '#test-result'); ok('100' === 100, 'not equal', '#test-result');

Object Modules

Object Modules

Creating Objects

            // While using the 'new'
            // keyword is possible
            var obj = new Object(); 
            
            // The object literal 
            // syntax is preferred
            var obj = {},
                t = typeof obj;
            ok(t == 'object', ':-)');
        
var obj = {}, t = typeof obj ; ok(t == 'object', ':-)', '#obj-result');
        // Defining properties 
        // and methods is easy
        var obj = {
            id: 44,
            innerObj: {
                prop: 'content',
                run: function(arg) {
                    return 'done';
                }
            }, // beware of the commas
            ary: [12, 
                'more', 
                {'even-more': 'items'}]
        };
    

Object Modules

Defining Functions

        // Function expression (anonymous) - preferred
        var func1 = function(args) { return 'result'; };

        // Function expression (named) - needed during recursion
        var func2 = function func2(args) { };

        // Function statement (named & hoisted) - can safely avoid
        function func3(args) { }

        // And can be passed into and out of functions
        var func4 = function(arg) { return arg; };
        var result = func4( func1 )();

    
var func1 = function(args) { }; ok(this.func1 == undefined, '1: ' + func1.name, '#func-result'); ok(func2 == undefined, '2: ' + func2.name, '#func-result'); var func2 = function func2(args) { }; ok(func2 == undefined, '2: ' + func2.name, '#func-result'); ok(func3 == undefined, '3: ' + func3.name, '#func-result'); function func3(args) { }

Object Modules

Understanding Context

    // Differ only in how parameters are passed
    // function.call(objContext, arg1, arg2)
    // function.apply(objContext, argArray)
    var obj = { p: 'foo' },
        func = function() { return this.p || 'default'; },
        result = func.call(obj);
    ok(result == 'foo', 'context changed');
    
var obj = { p: 'foo' }, func = function() { return this.p || 'default'; }, result = func.call(obj); ok(result == 'foo', 'context changed', '#context-result');

Object Modules

Closures

    var count = 0,
        setupLinkHandler = function(link) {
            link.addEventListener('click', function(e) {
                this.text('Clicked ' + count + ' times');
                e.preventDefault();
            });
        };
    

So variables can live beyond their scope

Object Modules

Immediate Functions

        (function(app, $, undefined) {
            var priv1 = 'foo',
                priv2 = 'bar',
                calc = function() { 
                    return 'baz'; 
                };

            app.myObj = {
                prop: priv1 + calc(),
                memb: function() {
                    // impl
                }
            };
        }(this.app = this.app || {}, jQuery));
    

Object Modules

When to use objects as modules

Let's have a closer look at the QuickStart

jQuery Plugin Modules

Notable things about jQuery

  • $ is the synonym for jQuery
  • Made up of:
    • Utility functions
    • Element functions
  • Method chaining is intentional

jQuery Plugin Modules

Selectors

    $('selector')
    'element'
    '#id'
    '.class'
    '.class1.class2'  // and
    '.class1, class2' // or
    'element decendent-element'
    '#id > child-element'
    'element[attribute]'
    'element[attribute="value"]'
    
    // And some useful extras
    'element[attribute^="val"]' 
    'element[attribute$="lue"]' 
    ':button'
    ':checked'
    ':even'
    ':nth-child(n)'

    // To increase performance
    $('selector', context)...
    wrapper.find('selector')...
    

jQuery Plugin Modules

The Wrapped Set

        var wrappedElems = $('
'), wrappedElem = wrappedElems.first(), nakedElem = wrappedElems[0]; ok(wrappedElem.css, 'wrapped'); ok(nakedElem.css, 'wrapped');
var wrappedElems = $('
'), wrappedElem = wrappedElems.first(), test = wrappedElems[0]; ok(wrappedElem.css, 'wrapped', '#wrap-result'); ok({}.css, 'wrapped', '#wrap-result'); // cheating :(

jQuery Plugin Modules

Declaring Plugins

    (function ($, undefined) {
        var timer;
        $.fn.tagger = function () {
            return this.each(function () {
                var $this = $(this);
                $this
                .addClass('qs-tagged')
                .bind('mouseenter', function (evnt) {
                })
                .bind('mouseleave', function () {
                });
            });
        };
    } (jQuery));
    

jQuery Plugin Modules

Options

    (function ($, undefined) {
        $.fn.infobox = function(options){
            this.options = { 
                maxItems: 10,
                dataUrl: 'http://feeds.delicious.com/v2/json/popular/'
            };
            $.extend(this.options, options);
        };
    } (jQuery));
    

jQuery Plugin Modules

When to use Plugins

Let's have a closer look at the QuickStart

jQuery UI Widget Modules

jQuery UI Widget Modules

How they work

jQuery UI Widget Modules

Public & Private methods

jQuery UI Widget Modules

Lifetime Management

jQuery UI Widget Modules

Options

    $.widget('qs.infobox', {
        options: {
            dataUrl: '',
            maxItems: 10
        }
    });
    
    $('body').infobox({
        dataUrl: 'http://feeds.delicious.com/v2/json/popular/'
    });
    

jQuery UI Widget Modules

Events

jQuery UI Widget Modules

When to use widgets as modules

Let's have a closer look at the QuickStart

Identifying Module Boundaries

JavaScript Objects jQuery Plug-ins jQuery UI Widgets
Infrastructure Modules Ideal OK No
Behavioral Modules OK Ideal OK
UI Modules No OK Ideal

Summary

Questions?

Contact Info

This presentation is online @

http://locksmithdon.net/talks/jsmodularity.html