2

I'm thinking of the following functionality:

$('.aclass').MyPluginInit()
$('.aclass').SomeMethodOfMine()

but how do we get from the first to the second line? In the ideal world, I'd be able to trap the exception generated in line 2 (when I attempt to invoke a method that doesn't exist), loop through the set of objects that $('.aclass') represents and for each, look at a property (say, $this) that contains said method and was placed there by the call to .MyPluginInit(). I would then invoke the method.

the problem is I can't trap the exception and find my way back to the object on which it was raised. the handler for window.onerror will tell me the url and line number that produced the exception but I can't tie that to an object.

any thoughts on how else I could accomplish my raising of the dead (or never-born in this case)?

  • ekkis

p.s. I did read Autovivification and Javascript, but what I'm asking is a bit different.

Community
  • 1
  • 1
ekkis
  • 9,804
  • 13
  • 55
  • 105

2 Answers2

0
// define your initializer
function MyPluginInit () {
  var e;
  for (e in this) {

    // give this object the method
    this[e].SomeMethodOfMine = function () {
      console.log("Wee!");
    }
  }
}

// call init using the array-ish thing returned by jQuery as `this`
MyPluginInit.call($(".aclass"));

// to call the method, you need to refer to an *element* in the array
// this is because we only gave the method to the elements, not to the array itself
$(".aclass")[0].SomeMethodOfMine();

I couldn't think of a great way to do this, but this code is functional and doesn't require any strange global exception handling. Alternatively, have you considered modifying the prototype of the array's elements? Then you'd only need to include some logic in your method to determine how to act in case the elements haven't been "initialized".

Normally I would recommend adding SomeMethodOfMine to the prototype of the object returned by jQuery, but that turns out to be Object, so it's probably not a good idea.

bkconrad
  • 2,620
  • 3
  • 20
  • 30
  • thanks for replying. ya, not quite there... having to dereference isn't pretty, and no, adding it to the Object prototype isn't a great idea. I did solve it though. will post separately here so I can mark it as an answer – ekkis May 22 '12 at 23:46
0

this is what I came up with: put the following function in some library you include before including plugins that use it:

function PluginMaker() {
    var plugin = url2fn($('script:last').attr('src'));
    $.fn[plugin] = function (opts) {
        opts = $.extend(true, {}, $[plugin], opts);
        for (fn in opts.fx) this[fn] = fxmk(fn);    // auto-vivification of methods
        this.each(function () { if (!this['$' + plugin]) this['$' + plugin] = opts; });
        opts.init(opts);  // plugin initialisation
        this.init(opts);  // per-object initialisation
        return this;
    };
    function fxmk(nm) {
        return function () {
            var args = arguments;
            this.each(function () {
                this['$' + plugin].fx[nm].apply(this, args);
            });
            return this;
        };
    }
    return plugin;
}

then define your plugins like this:

// -- myplugin.js ---------------------------------------------------------------

(function ($) {
    $[PluginMaker()] = {
        // whatever state data you want to keep for your plugin
        fx: {
            MyMethod1: function () { /* within these methods */ },
            MyMethod2: function (msg) { /* this refers to the HTML element */ },
            // whatever other methods you want to define
            init: function (opts) {
                // used for per-element initialisation
            }
        },
        init: function(opts) {
            // used for plugin initialisation (one time)
        }
    };
});    

then, having included the plugin you can do:

$('.class').MyPlugin({ /* whatever options */ });
$('.class').MyMethod1();

or even:

$('#someId').MyMethod2();
ekkis
  • 9,804
  • 13
  • 55
  • 105