My journey being at least on above basic level in front end is still on and I stumbled upon quite a big problem recently.
I can select DOM element, like
var element=document.getElementById("elementid")
and then add some function to it, like this
function testFunction() {
alert(this.getAttribute('data-self'));
}
element.customFunction=testFunction;
But is there by chance any way of doing this using jQuery?
Tried with attr(), prop(), data() and without any luck on that matter. data() was a close one though, because it allows me to execute function using $('#my-element-id').data('customFunction')(); for example, but still doesn't solve my problem, as this new property of that selected buttons is not accessible any other way.
To sum up: What is the simplest way to add generic function (like in an example) to collection of DOM elements in a way that it's accessible like any other property?
Adding a function directly to a DOM element is not considered a good practice for a variety of reasons.
I'd suggest a jQuery plugin method which is pretty easy:
jQuery.fn.myMethod = function() {
// iterate all items in the jQuery collection and apply any logic you want
return this.each(function() {
// `this` will be the DOM element so you can carry out your operation here
// for example, to flip a background color
if (this.tagName === "INPUT") {
this.style.backgroundColor = "red";
} else {
this.style.backgroundColor = "blue";
}
});
}
// usage of jQuery plugin method:
$("#elementid").myMethod();
$(".boxes, .ovals, .containers").myMethod();
You can also pass arguments to your jQuery plugin method and use those arguments in the implementation of your custom method.
It's pretty similar. jQuery just returns an object so you can add functions to it.
var myElement = $('#elementid');
function testFunction() {
alert($(this).attr('data-self'));
}
myElement.customFunction=testFunction;
myElement.customFunction();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="elementid" data-self="some value"></div>
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 ;)
Disclaimer:
I am sure that someone somewhere asked these question, but I couldn't think of the accurate google key words to locate similar questions. So please bear with me.
Question:
I am constantly suffering from the necessity to re-write entire bulks of JQuery code because of the following pattern:
<div class = 'foo'></div>
<script>
$('.foo').on('click', function(){
// Do something
});
</script>
The problem with this code is that it's too fragile. If I decide to rename my class to change the structure of the DOM, entire bulks of JS related to binding handlers to DOM elemenets are subject to editing.
What is the best-practice to make JQuery code less prone to such kind of risk or ideally eliminate it at all?
I find it easier to add a class to bind to based upon the event that is occurring instead of a class that is defining structure or component.
For example:
<button class="foo js-add-user">Add User</button>
<script>
$('.js-add-user').on('click', function() {
//..
});
</script>
That way if you want to change .foo, you don't need to mess with the handler.
You could cache your elements and just reference the variables:
var foo = $('.foo');
foo.on('click', function(){
// Do something
});
Then if you need to change the class name, you only need to change it in one place. This also has the added benefit of not having to re-query the DOM for your elements whenever you use them.
I don't know if it a good practice to do this way, but I usually use the following structure to call some function onclick:
<div onclick='myFunction();'></div>
<script>
function myFunction() {
alert('Hey!');
}
</script>
You could create an alias function with your custom parameters, allowing it to store them for you later. You can also add function to set on id too, or to remove the click event.. things like this:
function setClickOnClass(className, func){
var className = className;
$(className).click(function(){
func();
//...
});
}
then you make just one call, and you edit the class at that moment. If you want tou do it from multiple place and moments, you could create a "class"
function ClickOnClass(className, func){
var className = className;
this.setClick = function(optionalClassName){
var classN = (optionalClassName) ? optionalClassName : className;
$(classN).click(function(){
func();
//...
});
};
return this;
}
//initialization
var clickHandler = new ClickOnClass('.foo', func);
//later in code
clickHandler.setClick();
(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);
Trying to use an svg onClick to call a prototype function.
Usually to call a prototype function I would just do this.(functionName) but when I put it into the .setAttribute(onclick, "this.(functionName)") it does not recognise the prototype function. Has anyone had any experience in this?
In case the above wasn't clear heres the basic jist of it...
function myobject(svgShape) {
this.svgshape.setAttribute(onclick, 'this.doSomething()');
}
myobject.prototype.doSomething = function() {
alert("works");
}
Three things that may help:
1) First off, I think you're missing this line from the top of your myobject function:
this.svgshape = svgshape;
I'm assuming that was just an error posting the question and have inserted that below.
2) Normally when you're using Prototype (or any modern library), you don't use strings for callbacks, you use functions. Also, you normally assign handlers using the library's wrapper for addEventListener / attachEvent (observe, in Prototype's case) rather than the old DOM0 attribute thing. So:
function myobject(svgShape) {
this.svgshape = svgshape;
$(this.svgshape).observe('click', this.doSomething); // STILL WRONG, see below
}
myobject.prototype.doSomething = function() {
alert("works");
}
3) But JavaScript doesn't have methods (it doesn't really need them), it just has functions, so the above won't ensure that this (the context of the call) is set correctly. With Prototype you'd use bind to set the context:
function myobject(svgShape) {
this.svgshape = svgshape;
$(this.svgshape).observe('click', this.doSomething.bind(this));
}
myobject.prototype.doSomething = function() {
alert("works");
}
(Or you can use your own closure to do it. The advantage of bind is that the closure is in a very well-controlled environment and so doesn't close over things you don't want kept around.)
Now, I've never done any SVG programming with Prototype, so if observe doesn't work for some reason, you might try directly assigning to the onclick reflected property:
function myobject(svgShape) {
this.svgshape = svgshape;
this.svgshape.onclick = this.doSomething.bind(this);
}
myobject.prototype.doSomething = function() {
alert("works");
}
I'm still using bind there so that this has the correct value.
These posts from my anemic little blog offer more discussion of the above:
Mythical methods
You must remember this
Closures are not complicated
Is it inadvisable to add methods to a JQuery element?
eg:
var b = $("#uniqueID");
b.someMethod = function(){};
Update
Just to clarify, I am working on a JS-driven app that is binding JSON data to local JS objects that encapsulate the business logic for manipulating the actual underlying DOM elements. The objects currently store a reference to their associated HTML element/s. I was thinking that I could, in effect, merge a specific instance of a jquery element with it's logic by taking that reference add adding the methods required.
Well, there's nothing inherently wrong with it. It is, however, pretty pointless. For example:
$('body').someMethod = function(){};
console.log($('body').someMethod); // undefined
You are attaching the new function only to that selection, not to all selections of that element.
What you should do instead is to add a new function to jQuery.fn, which is a shortcut for jQuery.prototype:
jQuery.fn.someMethod = function() {
if (this[0].nodeName == 'body') {
// do your function
}
return this; // preserve chaining
};
The problem is that your function would be quite transient. A further requery and it will be gone. You can extend the jQuery object itself by $.fn.someMethod = function() {} and this method will be available for all queries.
$.fn.someMethod = function() {}
var b = $("body");
b.someMethod();
Or you can create a jQuery plugin. You can define a plugin this way:
$.fn.someMethod = function(options) {
# ...
});
Call it using $('body').someMethod();