I'm developing a jQuery plugin, and I want to know if there's any possibility to get the second parameter without set the first parameter.
MCVE:
https://jsfiddle.net/2fgb5agL/
//jQuery
$.fn.myPlugin = function(param1,param2) {
return this.each( function() {
if (param2) {
alert("param2 ok");
}
});
};
//Call the plugin
$("#call").click(function() {
$(this).myPlugin("", "xyz");
});
What I mean is: it's possible to call $(element).myPlugin("xyz") and expect the plugin recognize a defined string (ex. "xyz") and then 'do something' (call other function).
So, I don't gonna need to call $(element).myPlugin(undefined,"xyz") for get the second param without setting the first one.
Thanks for reading.
p.s.: What I want to achieve is a cleaner code.
Unless the parameter types are strictly different, you can't even create a distinction inside the function.
Is usual to use a single object parameter as argument like so:
//jQuery
$.fn.myPlugin = function(options) {
return this.each( function() {
if (options.param2) {
alert("param2 ok");
}
});
};
$("#call").click(function() {
$(this).myPlugin({ param1: "", param2: "xyz" });
});
This way you can chose which argument to pass for your plugin. For example: $(this).myPlugin({ param2: "xyz" });
Related
I have this javascript object:
return {
AccDocs: {
query: function() {
...
},
deleteAndQuery: function() {
...
AccDocs.query(); //Error: AccDocs is not defined
}
}
}
But, it returns an error that says AccDocs is not defined.
How can I achieve something like this?
Variables and properties on objects are different things. You cannot access the property of an object without specifying which object you mean.
You can probably access it using the this keyword:
this.query();
Keeping in mind that the value of this will vary depending on how the function is called (when a.b.c.d.AccDocs.deleteAndQuery() is called, this inside deleteAndQuery will be AccDocs as it is the first object to the left of the last ., but if you were to first copy query to another variable and then call query(), pass it to setTimeout, or if you were to use call or apply then the value of this would change).
For more robustness (but less flexibility, since being able to change the context can be useful) you can store your object in a variable which you can access by name.
var AccDocs = {
query: function() {
...
},
deleteAndQuery: function() {
...
AccDocs.query();
}
};
return { AccDocs: AccDocs };
By using the this keyword:
return {
AccDocs: {
query: function() {
...
},
deleteAndQuery: function() {
...
this.query(); //Here
}
}
}
I have the following code:
$.getJSON('getAllTerminals.json', renderTerminalsOnMapAndFitBounds.bind({index:globalRequestCounter++, navigateToTypedText:true}))
...
function renderTerminalsOnMapAndFitBounds(data, updateSelectedTerminals) {
renderTerminalsOnMap.call(this,data);
fitBounds();
if(this.navigateToTypedText === true){
navigateMapToTypedAdress();
}
if (updateSelectedTerminals) {
$.getJSON('getSelectedTerminals', {}, function (json) {
window.MARC.addTerminalPage.terminalsSelected = json;
update();
initPage();
});
}
}
Can you advise me how to make that all works as now but to renderTerminalsOnMapAndFitBounds was passed updateSelectedTerminals as true ?
No, you cannot use bind to partially apply non-initial parameters (and there's no flip). Just use a function expression:
$.getJSON('getAllTerminals.json', function(data) {
renderTerminalsOnMapAndFitBounds.call({
index:globalRequestCounter++,
navigateToTypedText:true
}, data, true);
});
If you have to use bind, either change the parameter order of renderTerminalsOnMapAndFitBounds, or make it accept that updateSelectedTerminals parameter as a property of the this object.
This is related to, but not a duplicate of, another SO Q&A Override jQuery functions.
It is clear from the answer to the above question that the pattern to override a jQuery function is:
(function($){
// store original reference to the method
var _old = $.fn.method;
$.fn.method = function(arg1,arg2){
if ( ... condition ... ) {
return ....
} else { // do the default
return _old.apply(this,arguments);
}
};
})(jQuery);
But why!?
I've been able to override a jQuery function simply by defining a function of the same name as the function to be overridden, within $.extend or $.fn.extend.
Consider this:
// random example showing jquery function overriding
$.fn.extend({
hide: function() {
$(this).css({"color":"red"});
}
});
$("#test").hide(); // this will actually paint the #test element red!
jsFiddle
I'd like to understand why _old.apply(this,arguments) would be the preferred way to override a jQuery function, as listed here and here.
From glancing at references provided at original post, summary of pattern could be to keep both "old" and "new" methods available ?
Edit, updated
Sorry, I don't get this. As far as I see, the reference to the overridden method is saved in a local variable in a closure is
unquestionably lost outside the closure. Can you explain how the "old"
method is still available? –SNag
I'd like to understand why _old.apply(this,arguments) would be the
preferred way to override a jQuery function, as listed here and
here.
Utilizing pattern at 1st link , above , if interpret pieces correctly, appear arguments test within if statement of jquery method within "self-executing anonymous function" determine return value of "old" or "new" (newly included; override) jquery method ?
i.e.g., try
html
<div>abc</div>
js
// See http://www.paulirish.com/2010/duck-punching-with-jquery/ , at
// `First we start off with a self-executing anonymous function,
// that makes a happy closure while remapping jQuery to $:`
// `closure` start
(function ($) {
// jquery `.css()`
var _oldcss = $.fn.css;
// jquery `.hide()`
var _oldhide = $.fn.hide;
// "new" `.css()`
$.fn.css = function (prop, value) {
// "new" `.css()` `test`
if (/^background-?color$/i.test(prop)
&& value.toLowerCase() === 'burnt sienna') {
return _oldcss.call(this, prop, '#EA7E5D');
} else {
return _oldcss.apply(this, arguments);
}
};
// "new" `.hide()`
$.fn.hide = function (prop, value) {
// "new" `.hide()` `test`
if (/color/i.test(prop) && /[a-f]|[0-9]/i.test(value)) {
return $.fn.css.call(this, prop, value);
} else {
return _oldhide.apply(this, arguments);
}
};
})(jQuery);
// `closure` stop
// and using it...
// "new" `.css()`
jQuery(document.body).css('backgroundColor', 'burnt sienna');
// "old" `.css()`
$("div").css("color", "yellow");
// "old" `.hide()`
$("div").hide(7500, function () {
// "old" `.css()`
$(document.body)
.css({
"transition": "background 2s",
"background": "#edd452"
})
.find($("div")).show(2500)
// "new" `.hide()`
.hide("color", "red")
});
jsfiddle http://jsfiddle.net/guest271314/5bEe4/
(function($){
// store original reference to the method
// stored locally
var _old = $.fn.method;
$.fn.method = function(arg1,arg2){
if ( ... condition ... ) {
return ....
} else { // do the default
// call apply method, in order to pass the this context.
return _old.apply(this,arguments);
}
};
})(jQuery);
Here in the above code, we are calling an anonymous function, in which we are declaring a local variable _old. When this anonymous function execute, it save the _old method reference and form a closure.
Now, when we call the new method, i.e,
$.fn.method = function(arg1,arg2){
if ( ... condition ... ) {
return ....
} else { // do the default
return _old.apply(this,arguments);
}
};
we also have an access to _old method, since its scope exists in the current context. And then, we can use it inside the new method.
Here we are calling _old method with the help of apply, because we want to have the same this context for that as well.
With this approach, we can easily override the jQuery method by preserving its original functionality.
I have a simple button. and I need to send data to the handler when clicked.
So I have this code using the ON overload method :
.on( events [, data ], handler(eventObject) )
I've created this sample :
var aaa="john";
function greet(event) { alert("Hello "+event.data.name); }
$("button").on("click", { name: aaa}, greet);
setTimeout(function (){aaa="paul"},2000)
But after waiting 2 sec , I still see: "Hello John"
So I assume that the aaa value is bounded at interpretation time.
Question :
How can I change the code so that after 2 seconds it will alert : Hello Paul ?
JSBIN
A simple way is to use an object literal. You can pass it as event data and keep a reference that you modify later:
var greetData = {
name: "john"
};
function greet(event)
{
alert("Hello " + event.data.name);
}
$("button").on("click", greetData, greet);
setTimeout(function() {
greetData.name = "paul";
}, 2000);
You will find an updated JS Bin here.
Frédéric Hamidi's answer is better. Will leave this just as an alternative.
If you change it so that you pass a function that loads the name instead of the name it self it will work:
var aaa="john";
function getName() {
return aaa;
}
function greet(event) { alert("Hello "+event.data.name()); }
$("button").on("click", { name: getName}, greet);
setTimeout(function (){aaa="paul";},2000);
http://jsbin.com/ohAJihi/4/edit
It is a little confusing to understand what are you
trying to achieve. If you are using setTimeout; theres no need to use a button onclick handler.
Secondly, the scope of the setTimeout function is always the window object. So if you need to access the value from your object, please create a reference of it and use in the setTimeout function.
I've written the following convenience function to let me easily put jquery UI autocomplete on elements.
jQuery.fn.bindAutocomplete = function() {
$(this).each( function() {
$(this).autocomplete({
source: $(this).data('autocomplete-source')
});
});
}
I always use the convention of attaching data-autocomplete-source to an element so I can call this anywhere just like so:
$('input#name').bindAutocomplete();
Now, the autocomplete function can take callback functions as optional arguments after the options hash. I almost never need to mess with that, but I've found that in a small number of instances I'd like to pass a success function through. Obviously I can just rewrite the full autocomplete function when I need to pass it callbacks, but I'd rather just rewrite my bindAutocomplete() function so it can accept optional callback functions and pass them through to autocomplete().
So, how do you do that?
Update
I tried this, based on a close but not quite answer below:
jQuery.fn.bindAutocomplete = function(callbacks) {
$(this).each( function(callbacks) {
options = $.extend({source: $(this).data('autocomplete-source')}, callbacks);
$(this).autocomplete(options);
});
}
This binds autocomplete correctly whether you pass callbacks in or not, but if you do pass callbacks they don't get called.
Ie: the following triggered autocomplete but not the callback.
$('input#name').bindAutocomplete({ select: function(){alert("working");} })
I guess you can do this if that's what you mean...
jQuery.fn.bindAutocomplete = function( opts ) {
return this.each(function(){
opts = $.extend({
source: $(this).data('autocomplete-source')
}, opts);
$(this).autocomplete( opts );
});
}
$('input#name').bindAutocomplete({
change: function() { ... },
close: function() { ... }
});