Select ALL elements with specific data attribute Javascript? - javascript

With jquery, I've got the following code:
$('a[data-hello]').click(function(){ = That select all "a" elements with "data-hello".
I'm trying to make this with raw Javascript. I stop here:
document.querySelectorAll("data-hello").onclick = function() {
(btw, theres a way to select all the A elements with data-hello and not all with data-hello? o.O)
But querySelectorAll returns a Array. Because of this, it only works if I determine a position. This way:
document.querySelectorAll("data-hello")[5].onclick = function() {
But I want ALL ELEMENTS, not specific elements, like with jQuery. I cant use jQuery.
It is so simple with Jquery :( I must make a "for" to wade through all the positions in JS? Is this necessary? sorry I do not understand...
What I want to do:
I want to get the data attribute value of the element that is clicked. I use this for this inside the function and, then, I applied another function that add a class in a specific element.
Basically, there is buttons with classes in data attribute value. This classes will be applied to a specific element.

Put the array (actually a NodeList) of elements in a variable and loop through them to set the event handler on each of them. That's what the jQuery methods do to apply something to all elements in a jQuery object. There is no way around the loop, with jQuery it's just hidden within the methods. You can use the same selector syntax as in jQuery with querySelectorAll.
var arr = document.querySelectorAll("a[data-hello]");
var f = function() {
// do something
};
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = f;
}

querySelectorAll accepts a string of comma-separated CSS selectors, just like jQuery, so you can give it the same string: 'a[data-hello]'.
The difference between native and jQuery that you are running into is in calling methods on the elements returned. jQuery returns a jQuery object, which has methods that often loop over all the elements, .click() being one such methods. You need to replicate that with the array of elements that querySelectorAll is returning by looping over the array and applying the same handler to each element's onclick property.
Try this:
var myElements = document.querySelectorAll("a[data-hello]");
Array.prototype.forEach.call(myElements, function (element) {
element.onclick = function () {
// Your onclick handler code goes here.
console.log('clicked', element);
};
});

as simple as that:
var dataElems = document.querySelectorAll("[data-hello]")
for (var i=0;i<dataElems.length;i++) {
dataElems[i].onclick = function(i,v) {
alert(this.innerHTML)
}
}
example http://jsfiddle.net/acrashik/W86k8/

Related

addEventListener function not working in javascript

I am trying to check if a function that is meant to be triggered by a click with a console.log but the console message never comes up
<script src="e-com.js" async></script>
this is how i linked the js file in the head
Remove
this is the link I want the event on
let removeItem=document.getElementById("remove")
for (i=0; i<removeItem.length; i++){
let remove = removeItem.addEventListener("click", function(){
console.log("Clicked");
})
}
This is the js function
The issue seems to be that you are trying to loop over the result of getElementById(), which doesn't return an iterable.
To fix it, you just need to remove the loop. The code below should work correctly^.
const removeItem = document.getElementById("remove");
removeItem.addEventListener("click", () => {
console.log("Clicked!");
});
Remove
According to MDN Web Docs:
The Document method getElementById() returns an Element object representing the element whose id property matches the specified string.
As it states, getElementById() returns an Element, which is just an object, in short. This is why you cannot iterate over it.
If you wanted to listen to multiple objects with a for loop, you need to change a few things.
First, you can't use an id, as the id attribute is unique, and can only be used once in a HTML document. Therefore, to get multiple elements, you need to use the class attribute. See an example of the class attribute in use below.
<div class="division">Division!</div>
The class attribute can be used by any HTML element.
So, to get all of the classes and iterate over them, you need to use either the getElementsByClassName() method, or the querySelectorAll() method.
The only difference between the two is that getElementsByClassName() returns a live HTMLCollection, while querySelectorAll() returns a static HTMLCollection.
If you were to use querySelectorAll(), your code would look like this^.
const removeItem = document.querySelectorAll("remove");
Array.from(removeItem).forEach((ele) => {
ele.addEventListener("click", () => {
console.log("Clicked!");
});
});
Remove
Remove
Remove
Both of these solutions should work correctly, but they depend on what you need to accomplish.
^ The code has been modified slightly.
.getElementById() doesn't return an array since you're not allowed to have more than one element with a single id.
Therefore, the for loop failed.
Try
let removeItem=document.getElementById("remove")
removeItem.addEventListener("click", function(){
console.log("Clicked");
})

JQuery to Javascript Document.Write

Fiddle (Uses JQuery) - http://jsbin.com/ponikasa/1/edit
I know JQuery is Javascript, but for the sake of an argument how do you write the following in pure Javascript without the need for a js library like JQuery?
$(document).ready(function() {
$('.preview-site').on('click', function(){
window.open('javascript:document.write("'+ $('.workflow').val() +'")', 'Opened Page', 'width=660, height=440');
return false;
});
});
I tried this, but doesn't work.
Any help is greatly appreciated.
window.onload = function() {
var preview = document.getElementsByClassName("preview-site"),
code = document.getElementsByClassName("workflow")[0].value;
preview.onClick = function() {
window.open('javascript:document.write("'+ code = +'")', 'Opened Page', 'width=660, height=440');
return false;
}
}
Well to write in javascript you would do the following
document.addEventListener('DOMContentLoaded', function() {
var previewSite = this.querySelectorAll('.preview-site');
var handler = function() {
var workflow = document.querySelector('.workflow')
window.open('javascript: document.write(' + workflow.value + ')', 'Opened Page', 'width=660, height=440')
return false;
};
for( var i = 0; i < previewSite.length; i++) {
previewSite[i].addEventListener('click', handler);
}
});
The problem you had is getElementsByClassName returns a collection, so you cannot use value or onclick on the collection.
I use querySelectorAll because it's easier and has almost better support that getElementsByClassName
I don't usually answer questions like this, but I am highly supportive of anyone that uses jQuery that want's to actually learn javascript it's self
also, in your question, you have onClick, for the event handler you want onclick
For one minor performance improvement you could move workflow out of handler, that way it won't fetch it on every click, only do this if you don't intend to add dynamic .workflow
Yeah, and also. (as pointed out in comments) window.onload is not the same as document ready, window.onload will wait for images & media to be fully loaded, so use DOMContentLoaded
One of the things jQuery selectors do is try to abstract the "array" when calling functions and assigning handlers. Consider something like this:
$('.preview-site').on('click', function(){
// code
});
This code doesn't just assign the click handler. On a lower level than that presented by the jQuery interface, this iterates the array of .preview-site elements and assigns the click handlers to each element. Sometimes it's one element, sometimes it's many. (Sometimes it's none.) jQuery makes the interface the same regardless of the count.
Without it, you need to handle that difference explicitly. These values are arrays:
var preview = document.getElementsByClassName("preview-site"),
code = document.getElementsByClassName("workflow");
Even if each one only finds a single element by that class name, the result from document.getElementsByClassName() is an array. So even if the array has only one element, it's still an array. And you can't assign a handler to an array, you need to assign it to each element in the array. Potentially something like this:
for (var i = 0; i < preview.length; i++) {
preview[i].addEventListener('click', function() {
window.open('javascript:document.write("'+ code[i].value[0] +'")', 'Opened Page', 'width=660, height=440');
return false;
}
}
Naturally, you'd probably want to put in some checks to ensure that the two arrays are the same length before assuming that for each preview element there exists a code element. But the principle is the same. You just need to account for the enumeration of the array manually.

Javascript Compare Objects to Elements

http://jsfiddle.net/PhilFromHeck/KzSxT/
In this fiddle, you can see at line 38 in the Javascript that I've attempted to make a comparison that isn't working. I believe it because one of the variables is an Object, where the other is an Element; does anyone have any advice as to how I can can find a match between these two?
menuID[0] = document.getElementById('menuOne');
menuID[1] = document.getElementById('menuTwo');
menuID[2] = document.getElementById('menuThree');
menuID[3] = document.getElementById('menuFour');
$('.menu').mouseenter(function () {
for (var i = 0; i < 3; i++) {
if(menuID[i] == $(this)){
//this condition is not met, there's an alert which will add more detail in the fiddle
}
}
}
Method document.getElementById returns a DOM element an not a jQuery object. In the mouseenter event handler this refers to a DOM element as well.
So in order to compare them you shouldn't convert this to a jQuery object:
if (menuID[i] === this) { ... }
You want to use jQuery's .is() for this.
if($(this).is(menuID[i])){
A few issues I see here:
One is simply that, in your jsfiddle, the first 4 lines of code that you list aren't running before the bottom block runs. I'm not sure why you have both an init function that you attach to window.onload and a document.ready() function; but you'll want to make sure that init runs.
Secondly; as VisioN said, I think the main issue is that you're trying to compare a jQuery wrapper around a DOM element $(this) with a DOM element (the result of getElementById). As he says, this == menuID[i] will work.
At a design level, why not simply use the id to identify the element? this.id will give you the the id; why not simply use that to determine which menu div you're looking at?

is there a way to return a selector to an element? is it $(this) or some other method?

I get a lot of stuff moving about, and i was going to make a hashmap in javascript to allow me to remember certain things, one of which is objects recently touched. With that said, i was curious if i could create a key->value or array which hold the selector of the item clicked.
I wasnt sure if it was something like:
var item = new Array();
$("div.item").click(function(){
item.push($(this));
});
Then each item that is clicked is added to the array and i could do something like:
$(item).each(function(){
$(this).css("background-color","red");
});
Instead of using an array, you can use a jQuery object:
var $items = $();
$("div.item").click(function () {
$items = $items.add(this);
});
$items.css('background-color', 'red');
http://jsfiddle.net/b5qaT/
Make an empty jQuery collection and add to it.
var items = $([]);
$("div.item").click(function(){
var elem = $(this);
items = items.add(elem);
});
You want to pass the event as an argument in your eventhandler function. Like so:
$("div.item").click(function(e){...
e.whateverYouWantToDoWithIt;
The event is a javascript object, not jquery. You can google javascript event methods, attributes, etc. to see what you can do with it.
EDIT
Sorry, I read your question kind of fast. If you want to store the actual DOM object (the div) in the array, then yes, you would use the $(this) selector.

How to grab all objects in a selector?

Like
$(":input")
How do you return each object if there are multiple inputs? Maybe in somekind of array?
Also, is it possible to return the individual objects while using $(":input").after(x) ?
jQuery each
$('input').each(function () {
$(this); // A Single Input
})
Or
$('input')[0]; // HTMLElement Input
Alternatively, jQuery's .get:
supports a little more than [...], e.g. .get(-1) returns the last
element (which can be useful) - pimvdb
How to get length: $('input').length
$('input')
will select all inputs
If you wanted to do something to them...
$('input').each(function(){
$(this).css('background','red')
})
see this http://jsfiddle.net/jasongennaro/RczBh/
the jQuery factory function, jQuery(...selector...) or $(...selector...), returns a jQuery.init object, which is essentially a fancy array of elements.
the each function is a simple way to continue to chain function calls while iterating through the entire selection of elements.
The .each() method is designed to make DOM looping constructs concise and less error-prone. When called it iterates over the DOM elements that are part of the jQuery object. Each time the callback runs, it is passed the current loop iteration, beginning from 0. More importantly, the callback is fired in the context of the current DOM element, so the keyword this refers to the element.
The function parameter has two parameters function( index, element ), you could use i in place of index as it has the same basic effect. this will also refer to the element, so the second parameter is largely unnecessary unless you plan on executing a function within inner scope while retaining the reference to the element.
var vals=[];
$('input').each(function(index,element){
var $this, val;
$this = $(this);
val = $this.val();
vals.push(val);
...do more stuff...
});
console.log( vals );
$(":input") // Returns a collection of DOM elements at 0-based indices wrapped
// in an object that contains jQuery methods
$(":input").length // Is used to discover the quantity of elements matched.
$(":input").after('something') // Implicitly applies .after() to each element.
// Most jQuery methods work this way.
$(":input").each(function() { // Lets you operate on each element individually.
alert( this.nodeName ); // "this" will reference the current element.
});
"Also, is it possible to return the individual objects while using $(":input").after(x)"
If you mean you want a collection of the resulting elements created by .after(), it will depend upon what x is.
If it's a single element (not a text node), just do this:
var new_elems = $(":input").after(x).next();
This places the new element after each input, then uses the next()[docs] method to traverse to the next element sibling of each input, which should be the new element that was inserted.

Categories