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();
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 want to create some events in javascript, but what I want is to be able to use them with jQuery objects because I want to do a framework and it has to be easy to use.
What I want is something like this:
function myEvent() {//code here}
$("#myObject").myEvent()
And trigger the event there, of course I want to know how to get the object which triggered it because I can't do anything without it.
I think that I might have to extend a prototype, but I'm not sure about that.
Can anyone help me? Thank you!!
I think you mean custom methods. Events work differently in JavaScript then what your code is trying to display. You can extend jQuery functions like this:
jQuery.fn.extend({
check: function() {
return this.each(function() {
this.checked = true;
});
}
});
// Use the newly created .check() method
$( "input[type='checkbox']" ).check();
DOCS: https://api.jquery.com/jquery.fn.extend/
JoshSpears' answer is perfect. Check also this one, I think you'll find easier to implement (just C&P):
Assuming you have, for example:
var myEvent = function(str) {
alert(str);
};
And you want something like:
$('div').myEvent('hey guys!');
Just implement this:
$.fn['myEvent'] = function( options ) {
return this.each( function() {
myEvent(options);
});
};
This is just a simplification of the jquery plugin pattern wrapper. Check it out here:
https://github.com/jquery-boilerplate/jquery-boilerplate/blob/master/dist/jquery.boilerplate.js
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>
Assuming I have something like:
var MyApp = function() {
this.name = "Stacy"
}
MyApp.prototype.updateName = function(newname) {
this.name = newname;
}
In my main page I have a :
$(function () {
var instance = new MyApp();
})
I have a button event handler that would update the name:
$("#button").on("click", function(evt) {
// Update the name in MyApp to something else...
instance.name = "john" // I do not like using instance here, because it has to be "instance" has to be created before I can use it. I want to be able to make this independent of "instance" being created or not
});
What is the proper way to do it such that the button handler would update "MyApp" to have the correct name, without explicitly using the created "instance" of myapp as part of the button's click handler?
ideally I would like to shove that jquery event handler somewhere into "MyApp" such that I could do something like:
MyApp.prototype.events = function() {
$("#button").on("click", function(evt) {
this.name = "john"
});
}
Though it doesnt work because this refers to something else.
How to properly structure my application such that the event handler is more or less updating the properties of the "MyApp" so that it can be independent of the created "instance" (i.e. i no longer have to use the "instance.")?
First, if you create an setter function, it's a good idea to use it !! :D
$("#button").on("click", function(evt) {
// Update the name in MyApp to something else...
//instance.name = "john"
instance.updateName("john");
});
And then, it does not make sense to do put an event handler inside of a method of your object MyApp, since it will never bind the onclick event until you fire events()
Then... my way to organize this, is to use the jQuery document onload to bind all the DOM objects with the function of your applications. Usually something like this:
MYAPP = {};
MYAPP.say_something = function () {
alert('lol, you clicked me!');
};
...
$(function () {
$('#my_button').click(MYAPP.say_something);
$('#other_element').mouseenter(MYAPP.another_method);
});
And for big applications, where you have to work with a lot of elements, you can organize your code much better if you have a namespace for your DOM elements, something like this:
MYAPP.fetch_dom = function () {
return {
my_button: $('#my_button'),
other_element: $('#other_element')
};
};
And you can bind the events in a very neat way
$(function () {
// first initiate DOM
my_dom = MYAPP.fetch_dom();
// Then bind events
my_dom.my_button.click(MYAPP.say_something);
my_dom.other_element.mouseenter(MYAPP.another_method);
});
This way you don't have to look for the specific elements in the DOM from a thousand points of your programme, spreading hardcoded id's everywhere and performing noneffective searches against the DOM structure.
Finally, it is much better to use literals in JS rather than using the word new. JS is a prototypical OOP language and new is a little bit "against nature" that can be a pain in the ass.
After discovering about Javascript namespaces, I tried to implement them but I run into a problem while trying to attach a namespace method to an element's onclick.
I used this method to wrap up my functions/methods/classes (a simplified concept, not my actual code):
;(function(window, undefined) {
//my namespace
var NS = {};
NS.test = {
f : function(param) {
alert(param);
}
}
NS.test.('test 2');
})(window);
Inside, everything works fine and "test 2" is prompted.
However, when I try to attach that function to a click event, by doing something like this:
<a href-"#" onclick="NS.test.f('test');">Click me!</a>
it doesn't work, just like it doesn't work when I call that function after the })(window); part.
I tried it calling it window.NS.test.f('test'); but with no effect.
How can I make an onclick event call my function?
I could attach an event listener inside my wrapper, like I do for other html elements with no difficulty, but it would be problematic in this case since I'm generating the links with javascript and I find it easier and simpler to just add onclick="doSomething" for all my links, instead of creating them, then cache them and add event listeners.
Call me lazy, but in this particular case I prefer to do
someDiv.innerHTML = my_Generated_Html_Code_With_OnClick;
instead of
//demo code, ignore the flaws and the fact it won't work on IE
someDiv.innerHTML = my_generated_Html_code;
myLink = document.getElementById(id);
myLink.addEventListener('mousedown', NS.test.f('test'));
I do not use any framework nor do I wish to, since I'm trying to get a better understanding of the so-called vanilla javascript first.
I set up a jsfiddle here.
P.S. I must admit I didn't understand namespaces completely so if I'm doing something wrong here or applying the concept in a way I am not supposed to, I would appreciate any tips or corrections
That's because NS is declared inside and hence only exists inside the function:
function(window, undefined) {
var NS = {};
// NS exists here ...
}
// ... but not here
If you want to make it available to the rest of the page, then you can do:
function(window, undefined) {
var NS = window.NS = {};
// NS and window.NS exist here ...
}
// ... and window.NS exists here.