(function($) {
$.fn.myFunction = function(config) {
var defaults = {
setting1: 'myDiv',
setting2: ''
};
var config = $.extend(defaults, config);
//code here
};
})(jQuery)
$(document).ready(function() {
$.fn.myFunction({
setting1: 'myDiv',
setting2: ''
});
});
This is how I've been using jQuery plugins, but I recently learned it should be used like:
$('#myDiv').myFunction({
setting1: 'myDiv',
setting2: ''
});
1) I take it this allows the usage of $(this) for $('#myDiv')?
2) Is $(document).ready(function() required?
3) Is there anything detrimental about the way I have been using this jQuery function?
4) If $('#myDiv').myFunction() is the proper usage, how would you call the function if it is simply a function to run at document ready - see my usage here: https://stackoverflow.com/a/12316349/1455709. Is this simply an incorrect usage of the function?
Calling $.fn.myFunction() and calling $('#myDiv').myFunction() are two different things. There is no right or wrong - it depends upon what you're doing.
Calling $.fn.myFunction()
This is essentially a static function and you can use it like that if you want. In the jQuery world, .fn is like .prototype so $.fn.myFunction() is like calling jQuery.prototype.myFunction(). It is allowed, but it's a static function call that is not associated with a specific jQuery object. If you just want a static function call, then you can do this, but this is not normally how the jQuery prototype is used and I would not generally recommend it. If you just want a static function and want to use the jQuery namespace, you can just do this:
$.myFunction = function(args) {/* your code here */};
and then call it like:
$.myFunction();
As there is no need to use the prototype at all.
Calling $('#myDiv').myFunction()
The prototype (e.g. .fn in the jQuery world is used when you want to add methods to actual jQuery objects.
When you do this $('#myDiv').myFunction() is a member function of a live jQuery object. You can refer to this inside the myFunction() implementation and it will be a jQuery object that, in this case holds the DOM object that corresponds to id="myDiv". If you return the jQuery object from your method, you can also use chaining.
Which to Use?
If your code operates on a jQuery object, then it should be a method on a live jQuery object and it should access this to get at the jQuery object instance data and you should declare it as $.fn.myFunction = function() {}; and call it as$('#myDiv').myFunction()`.
If you code does not operate on jQuery object and is just a utility function that you call and it doesn't always operate on a jQuery object, then, you should declare it as $.myFunction = function() {}; and you should call it as $.myFunction().
Yes, as well as proper chaining if you return this from inside your function.
Yes, if your code is run before the dom is loaded.
It's not really jQuery, it doesn't work how people would expect it to. Somebody could call it as $('#myDiv').myFunction() and it wouldn't perform as expect.
If you want a function that you can just run any time, don't add it to the jQuery prototype ($.fn). Instead you could add it onto $ like the other jQuery functions that don't require selectors, $.trim for example. Then you could call it like this: $.myFunction(options);
Related
new to writing a function in jquery, just testing the waters.
I have this just to to demo:
(function ( $ ) {
$.fn.update_notifications = function( options ) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
user_id: 0,
}, options );
alert('test');
};
}( jQuery ));
Which I include in a JS file included before the tag. What I want to know, is how to actually call it inside my html?
I was thinking something like:
<script type="text/javascript">
jQuery.update_notifications({
user_id: 1
});
</script>
But that tells me "jQuery.update_notifications is not a function"
You want to call it on selected element like this:
$("some_element").update_notifications();
You can find more here at the official documentation.
No, the function is not part of the jquery object, but of its fn child object
$.fn.update_notifications();
However, it doesnt make sense to add something to the jquery prototype if youre not doing sth jqueryobjectbased
To fix the issue you simply need to change $.fn.update_notifications to $.update_notifications. The $.fn namespace is used for attaching functions to instances of jQuery objects.
(function($) {
$.update_notifications = function(options) {
var settings = $.extend({
user_id: 0,
}, options);
console.log('test');
};
}(jQuery));
jQuery.update_notifications({
user_id: 1
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
That being said, your example is a little redundant as you've just wrapped the existing $.extend() function without adding any real logic - although I assume this is a work in progress.
If your function has nothing to do with any DOM elements, i would suggest you not to pollute jQuery. You can very well declare this function some where else (page, separate JS file etc.).
But if you still want to do this, you can try these
$.update_notifications();
or
$(window).update_notifications();
or
$(document).update_notifications();
Why are you exactly extending the Jquery object?
Usually, lacking a valid reason to do so you would simply write a function inside your script.
Let's assume you have a valid reason and proceed:
Once you bind your function to $ or better create object like $.custom and bind the function (and rest of custom things you wanna bind to Jquery) you can use it like a normal function - only prefix it with $.custom
Not sure I understand your question but are you searching how to run that function from HTML other than using jquery?
Are you asking for an example like this?
<p id="onThis" onclick="$.custom.yourFunctionName()">Click me.</p>
That is obtrusive JS code and is not best practice when dealing with Jquery.
You wanna bind that function to element with on or click handler when document is ready:
$(document).ready( function() {
$('#onThis').on('click', function here);
// OR //
$('#onThis').click(function here);
});
If there is no reason to bind it to jQuery, don't do it you are only implying to someone reading your code something that doesn't exist ;)
I have a question regarding the structure of a jQuery plugin that I found.
For better understanding, here is a simplified example of the plugins structure:
// Regular constructor function
function MyPlugin() {
this.myValue = "My Value";
}
// Methods on the prototype
MyPlugin.prototype.showValue = function() {
alert($.myplug.getValue());
}
MyPlugin.prototype.getValue = function() {
return this.myValue;
}
// jQuery plugin
$.fn.myplug = function() {
// Why is is possible to access $.myplug here although it's not created yet?
return this.each(function() {
$(this).html($.myplug.getValue());
});
};
// Create new MyPlug instance
$.myplug = new MyPlugin();
// Calling the jQuery plugin on a DOM element
$('div').myplug();
For the most part, I get what is happening. The actual plugin logic seems to be written as a normal JavaScript "class".
This is followed by a jQuery plugin definition – I think, actually, some new method is added to jQuery's prototype. This is where things get tricky to me:
How is is possible to access the class instance inside the plugin, although the class is instantiated after the plugin definition? Is there a mechanism at work similar to variable hoisting?
In case you want to try something, here is a Fiddle of the example: http://jsfiddle.net/kq8ykkga/
$(this).html($.myplug.getValue()); isn't evaluated until you call $('selector').myplug(), executing the function body.
I'm trying to follow this article to write a simple jQuery plugin: http://brolik.com/blog/how-to-create-a-jquery-plugin/
I seem to always get the following error in my console:
HTML
<div id="prod-part">TODO write content</div>
Javascript
(function($){
$.blogPost = function(el, options) {
var base = this;
base.$el = $(el);
base.el = el;
base.$el.data('blogPost', base);
base.init = function(){
console.log("hello");
};
};
})(jQuery);
$(function () {
$('#prod-part').blogPost();
});
Here is a simple jsfiddle which still creates the issue. I'm not sure If I am calling on the plug-in incorrectly or if the plugin is coded incorrectly. I've tried jQuery versions 1.7.2 and 1.11.0 and still come out with the same results. Any suggestions would be greatly appreciated.
http://jsfiddle.net/45oLp31m/1/
Background:
The jQuery function (jQuery() or $()) acts as a factory to return a new instance of jQuery collection when you pass in a selector. So $('#foo') returns an instance of jQuery collection. In order to call methods off of that instance, like $('#foo').somePlugin(), those methods have to be defined on the instance. The primary way we get methods onto instances is to add them to the constructor's prototype.
Solution
So the solution to your specific error is that jQuery plugins are defined on the jQuery collection constructor's prototype. This prototype is aliased at jQuery.fn (and jQuery is aliased as $, so $.fn is also ok). Adding methods to the prototype is as simple as $.fn.somePlugin = function () {}.
Thus your plugin needs to be defined like:
$.fn.blogPost = function(el, options) {
More
As I said, this is for the specific error you quoted. I assume at this point that you haven't made it much further in your tutorial, so I won't go into the other issues in your code (like the fact that your plugin does not return the collection for chaining).
Instead of
$.blogPost = function(el, options) {...}
Try
$.fn.blogPost = function(el, options) {...}
Functions in the $.fn namespace are available as methods on jQuery collections, which is what you want.
$(selector).blogPost();
Such methods a generally known as "plugins".
In other (rarer) circumstances, you might want to extend the jQuery namespace itself, in which case your $.foo = function() {...} would be applicable. Such functions are known as "static methods".
I am currently developing a rather complex jQuery plugin. One that I am designing to be extensible. The quandary I have is how to exactly provide my users with the APIs available to them.
There are two methods that I can come up with:
Provide the API via an object in the global scope
This is the method I am currently using. I do it similar to this:
(function ($, win, undefined) {
//main plugin functionality
function pluginStuff() { /*...including method calling logic...*/ }
//register function with jQuery
$.fn.extend({ Plugin: pluginStuff });
//register global API variable
win.PluginAPI = { extendMe: {}, getVar: function() {} };
})(jQuery, window);
Unfortunately since I impliment the standard $().plugin('method') architecture its a little strange to have to use the jQuery method for some things and the API variable for others.
Provide the API via an object placed in jQuery
I toyed with this method as well but its best practice to take up only a single slot in jQueries fn scope, as not to crowd the jQuery variable. In this method I would put my api variable in $.fn instead of the window:
//register function with jQuery
$.fn.extend({ Plugin: pluginStuff });
//register global API variable
$.fn.PluginAPI = { extendMe: {}, getVar: function() {} };
I would rather not break this convention and take up two places.
Now that I write this I can see a third option where I assign my plugins slot in jQuery's fn scope to be an object:
$.fn.Plugin = { plugin: pluginStuff, api: { extendMe: {}, getVar: function() {} } };
but how well received would this be if users had to do $('#elm').Plugin.plugin({ setting: 'value' }) to create a new instance of the plugin?
Any help or pointers would be greatly appreciated.
Please Note: I'm am not looking for a way to incorporate the API object into my plugin functionality. I am looking for a way to keep it separately modularized, but intuitively available for use/extension.
You could always do like
var plugin = function plugin() { /* do the main stuff */ };
// api stuff here
plugin.getVar = function() { };
plugin.extendMe = {};
$.fn.Plugin = plugin;
Or stick the extra stuff in an object that you assign to plugin.api.
Any way you do it, though, you're going to have to worry a bit about settings bleeding into each other. Since everything's going to be using the same function, regardless of how you choose to set it up, you'll need a way to keep invocations of the plugin separate from one another. Perhaps using something like, say, this.selector (in your plugin function) as a key into an associative array of properties, for example. I'd normally recommend .data() to attach settings to individual elements, but that doesn't help much if the same element gets the plugin called for it twice.
The method I eventually decided to use was registering the plugin under the fn namespace and the api variable under the jQuery $ namespace. Since methods and options set operate on an instance of the plugin $.fn is the best choice.
However, the API is global and does not link to a single instance. In this case $.fn doesn't quite fit. What I ended up using was something similar to this:
(function ($, win, undefined) {
//main plugin functionality
function pluginStuff() { /*...including method calling logic...*/ }
//register function with jQuery
$.fn.Plugin = pluginStuff;
//register global API variable
$.Plugin = { extendMe: {}, getVar: function() {} };
})(jQuery, window);
now you can create an use a plugin object as expected:
$('#elm').Plugin();
$('#elm').Plugin('option', 'something', 'value');
$('#elm').Plugin('method');
and you can easily extend and access the API:
$.extend($.Plugin.extendMe, {
moreStuff: {}
});
$.Plugin.getVar('var');
Thanks for the help everyone!
I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}