how to create jquery function using onstart and oncomplete - javascript

I'm trying to create my own jquery function, I know how to add options but don't know how to add 'onStart' or 'onComplete' functionality.
this is what I know so far:
jQuery.somefunctionname = function (options) {
var settings = {},
defaults = {
'someoption': 'somevalue',
'someoption2': 'somevalue2',
'someoption3': 'somevalue3'
}
settings = $.extend({}, defaults, options);
//do something functional
alert("hey i'm a function");
}
But If I want the user to be able to add their own code in before (onStart) and after (onComplete) my function, what should I code?
User should be able to write like this:
$.somefunctionname({
'someoption' : 'a',
'someoption2' : 'b',
'someoption3' : 'c',
'onStart' : function() {
//whatever user want when my function started
},
'onComplete' : function() {
//whatever user want when my function ended
} });
thx ;)

Within your function, do something like this:
jQuery.somefunctionname = function (options) {
if (typeof options.onStart === "function")
options.onStart.call(this);
// other function code here
if (typeof options.onComplete === "function")
options.onComplete();
// OR
options.onComplete.call(this);
// OR
options.onComplete.apply(this, argsArrayIfDesired);
// etc.
};
That is, if the property is defined in options and actually is a function then call it at the appropriate point. Specify a setting for this using .call() or .apply() if desired, and include any parameters. Integrate with your settings object or not as desired.

Simply have a default value for those settings of jQuery.noop, and then you can know that it is safe to call the value of that setting as a function, using apply() or similar.
e.g.
jQuery.somefunctionname = function (options) {
var settings = {},
defaults = {
'someoption': 'somevalue',
'someoption2': 'somevalue2',
'someoption3': 'somevalue3',
'onStart': jQuery.noop,
'onComplete': jQuery.noop
}
settings = $.extend({}, defaults, options);
settings.onStart.apply(this);
//do something functional
alert("hey i'm a function");
settings.onComplete.apply(this);
}

Related

How can I extend Backbone.history.navigate?

When I call Backbone.history.navigate, I want to be able to change a global variable.
I want to set
window.linkclicked = true; // when someone clicks a link
and
window.linkclicked = false; // when back button is pushed.
Is there a way to do this using javascript prototypes?
How do I insert that logic inside the "navigate" method?
You can extend the Backbone.history instance and just redefine the navigate function as you wish.
var originalNavigate = Backbone.history.navigate;
_.extend(Backbone.history, {
navigate: function(fragment, options) {
// do stuff before
var returnValue = originalNavigate.apply(this, arguments);
// do stuff after
return returnValue;
},
});
Or with the closure module pattern:
Backbone.history.navigate = (function(navigate) {
return function(fragment, options) {
/* ...snip ...*/
}
})(Backbone.history.navigate);
You can extend the functionality with underscore:
_.extend(Backbone.history.navigate, {
linkClicked : function( bool ){
//handle link clicked
}
});
You can call this with:
Backbone.history.navigate.linkClicked( true );
//or
Backbone.history.navigate.linkClicked( false );

jQuery plugin - update settings after initialization

I have a jQuery plugin, and I want to be able to change options on the fly, like this example: $('.element').pwstabs('options','effect',scale) or something simular to it. I tried adding update: function, tried adding Plugin.prototype.update, but still cant figure out how to do that :)
Here's the structure of the plugin:
;(function ($, window, document, undefined) {
var pluginName = "pwstabs",
defaults = {
effect: 'scaleout',
defaultTab: 1,
containerWidth: '100%',
tabsPosition: 'horizontal',
horizontalPosition: 'top',
verticalPosition: 'left',
responsive: false,
theme: '',
rtl: false,
controlls: false,
next: '',
prev: '',
first: '',
last: '',
auto: false,
play: '',
pause: ''
};
function Plugin(element, options) {
this.element = $(element);
this.$elem = $(this.element);
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function(){
// Here's the code for the plugin
}
};
$.fn[pluginName] = function ( options ) {
return this.each(function () {
new Plugin( this, options );
});
};
})(jQuery, window, document);
So now I use the plugin like:
$('.element').pwstabs({
effect: 'scalein',
defaultTab: 2
});
And when I click a button, i want to change effect to lets say scaleout. With code like:
$('.button').click(function(){
$('.element').pwstabs('options','effect','scalein');
});
So how do I implement this in the plugin?
Currently the only supported invocation pattern in that plugin is to send in an object literal containing the settings to overwrite the defaults. E.g.:
$('.element').pwstabs({
effect: 'scalein',
defaultTab: 2
});
That invocation pattern is defined in the following method:
$.fn[pluginName] = function ( options ) {
return this.each(function () {
new Plugin( this, options );
});
};
As you see, a dictionary of options is sent as the only parameter to the constructor function Plugin() to build the plugin and initialize it.
To support the invocation pattern you need, you would have to modify this method to support both invocation patterns (initialization with an object literal, but also invoking any method with more params, like your options setting method).
Here is an improved function that will handle both invocation patterns. In addition it will also store the instance of a plugin on an element, so you can access the existing settings etc. on subsequent invocations (e.g. settings changes) on the same element.
$.fn[pluginName] = function (options) {
// get the arguments
var args = $.makeArray(arguments),
after = args.slice(1);
return this.each(function () {
// check if there is an existing instance related to element
var instance = $.data(this, pluginName);
if (instance) {
if (instance[options]) {
instance[options].apply(instance, after);
} else {
$.error('Method ' + options + ' does not exist on Plugin');
}
} else {
// create the plugin
var plugin = new Plugin(this, options);
// Store the plugin instance on the element
$.data(this, pluginName, plugin);
return plugin;
}
});
}
This would allow you to invoke the plugin as requested:
$('.element').pwstabs('options','effect','slidedown');
However, this implies you have an 'options' method in the Plugin prototype, so make sure to add one:
Plugin.prototype = {
options: function (option, val) {
this.settings[option] = val;
},
// Constructing Tabs Plugin
init: function () {
// omitted code for brevity
}
}
As you see the options settings just sets the new option on the existing instance. Very simple and efficient. The new setting will be picked up by the click method handler and voila!
Here is a jsFiddle with example code in case you have trouble implementing what i was describing so far:
http://jsfiddle.net/7whs3u1n/6/
Update: I have much improved my answer to get rid of unneeded stuff, include more details and a full implementation that works (check the fiddle above) ;) i hope that this answers your question!
Adding statefulness to your plugin wasn't hard, but when you have spare time also check the alternative mechanism for writing stateful jQuery stateful plugins called jQuery widget factory:
http://learn.jquery.com/plugins/stateful-plugins-with-widget-factory/
In the future you can consider rewriting your plugin to use the widget factory. It would certainly make your code simpler ;)
Try this pattern
(function ($) {
var defaults = {
"text": "abcdefg",
}
, options = $.extend({}, defaults, options);
$.fn.plugin = function (options) {
var options = (function (opts, def) {
var _opts = {};
if (typeof opts[0] !== "object") {
_opts[opts[0]] = opts[1];
};
return opts.length === 0
? def
: typeof opts[0] === "object"
? opts[0] : _opts
}([].slice.call(arguments), defaults));
return $(this).text(options.text)
}
}(jQuery));
$(".results:eq(0)").plugin(); // return `defaults`
$(".results:eq(1)").plugin({"text":"gfedcba"}); // return `options`
$(".results:eq(2)").plugin("text", 123); // return `arguments` as `options`
(function ($) {
var defaults = {
"text": "abcdefg",
}
, options = $.extend({}, defaults, options);
$.fn.plugin = function (options) {
var options = (function (opts, def) {
var _opts = {};
if (typeof opts[0] !== "object") {
_opts[opts[0]] = opts[1];
};
return opts.length === 0
? def
: typeof opts[0] === "object"
? opts[0] : _opts
}([].slice.call(arguments), defaults));
return $(this).text(options.text)
}
}(jQuery));
$(".results:eq(0)").plugin(); // return `defaults`
$(".results:eq(1)").plugin({"text":"gfedcba"}); // return `options`
$(".results:eq(2)").plugin("text", 123); // return `arguments` as `options`
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="results"></div><br />
<div class="results"></div><br />
<div class="results"></div>

JQuery: pass in arguments to plugin to restrict code execution

I'm new to JQuery, and am wondering how exactly I should pass in parameters to a plugin that will restrict which code inside of the plugin gets executed?
Basically, I want to call the plugin in one of two ways:
$(".element").plugin(optionA);
$(".element").plugin(optionB);
UPDATE:
If I call optionA, a dropdown menu appears when you type in text in a text field which, after selection, filters a table. If I call optionB, the dropdown menu does not appear, but instead filters the table automatically. So both options offer different functionality on the same object. Essentially, I only want optionA code within the plugin to be executed if I pass in the optionA argument, and I only want optionB code within the plugin to be executed if I pass in optionB.
Here is the basic plugin structure:
(function ($) {
$.fn.plugin = function (options) {
var settings = $.extend({
//Default Settings
}, options);
return this.each(function () {
//Do some code here
});
};
} (jQuery));
So my question is:
Where do I pass in the parameter?
Do I need to do something like below?
(function ($, optionA, optionB) { ...
Then when I return the .each() function, do something like:
return this.each (function () {
if (optionA) { //execute code}
else if (optionB) { //execute code}
};
Or is it more like this:
return this.each ( function (optionA) {
//Do optionA code here
});
return this.each ( function (optionB) {
//Do optionB code here
});
Or is it neither?? If so, how is it done?
LIVE DEMO
(function ($) {
$.fn.plugin = function (options) {
var settings = $.extend({
filter : "optionA" // use A by default
}, options);
return this.each(function () {
if(settings.filter == "optionA"){
// DO SOMETHING HERE BY DEFAULT
}else if(settings.filter == "optionB"){
// DO SOMETHING IF "optionB" WAS SET
}
});
};
}(jQuery));
$(function(){ // DOM READY
// $(".element").plugin(); // will use A
// $(".element").plugin({filter:"optionA"}); // will use A
// $(".element").plugin({filter:"optionB"}); // will use B
});
try:
var options = {
optionA: value1,
optionB: value2,
optionC: value3,
};
and
$(".element").plugin(options);
just like the css function:
$(".element").css({color:"#f65", display:"block"});

jquery fn.extend() returning values and call values in object

I need some help in understanding something, that propably is easy for serious jquery and javascript programmers.
Lets say I have a code like this:
jQuery.fn.extend({
myNameSpace: {
myPlugIn: function (o) {
var o = { variable : o.variable || false };
var myfunction = function(v) {
o.variable = v;
};
return {
myfunction : myfunction
};
}
});
and now I am able to call that with:
x = new $.myNameSpace.myPlugIn({variable : 99}) ;
and then I call my function myfunction like this
x.myfunction(20);
I can understand that, now the question: how can I get the value of variable inside my plug in.
I tried something like alert(x.o[variable]); etc. but I just cant get it - It must be easy...
What I try to accomplish is a value I could call if something inside the plugin is finished, or calculated.
You can not get the variables inside with your current code, unless you change it to:
var myfunction = function(v) {
o.variable = v;
return v; //or o.variable
};
//...
x.myfunction(20) //20;
Added
It seems like you are trying to make a plugin for jQuery. To create a plugin, you do not use $.extend. $.extend is only used to preset default settings. [1] Normally this is how you set up a plugin:
(function($) {
var methods = {
getVar: function(){
return $.extend({
data: data,
}, methods);
},
setVar: function(d){
data = d;
return methods;
}
},
data = {};
$.fn.myPlugin = function(options) {
//do stuff
data = $.extend( data , options );
return methods;
};
})(jQuery);
http://jsfiddle.net/DerekL/wv5QH/1/

Overriding a function in jQuery plugin

I have an existing jQuery plugin, now I want to extend it. Consider the below mentioned plugin:
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
}
function def() {
//do something
}
};
Now the above one is the plugin I got from somewhere. I need to have custom behavior for abc method, say
function abc() {
//do something else
}
I don't want to change the existing plugin, Can you tell me how could I achieve the same by extending the same or by making my own custom plugin ?
EDIT:
I tried this too with method mentioned below:
(function($) {
$.fn.x = function(option) {
var defaults = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
console.log('Base method called');
}
function def() {
//do something
abc();
}
def();
};
})(jQuery);
(function() {
var x = $.fn.x;
$.fn.x.abc = function() {
console.log('Overidden method called');
//_x.abc();
};
})();
$('<div/>').x();
But I am still getting "Base method called" as the console output.
The best route can vary, but something that I've done in the past is to wrap the extension in my own! This works best when you're trying to operate on something that the plugin does without modifying its underlying code.
(function($){
$.fn.extendedPlugin = function(options) {
var defaults = {
//...
};
var options = $.extend(defaults, options);
//Here you can create your extended functions, just like a base plugin.
return this.each(function() {
//Execute your normal plugin
$(this).basePlugin(options);
//Here you can put your additional logic, define additional events, etc
$(this).find('#something').click(function() {
//...
});
});
};
})(jQuery);
I know this isn't terribly specific (it's hard without a specific scenario), but hopefully it'll get you started down the right path!
This is as far as I got. But when I uncomment _x.abc.apply( this, arguments );, it gets stuck in a recursive loop.
Here's the jsfiddle if someone wants to play with and fix it:
http://jsfiddle.net/TLAx8/
// PLUGIN DEFINITION
(function( $ ){
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
console.log( 'Plugin method called' );
}
function def() {
//do something
}
};
})( jQuery );
// OVERRIDING THE PLUGIN METHOD
(function(){
var _x = $.fn.x;
$.fn.x.abc = function() {
console.log( 'Overidden method called' );
//_x.abc.apply( this, arguments );
}
})();
// INVOKING THE METHOD
(function() {
$.fn.x.abc();
});

Categories