views:

95

answers:

2

Hey Everyone,

This maybe a very mundane question, but this is the first jQuery plugin that I write 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, its 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

A: 

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({
...
});
jitter
+2  A: 
jQuery(document).ready(function($) {
  $('#so-flair').jStackOverflow({domain:"superuser.com", id: 30162 });
  $('#su-flair').jStackOverflow({domain:"stackoverflow.com", id: 91130 });
});

COMPLETELY REWRITED ;-)

    (function($){


  $.fn.jStackOverflow = function(options) {

    // build main options before element iteration
    var opts = $.extend({}, $.fn.jStackOverflow.defaults, options);

    // iterate and reformat each matched element
    return this.each(function() {
      $this = $(this);

      // build element specific options
      var opt = $.meta ? $.extend({}, opts, $this.data()) : opts;

      //get single id
      var id = $this.attr('id');

      var flair = $.fn.jStackOverflow.flair( opt , id );

      $this.html(flair);
    });
  };




  $.fn.jStackOverflow.setApis = function (options)
        {
            var apis = options.protocol + options.domain + "/users/flair/" + options.id + "." +options.format;

            if (options.makeCallbacks)
            {
                apis += "?callback=?";
            }

            return apis;

        }; 


  $.fn.jStackOverflow.flair = function( options , id ){

            //this.setOptions(options);
            //var self = this;
            var api = $.fn.jStackOverflow.setApis(options);

            if ( options.makeCallbacks )
            {
                var result = $.getJSON( api , function(data){ $.fn.jStackOverflow.flairCallback(data,options,id)});
            } else {
                var result = $.getJSON( api , function(data){ $.fn.jStackOverflow.flairCallback(data,options,id)});
            }

            return result;
        };

  $.fn.jStackOverflow.flairCallback =  function(data, options,id)
                        { 

                          // console.log(options);
                           $("#"+id+" "+options.gravatarId).append(data.gravatarHtml);
                           $("#"+id+" "+options.reputationId).append(data.reputation);
                           $("#"+id+" "+options.badgesId).append(data.badgeHtml);
                           $("#"+id+" "+options.displayNameId).append(data.displayName);
                           $("#"+id+" "+options.profileUrlId).attr("href", data.profileUrl).append("Visit my profile");
                        };


  $.fn.jStackOverflow.defaults = {
            protocol:       "http://",
            domain:         "stackoverflow.com",
            format:         "json",          
            gravatarId:     ".gravatar",
            displayNameId:  ".displayName",
            reputationId:   ".reputation",
            badgesId:       ".badges",
            profileUrlId:   ".profileurl",
           // parentId:       "", 
            makeCallbacks:  true

  };

})(jQuery);​​​​​​​​​​

This work as expected! ;-) DEMO: http://jsbin.com/epeti3

Let me know!

aSeptik
Wow, I wasn't expecting a complete rewrite, just some general guidance. I guess I need to spend some time reading more about objects in Javascript.Thanks so much for the help.
Travis
no problem Bro! ;-)
aSeptik