Passing value from one callback to another callback - javascript

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) } )

Related

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);

jQuery: add callback function to another function

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

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.

String to jQuery function

Overview
I am trying to find the jQuery function that matches a selection attribute value and run that function on the selection.
Example.
$('[data-store="' + key + '"]').each(function() {
var $callback = $(this).attr('data-filter');
if($callback != null) {
var fn = window['$.fn.nl2br()'];
if(jQuery.isFunction(fn)) {
$(this).fn();
}
}
$(this).setValue(value);
});
Problem 1
I'm not sure how to create a jQuery function call from string.
I know I can call the function like this, $(this)'onclick'; however I have no way to check if it exists before trying to call it.
Normally I could do this:
var strfun = 'onclick';
var fn = body[strfun];
if(typeof fn === 'function') {
fn();
}
This seems to fail:
var fn = window['$.fn.nl2br()'];
if(jQuery.isFunction(fn)) {
$(this).fn();
}
EDIT:
I seem to be having success doing this:
if($callback != null) {
var fn = $(this)[$callback]();
if( typeof fn === 'function') {
$(this)[$callback]();
}
}
Problem 2
Using jQuery.isFunction() how do you check if a methods exists? can you do this with jQuery.isFunction()?
Example
Declare function:
$.fn.nl2br = function() {
return this.each(function() {
$(this).val().replace(/(<br>)|(<br \/>)|(<p>)|(<\/p>)/g, "\r\n");
});
};
Test if function existe, these options fail:
jQuery.isFunction($.fn.nl2br); // = false
jQuery.isFunction($.fn['nl2br']()); //false
Functions in JavaScript are referenced through their name just like any other variables. If you define var window.foobar = function() { ... } you should be able to reference the function through window.foobar and window['foobar']. By adding (), you are executing the function.
In your second example, you should be able to reference the function through $.fn['nl2br']:
$.fn.nl2br = function() {
return this.each(function() {
$(this).val().replace(/(<br>)|(<br \/>)|(<p>)|(<\/p>)/g, "\r\n");
});
};
console.log(jQuery.isFunction($.fn['nl2br']));
See a working example - http://jsfiddle.net/jaredhoyt/hXkZK/1/
var fn = window['$.fn.nl2br']();
and
jQuery.isFunction($.fn['nl2br']);

Trying to understand this code (pub/sub library)

This is Peter Higgins's pub sub library: https://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js
(function (d) {
var cache = {};
d.publish = function (topic, args) {
cache[topic] && d.each(cache[topic], function () {
this.apply(d, args || []);
});
};
d.subscribe = function (topic, callback) {
if (!cache[topic]) {
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback];
};
d.unsubscribe = function (handle) {
var t = handle[0];
cache[t] && d.each(cache[t], function (idx) {
if (this == handle[1]) {
cache[t].splice(idx, 1);
}
});
};
})(jQuery);
I don't understand the logic and the functionality of publish:
cache[topic] && d.each(cache[topic], function () {
**this.apply(d, args || []);** //what is happening here?
});
What is the purpose of this part? except the fact that it publishes the event
In this context, the && is used as a shorthand for:
if (cache[topic]) {
d.each(cache[topic], function() { … });
}
This is because && (and ||) are short-circuiting, so if the left hand side evaluates to a false-ish value (or true-ish value, in the case of ||), the right hand side does not get evaluated.
For example:
> function foo(result) { console.log("foo"); return result; }
> function bar(result) { console.log("bar"); return result; }
> foo(false) && bar(true);
foo
false
Basically, you call each topic callback (if any) with args (if any arguments are passed). So you can:
$.subscribe('do_something', function(str) { alert(str + ' world!')});
$.subscribe('do_something', function(str) { console.log(str)});
$.publish('do_something', ['Hello']); // will alert Hello world! and output 'Hello' to console
cache[topic] && d.each(cache[topic], function () {
this.apply(d, args || []);
});
Applying for each element of d, if cache[topic] is defined, function, which calls the apply method of it with d argument, and args, or an empty array, if args is not defined.

Categories

Resources