Is there a way to wrap a jquery function to an object? - javascript

Is there anyway to limit the scope of a jquery function to an object other than using a main function:
(function( $ ) {
$.fn.myLib = function( funcName ) {
if ( action === "func1") {
// Open popup code.
}
if ( action === "func2" ) {
// Close popup code.
}
};
}( jQuery ));
I'd like to do it so that I could call functions like this:
$(el).myLib.func1();
$(el).myLib.func2();

There's really not a lot of good reason to try to do this:
$(el).myLib.func1();
Because the this pointer when func1() executes will be myLib and you won't be able to access $(el). So, it doesn't do you a whole lot of good unless all you want is static methods. If that's what you actually want, then you can do this:
$.fn.myLib = {};
$.fn.myLib.func1 = function(...) {...};
$.fn.myLib.func2 = function(...) {...};
If you actually want to be able to have acceess to the jQuery object (which I presume), then stick to one level and use a name prefix which gives you about the same level of name conflict protection anyway.
$.fn.myLibFunc1 = function(...) {...};
$.fn.myLibFunc2 = function(...) {...};
Then, you can do:
$(el).myLibFunc1();
And, the this pointer in myLibFunc1 will be the jQuery object that called it.

(function( $ ) {
$.fn.myLib = function( funcName ) {
var obj=new Object
obj.func1=function () {alert('first')}
obj.func2=function () {alert('second')}
return obj
};
}( jQuery ));

Related

Create parameter based jquery plugin

I have a long jquery function and I want to separate it as an plugin.
Normally, most jquery plugin has a selector element as below.
;( function( $, window, document, undefined )
{
'use strict';
$.fn.myPlugin = function( options )
{
// codes goes here
}
})( jQuery, window, document );
and the usage is something like this.
$('.element').myPlugin();
But in my case, the javascript function doesn't really need a selector element, it only expect a value(parameter).
e.g
function coolMethods(Str){
return Str + doSomething;
}
So, how can I use this as a plugin?
I would expect the usage is like this
myPlugin.coolMethods(Str) // and this should return a value.
If you don't need any jquery functionality (the $(selector). part) and you want to call it like
myPlugin.CoolMethod("abc")
then you need a namespace rather than a plugin.
There's a number of ways to generate namespaces and scripts to help this, but essentially a namespace is an object that contains functions, the basic setup would be:
var myPlugin = {};
myPlugin.CoolMethod = function(param1) {
return param1 + param1;
};
// to use this:
console.log(myPlugin.CoolMethod("abc"))
Once you start using namespaces, you can then have private methods/variables within that namespace if needed and can easily add other methods / sub-namespaces.
Another common way to setup a namespace is something like:
var myPlugin = myPlugin || {};
(function(myplugin, $) {
// can also use $ within the namespace declaration
myplugin.CoolMethod = function(param1) {
return param1 + param1;
};
})(myPlugin, jQuery);
// to use this:
console.log(myPlugin.CoolMethod("abc"))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
There is no problem! you can create your plugin in this case and use it on each element without any relation with it!
generally, is not necessary that your function uses JQuery elems.
example:
$.fn.NewFunc /*Your plugin function*/ = function(param1){
console.log("Oh! It's ok!!");
console.log(arguments);
};
Usage:
$.fn.NewFunc("Hello!");
or
$("").NewFunc("I Am An Argument!");
or even:
$("AnySelector").NewFunc("param1", "param2");
If you dont need selected elems by selector, you can use other way similar these (this is not a plugin):
$.NewFunc = function(p1, p2){/*do somethings*/};
and use it similar this:
$.NewFunc("param1", "param2");
Here is my version
(function ($, window, document, undefined) {
'use strict';
var PLUGIN_NAME = 'myPlugin';
function plugin(options) {
var opts = $.extend(true, {}, $[PLUGIN_NAME].defaults, options);
_print(opts.name);
}
var _print = function (name) {
console.log(name);
};
$[PLUGIN_NAME] = function (options) {
new plugin(options);
};
$[PLUGIN_NAME].defaults = {
name: 'John'
};
}(jQuery, window, document));
Usage:
$.myPlugin({
name: 'Suzy'
});
Or
$.myPlugin();
Working example

Properly get "this" in jQuery plugin member

I have a JavaScript module that I would like to create a jQuery plugin interface to.
The module itself is like this:
var Foo = (function () {
"use strict";
var self = {};
self.add = function (selector, otherParam)
{
// Does things unto selector.
// Precisely what it does doesn't matter.
};
return self;
}());
and is used, with success, like this:
Foo.add(a);
Now, I would like to create a plugin that interfaces to this module,
so I can use it somewhat like this:
$.fn.foo = Foo;
$.fn.foo.add = function (param) {
var selector = this;
Foo.add(selector, param);
}
$(elem).foo.add(a);
The problem I'm facing is that I can't get "this" working in .add().
The best way I managed to do it was to not have Foo be self-initializing,
and use a syntax like:
$.fn.foo = Foo;
$(elem).foo().add(a);
It works, but I find it less aesthatically pleasing and less "clean".
Is there a way to do this? Am I on the wrong approach altogether?
Thankful for any input, and I apologize in advance if this has already been answered or is unfit in any other way.
I did search for answers, but I'm not well-versed in plugin authoring nor an expert on jQuery itself.
TL;DR: I have a module like Foo above, and would like to access it's members like a jQuery plugin.
Here is a simplified version of the pattern I normally use (error checking and extra features removed).
It uses a single class function and a plugin bridge extension method to allow attachment to multiple elements. Methods are called by using a string option value:
var Foo = (function () {
"use strict";
// Constructor
function Foo($element, options){
this.$element = $element;
this.options = options
this.fooVal = 0;
}
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = ~~this.$element.text()
};
// Add the specified val to the elements current value
Foo.prototype.add = function (val) {
this.fooVal += val;
// Update the element text with the new value
this.$element.text(this.fooVal);
};
return Foo;
})();
// Create a bridge to each element that needs a Foo
$.fn.foo = function (options, args) {
this.each(function () {
var $element = $(this);
// Try to get existing foo instance
var foo = $element.data("Foo");
// If the argument is a string, assume we call that function by name
if (typeof options == "string") {
foo[options](args);
}
else if (!foo) {
// No instance. Create a new Foo and store the instance on the element
foo = new Foo($element, options);
$element.data("Foo", foo);
// Record the connected element on the Foo instance
foo.$element = $element;
// Call the initial create method
foo.onCreate();
}
});
}
// testing
console.clear();
$('#test').foo();
$('#button2').click(function () {
$('#test').foo("add", 2);
});
$('#button10').click(function () {
$('#test').foo("add", 10);
});
For your example Foo takes the initial value from the element text and subsequent "add" calls modify that value.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/3/
Notes:
~~ is just a fast short-cut for parseInt()
You could supply an initial value via the options parameter (ignored in first example). See following:
e.g.
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = this.options.value || ~~this.$element.text()
// Set initial value
this.$element.text(this.fooVal);
};
and start with
$('#test').foo({value: 999});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/4/

jQuery call plugin method from inside callback function

I am using a boilerplate plugin design which looks like this,
;(function ( $, window, document, undefined ) {
var pluginName = "test",
defaults = {};
function test( element, options ) {
this.init();
}
test.prototype = {
init: function() {}
}
$.fn.test = function(opt) {
// slice arguments to leave only arguments after function name
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var item = $(this), instance = item.data('test');
if(!instance) {
// create plugin instance and save it in data
item.data('test', new test(this, opt));
} else {
// if instance already created call method
if(typeof opt === 'string') {
instance[opt].apply(instance, args);
}
}
});
};
})( jQuery, window, document );
Now say i have two <div> with same class container.
And now i would call my test plugin on these divs like so,
$(".container").test({
onSomething: function(){
}
});
Now when function onSomething is called from inside my plugin how can i call that plugin public methods referring to the instance onSomething function was called from?
For example something happened with the first container div and onSomething function was called for only first container div.
To make it a bit more clear I have tried to pass this instance to the onSomething function, that way i expose all plugin data and then i can do something like,
onSomething(instance){
instance.someMethod();
instance.init();
//or anything i want
}
To me me it looks quite wrong so there must be a better way... or not?
Well im not sure if it is the best idea, but you could pass the current object as a parameter. Let's say onSomething : function(obj) { }
So whenever "onSomething" is called by the plugin, you can call it like this: "onSomething(this)" and then refer to the object asobject`
Lets give a specific example.
var plugin = function (opts) {
this.onSomething = opts.onSomething;
this.staticProperty = 'HELLO WORLD';
this.init = function() {
//Whatever and lets pretend you want your callback right here.
this.onSomething(this);
}
}
var test = new Plugin({onSomething: function(object) { alert(object.staticProperty) });
test.init(); // Alerts HELLO WORLD
Hope this helps, tell me if its not clear enough.
Oh wait, thats what you did.

How to add a public method under another public method?

I am developing a website with a large library of JavaScript and jQuery code and I am trying to give it a more organized plugin-like structure. I read an article showing how to use a self-executing anonymous function to help with scope and it also allows your library to grow across files using the "window.namespace = window.namespace || {}" technique.
For example:
//Self-Executing Anonymous Function:
(function( skillet, $, undefined ) {
//Private Property
var isHot = true;
//Public Property
skillet.ingredient = "eggs";
//Public Method
skillet.fry = function() {
// do stuff...
};
//Private Method
function addItem( item ) {
// do stuff...
}
}( window.skillet = window.skillet || {}, jQuery ));
Demo: jsFiddle
My question is, how would I add a public method under skillet.fry(). So I could make a call to something like skillet.fry.cancel();
Or, if there is a better way to do this, I am open to suggestions.
You could try something like this. It would allow you to declare other variables (along with that) that would be available in the closure of cancel().
skillet.fry = (function() {
var that = {};
that.cancel = function() {
//...
}
return that;
})();

JS Object this.method() breaks via jQuery

I'm sure there's a simple answer to this, but it's Friday afternoon and I'm tired. :(
Not sure how to explain it, so I'll just go ahead and post example code...
Here is a simple object:
var Bob =
{ Stuff : ''
, init : function()
{
this.Stuff = arguments[0]
}
, doSomething : function()
{
console.log( this.Stuff );
}
}
And here it is being used:
$j = jQuery.noConflict();
$j(document).ready( init );
function init()
{
Bob.init('hello');
Bob.doSomething();
$j('#MyButton').click( Bob.doSomething );
}
Everything works, except for the last line. When jQuery calls the doSomething method it is overriding 'this' and stopping it from working.
Trying to use just Stuff doesn't work either.
So how do I refer to an object's own properties in a way that allows jQuery to call it, and also allows the object to work with the calling jQuery object?
i.e. I would like to be able to do things like this:
doSomething : function()
{
console.log( <CurrentObject>.Stuff + $j(<CallerElement>).attr('id') );
}
(Where <CurrentObject> and <CallerElement> are replaced with appropriate names.)
This is not jQuery's fault, it is integral to the way JavaScript handles objects.
Unlike in most other object-oriented languages, ‘this’ is not bound on a per-method level in JavaScript; instead, it's determined purely by how the function is called:
Bob= {
toString: function() { return 'Bob!'; },
foo: function() { alert(this); }
};
Brian= {
toString: function() { return 'Brian!'; },
};
Bob.foo(); // Bob!
Bob['foo'](); // Bob!
Brian.foo= Bob.foo;
Brian.foo(); // Brian! NOT Bob
var fn= Bob.foo;
fn(); // window NOT Bob
What you are doing in the case of:
$j('#MyButton').click( Bob.doSomething );
is like the last example with fn: you are pulling the function doSomething off Bob and passing it to jQuery's event handler setter as a pure function: it no longer has any connection to Bob or any other object, so JavaScript passes in the global window object instead. (This is one of JavaScript's worst design features, as you might not immediately notice that window isn't Bob, and start accessing properties on it, causing weird and confusing interactions and errors.)
To remember Bob, you generally make a function as in nickyt's answer, to keep a copy of ‘Bob’ in a closure so it can be remembered at callback time and used to call the real method. However there is now a standardised way of doing that in ECMAScript Fifth Edition:
$j('#MyButton').click( Bob.doSomething.bind(Bob) );
(You can also put extra arguments in the bind call to call doSomething back with them, which is handy.)
For browsers that don't yet support Fifth Edition's bind() method natively (which, at this point, is most of them), you can hack in your own implementation of bind (the Prototype library also does this), something like:
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}
Change
$('#MyButton').click( Bob.doSomething );
to
$('#MyButton').click( function() { Bob.doSomething() } );
You could also add to your Bob object a private field var that = this and use that everywhere in members instead of this if you really want to avoid the anonymous function.
e.g.
var Bob = new function() {
// Private Fields
var that = this;
// Public Members
this.Stuff = '';
this.init = function() {
that.Stuff = arguments[0];
}
this.doSomething = function() {
console.log( that.Stuff );
}
}
The identity of this is a common problem in javascript. It would also break if you tried to create a shortcut to doSomething:
var do = Bob.doSomething;
do(); // this is no longer pointing to Bob!
It's good practice to not rely on the identity of this. You can do that in a variety of ways, but the easiest is to explicitly reference Bob instead of this inside of doSomething. Another is to use a constructor function (but then you lose the cool object-literal syntax):
var createBob = function() {
var that = {};
that.Stuff = '';
that.init = function() {
that.Stuff = arguments[0];
};
that.doSomething = function() {
console.log( that.Stuff );
};
return that;
}
var bob = createBob();
You could always try doing something like this:
$j('#MyButton').click(function(event) {
Bob.doSomething(event, this);
});
Now doSomething will still have Bob for its this, and using the function arguments, it will have the event object, and the element it was triggered on.

Categories

Resources