jQuery: add callback function to another function - javascript

So I have this function
$.fn.myFunction = function( options, callback ) {
var settings = $.extend({
opacity : '',
margin : ''
}, options );
}
and I do some funny stuff like this
$('.selector').myFunction( options, function() { /* do some stuff */ } );
Where should I specify inside my function about the callback function and how?

Like this :
JS
$.fn.myFunction = function( options , callback ) {
var settings = $.extend({
opacity : '',
margin : ''
}, options );
// where you want your callback
if(callback && typeof callback === "function") callback();
}

A callback is simply a parameter in a function. So, your case could be expressed very simply:
var myFunction = function(options, callback) {
console.log('I am running in the main function');
if (callback) { callback(); }
};
myFunction('', function() {
console.log('I am running in the callback!');
});
Demo is here: http://repl.it/0b0

Related

Passing value from one callback to another callback

I created the following plugin that mostly works. It takes xeditable, but allows for jQueryUI's autocomplete to select the value. It mostly works, however, I am struggling on how to pass the returned id from jQueryUI Autocomplete to the success callback.
How do I pass a value from the jQueryUI autocomplete select callback to the xeditable success callback?
EDIT. I got it working, but think it is a bit of a kludge. What is the proper way to do so?
EDIT #2. See https://jsfiddle.net/fndnu5m0/5/ for a demo.
$('#targetID').xeditableAutoSource({
source: 'getSource.php',
success: function(response, newValue) {
console.log($(this).data('uid')); //This is the value I want!
}
});
(function($){
var defaults = {
source: [], //Replace with URL
placement: 'right',
title: 'XEditable Title',
success: function(response, newValue) {} //id will be $(this).data('uid')
};
var methods = {
init : function (options) {
var settings = $.extend({},defaults, options || {});
this.each(function () {
var $this=$(this).editable({
//send:'never',
placement:settings.placement,
title:settings.title,
success: settings.success
})
.on('shown', function(e, editable) {
var $input=editable.input.$input.val('');
var $button=$input.parent().next().find('button.editable-submit').css('opacity', 0.3)
.bind('click.prevent', function() {return false;});
$input.focus(function() {
$button.css('opacity', 0.3).bind('click.prevent', function() {return false;});
})
.autocomplete({
source: settings.source,
select: function(e, ui) {
$input.blur();
$button.css('opacity', 1).unbind('click.prevent');
$this.data('uid',ui.item.id); //This is the value I need in the success callback!
}
})
.autocomplete('widget').click(function() {return false;});
});
})
},
destroy : function () {
return this.each(function () {
return this.each(function () {});
});
}
};
$.fn.xeditableAutoSource = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.xeditableAutoSource');
}
};
}(jQuery));
Too much code... As far as I understood you want to pass to a function not just a callback but also its parameter. You can try the following technique:
var f1 = function(callback) { //we will pass a callback to this function
callback()
}
var f2= function(param1) { //that will be our callback
console.log(param1)
}
var p = 'Callback will always be called with this parameter'
f1( function() { f2(p) } ) //here we pass f2 with p as a callback to f1
Callback and it's parameter are wrapped into anonymous function. 'f1' and 'f2' are the functions from you libraries, you don't have to modify them, they are needed to illustrate the technique.
With some minor changes you can make it work if a function that accepts a callback passes some other parameters to it:
var f1 = function(callback) {
var p1 = 'Parameter set by f1'
callback(p1)
}
var f2= function(param1, param2) {
console.log(param1 +' '+ param2)
}
var p = 'Constant parameter'
f1( function(p1) { f2(p1, p) } )

Jquery optionally add callbacks

I am trying to write a reusable Jquery form function. I need it to optionally assign callback functions depending on if the function is defined on the page or not.
Is this example I use the Success but would be done for all.
On Main JS File:
function gJs_AjaxCustomSubmit(ObjectContext) {
var AS='';
if (typeof AjaxSuccess == 'function') { AS = 'AjaxSuccess' }
$('#frm').ajaxSubmit({
success: AS, //callback functions
});
}
On the page, if AjaxSuccess function exists, then it would execute on the success callback. If it does not exist, there would be no error.
On normal pages:
function AjaxSuccess(response) {
alert(response);
}
I want to be able to define all the functions on my global JS like this, and then if needed I can just add the actual function to my pages and they will run.
function gJs_AjaxCustomSubmit(ObjectContext) {
var AStart='';
if (typeof AjaxStart == 'function') { AS = 'AjaxStart' }
var ASuccess='';
if (typeof AjaxSuccess == 'function') { AS = 'AjaxSuccess' }
var ABSend='';
if (typeof AjaxBeforeSend== 'function') { AS = 'AjaxBeforeSend' }
var AComplete='';
if (typeof AjaxComplete== 'function') { AS = 'AjaxSuccess' }
var ASt='';
if (typeof AjaxStop== 'function') { AS = 'AjaxStop' }
var AError='';
if (typeof AjaxError== 'function') { AS = 'AjaxError' }
$('#frm').attr("action", $(ObjectContext).data('path'));
$('#frm').ajaxSubmit({
dataType: 'html',
start: AStart, //callback functions
send: ABSend, //callback functions
complete: AComplete, //callback functions
stop: AjaxStop,
success: ASuccess, //callback functions
error: AError, //callback functions
});
}
Here is a clean reusable function that returns either desired function(if it exists) or an empty function if it doesn't.
$('#frm').ajaxSubmit({
start: getFunction('AStart'),
send: getFunction('ABSend'),
complete: getFunction('AComplete'),
//... //callback functions
});
function getFunction(name){
if (typeof window[name] == 'function'){
return window[name];
}
return function(){}; // or null/false
}
If the function passed as parameter by name does not exist, an empty callback will be returned, which will do nothing and not throw any errors.
I ended up using this.
function gJs_AjaxCustomSubmit(ObjectContext) {
//Add function to your page if needed
//AjaxStart
//AjaxBeforeSend
//AjaxComplete
//AjaxSuccess
//AjaxStop
//AjaxError
var DataType = 'html', AStart = '', ASuccess = '', ABSend = '', AComplete = '', AStop = '', AError = '';
if ($(ObjectContext).data('type')) {
DataType = $(ObjectContext).data('type');
}
if (typeof AjaxStart == 'function') { AStart = AjaxStart }
if (typeof AjaxBeforeSend == 'function') { ABSend = AjaxBeforeSend }
if (typeof AjaxComplete == 'function') { AComplete = AjaxComplete }
if (typeof AjaxSuccess == 'function') { ASuccess = AjaxSuccess }
if (typeof AjaxStop == 'function') { AStop = AjaxStop }
if (typeof AjaxError == 'function') { AError = AjaxError }
$('#frm').attr("action", $(ObjectContext).data('path'));
$('#frm').ajaxSubmit({
dataType: 'html',
start: AStart, //callback functions
send: ABSend, //callback functions
complete: AComplete, //callback functions
stop: AStop,
success: ASuccess, //callback functions
error: AError, //callback functions
});
}

How can I create a wrapper function for addEventListener that works with removeEventListener?

I want to create a wrapper function for addEventListener that I can call as such:
aEvt('click', document, function (evt, target) {
//Code here
});
I want to do this because it allows me to always have the event target available first from the start as a parameter.
I attempted such a function, but the problem is, in order to have it work with removeEventListener (or my analogous rEvt function), I have to return a callback from the aEvt function and pass that to removeEventListener as the callback.
The aEvt function I currently have is as follows:
function aEvt(evt, elem, fn) {
'use strict';
var callback = function (evt) {
fn(evt, evt && evt.target ? evt.target : window.event.srcElement);
};
if (elem.addEventListener) {
elem.addEventListener(evt, callback);
} else if (elem.attachEvent) {
elem.attachEvent('on' + evt, callback);
} else {
elem['on' + evt] = callback;
}
return callback;
}
Is there any way I can change the aEvt function so that I can send the target to the callback passed to the aEvt function (i.e., fn), but also have the callback I send to the aEvt function be the same callback that I send to the analogous rEvt function I want to write?
In other words, how should I change aEvt to make the following work?
var callbackFn = function (evt, target) { console.log(target); };
aEvt('click', document, callbackFn);
rEvt('click', document, callbackFn);
Felix Kling, thanks a lot for your answer in the SO post you linked to in the comments.
I took what you did and modified it slightly to 1) follow the JS code standards set at my organization, and 2) make it so that I could get the event target as a parameter in the handler callback.
Having the target available as a parameter makes handling events a lot easier in a majority of the use cases I have as well as greatly minimizes the amount of refactoring required.
Anyway, here's the final code (please note that the each function in remove executes a simple for loop, and return false in the function essentially breaks the loop):
var evts = (function () {
'use strict';
var listeners = [],
add,
remove;
add = function (evt, elem, fn) {
var callback = function (evt) {
fn(evt, evt && evt.target ? evt.target : window.event.srcElement);
};
listeners.push({
evt: evt,
elem: elem,
fn: fn,
callback: callback,
removed: false
});
if (elem.addEventListener) {
elem.addEventListener(evt, callback);
} else if (elem.attachEvent) {
elem.attachEvent('on' + evt, callback);
} else {
elem['on' + evt] = callback;
}
};
remove = function (evt, elem, fn) {
var callback;
each(listeners, function (evtObj) {
if (evtObj.evt === evt && evtObj.elem === elem &&
evtObj.fn === fn && !evtObj.removed) {
evtObj.removed = true;
callback = evtObj.callback;
return false;
}
});
if (elem.removeEventListener) {
elem.removeEventListener(evt, callback);
} else if (elem.detachEvent) {
elem.detachEvent('on' + evt, callback);
} else {
elem['on' + evt] = null;
}
};
return {
add: add,
remove: remove
};
}());
And here's an example of using the methods:
var callback = function (evt, target) {
console.log(target);
};
evts.add('click', document, callback);
evts.remove('click', document, callback);

How to apply to the parameters that I have to create a plug-in plugin

(function( $ ){
var methods = {
init : function( options ) {
var settings = $.extend({ //Объявление настроек по умолчанию, которые можно переопределить в вызове плагина
code: 7,
listHeight: 160,
placeholder: "925000000",
phoneNumber: ""
}, options);
},
getCode : function( ) {
return $(this).settings.code;
}
};
$.fn.telephoneNumber = function( method ) {
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Метод с именем ' + method + ' не существует.' );
}
};
})( jQuery );
I need to refer to a variable code from a function getCode.
Function getCode returns nothing, how fix?
Since this in the call to your plugin will refer to the jQuery instance on which it was called, you can't use it to refer directly to your plugin's information.
The usual way to handle this is to store any information your plugin needs using jQuery's data function. Here's a simple example (this is loosely based in your code, but not an exact update of it; it's just an example):
(function ($) {
var methods = {
init: function (options) {
// Save settings using `data`
this.data("myplugin", $.extend({/*...*/}, options));
},
doSomething: function () {
// Get settings using `data`
var settings = this.data("myplugin");
// Use them...
}
};
var slice = Array.prototype.slice;
$.fn.myplugin = function (command) {
if (typeof command === "string") {
methods[command].apply(this, slice.call(arguments, 1));
} else {
methods.init.apply(this, arguments);
}
return this;
};
})(jQuery);
Live Example
Note that your code requires that the user call the plugin to initialize it, and then again to call a method on it, which I've reproduced above. So:
$("some selector").myplugin(); // Init
$("some selector").myplugin("doSomething"); // Use
You could auto-init with defaults if the user doesn't do that, by changing the plugin function like this:
$.fn.myplugin = function (command) {
if (typeof command === "string") {
if (!this.data("myplugin")) { // Not initialized?
methods.init.call(this); // Init with defaults
}
methods[command].apply(this, slice.call(arguments, 1));
} else {
methods.init.apply(this, arguments);
}
return this;
};
Here's that in action
settings has scope limited to init method as you've defined it there only. getCode function has no access to this variable.
Just define the settings globally, and you can access it in getCode.

How can I make a function act like a callback

How can I make shwOpts.show("fast"); to act when removeHighlight() is done?
I thought if I put an anonymous function as an argument in the other it will act as a callback. This didn't work.
removeHighlight : function(f) {
// remove previous highlight.
var highlight = $('#openid_highlight');
if (highlight) {
highlight.replaceWith($('#openid_highlight a')[0]);
}
},
moreOptsLink = $("#more-options-link").click(function () {
moreOptsLink.detach();
openid.removeHighlight(function(){$("#show-more-options").show("fast");});
//shwOpts.show("fast");
openid.setPref("showMoreOpenIdOptions", !0)
});
You're not executing the callback function
removeHighlight : function(f) {
// remove previous highlight.
var highlight = $('#openid_highlight');
if (highlight) {
highlight.replaceWith($('#openid_highlight a')[0]);
}
if (typeof(f) === "function") {
f();
}
},
You should call the callback in the removeHighlight function like this:
removeHighlight : function(f) {
// remove previous highlight.
var highlight = $('#openid_highlight');
if (highlight) {
highlight.replaceWith($('#openid_highlight a')[0]);
if( typeof f === 'function' ) {
f();
}
}
},
moreOptsLink = $("#more-options-link").click(function () {
moreOptsLink.detach();
openid.removeHighlight(function(){
$("#show-more-options").show("fast");
});
openid.setPref("showMoreOpenIdOptions", true);
});
By using typeof control, you don't take any error when you don't pass a function as parameter to the function.
removeHighlight : function(f) {
// remove previous highlight.
var highlight = $('#openid_highlight');
if (highlight) {
highlight.replaceWith($('#openid_highlight a')[0]);
}
//you need to call f
f()
},

Categories

Resources