I want to do this, because I am working with third-party scripts releated to Internet Marketing. Some of them may contain jQuery library included within and it interfere with recent or latest jQuery Library that is included on my website.
Hence, I'd like to switch between .on() and .bind() dynamically upon website load with a help of variable.
For example, let's say I have global variable:
var incJS = false;
And now depending of the third-party script, I know if they have older Lib included so I'd use this.
function tpNetwork ()
{
incJS = true;
startGateway('XXXXX');
$('#fancybox-outer')
.delay(1000)
.fadeTo(300, 1);
preventGTW();
widgetStyle();
}
Now as you may see there's a function at the very bottom widgetStyle()
That function contain loads of things, but important part is following:
$(window).on('resize', function () {
if ($('.widget_wrap').length) widgetCenter_horizontal();
});
It has .on() method there. That is not supported in very old jQuery that's been used by that third-party network. I'd like to switch every single .on() with .bind() but I don't know how to, without duplicating things.
I did it like this, but it's duplicate and I believe there's easier way.
if (!incJS)
{
$(window).on('resize', function () {
if ($('.widget_wrap').length) widgetCenter_horizontal();
});
}
else
{
$(window).bind('resize', function () {
if ($('.widget_wrap').length) widgetCenter_horizontal();
});
}
Any kind of tips/help is appreciated. I am really out of any ideas and by doing researches I found nothing.
What about:
$(function(){
if(!$.fn.on) $.fn.on = $.fn.bind;
});
Of course, this is excluding any delegation support.
DEMO
Well thanks to the comment of the #smerny and the answer of #roasted I have made it like this and it resolved my problem. Thank you for all tips and answers!
$.fn.onbind = function () {
if (!ajaxGateway)
$.fn.onbind = $.fn.on;
else
$.fn.onbind = $.fn.bind;
};
And now everything works as I wanted. Here's example.
$(window).onbind('resize', function () {
if ($('.widget_wrap').length) widgetTop();
});
Related
I posted a similar issue earlier, but it was flagged as a duplicate. However, this referenced article did not answer my question, so I'll try this again, this time using the solution of said article in my example.
The solution provided in this article creates the same issue I had before: when there is more than one element, I cannot call any of the public methods of the plugin.
Since no working example was provided, let's start with the code the article gave:
(function($){
$.fn.myPlugin = function(options) {
// support multiple elements
if (this.length > 1){
this.each(function() { $(this).myPlugin(options) });
return this;
}
// private variables
var pOne = '';
var pTwo = '';
// ...
// private methods
var foo = function() {
// do something ...
}
// ...
// public methods
this.initialize = function() {
// do something ...
return this;
};
this.bar = function() {
// do something ...
};
return this.initialize();
}
})(jQuery);
I LOVE the internal loop so that it's applied to each instance of the element, but I feel the repeated "return this" is redundant. I think if we removed every single one of them, this plugin would work exactly the same. But, for the sake of argument, I'm going to leave them in my working example.
As you can see in this jsfiddle example, it works fine when there is only one element. The public method runs fine.
However, if I were to comment the other 4 elements back in like here, it throws an error in the console: "undefined is not a function". This, of course, makes sense since I'm attempting to run the public method on a reference to all elements on not an individual element.
Well, then I use .eq(0) to run the method only on the first instance of the element here, but I get the exact same error in the console.
So, why isn't calling the public method on the individual element working? Is this a scoping issue?
Please advise. Thanks!
Ok, so I think I've answered my own question. The issue is that I'm not applying a jQuery plugin to a DOM element. I'm applying it to a jQuery element. So, if I were to apply the jQuery plugin to a jQuery element, referenced like $element or $('.element'), I can then run any public methods because the scope is the same. But, if I were to reference it in a different way, like say $parentelement.eq(0), I'm using a difference reference, one that did not get the plugin applied to it, so naturally, it would not have the defined method. I think I'm getting the concept right. Still a little shaky on this. Maybe someone else can explain it better.
Nevertheless, while the above code does technically work, public methods are not practical on a jQuery plugin. I suggest instead using a Custom Event to make the jQuery plugin do something. Like this:
(function($) {
$.fn.extend({
myTestPlugin: function() {
if (this.length > 1) {
this.each(function() { $(this).myTestPlugin(); });
}
this.done = function() {
$(this).html('Done!');
};
var alsoDone = function() {
$(this).html('Also done!');
};
this.html('Replace me!');
this.on('alsoDone', alsoDone);
}
});
})(jQuery);
Here is an example where I am using trigger to make the plugin do something on an individual element, which works, but the method still fails as expected.
I hope this helps other people with similar issues.
I currently work with prototype, so for instance if i want to create a class or something i would do something like (using it with asp.net)
function MyTestClass()
{
this.MyHtmlDiv = $("myHtmlDiv");
this.MyButton = $("myButton");
this.init();
}
MyTestClass.prototype.init = function()
{
Event.Observe(...some code here ..);
Event.Observe(...more code...);
}
So you get the idea. I like the way it is organized but I have read here in other posts that jquery is better. I would like to start using it but.. is it possible to create "classes" like this, neat?. I usually have a separate .js file for each aspx page. How can I create a class like this with JQuery?
Any pointers, links, ideas or suggestions would be appreciated. When I google this, I see some jquery functions but havent really found a nice template that i can follow to maintain it like above if i was to move to jquery.
jQuery has no confliction with the style you use now, you just need to change your mind of how jQuery selector work and how to bind event handler etc.
function MyTestClass() {
// note jQuery's selector is different from Prototype
this.MyHtmlDiv = $("#myHtmlDiv");
this.MyButton = $("#myButton");
this.init();
}
MyTestClass.prototype.init = function() {
this.MyHtmlDiv.on('event_type', function() {
// some code
});
this.MyButton.on('event_type', function() {
// some code
});
}
I don't know if I'm saying this right, so I'll just ask by explaining with an example.
Let's say I've written a jQuery plugin with an onShowEdit callback.
I later use my plugin and add a bunch of other default functions/methods to the event:
$('.editable_module:not(.custom)').editable({
onShowEdit: function(el){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
}
});
So now I have a basic/default element (.editable_module) that calls the plugin and has some methods/functions that are going to be used in all instances.
My question comes when I have a need to add something to this for a 'one time' kind of deal (I need to add some behavior to this callback/event but not something that is used normally). Is it possible to extend or add to this callback/event without overwriting it? I mean, I know I can go in and do this:
$('#new_selector').editable({
onShowEdit: function(el){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
//ADD SOME NEW STUFF HERE
}
});
But is that really my only option?
Thanks in advance for any input/suggestions.
You could consider jQuery's own event system as follows: http://jsfiddle.net/VQqXM/1/. You can integrate this in your $.fn function pretty easily - just pass the appropriate function as property of the object instead of a function literal.
$("input").on("foo", function() {
alert(1);
});
// later
$("input").on("foo", function() {
alert(2);
});
// later
$("input").trigger("foo"); // alerts 1 and 2
You can simply use .on/.off to bind and unbind events, and trigger them all with .trigger. jQuery also supports namespacing of the event names to make sure you're not using an already used event.
You could use the new $.Callbacks() method
var $onShowEditCBObj = $.Callbacks();
function onShowEditHandler() {
$onShowEditCBObj.fire();
}
$('#new_selector').editable({
onShowEdit: onShowEditHandler
});
// add default event to callbacks obj
$onShowEditCBObj.add(function(){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
});
// add a one time method to the callbacks obj
function oneTimeEvent () {
alert("worky");
$onShowEditCBObj.remove(oneTimeEvent);
}
$onShowEditCBObj.add(oneTimeEvent)
With this setup, you can change what callbacks will be fired without having to do anything extra to the editable plugin.
Edit: I didn't realize that you wrote the plugin. With that in mind, pimvdb's answer is more robust than requiring the developer to code a certain way.
If I understand the question correctly, the key word here is "factory".
jQuery is itself a factory but to get what you describe, you need your plugin also to be a factory within the factory. That requires the plugin to be written in a certain way.
Probably the easiest approach is to use jQuery's UI widget factory. Read about it here.
Defining a separate function for onShowEdit should work.
var myOnShowEdit = function(el, extra_fn) {
//standard functionality goes here
if (typeof extra_fn==='function') extra_fn(); //support for extra stuff
}
$('.editable_module:not(.custom)').editable({
onShowEdit: function(el) {
myOnShowEdit(el);
}
});
$('#new_selector').editable({
onShowEdit: function(el) {
myOnShowEdit(el, function(){console.log('hi');});
}
});
This will give you fair flexibility to add whatever functionality you need in addition to the standard stuff. Just be aware of how this may shift contexts.
I've been playing around with the revealing module patter. I originally started using the Singleton pattern but from reading around the module pattern seems to be the better option.
So i've tested the following:
var test = (function() {
var init = function () {
alert('hello');
};
return {
init: init
};
})();
and this works fine when calling
<script>test.init();</script>
However, i want to use jQuery so i tried:
var test = (function($) {
var init = function () {
$("#samplediv").html('test');
alert('hello');
};
return {
init: init
};
})(jQuery);
but this doesn't work. It does work when using:
<script>$(function() { test.init(); });</script>
How can i get it to work without the added jQuery when calling it?
Usually, anything that touches the DOM needs to done in the $(document).ready(fn) callback. $(fn) is a shortcut for this.
So the reason it doesn't work is because you are searching for DOM elements that don't exist yet. So you have 2 choices. Either you must use the $() wrapper, or find another way to run your code only after the DOM elements exist. Another way to do this is to move your script tag the bottom of the body tag so that the DOM elements can exist when it's ran.
<body>
<!-- your page elements here -->
<script>test.init();</script>
</body>
I have a function that accepts the element it needs to operate on as a parameter element
function changeColor(element){
$(element).find('.middleBox').each(function(){
$(this).//do some stuff that does not matter now;
});
}
and I call it this way
changeColor($(document)); //this applies it to the whole document
changeColor($('#sectionOne')); //this applies it to only part of the document
I want to change it from the format where it accepts its object as a param to this format. How do I do it
$('#sectionOne').changeColor();
$(document).changeColor();
As Nikita said, you need to write a jQuery plugin. Here's a basic example, which should be enough for what you are trying to do:
(function($) {
$.fn.changeColor = function() {
return this.each(function() {
$(this).find('.middleBox').each(function() {
$(this).//do some stuff that does not matter now;
});
});
};
})(jQuery);
You want to create a jQuery plugin. jQuery folks provide a tutorial for that.
If you don't like reading much, you can practically copy-paste maxHeight example and replace logic inside.