Patterns for DRY-er JavaScript

I came across a little code the other day that reminded me I've been meaning to write about JavaScript patterns I take for granted. The code in question was intended to set the value of some fields in a form when a checkbox was selected; when it was deselected, the same fields were to be emptied. It looked not unlike this:

// config is defined outside of this snippet,
// and may contain more than the properties
// we care about 
$('#myCheckbox').click(function() {         
  if (this.checked) {                 
    $('#field_foo').val(config.foo);                 
    $('#field_bar').val(config.bar);                 
    $('#field_baz').val(config.baz);         
  } else {                 
    $('#field_foo').val('');                 
    $('#field_bar').val('');                 
    $('#field_baz').val('');         
  } 
});

This is a wholly readable bit of code -- there's almost no question what's going on here. On the other hand, it's pretty easy to see the rampant repetition; this code isn't interested in "don't repeat yourself" (DRY). We're calling the same method on every selection we make, and our selections are repeated in both the if and else block. When I saw this code, I had an immediate inclination to rewrite it. Here's what I came up with first:

// config is defined outside of this snippet,
// and may contain more than the properties
// we care about

$('#myCheckbox').click(function() {
        // note whether the checkbox is checked
        var checked = this.checked;

        // iterate over the keys we care about
        $.each(['foo', 'bar', 'baz'], function(i,v) {
                // find the field for the given key
                $('#field_' + v)
                        // and set its value either to the string
                        // stored for the key, or to an empty string,
                        // depending on whether the checkbox was checked
                        .val(checked ? config[v] : '');
        });
});

This looks approximately nothing like the initial code, and without the comments, the code itself would be substantially less readable than the original. The idealistic part of me -- the part that believes people who write JavaScript should understand JavaScript -- says this is an acceptable price to pay. And besides, there's something to be said for explaining the code in a comment that can be stripped by a minifier, rather than explaining the code via the code. In this iteration, we've introduced two patterns for DRY-er code: iterating over an array literal (or, alternately, an object) to achieve repetition without repeating ourselves, and using the ternary operator in place of an if/else statement when the simplicity of our logic allows it. The array literal serves as a list of the fields we care about. When our checkbox is clicked, we iterate over this list, build up a selector for each item in the list, make our selection, and then set the field value using a ternary operator. We've gone from 11 lines of code to six, with the added bonus that we have to do a lot less typing if we need our checkbox to affect more fields. (A side note: Is this premature optimization? I'd argue no, if you've learn to see these patterns before you start writing code. Once you learn how to spot these patterns in a requirement, writing code that embraces them can actually be easier than writing code that takes a more "literal" approach to the problem. For example, imagine if the checkbox affected 20 other fields instead of one? You'd undoubtedly find yourself copying and pasting code if you took the more "literal" approach to the problem, and that would be your first clue that you were doing something inefficiently.) The great thing about using a pattern like this is that it rapidly exposes the actual meat of what you're doing, and makes refactoring far less painful. I also find that it helps me see opportunities for reuse that I might not have spotted in the more literal version of the code. Let's say we're feeling all proud of ourselves for DRYing out our code using clever JavaScript that only super-smart people can read. Now there's another checkbox that needs similar behavior, but it's going to use a different config object and a different list of fields. No problem! You've already written this code, so you can just copy and paste it and then change what's different. Sweet. Er ... suddenly you're not looking so DRY after all. This is when another pattern comes into play: creating a function that returns another function with certain variables already baked in (that is, creating a closure). We'll execute this creator function and then use the function it returns in place of the anonymous function we were using previously when we bound to the click event.

// handleClick accepts a config object
// and a makeSelector function; it returns
// a function that can be bound to 
// a click event, using the config object
// and the makeSelector function to react
// appropriately to the click
var handleClick = function(fields, config, makeSelector) {
        return function() {
                var checked = this.checked;

                fields && $.each(fields, function(i, v) {
                        // build the selector using the provided
                        // makeSelector function
                        $(makeSelector(v))
                                // set the value using the
                                // config object, depending
                                // on whether the checkbox
                                // is checked
                                .val(checked ? config[v]: '');
                });
        };
};

$('#myCheckbox').click(
        // use handleClick to create a function
        // that has these variables baked in;
        // pass the created function as the
        // click handling function
        handleClick(
                ['foo','bar','baz'],
                myCheckboxConfig, 
                function(field) {
                        return '#field_' + field;
                }
        )
);

$('#myOtherCheckbox').click(
        handleClick(
                ['bim','bar','bop'],
                myOtherCheckboxConfig, 
                function(field) {
                        return 'input[name="' + field + '"]';
                }
        )
);

By creating a function that returns a function, we can isolate what's different about the two different handlers while centralizing the pieces that are the same. If your event handling function was slightly less trivial than this one, or if you were binding to five different checkboxes instead of two, the benefit of consolidating the code would be even more substantial. JavaScript offers plenty of patterns for writing DRY-er code; it's important to learn to both recognize and use them. It's also important to recognize when you're writing un-DRY code in the first place -- copying and pasting code is one crystal-clear indicator, but others are more subtle and you may not identify them on the first go-round. For example, take these two functions; each receives a list item as its only argument and returns either the next or previous list item, returning to the beginning or end of the list if there is no next or previous item.

var getNextItem = function($item) {
        return $item.next().length ? 
                $item.next() : $items.first();
};

var getPrevItem = function($item) {
        return $item.prev().length ?
                $item.prev() : $items.last();
};

This felt repetitive when I first wrote it, but I couldn't quickly come up with a single function that would work. A little thinking about it, though, led me to this single function which gets a second argument: direction. That argument is used to decide whether to run the item's next or previous method, and then whether to run the item's first or last method. Besides combining two functions into one, it also eliminates calling next or prev twice inside each function.

var getItem = function($item, direction) {
        var $returnItem = $item[direction]();
        return $returnItem.length ? 
                $returnItem : 
                $items[(direction == 'next') ? 'first' : 'last']();
};

Learning about patterns and then discovering opportunities to use them is one of the more pleasing parts of my job. I hope this helps you identify some of those opportunities for yourself :)

Loading mentions Retweet

Filed under  //  front-end development   howto   javascript  
Comments (24)
Posted 1 month ago

Announcing jQuery Fundamentals: An Open-Source jQuery Training Curriculum

I've been leading jQuery trainings for more than a year now, from tiny gatherings that I organized myself at the local coworking space, to intensive two-day sessions at local web companies, to whirlwind one-day classes at governmental agencies. Over the course of those trainings, I've developed what I'd like to think is a decent curriculum -- training material that's the size of a small book, exercises that demonstrate core concepts, and solutions to those exercises that students can peek at later or when they get stuck. I decided recently that it was time for all of this material to see the light of day, so I spent the last several days converting it all to DocBook files that allow for easy publication to HTML and PDF (and other formats, if I'm later so inclined). I also fleshed out some topics that I'd given short shrift, and started planning sections covering advanced topics such as plugin authoring, code organization, best practices, and more. There's more to come in the next few days, but I think what I've done so far is worth sharing. I hope you'll agree.



My goals in releasing this are several. First and foremost, I want to see people writing better jQuery. The free resources for learning jQuery are scattered across the internets, and my personal experience of learning the library was haphazard — it was a long time before I learned some things I wish I'd known from the get-go. In addition, I want people who are writing jQuery to understand JavaScript. To that end, the book begins with a survey of JavaScript itself before jumping into jQuery. Finally, I want to enlist the bright minds of the jQuery community to help developing a robust, authoritative, in-depth jQuery curriculum, and in exchange it only seemed fair to make it available to everyone. I should mention that the goal of this material is to serve as a companion to a human instructor. That said, individuals may find it useful for self-study, especially if they're diligent about doing the exercises at the end of each chapter. If you're inclined to help -- by adding a chapter, a section, a paragraph, an exercise, or even just a correction -- fork the repo and send me a pull request. I look forward to seeing how this project might evolve with the community's help. Note: If you comment on this post pointing out an issue with the material, I will do my best to tend to the issue, but I probably won't publish your comment, as this post isn't the right place for reporting issues in the code. You can report issues at the repository, but if it's important to you, please fork the repository, make the change, and send me a pull request.

Loading mentions Retweet

Filed under  //  front-end development   howto   javascript   jquery   jquery fundamentals   training  
Comments (35)
Posted 2 months ago

jQuery: Storing and retrieving data related to elements

It’s very common to need to get information about a DOM element when a user interacts with it — for example, perhaps you have an unordered list of names, and when a user clicks on a name, you want to show a picture of the person above the list. In order to do this, you need to figure out which person the clicked list item represents. Many beginning jQuery users will attempt to achieve this by putting ID attributes on each list item, such as id="rebecca". Then, they’ll read the ID attribute off the clicked element and use it to build a URL for the related image.

<ul class="people">
<li id="paul">Paul</li>
<li id="rebecca">Rebecca</li>
<li id="alex">Alex</li>
<li id="adam">Adam</li>
</ul>


var portrait = $('#portrait');

$('ul.people li').click(function() { 
    var name = $(this).attr('id');
    portrait.html('<img class="posterous_download_image" src="/images/people/'%20+%20name%20+%20'.jpg" alt="" />');
});

Strictly speaking, this will work. But is the ID really the right place to store this information? What if you need this behavior on other elements on the page too? You can’t have more than one element with the same ID on the page, so you might find yourself using funny prefixes in your IDs, like person_rebecca, and then stripping out the prefix. You could do it with classes, but then you’d have the opposite problem: you’re using (generally) unique classes like rebecca, but really classes are meant to indicate similarities among a set of elements. And what if you need to store more than one piece of information about an element on the element? Next thing you know you’ve got id="person_alex_red" and you’re jumping through all sorts of hoops to parse out the data you need.

Custom Data Attributes

HTML5 makes available [custom data attributes](http://dev.w3.org/html5/spec/Overview.html#custom-data-attribute, and they prove to be a much more elegant and robust solution to this problem. They’re custom, so they can contain pretty much anything you want, and each element can have as many of them as you want.

<ul class="people">
  <li>Paul</li>
  <li>Rebecca</li>
  <li>Alex</li>
  <li>Adam</li>
</ul>


var $portrait = $('#portrait');

$('ul.people li').click(function() { 
    var $li = $(this),
        name = $li.attr('data-name'),       
        color = $li.attr('data-hairColor'),
        $img = $('<img class="posterous_download_image" src="/images/people/'%20+%20name%20+%20'.jpg" alt="" />');

    $portrait.append($img).css('border', '5px solid ' + color);
});

$.fn.data

When you want to embed information about an element in the HTML you send down from your server, custom data attributes offer a clear and easy solution. But what if you want to attach data to elements that you’ve added to the page using JavaScript? For example, you might have some data you fetched from your server via an Ajax request:

{
    "items" : [
        { "name" : "Paul", "image" : "paul", "hairColor" : "black" },
        { "name" : "Rebecca", "image" : "rebecca", "hairColor" : "brown" },
        { "name" : "Alex", "image" : "alex", "hairColor" : "red" },
        { "name" : "Adam", "image" : "adam", "hairColor" : "red" }
    ]
}

You’re going to iterate over the data to produce a structure much like the one above, but in this case, it doesn’t make sense to store the related data in markup, because you’ll just have to extract it again later. Instead, you can use the $.fn.data() method in jQuery to store the data using JavaScript instead of markup:

var $target = $('ul.people');

$.each(response.items, function(i, data) {
    $('<li/>', { html : data.name })        
      .data({  
        name : data.image,              
        hairColor: data.hairColor       
      })        
      .appendTo($target); 
});

Later, you can read the data off the element using the $.fn.data() method again, this time passing just the name of the key you’re after:

var $portrait = $('#portrait');

$('ul.people li').click(function() { 
    var $li = $(this),
        name = $li.data('name'),
        color = $li.data('hairColor'),
        $img = $('<img class="posterous_download_image" src="/images/people/'%20+%20name%20+%20'.jpg" alt="" />');

    $portrait.append($img).css('border', '5px solid ' + color);
});

Mixing the two methods

This is all well and good, but what if you have a list of people that was sent from the server using HTML and custom data attributes, and then you add elements to it later using JavaScript and store data on them using $.fn.data()? Now your data is stored on elements in two different ways, so how do you extract it reliably? One option is to handle both cases. First, you’ll switch to using jQuery’s delegate method for the event binding, so you don’t have to keep binding click handlers as you add list items to your list. Then, inside of your click handler, you’ll figure out where you can get your data from:

var $portrait = $('#portrait');

$('ul.people').delegate('li', 'click', function() { 
    var $li = $(this), 
        name = $li.attr('data-name'), 
        color, $img;

    if (!name) { // did the li have custom data attributes?
        name = $li.data('name');
        color = $li.data('hairColor');
    } else {
        color = $li.attr('data-hairColor');
    }

    $img = $('<img class="posterous_download_image" src="/images/people/'%20+%20name%20+%20'.jpg" alt="" />');
    $portrait.append($img).css('border', '5px solid ' + color);
});

Another option is to iterate over the original elements, and store the data from the custom data attributes using the $.fn.data() method:

var $portrait = $('#portrait'), 
      $ul = $('ul.people');

$ul.find('li').each(function() {
    var $li = $(this);
    $li.data({
        name : $li.attr('data-name'),
        hairColor : $li.attr('data-hairColor')
    });
});

$('ul.people').delegate('li', 'click', function() { 
    var $li = $(this), 
        name = $li.data('name'),
        color = $li.data('hairColor'),
        $img = $('<img class="posterous_download_image" src="/images/people/'%20+%20name%20+%20'.jpg" alt="" />');

    $portrait.append($img).css('border', '5px solid ' + color);
});

// load more list items via ajax at some point
// to make that whole delegate thing worthwhile

Which option you use will depend on how large your original list is (and thus how long it will take to iterate over it), and how likely people are to click on a lot of items in the list (and thus whether the initial iteration is worth the time). I leave it as an exercise for the reader to decide which approach makes sense for you.

In Conclusion

When you need to attach data to elements and then extract that data later, there are options beyond classes and IDs, and in fact classes and IDs may be an especially poor way to approach the problem. Taking advantage of custom data attributes and the $.fn.data() method in jQuery can make it painless to store and retrieve data related to elements, and the metadata plugin can streamline the process for you even further.

Further Reading

Loading mentions Retweet

Filed under  //  data   howto   html5   javascript   jquery  
Comments (8)
Posted 2 months ago

Building a standalone JavaScriptMVC controller.js

I've been doing a lot of work lately with a client who's using just the controller portion of JavaScriptMVC. I plan to write a more in-depth post about this while I'm traveling this week, but in the meantime, I wanted to jot down the steps to create the standalone controller.js file for my future reference. These instructions work for me on OSX 10.6.

  1. Go to the JavaScriptMVC downloads page on Github
  2. Download the latest version (3.0.0a0 as of this writing) of the framework and unzip it
  3. Open a terminal window and cd to the directory created when you unzipped the file
  4. Run steal/js steal/compress/plugin.js jquery/controller
  5. You should now have a new controller.js file in the directory; you're all set!

Loading mentions Retweet

Filed under  //  howto   javascript   javascriptmvc   jquery  
Comment (1)
Posted 5 months ago

Demystifying custom events in jQuery

This article originally appeared in the May 2009 issue of JSMag. We’re all familiar with the basic events — click, mouseover, focus, blur, submit, etc. — that we can latch on to as a user interacts with the browser. Custom events open up a whole new world of event-driven programming. In this article, we’ll use jQuery’s custom events system to make a simple Twitter search application, but the general concepts should apply to any framework that supports custom events. I confess: it took me a long time to decide to learn about custom events. The built-in events seemed to suit my needs just fine, and it was difficult to understand why I’d want to start adding my own. Boy, was I missing out. It turns out that custom events offer a whole new way of thinking about event-driven JavaScript. Instead of focusing on the element that triggers an action, custom events put the spotlight on the element being acted upon. This brings a bevy of benefits, including:

  • behaviors of the target element can easily be triggered by different elements using the same code;
  • behaviors can be triggered across multiple, similar, target elements at once; and
  • behaviors are more clearly associated with the target element in code, making code easier to read and maintain
Why should you care? An example is probably the best way to explain. Suppose you have a lightbulb in a room in a house. The lightbulb is currently turned on, and it’s controlled by two three-way switches and a clapper, as shown here:
Triggering the clapper or either of the switches will change the state of the lightbulb. The switches and the clapper don’t care what state the lightbulb is in; they just want to change the state. Without custom events, you might write some code like this:
$('.switch, .clapper').click(function() {
        var $light = $(this).parent().find('.lightbulb');
        if ($light.hasClass('on')) {
                $light.removeClass('on').addClass('off');
        } else {
                $light.removeClass('off').addClass('on');
        }
});
With custom events, your code might look more like this:
$('.lightbulb').bind('changeState', function(e) {
        var $light = $(this);
        if ($light.hasClass('on')) {
                $light.removeClass('on').addClass('off');
        } else {
                $light.removeClass('off').addClass('on');
        }
});
$('.switch, .clapper').click(function() { 
        $(this).parent().find('.lightbulb').trigger('changeState');
});
This last bit of code is not that exciting, but something important has happened: we’ve moved the behavior of the lightbulb to the lightbulb, and away from the switches and the clapper. Let’s make our example a little more interesting. We’ll add another room to our house, along with a master switch, as shown here:
If there are any lights on in the house, we want the master switch to turn all the lights off; otherwise, we want it to turn all lights on. To accomplish this, we’ll add two more custom events to the lightbulbs: turnOn and turnOff. We’ll make use of them in the changeState custom event, and use some logic to decide which one the master switch should trigger:
$('.lightbulb').
bind('changeState', function(e) {
        var $light = $(this);
        if ($light.hasClass('on')) {
                $light.trigger('turnOff');
        } else {
                $light.trigger('turnOn');
        }
}).
bind('turnOn', function(e) {
        $(this).removeClass('off').addClass('on');
}).
bind('turnOff', function(e) {
        $(this).removeClass('off').addClass('on');
});

$('.switch, .clapper').click(function() { 
        $(this).parent().find('.lightbulb').trigger('changeState');
});

$('#master_switch').click(function() {
        if ($('.lightbulb.on').length) {
                $('.lightbulb').trigger('turnOff');
        } else {
                $('.lightbulb').trigger('turnOn');
        }
});
A bit more interesting, huh? Note how the rules about what the master switch does belongs to the master switch; the rules about how a lightbulb turns on and off belong to the lightbulb. It’s also worth noting that the master switch is able to affect all of the lightbulbs without having to iterate over them — it just triggers an event on all elements that have the class “lightbulb”. This isn’t critical to the example, but if we were to perform more elaborate manipulations of each lightbulb than adding and removing a class, this would be an important benefit of custom events, as you’ll see in the rest of the article. (If you’re accustomed to object-oriented programming, you may find it useful to think of custom events as methods of objects. Loosely speaking, the object to which the method belongs is created via the jQuery selector. Binding the changeState custom event to all $('.light') elements is akin to having a class called Light with a method of changeState(), and then instantiating new Light objects for each element with a classname of light.)

jQuery Event Primer

Before we dive in, a couple of things we need to recap. In the world of custom events, there are two important jQuery methods: .bind() and .trigger(). I encourage you to read the jQuery docs for details, but basically:
  • The .bind() method takes an event type and an event handling function as arguments. Optionally, it can also receive data, which will be available to the event handling function in the data property of the event object. The event handling function always receives the event object as its first argument.
  • The .trigger() method takes an event type as its argument. Optionally, it can also take an array of values. The first item in the array will be the second argument passed to the event handling function (after the event object).
Confused? I don’t blame you. Read on and I’ll try to clear some things up.

Our Mission

To demonstrate the power of custom events, we’re going to create a simple tool for searching Twitter. The tool will offer several ways for a user to add search terms to the display: by entering a search term in a text box, by entering multiple search terms in the URL, and by querying Twitter for trending terms. The results for each term will be shown in a results container; these containers will be able to be expanded, collapsed, refreshed, and removed, either individually or all at once. When we’re done, it will look like this:

The Setup

We’ll start with some basic HTML:
Twitter Search

Search Results for

This gives us a container (#twitter) for our widget, a template for our results containers (hidden via CSS), and a simple form where users can input a search term. (For the sake of simplicity, we’re going to assume that our application is JavaScript-only and that our users will always have CSS.) First, the setup. We’ll build an $actions object that we’ll use later to create the buttons in each results container, and we’ll also create a global search_terms object so we can store a list of search terms that are being displayed on the page. Next, we’ll do our custom event binding. There are two types of objects we’ll want to act on: the results containers, and the Twitter container.

The Results Containers

The results containers are the heart of the application. We’ll create a setupResults() plugin that will prepare each results container once it’s added to the Twitter container. Among other things, it will bind the custom events for each container and add the action buttons at the top right of each container. Each results container will have the following custom events:
  • The refresh event will mark the container as being in the “refreshing” state, and fire the $.getJSON() request to fetch the data for the search term.
  • The populate event will receive the returned JSON data and use it to populate the container.
  • The remove event will remove the container from the page after the user verifies the request to do so. Verification can be bypassed by passing true as the second argument to the event handler. The remove event also removes the term associated with the results container from the global search_terms object.
  • The collapse event will add a class of collapsed to the container, which will hide the results via CSS. It will also turn the container’s “Collapse” button into an “Expand” button.
  • The expand event will remove the collapsed class from the container. It will also turn the container’s “Expand” button into a “Collapse” button.
The plugin is also responsible for adding the action buttons to the container by cloning the $actions object that was created earlier. It binds a click event to each action’s list item, and uses the list item’s class to determine which custom event will be triggered on the corresponding results container.
// we'll use this every time we add a new results panel,
// so let's build it once and cache it in $actions
var $actions = $('
    '); $('
  • Refresh
  • ').appendTo($actions); $('
  • Remove
  • ').appendTo($actions); $('
  • Collapse
  • ').appendTo($actions); // this is where we'll keep track of which search terms // are shown on the page already var search_terms = {}; Here's the setupResults plugin:
    $.fn.setupResults = function(settings) {
            return $(this).each(function() {
                    
                    var $results = $(this);
                    var $actions = settings.actions;
                    var term = settings.term;
    
                    // change the "Search results for" text
                    $results.find('span.search_term').text(term);
    
                    // bind custom events for results box
                    $results. 
            
                    // the "refresh" event fetches 
                    // the latest content for the term
                    bind('refresh', function(e) {
                            // indicate that the results are refreshing
                            var $this = $(this).addClass('refreshing');
    
                            $this.find('p.tweet').remove();
                            $results.append('Loading ...');
    
                            // get the twitter data using jsonp
                            $.getJSON(
                                    'http://search.twitter.com/search.json?q=' +                                         escape(term) + '&rpp=5&callback=?', 
                                    function(json) { 
                                            $this.trigger('populate', [ json ]); 
                                    }
                            );
                    }).
                    
                    // the "populate" event takes results 
                    // in json format 
                    // and populates the results container
                    bind('populate', function(e, json) {
                            var results = json.results;
                            var $this = $(this);
                            
                            $this.find('p.loading').remove();
    
                            $.each(results, function(i,result) {
                                    var tweet = '' + 
                                            '' +
                                            result.from_user + 
                                            ': ' +
                                            result.text + 
                                            ' ' + 
                                            result.created_at + 
                                            '' +
                                    '';
                                    $this.append(tweet);
                                            });
    
                                            // indicate that the results 
                                            // are done refreshing
                                            $this.removeClass('refreshing');
                                    }).
                                                    // the remove event removes 
                                                    // the results from the page
                                                    // after the user confirms the action
                                                    bind('remove', function(e, force) {
                                                            // allow forced removal without confirmation
                                                            if (
                                                                    !force &&         
                                                                    !confirm('Remove panel for term ' + term + '?')
                                                            ) {
                                                                    return;
                                                            }
                                                            $(this).remove();
    
                                                            // indicate that we no longer 
                                                            // have a panel for the term
                                                            search_terms[term] = 0;
                                                    }).
    
                                                    // the collapse event collapses the results so only the
                                                    // header of the results section is showing
                                                    bind('collapse', function(e) {
                                                            $(this).find('li.collapse').removeClass('collapse')
                                                                    .addClass('expand').text('Expand');
    
                                                            $(this).addClass('collapsed');
                                                    }).
    
                                                    // the expand event
                                                    bind('expand', function(e) {
                                                            $(this).find('li.expand').removeClass('expand')
                                                                    .addClass('collapse').text('Collapse');
    
                                                            $(this).removeClass('collapsed');
                                                    });
    
                                                    if ($actions && $actions.length) {
                                                            // add a clone of $actions to the results panel
                                                            var $a = $actions.clone().prependTo($results);
    
                                                            // use the class of each action to figure out 
                                                            // which event it will trigger on the results panel
                                                            $a.find('li').click(function() {
                                                                    // pass the li that was clicked to the function
                                                                    // so it can be manipulated if needed
                                                                    $results.trigger(
                                                                            $(this).attr('class'), [ $(this) ]
                                                                    );
                                                            });
                                                    }
                                            });
                                    };

    The Twitter Container

    The Twitter container itself will have just two custom events:
    • The getResults event will receive a search term. It will check the global search_terms object to determine whether there’s already a results container for the term; if not, it will add a results container using the results template (div.template), set up the results container using the setupResults() plugin discussed above, and then trigger the refresh event on the results container in order to actually load the results. Finally, it will store the search term in the global search_terms object, so the application knows not to re-fetch the term.
    • The getTrends event will query Twitter for the top 10 trending terms. It will iterate over them and trigger the widget’s getResults event for each of them, thereby adding a results container for each term. Here you can see how we go about passing data to a triggered event.
    The Twitter container bindings are shown here:
    $('#twitter').
    bind('getResults', function(e, term) {
            // make sure we don't have a box for this term already
            if (!search_terms[term]) { 
                    var $this = $(this);
                    var $template = $this.find('div.template');
    
                    // make a copy of the template div
                    // and insert it as the first results box
                    $results = $template.clone().
                            removeClass('template').
                            insertBefore($this.find('div:first')).
                            setupResults({
                                    'term' : term,
                                    'actions' : $actions
                            });
    
                    // load the content using the "refresh" 
                    // custom event that we bound to the results container
                    $results.trigger('refresh');
                    search_terms[term] = 1;
            }
    }).
    
    bind('getTrends', function(e) {
            var $this = $(this);
            $.getJSON('http://search.twitter.com/trends.json?callback=?',                 function(json) {
                            var trends = json.trends; 
                            $.each(trends, function(i, trend) {
                                    $this.trigger('getResults', [ trend.name ]);
                            });
                    });
    });
    So far, we’ve written a lot of code that does approximately nothing, but that’s OK. By specifying all the behaviors that we want our core objects to have, we’ve created a solid framework for rapidly building out the interface. Let’s start by hooking up our text input and the “Load Trending Terms” button. For the text input, we’ll make the form submission stop in its tracks using e.preventDefault(), then capture the term that was entered in the input and pass it to the Twitter widget’s getResults event. (Again, you can see how we go about passing data to a triggered event.) Clicking the “Load Trending Terms” will simply trigger the Twitter widget’s getTrends event:
    $(document).ready(function() {
    
    $('form').submit(function(e) {
            e.preventDefault();
            var term = $('#search_term').val();
            $('#twitter').trigger('getResults', [ term ]);
    });
    
    $('#get_trends').click(function() {
            $('#twitter').trigger('getTrends'); 
    });
    
    });
    Just entering a search term into a text box is boring, of course — the following code shows how we can capture search terms from the URL’s hash (e.g., http://foo.com/index.html#foo,bar):
    $(document).ready(function() {
    
    // pass search terms via URL hash 
    if (document.location.hash) {
            var terms = document.location.hash.split(',').reverse();
            $.each(terms, function(i,term) {
                    $('#twitter').trigger('getResults', [ term ]);
            });
    }
    
    });
    By adding a few buttons with the appropriate IDs, we can make it possible to remove, collapse, expand, and refresh all results containers at once, as shown below. For the remove button, note how we’re passing a value of true to the event handler as its second argument, telling the event handler that we don’t want to verify the removal of individual containers.
    $(document).ready(function() {
    
    $('#refresh').click(function(e) {
            $('#twitter div.results').trigger('refresh'); 
    });
    
    $('#expand').click(function(e) {
            $('#twitter div.results').trigger('expand'); 
    });
    
    $('#collapse').click(function(e) {
            $('#twitter div.results').trigger('collapse'); 
    });
    
    $('#remove').click(function(e) {
            if (confirm('Remove all results?')) {
                    $('#twitter div.results').
                            trigger('remove', [ true ]);
            }
    });
    });
    It should be noted that you don’t have to choose one or all results containers — really, you can choose any results containers you want to affect. For example, if for some (strange) reason you wanted to refresh only the first and last results containers, you could do:
    $('div.results:first, div.results:last').
            trigger('refresh');
    You can see the entire application, including the full HTML and CSS, at http://www.rebeccamurphey.com/jsmag/custom-events/.

    Conclusion

    Custom events offer a new way of thinking about your code: they put the emphasis on the target of a behavior, not on the element that triggers it. If you take the time at the outset to spell out the pieces of your application, as well as the behaviors those pieces need to exhibit, custom events can provide a powerful way for you to “talk” to those pieces, either one at a time or en masse. Once the behaviors of a piece have been described, it becomes trivial to trigger those behaviors from anywhere, allowing for rapid creation of and experimentation with interface options. Finally, custom events can enhance code readability and maintainability, by making clear the relationship between an element and its behaviors.

    Learn More

    Loading mentions Retweet

    Filed under  //  howto   javascript   jquery  
    Comments (7)
    Posted 9 months ago

    Using Objects to Organize Your Code

    This is a reprint of an article that originally appeared in the March 2009 issue of JSMag.

    When you move beyond simple snippets of jQuery and start developing more complex user interactions, your code can quickly become unwieldy and difficult to debug. This article shows you how to start thinking about these interactions in terms of the bits of behavior the feature comprises, using the object literal pattern.

    In the past few years, JavaScript libraries have given beginning developers the ability to add elaborate interactions to their sites. Some, like jQuery, have a syntax so simple that people with zero programming experience can quickly add bells and whistles to their pages. Adding all those bells and whistles, even some pretty elaborate ones, seems to be just a few Google searches away. A copy here, a paste there, a plugin or a few dozen lines of custom code — the client is duly impressed, and you’re adding jQuery to your resume.

    But wait. Now the requirements have changed. Now the thing that needed to work for three elements needs to work for ten. Now your code needs to be reused for a slightly different application where all the IDs are different. We’ve all seen the snippets that make jQuery (and other libraries) look dead-simple. What those snippets leave out — and hey, they’re just snippets, right? — is how to design your code when your needs go beyond dropping in a plugin or doing some show() and hide().

    Introducing the Object Literal pattern

    The object literal pattern offers a way to organize code by the behaviors it comprises. It’s also a means to keep your code from “polluting the global namespace,” which is a good practice for all projects and imperative for larger ones. It forces you to think at the outset about what your code will do and what pieces need to be in place in order for you to do it. An object literal is a way to encapsulate related behaviors, as shown here:

    var myObjectLiteral = {
        myBehavior1 : function() {
            /* do something */
        },
    
        myBehavior2 : function() {
            /* do something else */
        }
    };

    As an artificially simplistic example, suppose you had the jQuery shown in Listing 2 for showing and hiding content when a list item was clicked.

    $(document).ready(function() {
        $('#myFeature li')
            .append('<div/>')
            .each(function() {
                $(this).find('div')
                    .load('foo.php?item=' + $(this).attr('id'));
            })
        .click(function() {
            $(this).find('div').show();
            $(this).siblings().find('div').hide();
        });
    });

    Simple enough, and yet even in this example there are several things you might want to change later — for example, the way you determine the URL for loading the content, the destination of the loaded content, or the show and hide behavior. An object literal representation of the feature cleanly separates these aspects. It might look like this:

    var myFeature = {
        config : {
            $wrapper : $('#myFeature'),
            container : 'div',
            urlBase : 'foo.php?item='
        },
    
        init : function(config) {
            $.extend(myFeature.config, config);
            myFeature.config.$wrapper.find('li').
                each(function() {
                    myFeature.getContent($(this));
                }).
                click(function() {
                    myFeature.showContent($(this));
                });
        },
    
        buildUrl : function($li) {
            return myFeature.config.urlBase + $li.attr('id');
        }, 
    
        getContent : function($li) {
            $li.append(myFeature.config.container);
            var url = myFeature.buildUrl($li);
            $li.find(myFeature.config.container).load(url);
        },
    
        showContent : function($li) {
            $li.find('div').show();
            myFeature.hideContent($li.siblings());
        },
    
        hideContent : function($elements) {
            $elements.find('div').hide();
        }
    };
    
    $(document).ready(function() { myFeature.init(); });

    Because the initial example was incredibly simplistic, the object literal incarnation is longer. Truth be told, the object literal method generally won’t save you lines of code. What it will save is headaches. By using an object literal, we’ve broken our code into its logical parts, making it easy to locate the things we might want to change down the road. We’ve made our feature extendable, by providing the ability to pass in overrides to the default configuration. And, we’ve done some limited self-documentation — it’s easy to see at a glance what the feature does. As your needs grow beyond the simplicity of this example the benefits of the structure will become clearer, as you’ll see below.

    _Note: For an excellent primer on objects, properties, and methods, check out Object-Oriented JavaScript: Create scalable, reusable high-quality JavaScript applications and libraries by Stoyan Stefanov. You may also want to read up on JSON (JavaScript Object Notation).

    An in-depth example

    Our mission will be to create a UI element that features multiple pieces of content divided into several sections. Clicking on a section will show a list of items in the section; clicking on an item in the left nav will show the item in the content area. Whenever a section is shown, the first item in the section should be shown. The first section should be shown when the page loads.

    Step 1: Crafting the HTML

    Writing good semantic HTML is a crucial prerequisite to writing good JavaScript, so let’s start by thinking about what the HTML for something like this might look like. The HTML should:

    • Make sense (and work) when JavaScript isn’t available.
    • Provide a predictable DOM to which we can attach JavaScript.
    • Avoid unnecessary IDs and classes (and you might be surprised by how few are necessary).

    With those guidelines in mind, we’ll start with this html. Note that we haven’t included any markup to display the section navigation or the item navigation; those pieces will be added by jQuery since they will only work with jQuery; non-JavaScript users will get nice semantic markup. (If there’s anything surprising or confusing in that HTML, now would be a good time to read up on POSH (plain-old semantic HTML) and progressive enhancement.)

    Step 2: Scaffolding the Object

    My first step in creating an object for a feature is to create “stubs” within the object. Stubs are basically placeholders; they’re the outline for the feature we’re going to build. Our object will have the following methods:

    • myFeature.init() will run on $(document).ready(). It will turn the semantic HTML we start with into a JavaScript-enabled user interface.
    • myFeature.buildSectionNav() will be called by myFeature.init(). It will take a jQuery object that contains all of the sections from the semantic HTML and use those sections to build the top navigation. It will bind the click handlers to the top navigation items so that clicking on them will show the appropriate section.
    • myFeature.buildItemNav() will be called by myFeature.showSection(). It will ake a jQuery object that contains all of the items associated with the section from the semantic HTML, and use them to build the side navigation. It will bind the click handlers to the side navigation items so that clicking on them will show the appropriate content.
    • myFeature.showSection() will be called when the user clicks on an item in the top navigation. It will use the navigation item that’s clicked on to figure out which section to show from the semantic HTML.
    • myFeature.showContentItem() will be called when the user clicks on an item in the side navigation. It will use the navigation item that’s clicked on to figure out which content item to show from the semantic HTML.

    We’ll also make room for a configuration property, myFeature.config, which will be a single location for setting default values rather than scattering them throughout the code. We’ll include the ability to override the defaults when we define the myFeature.init() method.

    var myFeature = { 
        'config' : { },
        'init' : function() { },
        'buildSectionNav' : function() { },
        'buildItemNav' : function() { },
        'showSection' : function() { },
        'showContentItem' : function() { }
    };

    Step 3: The Code

    Once we’ve built this skeleton, it’s time to start coding. Let’s start by setting up a simple myFeature.config object and writing the myFeature.init() method:

    'config' : { 
        // default container is #myFeature
        'container' : $('#myFeature')
    },
    
    'init' : function(config) { 
        // provide for custom configuration via init()
        if (config && typeof(config) == 'object') {
            $.extend(myFeature.config, config);
        }
    
        // create and/or cache some DOM elements 
        // we'll want to use throughout the code
        myFeature.$container = myFeature.config.container;
    
        myFeature.$sections = myFeature.$container.
            // only select immediate children!
            find('ul.sections > li'); 
    
        myFeature.$section_nav = $('<p/>')
          .attr('id','section_nav')
          .prependTo(myFeature.$container);     
    
        myFeature.$item_nav = $('<p/>')
          .attr('id','item_nav')
          .insertAfter(myFeature.$section_nav);     
    
        myFeature.$content = $('<p/>')
          .attr('id','content')
          . insertAfter(myFeature.$item_nav);   
    
      // build the section-level nav and    
      // "click" the first item
      myFeature.buildSectionNav(myFeature.$sections);   
      myFeature.$section_nav.find('li:first').click();      
    
      // hide the plain HTML from sight
      myFeature.$container.find('ul.sections').hide();      
    
      // make a note that the initialization    
      // is complete; we don't strictly need this   
      // for this iteration, but it can come in handy   
      myFeature.initialized = true;  
    }

    Next we’ll create the myFeature.buildSectionNav() method:

    'buildSectionNav' : function($sections) {
    
        // iterate over the provided list of sections
        $sections.each(function() {
    
            // get the section
            var $section = $(this);     
    
            // create a list item for the section navigation
            $('<li/>')
              // use the text of the first h2
              // in the section as the text for
              // the section navigation
              .text($section.find('h2:first').text())
    
              // add the list item to the section navigation
              .appendTo(myFeature.$section_nav)
    
              // use data() to store a reference
              // to the original section on the
              // newly-created list item
              .data('section', $section)
    
              // bind the click behavior
              // to the newly created list itme
              // so it will show the section
              .click(myFeature.showSection);
    });

    Next we’ll create the myFeature.buildItemNav() method:

    ‘buildItemNav’ : function($items) {

    // iterate over the provided list of items
    $items.each(function() {
    
        // get the item
        var $item = $(this);
    
        // create a list item element for the
        // item navigation
        $('<li>')
    
          // use the text of the first h3
          // in the item as the text for the
          // item navigation
          .text($item.find('h3:first').text())
    
          // add the list item to the item navigation
          .appendTo(myFeature.$item.nav)
    
          // use data to store a reference 
          // to the original item on the 
          // newly created list item
          .data('item', $item)
    
          // bind the click behavior to the
          // newly created list item so it will
          // show the content item
          .click(myFeature.showContentItem);
    
    });

    Finally, we’ll write the methods for showing sections and content items:

    'showSection' : function() { 
        // capture the list item that was clicked on
      var $li = $(this);
    
      // clear out the left nav and content area
      myFeature.$item_nav.empty();
      myFeature.$content.empty();
    
      // get the jQuery section object from the orginal HTML,
      // which we stored using data() during buildSectionNav
      var $section = $li.data('section');
    
      // mark the clicked list item as current
      // and remove the current marker from its siblings
      $li.addClass('current')
        .siblings().removeClass('current');
    
      // find all of the items related to the section
      var $items = $section.find('ul li');
    
      // build the item nav for the section
      myFeature.buildItemNav($items);
    
      // "click" on the first list item in the section's item nav
      myFeature.$item_nav.find('li:first').click();
    
    }, 
    
    'showContentItem' : function() {
      var $li = $(this);
    
      // mark the clicked list item as current
      // and revmoe the current marker from its siblings
      $li.addClass('current')
        .siblings().removeClass('current');
    
      // get the jQuery item object from the original HTML,
      // which we stored using data during buildContentNav
      var $item = $li.data('item');
    
      // use the item's HTML to populate the content area
      myFeature.$content.html($item.html());
    }

    All that’s left to do is to call the myFeature.init() method:

    $(document).ready(myFeature.init);

    You can see the whole thing (including a little CSS to make it presentable) here.

    Step 4: Changing Requirements

    No project is complete without some last-minute change in the requirements, right? Here’s where the object literal approach really shines by making it quick and fairly painless to implement last-minute changes. What if we need to get the content item excerpts via AJAX instead of from the HTML? Assuming the backend is set up to handle it, try this:

    var myFeature = {
    
        'config' : { 
            'container' : $('#myFeature'),
    
            // configurable function for getting
            // a URL for loading item content
            'getItemURL' : function($item) {
                return $item.find('a:first').attr('href');
            }
    
        },
    
        'init' : function(config) { 
            // stays the same   
        },
    
        'buildSectionNav' : function($sections) {
            // stays the same   
        },
    
        'buildItemNav' : function($items) {
            // stays the same   
        },
    
        'showSection' : function() { 
            // stays the same
        },
    
        'showContentItem' : function() {
    
            var $li = $(this);
    
            $li.addClass('current').
                siblings().removeClass('current');
    
            var $item = $li.data('item');
            var url = myFeature.config.getItemURL($item);
    
            // myFeature.$content.html($item.html());
            myFeature.$content.load(url);
    
        }
    
    };

    Do you need more flexibility? There’s a lot more you can configure (and therefore override) if you really want to make this flexible. For example, you can use myFeature.config to specify how to find and process the title text for each item in the left nav.

    var myFeature = { 
        'config' : { 
            'container' : $('#myFeature'),
    
            // specify the default selector
            // for finding the text to use
            // for each item in the item nav
            'itemNavSelector' : 'h3',
    
            // specify a default callback 
            // for "processing" the jQuery object
            // returned by the itemNavText selector
            'itemNavProcessor' : function($selection) {
                return 'Preview of ' + 
                    $selection.eq(0).text();
            }
        },
    
        'init' : function(config) {
            // stays the same
        },
    
        'buildSectionNav' : function($sections) {
            // stays the same
        },
    
        'buildItemNav' : function($items) {
    
            $items.each(function() {
                var $item = $(this);
    
                // use the selector and processor 
                // from the config
                // to get the text for each item nav
                var myText = myFeature.config.itemNavProcessor(
                    $item.find(myFeature.config.itemNavSelector)
                );
    
                $('<li/>')
                // use the new variable                 
                // as the text for the nav item                 
                  .text(myText)
                  .appendTo(myFeature.$item_nav)
                  .data('item', $item)
                  .click(myFeature.showContentItem);        
          });   
      },    
    
      'showSection' : function() {      
        // stays the same   
      },    
    
      'showContentItem' : function() {      
        // stays the same   
      }  
    
    };

    Once you’ve added defaults to the config object, you can override them when you call myFeature.init():

    $(document).ready(function() { 
        myFeature.init({ 'itemNavSelector' : 'h2' });
    });

    Beyond the scope of this article (but also interesting to contemplate and much easier with the object literal pattern) is this: making the back button retrace your path through the tabs using the jQuery history plugin. I leave it as an exercise for the reader.

    Conclusion

    If you’ve stepped through the code examples in this column, you should have a basic understanding of the object literal pattern and how it might prove useful to you as you develop more complex features and interactions. You also have access to some code that you can use to build on this basic foundation.

    I encourage you to give this pattern a try the next time you find yourself writing more than a few lines of JavaScript — it forces you to think through the elements and behaviors that make up a complex feature or interaction. Once you become proficient, it provides a sturdy foundation for extending and reusing your code.

    Learn More

    Loading mentions Retweet

    Filed under  //  howto   jquery  
    Comments (7)
    Posted 10 months ago

    My first guest post!

    Steve Reynolds, web services manager at Sony Computers (SCEE), contacted me last week about writing a guest post on his blog, reynoldsftw.com, and I happily obliged. Check out my post there about custom events in jQuery, and how they can change your approach to event binding by putting the emphasis on the element being acted on, rather than the element doing the acting.

    Loading mentions Retweet

    Filed under  //  front-end development   howto   jquery  
    Comment (1)
    Posted 1 year ago

    Twitter for personal branding: Getting started

    This post is focused on using Twitter for "personal branding" -- establishing yourself as an influential voice on a topic in which you have some expertise. I want to say up front that I don't deign to suggest that I'm adding anything new to the sea of "getting started on Twitter" content that's out there. However, I just got home from drinks with a friend, and when we parted she seemed intrigued by the idea of using Twitter to more firmly establish herself as an expert in her field, a task for which I think Twitter is particularly well suited. I was going to write her an email, but instead I thought I would write down some notes for her and anyone else who happens to be reading. If you've read any posts on this topic already, there's probably not much new to read here; if you haven't, I suggest you read this and then keep reading -- there are a whole lot of opinions on how best to use Twitter for all sorts of purposes, and these are just mine. That said, here's my abbreviated list of steps for getting started on Twitter if personal branding is your goal. Below this list, I've also noted a few Twitter vocabulary terms you'll probably want to know.

    Getting Started

    • Step 1: Sign up for a Twitter account at twitter.com. Since the focus is on personal branding, choose a username that has some association with your actual name. Pay a quick visit to the Settings page, and pay special attention to the Notices tab; you'll probably want to receive e-mails about direct messages from other Twitter users, and also e-mails when people follow you. On the Account tab, make sure the "Protect my updates" checkbox is NOT checked -- otherwise, you're defeating the purpose.
    • Step 2: Download a desktop Twitter application. I run TweetDeck on my desktop, and TwitterFox in Firefox. TweetDeck is great because it allows you to have several panels that you can view at once. I have one for viewing messages for people I'm following, one for capturing tweets related to a search term, one for public replies to my tweets, and one for direct messages from people I'm following. TweetDeck and other applications are also great because they have built-in tools for filtering tweets, replying to tweets, following users, shortening URLs, etc. -- once you start using TweetDeck or something similar, you'll rarely need to return to the Twitter site.
    • Step 3: Start tweeting. If you read something interesting related to your area of expertise, write about it. If you do something interesting for work, write about it. If you're traveling, write about it. If you have a question about your field, ask it. Strive to be professional but human. Remember that you only have 140 characters, so choose your words carefully, and strive to include keywords. Remember to shorten URLs so long ones don't eat up precious characters.
    • Step 4: Follow people. After you've been posting ("tweeting") for a few days and you're ready for people to start paying attention, go to search.twitter.com or use TweetDeck to search for keywords related to your area of expertise. Read what's being said, and click on the usernames of the person saying it. If that user's posts ("tweets") are generally interesting to you, click the button on their page to follow them, and you'll start to see their tweets on your Twitter homepage. It's customary (but not required) that users follow people who follow them, so if you choose the people you follow with care, chances are they will follow you back.
    • Step 5: Keep participating. Take a little time each day to scan the tweets from people you're following and from search terms you're watching. Reply to people, retweet interesting things other people are saying, and post your own new content. Over time you'll discover the interesting people, and start to accumulate your own followers. Remember that people will decide whether to pay attention to you based on how much you're contributing -- that doesn't mean you need to tweet 20 times a day, but once or twice a day is a reasonable pace.

    Twitter Vocabulary

    Some of the words surrounding Twitter can make it sound a bit foreign, or at least geeky and slightly uncool. Here's what they mean so you won't be so intimidated:
    • Tweet: Messages posted by Twitter users, or, as a verb, the act of posting a message on Twitter.
    • Follow: This is like "friending" someone on Facebook; when you follow someone, you are saying that you want to read what they say. Their tweets will appear on your Twitter homepage, as well as in TweetDeck and other Twitter applications.
    • Reply: Replies are like notes to people posted on a public bulletin board: there's no strict guarantee they'll read it, and anyone else is welcome to read it. You can reply to any user, and sending topical replies to people can be a great way to get them to follow you. To reply to someone, put an @ symbol before their username. For example: @rmurphey great tweet!
    • Direct Message: Direct messages are like e-mail, and in most cases they'll arrive in the user's actual email inbox. Unlike replies, they are not public; only the user receives them. To send a direct message to someone, put a d followed by a space before their username. For example: d rmurphey this is a secret message.
    • Retweet: If you like someone's tweet, you can retweet it. There's no official syntax for this, but the customary way to do it is to put RT before their message (and then to truncate their original message as necessary). For example: RT @rmurphey just wrote a great blog post.
    Good luck! Don't forget to follow me @rmurphey.

    Loading mentions Retweet

    Filed under  //  howto   twitter  
    Comment (1)
    Posted 1 year ago

    jQuery validation and TinyMCE

    Just solved a problem where the jQuery validation plugin wasn't playing so nicely with TinyMCE -- the validation plugin was trying to validate the textarea before TinyMCE had a chance to copy the editor contents back to the textarea. I was about to yank TinyMCE out of the page but a little reading through the TinyMCE docs led me to try this:

    $('#mySubmitButton').click(function() {
        var content = tinyMCE.activeEditor.getContent(); // get the content
        $('#myTextarea').val(content); // put it in the textarea
    });
    
    $('#myForm').validate();
    And what do you know, it works. One note: it's important to bind the content replacement to the click event of the submit button, not to the actual form submission, or else the validation may try to run before the content gets copied back to the textarea.

    Loading mentions Retweet

    Filed under  //  howto   jquery  
    Comments (20)
    Posted 1 year ago

    6 criteria for evaluating business blog post ideas

    When I work with a client to start a blog, one of the first things I do is ask them to give me a list of ideas they have for what they will write about. Seeing the list helps me assess where they are when it comes to understanding what blogging is about; seeing who offers good ideas gives me insight into who in the company will be a strong contributor. To help evaluate that list, and to evaluate future ideas as they come up, I find it's helpful to provide some really simple criteria by which to evaluate post ideas before you start writing. They need to be adapted to fit the particular situation, of course, but in general I think they are a good starting point:

    • Can you write a headline for it right now (even if it might change once you're done writing)? If not, you may want to think a bit more about what you want to say before you sit down to write it. Ideas like "exploring trends in the industry" don't pass this test; ideas like "5 ways [insert service here] will help you [solve a problem]" are obviously going to make better blogging fodder. Having an idea at the outset of what you're going to write will help focus your writing. Here are some examples of blog headline approaches to get you started.
    • Does it provide some value to the reader? A post that doesn't solve a problem, point to a resource, or otherwise leave the reader more informed than when they arrived may be more suited to a news and events section. Viget has a good discussion of the difference between a blog and a news and events section.
    • Can you write it in a well organized, scannable format? Bulleted lists and copy interspersed with subheads are your friend; long essays, not so much. Think about how you'll organize your ideas, and remember that blog readers will scan your content to find information of interest to them; it's in your interest to help them find what they're looking for.
    • Can you think of at least two links you'll include in your post? Links have the altruistic benefit of pointing readers to more information on a subject, but they also give your post visibility through trackbacks. If not, you may need to do a bit more homework before you start writing, or you may be trying to write about a subject with which you don't have a ton of expertise. Can you reframe the subject, or find someone else in the business who may be better qualified to write about it?
    • Can you research and write it in less than two hours? If not, the topic may be too broad, or you may not be sufficiently fluent in the subject to be writing about it in a blog setting. Perhaps more importantly, you may be overinvesting your valuable time. Some of the best posts are written from personal experience with the subject: solving a problem for a customer or client, attending a conference, trying out a product. The real-world experience makes you more capable of writing something compelling and valuable about it than if you approach the subject cold and need to do a bunch of research.
    • Lastly, is the topic related to your business, at least tangentially? If not, this isn't a deal-killer, but you may want to evaluate whether it fits with the overall objective of your business blog.

    Loading mentions Retweet

    Filed under  //  howto   small business websites   social media  
    Comments (2)
    Posted 1 year ago