Question

This may be a very mundane question, but this is the first jQuery plugin that I have written and I'm a bit fuzzy on understanding the scope rules in JavaScript.

I'm trying to write an simple jQuery plugin that wraps around the Stack Overflow API. I'm starting off by trying to work with the Flair API.

I wanted to make the plugin as configurable as possible so that you can easily pass it the domain and user id, and generate multiple Flairs.

    var superUser = $.jStackOverflow.flair({domain:"superuser.com", id: 30162, parentId:'#su-flair'});
    var stackOverflow = $.jStackOverflow.flair({domain:"stackoverflow.com", id: 55954, parentId:'#so-flair'});

The problem is, when it makes the second call, it's somehow using the correct domain and id parameters, but the parentId field that it's using in the callback function to create the HTML is using the first parameter.

You can see the plugin here and the HTML here

Was it helpful?

Solution

UPDATED

DEMO: http://jsbin.com/epeti3/5

/* 16/02/2012 02.04.38 */
(function($) {
    $.fn.jStackOverflow = function(options) {
        var opts = $.extend({},
        $.fn.jStackOverflow.defaults, options);
        return this.each(function() {
            $this = $(this);
            var opt = $.meta ? $.extend({},
            opts, $this.data()) : opts;
            var result;
            var id = this.id;
            var flair = $.fn.jStackOverflow.flair(opt, id);
            $this.html(flair);
        });
    };
    $.fn.jStackOverflow.setApis = function(options) {
        var apis = options.protocol + options.domain + options.gTLD + "/users/flair/" + options.id + "." + options.format;
        if (options.makeCallbacks) {
            apis += "?callback=?";
        }
        return apis;
    };
    $.fn.jStackOverflow.flair = function(options, id) {
        var api = $.fn.jStackOverflow.setApis(options);
        if (options.makeCallbacks) {
            result = $.getJSON(api,
            function(data) {
                $.fn.jStackOverflow.flairCallback(data, options, id);
            });
        }
        return result;
    };
    $.fn.jStackOverflow.flairCallback = function(data, options, id) {
        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                $('<div class="' + key + '"></div>').html(key + ' : ' +data[key]).appendTo('#' + id);
            }
        }
    };
    $.fn.jStackOverflow.defaults = {
        protocol: 'http://',
        domain: 'stackoverflow',
        gTLD: '.com',
        format: 'json',
        makeCallbacks: true
    };
})(jQuery);

use:

<div id="so-flair"></div>

 $(function() {
      $('#so-flair').jStackOverflow({domain:"stackoverflow", id: 91130 });
    });

OTHER TIPS

The problem is that you only have a single instance of your plugin. This means that the two calls to $.jStackOverflow.flair() interfere with each other as both manipulate interal data of a single object.

Check for a demo what happens if there is some delay between the two calls (click the two buttons at the bottom)

http://jsbin.com/esovu (to edit http://jsbin.com/esovu/edit

Suddenly it starts working. So you need to investigate how to write a plugin which supports multiple instances on a single page.

You can pick any "good" jQuery plugin which multiple instances support to check how to do it.

e.g. jQuery Carousel.

Check how the lines interact to allow creating multiple Carousel instances on one page (code taken from jQuery Carousel source)

$.fn.jcarousel = function(o) { //this would match your `jStackOverflow`
    return this.each(function() { //for each matched element return a new carousel
        new $jc(this, o);
    });
};
...
var defaults = {
...
};
...
$.jcarousel = function(e, o) { //the acutal constructor
...
}
...
$jc.fn.extend({
...
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top