I'm trying to give my plugin callback functionality, and I'd like for it to operate in a somewhat traditional way:
myPlugin({options}, function() {
/* code to execute */
});
or
myPlugin({options}, anotherFunction());
How do I handle that parameter in the code? Is it treated as one full entity? I'm pretty sure I know where I'd place the executory code, but how do I get the code to execute? I can't seem to find a lot of literature on the topic.
Just execute the callback in the plugin:
$.fn.myPlugin = function(options, callback) {
if (typeof callback == 'function') { // make sure the callback is a function
callback.call(this); // brings the scope to the callback
}
};
You can also have the callback in the options object:
$.fn.myPlugin = function() {
// extend the options from pre-defined values:
var options = $.extend({
callback: function() {}
}, arguments[0] || {});
// call the callback and apply the scope:
options.callback.call(this);
};
Use it like this:
$('.elem').myPlugin({
callback: function() {
// some action
}
});
I don't know if I understand your question correctly. But for the second version: This would call anotherFunction immediately.
Basically your plugin should be some kind of function that looks like this:
var myPlugin = function(options, callback) {
//do something with options here
//call callback
if(callback) callback();
}
You have to provide a function object as callback, so either function(){...} or anotherFunction (without () ).
Bringing back a blast from the past.
Worth noting that if you have two arguments passed, for example:
$.fn.plugin = function(options, callback) { ... };
Then you call the plugin without the options argument but with a callback then you'll run into issues:
$(selector).plugin(function() {...});
I use this to make it a little more flexible:
if($.isFunction(options)) { callback = options }
I think this might help you
// Create closure.
(function( $ ) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
onready: function(){},
//Rest of the Settings goes here...
}, options );
// Plugin definition.
$.fn.hilight = function( options ) {
//Here's the Callback
settings.onready.call(this);
//Your plugin code goes Here
};
// End of closure.
})( jQuery );
I had shared a article about Creating your Own jQuery Plugin.I think you should check that http://mycodingtricks.com/jquery/how-to-create-your-own-jquery-plugin/
Change your plugin function to take a second parameter. Assuming that the user passes a function, that parameter can be treated as a regular function.
Note that you can also make the callback a property of the options parameter.
For example:
$.fn.myPlugin = function(options, callback) {
...
if(callback) //If the caller supplied a callback
callback(someParam);
...
});
An example bit late, but it can be useful.
Using arguments can create the same functionality.
$.fn.myPlugin = function() {
var el = $(this[0]);
var args = arguments[0] || {};
var callBack = arguments[1];
.....
if (typeof callback == 'function') {
callback.call(this);
}
}
Related
I am looking through someone else's code and keep seeing functions written in this style:
getConsents: (_, callback = () => {}) => {
const data = {};
callback(data, true);
}
I'm aware some use the underscore as a convention for skipping a parameter when it's not appropriate, though I cannot make sense of why the callback function parameter is written in this manner.
I tried using babel to see if it made anymore sense in es5, though was out of luck:
getConsents: (function (_) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var data = {};
callback(data, true);
});
If someone could explain this convention, or detail what it this is doing, it would be much appreciated.
Since ES6 you can specify default values for function parameters. For example:
function greet(name = 'John Doe') {
console.log('hello', name);
}
greet('Alan Alda');
greet();
The function in your example is defaulting the callback parameter to an empty function. That way it can blindly call it without checking for undefined first.
In ES5 it might look something like:
getConsents: (function(_, callback = function() {}) {
const data = {};
callback(data, true);
})
It's just setting a default value for the callback.
I would like to bind or chain a callback/function to another function.
There is a similar question (without any valid answer): jQuery , bind a callback to any function
But, for me I would not want to be limited only to jQuery realm.
I looking for a broader answer, I wonder if it's possible with vanilla javascript or library other than jQuery.
Example:
// a function which I don't want or I can't edit it's body
var thirdPartyObject = {
doSomething: function(args) {
// a lot of code
console.log('doing stuff: ' + args);
}
};
// my function
var easyCallback = function() {
// processing stuff
console.log('doing more stuff');
}
// the bind
magicLibrary.bind(thirdPartyObject.doSomething, easyCallback);
// run
thirdPartyObject.doSomething(1);
thirdPartyObject.doSomething(10);
When I run this "code", the following output represents the behaviour I'm looking for:
doing stuff: 1
doing more stuff
doing stuff: 10
doing more stuff
Is it possible?
EDIT: the bind is a conceptual term, maybe you think this like a chain, trigger or even another term.
But the import is the second function or callback which in my example is easyCallback() must be somehow connected to the first one doSomething().
And every time the doSomething() is called or executed I want the easyCallback() to be executed as well after the first is finished.
But the without "wrapping" them around or without rewriting the first one.
You would have to wrap the doSomething function inside yet another function, like so:
// a function which I don't want or I can't edit it's body
var thirdPartyObject = {
doSomething: function(args) {
// a lot of code
console.log('doing stuff: ' + args);
}
};
// my function
var easyCallback = function() {
// processing stuff
console.log('doing more stuff');
}
// the bind
// magicLibrary.bind(thirdPartyObject.doSomething, easyCallback);
const doSomething = thirdPartyObject.doSomething.bind(thirdPartyObject);
thirdPartyObject.doSomething = function(args) {
doSomething(args);
easyCallback(args);
};
// run
thirdPartyObject.doSomething(1);
thirdPartyObject.doSomething(10);
I want to extend all of my application's ajax calls with some special case handlers and be able to refire the method that started the ajax call if I need to. The problem I am having is I cannot get the name of the calling function that triggered the ajax call from my anonymous function event handlers, either ajaxSend or ajaxSuccess. I have tried all of the variations of caller/callee that are commented below plus many others. Here is some sample code:
var ajaxcaller;
$(document).ajaxSend(function(event,xhr,settings){
// Before we fire off our call lets store the caller.
// ajaxcaller = arguments.callee.caller.name;
//alert("get caller:"+arguments.callee.caller.name);
//alert("get caller:"+caller.name);
//alert("get caller:"+this.caller.toString());
//alert("get caller:"+event.caller.toString());
});
$(document).ajaxSuccess(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Successful ajax call but not results we expected, let's refire
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
$(document).ajaxError(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
Here's an idea, however I am not sure how reliable it would be, but you could intercept jQuery.ajax calls and append a caller property to the options that would reference the calling function as well as an args property that would reference the arguments that were passed to that function.
I am sure that if you play around with that idea, you will find a solution to your problem. If you don't like the idea of overriding jQuery.ajax, you could simply make sure to pass those references as options in all your ajax calls.
DEMO: http://jsfiddle.net/zVsk2/
jQuery.ajax = (function (fn) {
return function (options) {
var caller = arguments.callee.caller;
options.caller = caller;
options.args = caller.arguments;
return fn.apply(this, arguments);
};
})(jQuery.ajax);
$(document).ajaxSend(function (e, xhr, options) {
console.log('caller', options.caller);
console.log('args', options.args);
});
function getRecords(someArgument) {
return $.ajax({
url: '/echo/json/',
dataType: 'json',
data: {
json: JSON.stringify({ test: someArgument})
}
});
}
getRecords(1);
getRecords(2);
I found a bug, and tracked it down.
You can see a simplified example of my code here.
As it turns out, I need to debounce my if() statement rather than debouncing the function itself.
I'd like to keep the debounce as a standalone function, but I'm not sure then how to pass the conditional in.
Any pointers?
Here's the code:
var foo = function(xyz) {
alert(xyz);
};
function setter(func, arg1, arg2) {
return {
fn: func,
arg1: arg1,
arg2: arg2
};
}
function debounce(someObject) {
var duration = someObject.arg2 || 100;
var timer;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
someObject.fn(someObject.arg1);
timer = 0;
}, duration);
}
var toggle = true;
if (toggle) {
debounce(setter(foo, 'The best things in life are worth waiting for.', 1250));
} else {
foo('Instant gratification is sweet!!');
}
Using your example, why not pass toggle in as arg 1... something like:
var toggle = true;
var debouncedFunk = function(toggle) {
if (toggle)
// the function call
else
// something else
};
debounce(debouncedFunk, toggle, 1250);
You should also look into using the Function objects .call and .apply methods. They are for calling the function and passing in arguments. Taking the example function:
var example = function(one, two) {
// Logic here
};
You can call it in three ways:
// First
example(1, 2);
// Second
example.call({}, 1, 2);
// Third
example.apply({}, [ 1, 2 ]);
The first is the standard way to call a function. The difference between the first and the .call is that the first parameter to .call is the context object of the function (what this will point to inside the function), the other parameters are passed after that (and a known list is required for .call. The benefit of .apply is that you can pass an array to the function of arguments and they will be assigned to the parameter list appropriately, the first parameter is still the context object.
It would simplify your debounce function, instead of having to deal with a structured object as you currently do.
A suggestion for your debounce:
var debounce = function(funk, delay) {
var args = [];
if (arguments.length > 2)
args = [].slice.call(arguments, 2);
setTimeout(function() { funk.apply({}, args); }, delay);
};
Changing your current if to:
var toggle = true;
var debouncedFunk = function(toggle) {
if (toggle)
// Do if true
else
// DO if false
};
debounce(debouncedFunk, 1000, toggle);
Maybe too much information (sorry)?
As a last note, I'd recommend using a framework (if possible) where these functions have been implemented already (and many other useful functions) such as Underscore. Using Underscore your example would look like:
// Define debouncedFunk and toggle
debouncedFunk = _.bind(debouncedFunk, {}, toggle);
debouncedFunk = _.debounce(debouncedFunk, 1000);
debouncedFunk();
EDIT
Fixed the underscore example, _.debounce returns a function that will execute only after the delay but it still needs to be called.
var ajaxStuff = (function () {
var doAjaxStuff = function() {
//an ajax call
}
return {
doAjaxStuff : doAjaxStuff
}
})();
Is there any way to make use of this pattern, and fetch the response from a successful ajaxcall when calling my method? Something like this:
ajaxStuff.doAjaxStuff(successHandler(data){
//data should contain the object fetched by ajax
});
Hope you get the idea, otherwise I'll elaborate.
Two things:
1. Add a parameter to the doAjaxStuff function.
2. When invoking doAjaxStuff, pass in an anonymous function (or the name of a function)
var ajaxSuff = (function () {
var doAjaxStuff = function(callback) {
// do ajax call, then:
callback(dataFromAjaxCall);
}
return {
doAjaxStuff : doAjaxStuff
}
})();
// calling it:
ajaxStuff.doAjaxStuff(function(data){
//data should contain the object fetched by ajax
});
Just let doAjaxStuff accept a callback:
var doAjaxStuff = function(callback) {
// an ajax call
// Inside the Ajax success handler, call
callback(response); // or whatever the variable name is
}
Depending on your overall goals, you could also use deferred objects instead (or in addition). This makes your code highly modular. For example:
var doAjaxStuff = function() {
// $.ajax is just an example, any Ajax related function returns a promise
// object. You can also create your own deferred object.
return $.ajax({...});
}
// calling:
ajaxStuff.doAjaxStuff().done(function(data) {
// ...
});
I believe you need to read the jQuery docs for jQuery.ajax. You could make a call as simple as:
$.ajax('/path/to/file').success(function (data) {
doStuff();
})