When adding a dynamically added element, how can I get attributes for that element (when clicking on it, for example)? I figured out that I need to delegate an event, but I still can't access any of the attributes of that event.
This JSFiddle shows the issue problem: https://jsfiddle.net/wgc499n9/
$(this).data('index') comes up as 'undefined' - I think $(this) is referencing 'document' instead of .remove_link; even the event data doesn't seem to have any useful information in it. $(this).attr('id') also comes up as 'undefined'.
In the end, I just need to be able to click that remove link to remove the row it's on. How can I accomplish that? I even tried inline JS, but that caused even stranger behavior.
P.S. I also learned that my dynamically added data-index attribute is not stored in the DOM; jQuery stores it separately, so its containing element has to be accessed by using .find()...but I can't figure out how to use .find() to access the specific individual elements I need.
Use element event(e) parameter instead this:
let i = 0;
$('#add').on('click', () => {
$('#container').append(`<div>row #${(i+1)} <a "href="#" data-index="${i}" class="remove_link">remove</a></div>`);
i++;
})
$(document).on('click', '.remove_link', (e) => {
//alert(JSON.stringify(e));
alert($(e.target).data('index'));
})
.remove_link {
color: red;
font-size: 0.8em;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="add">Add row</button>
<div id="container"></div>
For more detail read difference b/w $(this) ans event.target.
In your event handler, this represent window. You have access to e.target to get the clicked element.
This should works:
$('#container').on('click', '.remove_link', (e) => {
alert($(e.target).data('index'));
})
Related
I use jquery and es6 template strings to create a checkbox with a label:
function createCheckBx(id, text) {
return $(`<div>
<input id ="${id}" type="checkbox"/>
<label for="${id}">${text}</label>
</div>`);
}
Now I would like to attach an eventlistener to the checkbox
checkBox = createCheckBx("42", "Answer");
cb.???.addEventListener("change", (evt) => {
// do smth. when toggled
})
but the div is not attached to the dom yet so I can't use document.getElementById (or jquery's $("#...") and I don't want to access it by any kind of index like cb.childNodes[0], since the caller can't know the index and the html structure may change. Any help?
kindly regards, AJ
Just because the element doesn't yet exist in the DOM doesn't mean you can't attach an event handler to it. The only issue in your example is the syntax you're using as you're mixing jQuery and plain JS methods. You should stick to one or the other.
As you're including jQuery in the page, here's how to make your example work:
let createCheckBox = text => $(`<div><label><input type="checkbox" />${text}</label></div>`);
let $checkBox = createCheckBox("Answer");
$checkBox.on('change', e => {
console.log(`Checkbox checked? ${e.target.checked}`);
});
// add the checkbox to the DOM at some point:
$('body').append($checkBox);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
Note that I removed the id attribute from the function which creates the element and also the HTML it generates. This is because creating id at runtime is an anti-pattern and should be avoided. Use common classes instead.
Also note that you may be better served by creating a single delegated event handler to handle all your dynamically appended content, instead of attaching an event as you create the new elements. Here's an example of how to do this:
let createCheckBox = text => $(`<div><label><input type="checkbox" />${text}</label></div>`);
let $container = $('.checkbox-container');
$('button').on('click', e => $container.append(createCheckBox("Answer")));
$container.on('change', ':checkbox', e => {
console.log(`Checkbox checked? ${e.target.checked}`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<button type="button">Add</button>
<div class="checkbox-container"></div>
Suppose I want to transform all (existing and dynamically created) <a> tags having a data-params property, e.g. by setting the href attribute.
It seems that this code:
$('body').on('change', 'a[data-params]', function() { ... })
only works on dynamically created elements, not existing elements.
On the other hand, this code:
$('a[data-params]').each(function(index) { ... });
only works on existing elements.
So if I want both (existing and dynamically created), I need both codes, ideally defining my transformation function first, then:
$('a[data-params]').each(function(index) { processDataParams(this); });
$('body').on('change', 'a[data-params]', function() { processDataParams(this); });
or am I missing some simpler way to do this?
$('a[data-params]') returns all nodes with this data attribute. Always.
I think that the problem is before, in the creation of dinamic elements. Avoid use the jQuery data method when you add the elements, because it does not update the DOM (don't adds the desired data-params attribute).
// Add some elements to the current doc
['magenta', 'olive'].forEach(color => {
$('<a>', {html:color})
// .data('params', color) <-- this don't updates de DOM, 👎 jQuery
.attr('data-params', color)
.appendTo('#root')
})
// Element unable to find with $('a[data-params]')
$('<a>', {html: 'This elemnt won\'t update'})
.data('params', 'purple')
.appendTo('#root')
function transform() {
$('a[data-params]').each((i, node) => {
$(node).css('color', $(node).data('params'))
$(node).attr('href', '#' + $(node).data('params'))
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="display: flex; flex-direction: column" id="root">
<a data-params='red'>red</a>
<a data-params='blue'>blue</a>
<a data-params='green'>green</a>
</div>
<hr>
<button onclick="transform()">Transform Elements</button>
Edited with the corrections of #Spectric and #RokoC.Buljan. Thanks to all.
You can use Jquery Event Delegation to run code (an event listener) on all child (internal) elements of an element, whether or not they already exist (because its set on the parent, which does already exist). You can read more about Event Delegation in JQuery's docs - https://learn.jquery.com/events/event-delegation/
Example:
$('ul').on('click', 'li', function(event) {
//code that will run on al <li> element clicks
});
this code is set on ul element, and allows an event listener to be set for all current and future li elements that are within the ul.
I try to have access to the row i clicked to add or remove a class, but it seems like i misinterpreted the value of this. Isn't it supose to be the DOM where the event go called (in this case, the <li>)? Here is my code:
JAVASCRIPT
$(document).on('click', '.ToDownload', function()
{
if($(this).className.lastIndexOf("isSelected") != -1)
{
$(this).addClass("isSelected");
$(this).css('border', '2px solid #000099')
}
else
{
$(this).removeClass("isSelected");
$(this).css('border', 'none')
}
});
HTML
<li id="addedDownloadFileRow" class="fitting ToDownload">
<a href="#">
<div class="ui-grid-a">
<div class="ui-block-a">test1</div>
<div class="ui-block-b">test2</div>
</div>
</a>
</li>
In fact, i thought i could use the property className to find if my row is already selected, but it seems like this isnt the DOM of the <li> tag. Any information or a way to see what this really is would be appreciated.
P.S. The class "fitting" is only used for some css purpose.
this is a DOM Element, $(this) is a jQuery object
Full working code is in http://jsfiddle.net/tomi77/xgv8q9md/
If you use Chrome (not sure whether this works in Firefox), you can log the value of this to the console.
If it is a jQuery object, it might not be clear to see which element it refers to, however it's straightforward to get the underlying element out.
console.log(this[0]);
This will give you a minimal representation of the element itself and if you hover over it, you'll see the element highlighted in the web view itself.
This lets you see exactly which element it refers to. As mentioned in the comments, you can also log the direct object form of the element to the console with console.dir(element).
I have to add a list of checkboxes dynamically. I then need to know which one performed the click, then ask if it's checked or not.
I have this code:
$('#MyContainerOfChecksDiv').click( '.MySelectorClass', function(){
if ("MyCheckClicked".is(':checked'))
{
//...here i need to use the label and id
}
else{...}
})
using "$(this)" i get the "MyDiv", obviously using $(this).find('input:checkbox') I get the whole list of checks.
I have to get this checkbox because I need to use its properties.
Add a formal parameter to click handler and use it like this
$('#myDiv').click('.MySelectorClass', function (e) {
if ($(e.target).is(':checked')) {
alert(e.target.id);
}
})
fiddle
Also it's not quite clear to me how you distinguish dynamically added elements and static. Do you have different class for them? If so then you dynamic and static elements can have different handlers and this will be the way to tell whether it was created dynamically
To delegate to dynamic elements you have to use .on(). The element that you clicked on will be in this.
$("#myDiv").on("click", ".MySelectorClass", function() {
if (this.clicked) {
// here you can use this.id
} else {
// ...
}
});
You can't use .click() to delegate like you tried. You're just binding the click handler to the DIV, and the string ".MySelectorClass" is being passed as additional data to the handler.
I have a list of buttons that is created by the DOM which references an array. When a button in the list is clicked, I want to retrieve the String that is displayed on the Button.
I have tried the following code to reference the string value, but get undefined:
this.String; inside the function when the button is clicked to retreive the string.
How can I properly retrieve the string.
The click handling function is:
$('.timeButtons').click(function() {
confirmation.push(this.textContent);
})
This is how the list of buttons is created:
var populateList=function(array){
var list = document.createElement('ul');
list.className="delete";
for(var i = 0; i < array.length;- i++) {
var item = document.createElement('li');
var itemButton=document.createElement('button');
itemButton.style.cssText='background:#f85a5a; border:none; width:200px; height:50px; margin-bottom:50px; align:center; border-radius:25px; color:#ffffff;'
itemButton.appendChild(document.createTextNode(array[i]));
item.appendChild(itemButton);
list.appendChild(item);
}
return list;
}
Assuming that this is a reference to the button element in question, you can use this.textContent to get the button's text. (Or .innerHTML.)
Demo: http://jsfiddle.net/w0ntsrLx/
Or since in your edited question you seem to be using jQuery, use the .text() method. In a comment you say that the containing div has the "timeButtons" class, so bind a delegated handler to that div as follows:
$(".timeButtons").on("click", "button", function(e) {
confirmation.push($(this).text());
});
Demo: http://jsfiddle.net/w0ntsrLx/1/
That way the function will only be called if the click is on a button element within the .timeButtons div, and this will be the clicked button. The click handler that you show in your question with $(".timeButtons").click(...) is bound to the div and doesn't in any way test for the buttons, so within the handler this will be the div, not the clicked button.
Check this out
Assuming you want pure javascript code,
Whenever an event is triggered, an object is passed back in callback (generally being named as 'event'). this object has many properties including source element, position of click and many more.
get the element using event.srcElement
You can use element.innerHTML or element.innerText to find out the content of the Button.
There is a difference between using innerText and innerHTML, but in your case, both can be used.
Also, you can use jquery too to easily append child, create elements and binding events.