How to refactor this simple code - javascript

I have a following script:
$(document).ready(function() {
$('#q1_6').on("click", function(event){
$('#q1-f').slideToggle(350);
});
$('#q1_7').on("click", function(event){
$('#q1-m').slideToggle(350);
});
$('#q1_15').on("click", function(event){
$('#q1-o').slideToggle(350);
});
$('#q2_6').on("click", function(event){
$('#q2-f').slideToggle(350);
});
$('#q2_7').on("click", function(event){
$('#q2-m').slideToggle(250);
});
$('#q2_15').on("click", function(event){
$('#q2-o').slideToggle(350);
});
$('#q3_13').on("click", function(event){
$('#q3-o').slideToggle(350);
});
});
Are these calls proper, or maybe I should somehow refactor the script to avoid duplication?
Edit:
I am creating a survey with about 20 questions displayed on one page. Answers are in checkboxes. Some answers have additional options (sub-answers), which should be shown when user clicks parental answer. Here is HTML markup for better understanding
<div>
<input type="checkbox" id="q1_5"/><label for="q1_5">Answer 5</label>
</div>
<div>
<input type="checkbox" id="q1_6"/><label for="q1_6">Answer 6</label>
</div>
<div id="q1-f">
<div>
<input type="checkbox" id="q1_6_1"/><label for="q1_6_1">Answer 6-1</label>
</div>
<div>
<input type="checkbox" id="q1_6_2"/><label for="q1_6_2">Answer 6-2</label>
</div>
<div>
<input type="checkbox" id="q1_6_3"/><label for="q1_6_3">Answer 6-3</label>
</div>
</div>
Current script works well, but I am wondering if I can avoid repeats of the same code snippets.

If you have access to the HTML and can influence the structure of the elements which when clicked initiate the toggle, then I'd add a class and data attribute:
<a href='#' id='q1_6' class='toggle' data-toggle-id='q1-f'>blah</a>
$(document).ready(function() {
$('a.toggle').on('click', function(){
var $el = $(this),
toggleID = '#' + $el.attr('data-toggle-id'),
toggleValue = 350;
$(toggleID).slideToggle(toggleValue);
});
});

given no idea on how IDs are correlated in your example.
function toggle(id, id2, value){
$(id).on("click", function(event){
$(id2).slideToggle(value);
});
}
toggle('#q1_15', '#q1-0', 350);

You could do :
$('[id^="q"]').on("click", function(e){
//get the id of the clicked button
var id = e.target.id;
switch(id){
//do all cases based on id
}
});
This could be done in an even cleaner way if there is some element to which we could delegate the event handling, but you didn't show us your markup. It would be something like
$('body').on("click",'[id^="q"]', function(e){
//get the id of the clicked button
var id = e.target.id;
switch(id){
//do all cases based on id
}
});
This second option use only one event handler (good) but it has to wait until the event is bubbled up the DOM (might be bad)

Why don't you create a javascript object where keys denote the id of element that accepts clicks and corresponding value is the id of element to show. Something like:
var clickHanders = {
"q1_6": "q1-f",
"q1_7": "q1-m"
// ...
};
Then all you need is:
$(document).ready(function() {
$("div[id^=q]").on("click", function(event) {
var srcId = this.id;
var dstId = clickHanders[srcId];
if (dstId) {
$("#" + dstId).slideToggle(350);
}
});
});
Edit
I now see that the slide duration can be different as well. You can still use the above approach:
var clickHanders = {
"q1_6": {
"elementId": "q1-f",
"duration": "350"
},
"q2_7": {
"elementId": "q2-m",
"duration": "250"
}
//...
};
$(document).ready(function() {
$("div[id^=q]").on("click", function(event) {
var srcId = this.id;
var dstData = clickHanders[srcId];
if (dstData) {
$("#" + dstData.elementId).slideToggle(dstData.duration);
}
});
});
This code looks longer than your original code but perhaps more sensible.

There are some things to ask when you refactor:
Are you having speed problems?
Are you having memory problems?
Does the code look ugly?
You should not be refactoring code just to refactor it and optimize something where it is not needed. If the code is not too slow and does not have a too high memory consumption (all in the eye of the beholder) and is readable, you have good code.
My idea would be to serialize the event trigger, event target and slideToggle amount, so you could iterate through some kind of Collection and bind it. But would that be worth it?

Well, each handler does the very same thing, so here's what you should do:
Refactor your HTML, for example:
<div id="q1-6" data-to="q1-f"></div>
for each object (you can use other HTML attributes). Then you can define handlers:
$('#q1-6,#q1-7,#someother_id,#watman,#foo').click(function() {
var id = $(this).attr('data-to');
$('#'+id).slideToggle(350);
});

There is no way to shorten your code, because there is nothing exactly the same, so your code is ok.

Related

Is it allowed to use jQuery $(this) selector twice in a function and in an included each loop?

I have a list, which contents x columns of data. When clicking an edit button in a row, I want to set the html content of each column of this row, which has a name attribute into an array, which key is named by the columns name attributes value.
data['id'] = '123';
data['name'] = 'John Doe';
data['city'] = 'Arlington';
For that I'm starting a click event on the edit div. Inside this function I'm working with $(this) selector for setting up an each() loop over all elements having a name attribute.
Inside this loop I'm catching the names and values of each matched element with $(this) selector again.
So, my question: although it works - is it allowed to do it this way? Using $(this) for two different things inside the same function?
Is there a different way?
Here is my working example code
$( document ).ready(function() {
$(document).on( "click", ".edit", function() {
var data = {};
$(this).closest('.row').children('div[name]').each(function() {
//form_data.append($(this).attr('name'), $(this).html());
data[$(this).attr('name')] = $(this).html();
});
$('#result').html(JSON.stringify(data, null, 4));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div name="id">123</div>
<div name="name">John Doe</div>
<div name="city">Berlin</div>
<div class="edit">> edit <</div>
</div>
<br clear="all">
<div id="result"></div>
Is it allowed?
It works, so of course.
Depends on what you mean by "allowed".
Is it confusing - perhaps.
Can it cause problems - definitely.
(There are plenty of questions on SO with this or problems caused by this that confirm it causes problems).
Reusing variable names ('this' in this case) is common and is based on scope.
It's hard to tell if you have a bug because you actually wanted the ".edit" html or the ".edit" attr rather than the div, so you can remove that confusion by copying this to a variable:
$(document).on( "click", ".edit", function() {
var data = {};
var btn = $(this); // the button that was clicked
btn.closest('.row').children('div[name]').each(function() {
// Do you mean the div or did you really mean the clicked button?
data[$(this).attr('name')] = $(this).html();
var div = $(this); // the child div
// clearly not what is desired
// `btn` variable referring to the outer `this`
data[div.attr('name')] = btn.html();
// intention clear
data[div.attr('name')] = div.html();
});
$('#result').html(JSON.stringify(data, null, 4));
});
In this case, it's "clear" as you wouldn't use the btn html on all the data entries (or would you? I don't know your requirements...). So "unlikely".
But it's easy to see how, in another scenario, you would want to refer to what was clicked btn==this inside the nested .each.
Try this trick:
$( document ).ready(function() {
$(document).on( "click", ".edit", function() {
var data = {};
var that = this; // trick here
$(this).closest('.row').children('div[name]').each(function() {
//form_data.append($(this).attr('name'), $(this).html());
data[$(this).attr('name')] = $(that).html();// replace this = that if you want to get parent element
});
$('#result').html(JSON.stringify(data, null, 4));
});
});
there is nothing wrong, what you do is simply this
function setDivs() {
//form_data.append($(this).attr('name'), $(this).html());
data[$(this).attr('name')] = $(this).html();
}
function docClick(){
var data = {};
$(this).closest('.row').children('div[name]').each(setDivs);
$('#result').html(JSON.stringify(data, null, 4));
}
function docReady(){
$(document).on( "click", ".edit", docClick)
}
$( document ).ready(docReady);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div name="id">123</div>
<div name="name">John Doe</div>
<div name="city">Berlin</div>
<div class="edit">> edit <</div>
</div>
<br clear="all">
<div id="result"></div>

Copy value from input 1 to input 2 onclick

Looking for a script that copies input value 1 to input 2 on button click and add +1 to sets text box.
b = document.getElementById('tussenstand').value;
var theTotal1 = b;
$(document).on("click", "#button1", function(){
theTotal1 = Number(theTotal2)
$('#eindstand').val(theTotal2);
});
$('#eindstand').val(theTotal2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="tussenstand"></input>
<input id="eindstand"></input>
<input id="sets"></input>
<button id="button1">click</button>
Thanks in advance.
I think this will do it.
$(document).on("click", "#button1", function(){
var total = document.getElementById('tussenstand').value;
$('#eindstand').val(total);
var sets = parseInt($('#sets').val());
$('#sets').val( (sets || 0) + 1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="tussenstand"></input>
<input id="eindstand"></input>
<input id="sets"></input>
<button id="button1" onclick="">click</button>
$('#button1').click(function(){
$('#eindstand').val($('#tussenstand').val());
$('#sets').val(Number($('#sets').val())+1);
});
check here : jsfiddle
Edited as you commented
The code below should work. There are several issues that will help you in the future. In the HTML the function that is triggered via the onclick will interfere with the jQuery onclick. You may want to remove it.
onclick="bereken();
The way that you have your code the b variable is not declared.
b=document.getElementById('tussenstand').value;
The way that the jQuery onclick is written should have a narrower scope (not the document). The way that it is now every time you click any were in the document it fires. I changed this:
$(document).on("click", "#button1", function(){
to this:
$("#button1").on("click", function() {
The full edited code is here.
var count = 0;
$("#button1").on("click", function(){
if ( typeof b === 'number') {
count++;
$("#eindstand").val(b);
$("#sets").val(count);
}
});
Look at the JQuery API Documentation for the .on() method. The function doesn't take the target as a parameter, but as the caller object! EDIT: well, it would actually still work the other way around, but that makes event delegation. Only do that if you know what you're doing. I prefer changing this:
$(document).on("click", "#button1", function(){ ... });
into this:
$("#button1").on("click", function() { ... });
Which in vanilla JS would be:
document.getElementById("button1").addEventListener("click", function() { ... });
Next, you shouldn't need to define variables outside of your function, and naming variables with numbers in them is a bad practice. Try to make the names as clear as possible.
Now that this is clear, here's how I'd write it:
$("#button1").on("click", function() {
$("#eindstand").val($("#tussenstand").val());
$("#sets").val(parseInt($("#sets").val())+1);
});
To achieve that use:
$(function() { //on DOM ready
$('#button1').click(function(){ //Attach event
//Get value safe - can use parseFloat() too:
val1 = parseInt($('#tussenstand').val());
val2 = parseInt($('#eindstand').val());
sets = parseInt($('#sets').val());
//Make sure we are using integers:
if (isNaN(val1) || isNaN(val2) || isNaN(sets)) return;
//Add
$('#eindstand').val(val1 + val2);
//Increment:
$('#sets').val(sets+1);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="tussenstand" type='number' />
<input id="eindstand" value='0' type='number' />
<input id="sets" value='0' type='number' />
<button id="button1">click</button>

Why would this JS fire on a form partial rendered on 1 page but not another?

I have a posts.js file that looks like this:
var ready;
ready = function() {
var toggleSidebar = $(".togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
toggleSidebar.on("click", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
};
var counter = function(event) {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /\s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
};
$(document).ready(ready);
$(document).on('ready page:load', function () {
$('#post_title, #body-field').on('change keyup paste', counter);
});
In my application.html.erb page, I have this:
<div id="secondary" class="col-sm-3 sidebar" style="display: none;">
<aside>
<div class="about">
<h4>Submit Report</h4>
<%= render "posts/form" %>
</div>
</aside>
</div> <!-- /#secondary -->
And when I toggle this div, and the _form partial is displayed, the JS works fine in those fields.
But if I go to posts/new or /posts/:id/edit, it doesn't.
Even though if I check the source of that page, I see the post.js included there.
What could be causing this?
Edit 1
I am using Turbolinks, if that matters.
Edit 2
I tried this, per suggestions in the Answers:
var ready;
ready = function() {
// This is the Sidebar toggle functionality
var toggleSidebar = $(".togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
$(document).on("click", ".togglesidebar", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
};
But that hasn't worked.
The key issue I am having a problem with is the 'counters', i.e. #wordCountTitle and #wordCountBody don't work on my /posts/new even though they work on the posts/index when .toggleSidebar is activated.
Instead of binding directly to the element's onclick which needs careful handling of Turbolinks events, you can use an event handler on the document, try changing the direct event
toggleSidebar.on("click", function(){
to the delegated event
$(document).on("click", ".togglesidebar", function(){
When you modify the DOM dynamically (as when Turbolinks replaces it) if you use a direct event then you would need to re-assign it.
For a detailed explanation see http://api.jquery.com/on/#direct-and-delegated-events
The same that goes for the first function stands for the second. Also, with delegated events the "ready" check becomes unnecessary. With this in mind, your code would become:
$(document).on("click", ".togglesidebar", function(){
var primary = $("#primary");
var secondary = $("#secondary");
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
$(document).on('change keyup paste', '#post_title, #body-field', function () {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /\s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
});
I am using something like this on one of my projects, had the same problem hope it helps:
window.onLoad = function(callback) {
$(document).ready(callback);
$(document).on('page:load', callback);
};
and then wrap up my functions with onLoad, something like
onLoad(function() {
counter()
});
The onLoad function binds the ready event and the turbolink page:load event
when you do
$("selector").on("click", function(){});
you actually bind the selector to the click event.
White if you use
$(document).on("click", "selector", function(){});
You bind the click event to the document, which after the click checks if the clicked element was the selector you used. if yes, it executes the function. So you should use the second approach whenever binding events on dynamic elements.
I hope that answers the question of "why"
Long time I don't work with jQuery, but since I got here: If you have more than one element with the selector ".sidebar", I believe you'll need to use ".each" to bind the function to all elements that match that selector on the dom.
For the reference go here http://api.jquery.com/each/
Hope this helps, good luck.
I took a look on Turbolinks, and it does what I thought it did: It loads the HTML content of a link inside a container on the main page. Problem is, anything it loads is agnostic of whatever events and functions you have declared when the main page loaded, so indeed, after the first click, the selector on the HTML it has just loaded won't have the click event attributed to it (it was not on the DOM when you did the binding).
Possible solution: I did a little research on the .live() method, but is has been deprecated, so I recommend doing something like this:
$('body').on('click','a.saveButton', saveHandler)
Binding closer to the element you need will, it seems, will assure that whatever Turbolinks loads inside the body will get the bindings you have declared.
There is a more detailed answer here: Javascript event binding persistence
The documentation for the .live hook is here: http://api.jquery.com/live/#typefn
I used to have the same architecture on my web pages back in the day, and I did run on a problem similar to yours.
Hope it helps.
Should it work.. make sure:
Nothing id conflict.
Your html structure, maybe you forgot put value in your post.
Maybe wrong path posts.js, open with CTRL+U and then click post.js what is showing your code, if there so it's ok.
I try like this, it's ok(dummy):
$(document).on("click", ".togglesidebar", function(){
var primary = $("#primary");
var secondary = $("#secondary");
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
$(document).on('change keyup paste', '#post_title, #body-field', function () {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
console.log(wc);
var regex = /\s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="togglesidebar">Toogle</div>
<div id="wordCountTitle"></div>
<div id="wordCountBody"></div>
<div id="primary">
<div id="secondary" class="col-sm-3 sidebar" style="display: none;">
<aside>
<div class="about">
<h4>Submit Report</h4>
<input type="text" id="body-field"/>
</div>
</aside>
</div> <!-- /#secondary -->
</div>
Honestly with Js problems involving Turbolinks the best way to have it work efficiently is to install jquery rails gem, add // require jquery-Turbolinks and then remove //require turbolinks in your Js file
Make sure that the ids you are passing on the jQuery selectors are unique. If that page/partial is loaded without a postback, you should use
//document or selector that does not get removed
var primary = $(document).find('#primary');
var secondary = $(document).find('#secondary');
this, with
$(document).click('eventName', 'contextSelector', function)
should help resolve the issue.
If #post_title and #body-field are created dynamically you'll need to change:
$('#post_title, #body-field').on('change keyup paste', counter);
To this:
$(document).on('change keyup paste', '#post_title, #body-field', counter);
You'll need to delegate your events to elements that exist on page load (the document itself, in this case) when targeting elements that don't exist when the page is loaded (probably #post_title and #body-field).
Regarding $('#wordCountTitle') and $('#wordCountBody') on /posts/new, have you tried just typing in either of them at the console? It's possible that the view for /posts/new is different to your index and is missing those ids (or you made them classes or some other transposition happened).
I was having all kinds of issues with Turbolinks and jquery so a few suggestions on how I would go about trying to fix your problems:
Use gem 'turbolinks' to include it. Follow the instructions and do it the Ruby (gems) way rather than the PHP way.
Using Turbolinks means that$(document).ready doesn't fire when a new 'page' loads. The solution is to use: $(document).on('page:load', ready) along with $(document).ready(ready). The page:load event is the Turbolinks version of the ready event.
Others have suggested it but I've found it incredibly valuable in my rails app: Rather than binding events directly to selectors $("a").click(/* function */), binding to the document means that when Turbolinks loads a new page, the document binding survives the page load: $(document).on('click', 'a.particularAnchor', particularAnchorClicked)
With your specific code in mind, I would change this:
$('#post_title, #body-field').on('change keyup paste', counter);
To
$(document).on('change keyup paste', '#post_title, #body-field', counter);
It also seems to me that in your counter function you have mixed the following two lines up (regex needs to be defined first)
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /\s+/gi;

Same function for few elements

I have on my site alot of payment systems and instructions for them (visa, mastercard, amex and so..).
This script shows instructions when clicking on button.
$('#show-visa').click(function() {
$('#instruction-visa').fadeIn();
});
$('#close-visa').click(function() {
$('#instruction-visa').fadeOut();
});
I would need to duplicate this same script for every payment system, but there are many of them (aroung 20-25).. Writing same script for every payment system is not good idea. How can i do it better way?
Since I cannot see your markup, I will improvise...
Several things to note:
I am using .fadeToggle() instead of .fadeIn() and .fadeOut()
Use a common class for toggle buttons and have one .click() handler for all of them
Make use of data-* in your markup
jQuery:
$('.toggle-option').click(function() {
var $target = $(this).data('target'); // Get the data-target attribute
$('#' + $target).fadeToggle(); // Toggle the id specified by data-target
});
HTML:
<button class="toggle-option" data-target="visa">Toggle Visa</button>
<button class="toggle-option" data-target="mastercard">Toggle Mastercard</button>
<button class="toggle-option" data-target="maestro">Toggle Maestro</button>
DEMO
You can extend the jquery prototype object. I created a simple jsfiddle for you.
JSFiddle
$.fn.test = function(){
alert('the id is: ' + $(this).attr('id'));
}
If you want to have different selectors in your html structure for each payment system you could make an array with your payment system names and use $.each function on it to add handler for each one.
var paymentSystems = ['visa', 'mastercard', etc... ];
$.each(paymentSystems, function(name){
$('#show-' + name).on('click', function() {
$('#instruction-'+name).fadeIn();
});
$('#close-' + name).on('click', function() {
$('#instruction-'+ name).fadeOut();
});
};
Add a class to every single element and use the data- attribute to get the element which should be shown.
HTML
<button class="show" data-id="element1">Show</button>
<button class="hide" data-id="element1">Hide</button>
<button class="show" data-id="element2">Show</button>
<button class="hide" data-id="element2">Hide</button>
<div class="element" id="element1">Element1</div>
<div class="element" id="element2">Element2</div>
Js
$(function () {
$(".show").click(function () {
$("#" + $(this).data("id")).fadeIn();
});
$(".hide").click(function () {
$("#" + $(this).data("id")).fadeOut();
});
});
JsFiddle

Getting the ID of the element that fired an event

Is there any way to get the ID of the element that fires an event?
I'm thinking something like:
$(document).ready(function() {
$("a").click(function() {
var test = caller.id;
alert(test.val());
});
});
<script type="text/javascript" src="starterkit/jquery.js"></script>
<form class="item" id="aaa">
<input class="title"></input>
</form>
<form class="item" id="bbb">
<input class="title"></input>
</form>
Except of course that the var test should contain the id "aaa", if the event is fired from the first form, and "bbb", if the event is fired from the second form.
In jQuery event.target always refers to the element that triggered the event, where event is the parameter passed to the function. http://api.jquery.com/category/events/event-object/
$(document).ready(function() {
$("a").click(function(event) {
alert(event.target.id);
});
});
Note also that this will also work, but that it is not a jQuery object, so if you wish to use a jQuery function on it then you must refer to it as $(this), e.g.:
$(document).ready(function() {
$("a").click(function(event) {
// this.append wouldn't work
$(this).append(" Clicked");
});
});
For reference, try this! It works!
jQuery("classNameofDiv").click(function() {
var contentPanelId = jQuery(this).attr("id");
alert(contentPanelId);
});
Though it is mentioned in other posts, I wanted to spell this out:
$(event.target).id is undefined
$(event.target)[0].id gives the id attribute.
event.target.id also gives the id attribute.
this.id gives the id attribute.
and
$(this).id is undefined.
The differences, of course, is between jQuery objects and DOM objects. "id" is a DOM property so you have to be on the DOM element object to use it.
(It tripped me up, so it probably tripped up someone else)
For all events, not limited to just jQuery you can use
var target = event.target || event.srcElement;
var id = target.id
Where event.target fails it falls back on event.srcElement for IE.
To clarify the above code does not require jQuery but also works with jQuery.
You can use (this) to reference the object that fired the function.
'this' is a DOM element when you are inside of a callback function (in the context of jQuery), for example, being called by the click, each, bind, etc. methods.
Here is where you can learn more: http://remysharp.com/2007/04/12/jquerys-this-demystified/
I generate a table dynamically out a database, receive the data in JSON and put it into a table. Every table row got a unique ID, which is needed for further actions, so, if the DOM is altered you need a different approach:
$("table").delegate("tr", "click", function() {
var id=$(this).attr('id');
alert("ID:"+id);
});
Element which fired event we have in event property
event.currentTarget
We get DOM node object on which was set event handler.
Most nested node which started bubbling process we have in
event.target
Event object is always first attribute of event handler, example:
document.querySelector("someSelector").addEventListener(function(event){
console.log(event.target);
console.log(event.currentTarget);
});
More about event delegation You can read in http://maciejsikora.com/standard-events-vs-event-delegation/
The source element as a jQuery object should be obtained via
var $el = $(event.target);
This gets you the source of the click, rather than the element that the click function was assigned too. Can be useful when the click event is on a parent object
EG.a click event on a table row, and you need the cell that was clicked
$("tr").click(function(event){
var $td = $(event.target);
});
this works with most types of elements:
$('selector').on('click',function(e){
log(e.currentTarget.id);
});
You can try to use:
$('*').live('click', function() {
console.log(this.id);
return false;
});
Use can Use .on event
$("table").on("tr", "click", function() {
var id=$(this).attr('id');
alert("ID:"+id);
});
In the case of delegated event handlers, where you might have something like this:
<ul>
<li data-id="1">
<span>Item 1</span>
</li>
<li data-id="2">
<span>Item 2</span>
</li>
<li data-id="3">
<span>Item 3</span>
</li>
<li data-id="4">
<span>Item 4</span>
</li>
<li data-id="5">
<span>Item 5</span>
</li>
</ul>
and your JS code like so:
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target),
itemId = $target.data('id');
//do something with itemId
});
});
You'll more than likely find that itemId is undefined, as the content of the LI is wrapped in a <span>, which means the <span> will probably be the event target. You can get around this with a small check, like so:
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target).is('li') ? $(event.target) : $(event.target).closest('li'),
itemId = $target.data('id');
//do something with itemId
});
});
Or, if you prefer to maximize readability (and also avoid unnecessary repetition of jQuery wrapping calls):
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target),
itemId;
$target = $target.is('li') ? $target : $target.closest('li');
itemId = $target.data('id');
//do something with itemId
});
});
When using event delegation, the .is() method is invaluable for verifying that your event target (among other things) is actually what you need it to be. Use .closest(selector) to search up the DOM tree, and use .find(selector) (generally coupled with .first(), as in .find(selector).first()) to search down it. You don't need to use .first() when using .closest(), as it only returns the first matching ancestor element, while .find() returns all matching descendants.
This works on a higher z-index than the event parameter mentioned in above answers:
$("#mydiv li").click(function(){
ClickedElement = this.id;
alert(ClickedElement);
});
This way you will always get the id of the (in this example li) element. Also when clicked on a child element of the parent..
$(".classobj").click(function(e){
console.log(e.currentTarget.id);
})
var buttons = document.getElementsByTagName('button');
var buttonsLength = buttons.length;
for (var i = 0; i < buttonsLength; i++){
buttons[i].addEventListener('click', clickResponse, false);
};
function clickResponse(){
// do something based on button selection here...
alert(this.id);
}
Working JSFiddle here.
Just use the this reference
$(this).attr("id")
or
$(this).prop("id")
this.element.attr("id") works fine in IE8.
Pure JS is simpler
aaa.onclick = handler;
bbb.onclick = handler;
function handler() {
var test = this.id;
console.log(test)
}
aaa.onclick = handler;
bbb.onclick = handler;
function handler() {
var test = this.id;
console.log(test)
}
<form class="item" id="aaa">
<input class="title"/>
</form>
<form class="item" id="bbb">
<input class="title"/>
</form>
Both of these work,
jQuery(this).attr("id");
and
alert(this.id);
You can use the function to get the id and the value for the changed item(in my example, I've used a Select tag.
$('select').change(
function() {
var val = this.value;
var id = jQuery(this).attr("id");
console.log("value changed" + String(val)+String(id));
}
);
I'm working with
jQuery Autocomplete
I tried looking for an event as described above, but when the request function fires it doesn't seem to be available. I used this.element.attr("id") to get the element's ID instead, and it seems to work fine.
In case of Angular 7.x you can get the native element and its id or properties.
myClickHandler($event) {
this.selectedElement = <Element>$event.target;
console.log(this.selectedElement.id)
this.selectedElement.classList.remove('some-class');
}
html:
<div class="list-item" (click)="myClickHandler($event)">...</div>
There's plenty of ways to do this and examples already, but if you need take it a further step and need to prevent the enter key on forms, and yet still need it on a multi-line textarea, it gets more complicated. The following will solve the problem.
<script>
$(document).ready(function() {
$(window).keydown(function(event){
if(event.keyCode == 13) {
//There are 2 textarea forms that need the enter key to work.
if((event.target.id=="CommentsForOnAir") || (event.target.id=="CommentsForOnline"))
{
// Prevent the form from triggering, but allowing multi-line to still work.
}
else
{
event.preventDefault();
return false;
}
}
});
});
</script>
<textarea class="form-control" rows="10" cols="50" id="CommentsForOnline" name="CommentsForOnline" type="text" size="60" maxlength="2000"></textarea>
It could probably be simplified more, but you get the concept.
Simply you can use either:
$(this).attr("id");
Or
$(event.target).attr("id");
But $(this).attr("id") will return the ID of the element to which the Event Listener is attached to.
Whereas when we use $(event.target).attr("id") this will return the ID of the element that was clicked.
For example in a <div> if we have a <p> element then if we click on 'div' $(event.target).attr("id") will return the ID of <div>, if we click on 'p' then $(event.target).attr("id") will return ID of <p>.
So use it as per your need.

Categories

Resources