convert .each (jquery) to Pure Javascript - javascript

I'm trying to convert a function writing on jquery to javascript vanilla
i know that .each() is .forEach() on pure javascript but i dont understand what i'm missing with my code !
here the jquery code :
addClickItems: function(classe) {
$(classe).each(function (index) {
$(classe + ":eq(" + (index) + ")").click(function () {
if (classe === ".droite") {
});
});
},
and here the javascript code :
clickImages : function (classe) {
//classe = new Object(diaporama);
Object.keys(classe).forEach(index => {
classe[index].addEventListener("click", function () {
});
});
},
thanks for help !

The jQuery.each() method enumerates all the individual DOM elements that are contained within the jQuery wrapped set of elements that you call it on:
$("div").each(function(index, value){
console.log(index, value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="one">one</div>
<div id="two">two</div>
<div id="three">three</div>
Your attempt at conversion goes to using Object.keys(class).forEach, where Object.keys is not a set of elements, but keys/properties of an Object.
var myObj = {
key1: 10,
key2: true,
key3: "foo"
};
Object.keys(myObj).forEach(function(key, index){
console.log(index, key, myObj[key]);
});
So, the two uses of each are not analogous.
If you do indeed have DOM elements to enumerate, you need to get them into a JavaScript array and then you can call .forEach() on that array.
NOTE 1: Most modern browsers allow you to call .forEach on node lists/HTML Collections directly, but for compatibility with those browsers that do not, you need to convert the node list/HTML Collection into an array to be sure that the code will work. This is shown below.
NOTE 2: Be mindful that the callback function you pass to jQuery.forEach() is, itself, passed two arguments: index and value, where for the vanilla JavaScript Array.forEach(), the callback is passed value and index (reversed order).
var elements = document.querySelectorAll("div"); // Get all the elements into a node list
var elArray = Array.prototype.slice.call(elements); // Convert node list to array
// Now, enumerate the array with .forEach()
elArray.forEach(function(value, index){
console.log(index, value);
});
<div id="one">one</div>
<div id="two">two</div>
<div id="three">three</div>

In the original code classe appears to be a jQuery selector. You need to use document.querySelectorAll() to search for all the matching elements and iterate over that:
document.querySelectorAll(classe).forEach(elt => elt.addEventListener("click", function() {
...
});

Related

How to get the value of a div using javascript in a foreach loop

I have many divs that were generated in a foreach, and i have to get the value of this divs.
#model Recall
#foreach (var veiculo in Model)
{
<div value="#veiculo.Veiculo.Vin" class="chassi-importado" id="myDiv">
#veiculo.Veiculo.Vin
<i name="icon-remover-um-chassi" class="bx bx-x-circle"></i>
</div>
}
I´ve trying to use the following code in javascript, but i am getting a null value in the list. How can i get the correct value?
let veiculos = [];
$.each($('.chassi-importado'),
function () {
veiculos.push({ vin: $(".chassi-importado").val() });
});
According to documentation https://api.jquery.com/each/ $.each passes index and element params into the callback provided by you but you don't use them. Also, instead of val() you need to use text() to retrieve innerText value. val() is used mostly for inputs.
Here is what you need to do instead:
let veiculos = [];
$.each($('.chassi-importado'),
function (index, element) {
veiculos.push({ vin: $(element).text() });
}
);
Even better would be to utilize map because you are not just traversing through elements but extracting their values.
Here is how you can do this:
let veiculos = $.map($('.chassi-importado'), (el) => $(el).text());

JQuery - Select custom elements by suffix or prefix of their tagName

Consider that I create some custom elements with HTML5
<orange-juice>...</orange-juice>
<apple-juice>...</apple-juice>
<banana-juice>...</banana-juice>
There are many type of juice elements. And I want to select them with a single instruction with jQuery using their suffix.
I try that but it does not work :
$('$=juice').html('juice'); //the .html instruction is not important
If i take them one by one this work.
$('orange-juice').html('juice'); //this work
$('apple-juice').html('juice'); //this work
$('banana-juice').html('juice'); //this work
But there are many of these custom element suffixed by juice. How can I select them in one instruction.
EDIT 1
It's sure that a common class will work but, it's not my code and there are too many of these elements to take theme one by one.
But if no solution then, I will make this (during a month).
You can try .filter(fn) function, Here is an example of prefix
$('body *').filter(function() {
return this.tagName.toLowerCase().indexOf('juice') == 0;
}).html('juice');
However I would recommend, you to assign a common class then Class Selector (“.class”) can be easily used.
Example of Suffix, Here I have used endsWith() method
jQuery(function($) {
$('body *').filter(function() {
return this.tagName.toLowerCase().endsWith('juice');
}).html('juice');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<orange-juice>...</orange-juice>
<apple-juice>...</apple-juice>
<banana-juice>...</banana-juice>
While you've already accepted a jQuery solution to the problem, which is what you asked for, it's worth also adding – if only for the sake of completion – a plain JavaScript approach for the same.
// declaring an object to contain the two functions:
let findElementsBy = {
// retrieving all elements held within the <body> element,
// we could instead use:
// document.getElementsByTagName('*')
// but this is just personal preference:
'allElems': document.querySelectorAll('body *'),
// declaring the 'suffix' function:
// ending: String, a required argument which is 'ending'
// by which we're filtering the retrieved elements:
'suffix': function(ending) {
// here we use Array.from() to convert the Array-like
// NodeList into an Array:
return Array.from(this.allElems)
// we filter that Array using Array.prototype.filter():
.filter(
// here we use an Arrow function to keep only those
// elements ('el', the current Array-element of the
// Array over which we're iterating) whose lower-case
// tagName ends with the supplied 'ending' String,
// determined using String.prototype.endsWith(),
// which returns a Boolean:
el => el.tagName.toLowerCase().endsWith(ending)
// this filtered Array is then passed back to the
// calling context as an Array, which allows that
// context to iterate through the returned elements
// using Array methods.
);
},
'prefix': function(beginning) {
return Array.from(this.allElems)
.filter(
// this function is exactly the same as the above,
// but here we use String.prototype.startsWith()
// to find those elements whose lower-cased tagName
// begins with the supplied String:
el => el.tagName.toLowerCase().startsWith(beginning)
);
}
}
findElementsBy.suffix('juice').forEach(e => e.style.borderColor = 'limegreen');
findElementsBy.prefix('banana').forEach(e => e.style.backgroundColor = '#ffa');
let findElementsBy = {
'allElems': document.querySelectorAll('body *'),
'suffix': function(ending) {
return Array.from(this.allElems)
.filter(
el => el.tagName.toLowerCase().endsWith(ending)
);
},
'prefix': function(beginning) {
return Array.from(this.allElems)
.filter(
el => el.tagName.toLowerCase().startsWith(beginning)
);
}
}
findElementsBy.suffix('juice').forEach(e => e.style.borderColor = 'limegreen');
findElementsBy.prefix('banana').forEach(e => e.style.backgroundColor = '#ffa');
orange-juice,
apple-juice,
banana-juice {
display: block;
border: 1px solid transparent;
margin: 1em auto 0 auto;
width: 80%;
}
<orange-juice>...</orange-juice>
<apple-juice>...</apple-juice>
<banana-juice>...</banana-juice>
JS Fiddle demo.
References:
Array.from().
Array.prototype.filter().
Array.prototype.forEach().
Arrow functions.
document.getElementsByTagName()
document.querySelectorAll().
String.prototype.endsWith().
String.prototype.toLowerCase().
String.prototype.startsWith().

Get each element's attribute through $.each()

Trying to do $('div').attr('data', 'ip') through a .each() just returns undefined.
Let's say I have 4 divs
<div class="box" data-ip="ipvalue">content</div>
<div class="box" data-ip="ipvalue">content</div>
<div class="box" data-ip="ipvalue">content</div>
<div class="box" data-ip="ipvalue">content</div>
and I need to iterate each one and get the data-ip value.
My code, it just returns undefined (server, serverObj, are variables).
var serversObj = $('.server');
serversObj.each(function(index, el) {
return $(this).data('ip');
});
What am I doing wrong?
You want to use map if you want to get all of the values of all of the elements
var ips = $(".box") //get all of the elements
.map(
function(){
return $(this).data("ip"); //get the value from the attribute
}
).get(); //returns an Array
Fiddle
Here is what the code should be for the markup sample you gave.
var serversObj = $('.box'),
Ipvals = [];
serversObj.each(function(index, el) {
Ipvals.push( $(this).data('ip'));
});
console.log( Ipvals);
You can also use $.map() to return the same array.
$('.box').each(function(){
console.log($(this).attr('data-ip'));
});
First off, this is totally wrong:
$('div').attr('data', 'ip')
This is setting an attribute called data to a value of "ip", it does nothing involving data attributes. Effectively, you're doing this: <div data='ip'>.
If you want to access a data attribute called data-ip, you want
$('div').data('ip')
If you want to access it for a series of elements, you can't just return it out of a .each loop. That value is discarded. You need to map your input set of elements to a set of outputs:
$('.server').map(function () { return $(this).data('ip') })
This will produce an array that has each element matched by .server's data-ip attribute.

Calling in multiple attributes

still quite new to jQuery / Javascript and am struggling a little.
I have created an attribute called catno that I have assigned to several links. Then I want all instances inside banner-1 to be called into another link separated by a comma. i.e
New Link
I'm just struggling in making this happen. The code I have right now only returns the first catno.
Any help would be great!
JSFIDDLE
<div id="banner-1>
New Link
</div>
$sd('.buy-outfit').attr('href', function() {
return $sd("#banner-1 .add-catno").attr('catno') + ',';
});
Fiddle Demo
var arr_catno = $("#banner-1 a").map(function () { //create array using .map
return $(this).attr('catno'); // add element attribute catno to array
}).get().join(); //use .join() to get comma separated string of array
$('.new-link').attr('href', arr_catno); //assign it to href
.map()
Updated after OP's Comment
Fiddle Demo
$('[id^=banner-] .new-link').attr('href', function () {
return $(this).parent().find('a').map(function () {
return $(this).attr('catno');
}).get().join();
});
Attribute Starts With Selector [name^="value"]
.parent()
.find()
[id^=banner-] --> select all the elements with id starting with banner-
Use $.map to produce an array of catnos and them join them into a string.
$('.new-link').attr('href', function() {
return $.map($(".add-catno"), function (el) {
return $(el).data('catno');
}).join(',');
});
Note in the example that I've changed the catnos attributes to data attributes. Using data is considered good practice for when you want to add arbitrary data to your HTML.
Fiddle

Get list of data-* attributes using javascript / jQuery

Given an arbitrary HTML element with zero or more data-* attributes, how can one retrieve a list of key-value pairs for the data.
E.g. given this:
<div id='prod' data-id='10' data-cat='toy' data-cid='42'>blah</div>
I would like to be able to programmatically retrieve this:
{ "id":10, "cat":"toy", "cid":42 }
Using jQuery (v1.4.3), accessing the individual bits of data using $.data() is simple if the keys are known in advance, but it is not obvious how one can do so with arbitrary sets of data.
I'm looking for a 'simple' jQuery solution if one exists, but would not mind a lower level approach otherwise. I had a go at trying to to parse $('#prod').attributes but my lack of javascript-fu is letting me down.
update
customdata does what I need. However, including a jQuery plugin just for a fraction of its functionality seemed like an overkill.
Eyeballing the source helped me fix my own code (and improved my javascript-fu).
Here's the solution I came up with:
function getDataAttributes(node) {
var d = {},
re_dataAttr = /^data\-(.+)$/;
$.each(node.get(0).attributes, function(index, attr) {
if (re_dataAttr.test(attr.nodeName)) {
var key = attr.nodeName.match(re_dataAttr)[1];
d[key] = attr.nodeValue;
}
});
return d;
}
update 2
As demonstrated in the accepted answer, the solution is trivial with jQuery (>=1.4.4). $('#prod').data() would return the required data dict.
Actually, if you're working with jQuery, as of version 1.4.3 1.4.4 (because of the bug as mentioned in the comments below), data-* attributes are supported through .data():
As of jQuery 1.4.3 HTML 5 data-
attributes will be automatically
pulled in to jQuery's data object.
Note that strings are left intact
while JavaScript values are converted
to their associated value (this
includes booleans, numbers, objects,
arrays, and null). The data-
attributes are pulled in the first
time the data property is accessed and
then are no longer accessed or mutated
(all data values are then stored
internally in jQuery).
The jQuery.fn.data function will return all of the data- attribute inside an object as key-value pairs, with the key being the part of the attribute name after data- and the value being the value of that attribute after being converted following the rules stated above.
I've also created a simple demo if that doesn't convince you: http://jsfiddle.net/yijiang/WVfSg/
A pure JavaScript solution ought to be offered as well, as the solution is not difficult:
var a = [].filter.call(el.attributes, function(at) { return /^data-/.test(at.name); });
This gives an array of attribute objects, which have name and value properties:
if (a.length) {
var firstAttributeName = a[0].name;
var firstAttributeValue = a[0].value;
}
Edit: To take it a step further, you can get a dictionary by iterating the attributes and populating a data object:
var data = {};
[].forEach.call(el.attributes, function(attr) {
if (/^data-/.test(attr.name)) {
var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) {
return $1.toUpperCase();
});
data[camelCaseName] = attr.value;
}
});
You could then access the value of, for example, data-my-value="2" as data.myValue;
jsfiddle.net/3KFYf/33
Edit: If you wanted to set data attributes on your element programmatically from an object, you could:
Object.keys(data).forEach(function(key) {
var attrName = "data-" + key.replace(/[A-Z]/g, function($0) {
return "-" + $0.toLowerCase();
});
el.setAttribute(attrName, data[key]);
});
jsfiddle.net/3KFYf/34
EDIT: If you are using babel or TypeScript, or coding only for es6 browsers, this is a nice place to use es6 arrow functions, and shorten the code a bit:
var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
Have a look here:
If the browser also supports the HTML5 JavaScript API, you should be able to get the data with:
var attributes = element.dataset
or
var cat = element.dataset.cat
Oh, but I also read:
Unfortunately, the new dataset property has not yet been implemented in any browser, so in the meantime it’s best to use getAttribute and setAttribute as demonstrated earlier.
It is from May 2010.
If you use jQuery anyway, you might want to have a look at the customdata plugin. I have no experience with it though.
As mentioned above modern browsers have the The HTMLElement.dataset API.
That API gives you a DOMStringMap, and you can retrieve the list of data-* attributes simply doing:
var dataset = el.dataset; // as you asked in the question
you can also retrieve a array with the data- property's key names like
var data = Object.keys(el.dataset);
or map its values by
Object.keys(el.dataset).map(function(key){ return el.dataset[key];});
// or the ES6 way: Object.keys(el.dataset).map(key=>{ return el.dataset[key];});
and like this you can iterate those and use them without the need of filtering between all attributes of the element like we needed to do before.
You should be get the data through the dataset attributes
var data = element.dataset;
dataset is useful tool for get data-attribute
or convert gilly3's excellent answer to a jQuery method:
$.fn.info = function () {
var data = {};
[].forEach.call(this.get(0).attributes, function (attr) {
if (/^data-/.test(attr.name)) {
var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) {
return $1.toUpperCase();
});
data[camelCaseName] = attr.value;
}
});
return data;
}
Using: $('.foo').info();
You can just iterate over the data attributes like any other object to get keys and values, here's how to do it with $.each:
$.each($('#myEl').data(), function(key, value) {
console.log(key);
console.log(value);
});
I use nested each - for me this is the easiest solution (Easy to control/change "what you do with the values - in my example output data-attributes as ul-list) (Jquery Code)
var model = $(".model");
var ul = $("<ul>").appendTo("body");
$(model).each(function(index, item) {
ul.append($(document.createElement("li")).text($(this).text()));
$.each($(this).data(), function(key, value) {
ul.append($(document.createElement("strong")).text(key + ": " + value));
ul.append($(document.createElement("br")));
}); //inner each
ul.append($(document.createElement("hr")));
}); // outer each
/*print html*/
var htmlString = $("ul").html();
$("code").text(htmlString);
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/prism.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="demo"></h1>
<ul>
<li class="model" data-price="45$" data-location="Italy" data-id="1234">Model 1</li>
<li class="model" data-price="75$" data-location="Israel" data-id="4321">Model 2</li>
<li class="model" data-price="99$" data-location="France" data-id="1212">Model 3</li>
</ul>
<pre>
<code class="language-html">
</code>
</pre>
<h2>Generate list by code</h2>
<br>
Codepen: https://codepen.io/ezra_siton/pen/GRgRwNw?editors=1111
One way of finding all data attributes is using element.attributes. Using .attributes, you can loop through all of the element attributes, filtering out the items which include the string "data-".
let element = document.getElementById("element");
function getDataAttributes(element){
let elementAttributes = {},
i = 0;
while(i < element.attributes.length){
if(element.attributes[i].name.includes("data-")){
elementAttributes[element.attributes[i].name] = element.attributes[i].value
}
i++;
}
return elementAttributes;
}
If you know the name of keys you can also use object destructuring to get values like this
const {id, cat, cid } = document.getElementById('prod').dataset;
You can also skip keys you don't need and get the ones you need like this
const { cid, id } = document.getElementById('prod').dataset;
100% Javascript no jQuery ;)
DOMStringMap :
console.log(document.getElementById('target-element-id').dataset);
or custom variable :
var data = {};
Object.entries(document.getElementById('target-element-id').dataset).forEach(([key, val]) => {
data[key] = val;
});
console.log(data);

Categories

Resources