Custom attribute issue - javascript

I'm trying to get the "quantity" attribute of multiple Elements ID at the same time.
Here's what I tried :
productMinimum : document.getElementsById("id1","id2").getAttribute("quantity")
How can I make this work? The "id1" and "id2" elements all have the "quantity" attribute.
Here's what it looks like from the HTML side :
<li class="product" name="RD-101" id="id1" price="18" quantity="2">
<li class="product" name="RD-101" id="id2" price="18" quantity="4">

The problem you're having is that getElementsById() doesn't exist (unless you've defined it elsewhere). What you should be using is getElementById(), albeit twice (as getElementById(), as its name implies, returns only one element, even if there are multiple elements with that same id, which is invalid mark-up, so please don't do that), and then pushing the returned elements into an array:
var products = [];
products.push(document.getElementById("id1"));
products.push(document.getElementById("id2"));
You could, of course, create your own function to return multiple elements based on their id:
function getElementsById(ids) {
if (!ids) {
return false;
}
else {
var elems = [];
for (var i = 0, len = ids.length; i < len; i++) {
if (document.getElementById(ids[i])) {
elems.push(document.getElementById(ids[i]));
}
}
return elems;
}
}
console.log(getElementsById(['id1','id3']));​
JS Fiddle demo.
Bear in mind, though, that this returns a regular array, not a nodeList (as would be returned, for example, by getElementsByClassName()). And the returned array, even if it's only a single element, would have to be iterated over in the same way as any other array.
References:
getElementById().
nodeList.
push().

function getQuantity(id) {
return document.getElementById(id).getAttribute("quantity");
}
var quantId1 = getQuantity('id1');
var quantId2 = getQuantity('id2');
getElement*s*ById is returning an array. You need to get the individual items. If you had a whole lot of elements you could select by class product and write a simple function to loop over them and create an array.

There is no such function as getElementsById. you can use either getElementsByClassName or getElementsByName
https://developer.mozilla.org/en/DOM/document.getElementsByName
https://developer.mozilla.org/en/DOM/document.getElementsByClassName
Take note that getElementsByClassName is fairly new and not supported by older browsers.

Using pure JavaScript you need to write your own function for that:
function getQuantities() {
var args = Array.prototype.slice.call(arguments);
var quantityValue = 0;
for(var i = 0; i < args.length; i++) {
quantityValue += document.getElementsById(args[i]).getAttribute("quantity");
}
return quantityValue;
}
// your code
productMinimum : getQuantities("id1","id2")

As I understand it, document.getElementById takes one id at the time
Also, consider using html5 custom data attributes

There is no such thing as getElementsById()
But there is querySelectorAll, but it's not supported in IE7 and older though
here's a sample which should return the two <li> in a nodelist.
document.querySelectorAll('#id1, #id2')

You can only get one element at once (with getElementById()). If you want an array containing the quantities, use this:
[document.getElementById('id1').getAttribute('quantity'), document.getElementById('id2').getAttribute('quantity')]
Consider using jQuery, there you can use $('#id1, #id2') and besides that it supports easy access to data- attributes - what you are doing right now is invalid HTML since li does not have price or quantity attributes:
<li class="product" name="RD-101" id="id1" data-price="18" data-quantity="2">
<li class="product" name="RD-101" id="id2" data-price="18" data-quantity="4">
To get the quantities array:
$('#id1, #id2').map(function() { return $(this).data('quantity'); }).get();

Related

getElementsByClassName isn't returning all elements

I'm creating a button that I should highlight certain words within a specified class, but I am having issues with it returning all elements within the class. It will only work if I specify an index, so I'm assuming there may be something wrong with the existing "for loop". Any help is appreciated!
This will work, but only "highlights" the first element in the class, of course:
var bodyText = document.getElementsByClassName('test')[0].innerHTML;
for (var i = 0; i < searchArray.length; i++) {
bodyText = doHighlight(bodyText, searchArray[i], highlightStartTag,
highlightEndTag);}
document.getElementsByClassName('test')[0].innerHTML = bodyText;
return true;
This will not work at all:
var bodyText = document.getElementsByClassName('test').innerHTML;
for (var i = 0; i < searchArray.length; i++) {
bodyText = doHighlight(bodyText, searchArray[i], highlightStartTag,
highlightEndTag);}
document.getElementsByClassName('test').innerHTML = bodyText;
return true;
If you want to replace multiple words in multiple elements, you need two loops:
const testElements = document.getElementsByClassName('test');
for (const element of testElements) {
for (const search of searchArray) {
element.innerHTML = doHighlight(element.innerHTML, search, highlightStartTag, highlightEndTag);
}
}
As you can see getElementsByClassName is pluralized (Elements). Indeed a same class can be assigned to multiple HTML elements. You won't find any way to ommit the [0] and you shouldn't anyway as it might mean you're getting data from the wrong node. If you need data from a specific element that you can ensure is unique then you need to give it an id and use getElementById instead.
You cannot access innerHTML in something which returns an htmlcollection
document.getElementsByClassName('test').innerHTML
Because it's written in plain english: getElementsByClassName. plural.
"Elements".
with an "s" at the end...
meaning it's a (sort of) Array (an htmlcollection)

JS: I can't get the inner HTML of elements with a specific class name

I'm trying to create a calculator out of javascript to work on my skills. I've added the class num to all of my buttons that have a number.
I'm trying to display to display the innerHTML of those buttons in the console when I click them with this code:
var num = document.getElementsByClassName('num');
num.addEventListener('click', getNum);
function getNum(){
console.log(num.innerHTML);
}
getNum();
However all I get is
num.addEventListener is not a function.
Here is my codepen: https://codepen.io/teenicarus/pen/wrEzwd
what could I be doing wrong?
You need to change the code like below. getElementsByClassName returns collection of elements. Loop through the elements and add click event listener. In getNum, you can use this to get access to the button clicked.
var num = document.getElementsByClassName('num');
for (var i = 0; i < num.length; i++) {
num[i].addEventListener('click', getNum);
}
function getNum(){
console.log(this.innerHTML);
}
You can also use Array forEach like the following:
[].forEach.call(num, function(el){
el.addEventListener('click', getNum);
})
getElementsByClassName returns a collection of elements, not a single element. If you want to get single element assign it an id attribute and use getElementById. This way you can use addEventListener function
Here's a solution you can plug directly in your codepen:
var nums = document.getElementsByClassName('num');
[].forEach.call(nums, num => num.addEventListener('click', numClick));
function numClick(){
// adding + turns the text into an actual number
console.log(+this.innerHTML);
}
getElementsByClassName() returns an HTMLCollection, to iterate over it you can pass it to [].forEach.call() like I showed above.
I also renamed the handler to numClick, since it doesn't "get" the number. And added +, which is a nice shortcut to turn text into a number (otherwise, adding two numbers would yield unexpected results, like "1" + "2" => "12"
The .getElementsByClassName returns not an element, but a collection of them.
You can access elements using .getElementsByClassName(num)[element's sequential number], or better use id's and getElementById method.
Here is the modified code for your desired output.just copy and try:
var num = document.getElementsByClassName('num');
//num.addEventListener('click', getNum);
for (var i = 0; i < num.length; i++) {
num[i].addEventListener('click', getNum);
}
function getNum(){
document.getElementById('result').innerHTML+=this.innerHTML;
console.log('value:'+this.innerHTML);
}
//getNum();
As you tagged Jquery to your question I suppose that you are able to use Jquery as well. You can grab the clicked element's class and referance it with 'this' to get its text.
$('.num').click(function(){
var x = $(this).text();
console.log(x);
});
This is a working example you can check the console.log DEMO

Iterating over DOM element

I am iterating DOM elements using a for loop, using 2 syntax and in both I am getting different results.
The JavaScript method 1 is
for (var sortable in document.getElementsByClassName('test')) {
console.log("---- " + sortable)
sortable.setAttribute('class', '');
}
Th output for this gives error
undefined is not a function
for sortable.setAttribute('class', ''); line.
And using javascript 2 method
var elements = document.getElementsByClassName("test");
for (var i=0; i< elements.length;i++) {
elements[i].setAttribute("class", "");
}
I get the appropriate result.
My html code is
<span class="test" id="test1">Test1 </span>
<span class="test" id="test2">Test2 </span>
<span class="test" id="test3">Test3 </span>
I don't know why I don't get DOM elements in var sortable in document.getElementsByClassName('test') as sortable?
If you do a for .. in loop in JavaScript, it is important to know that the value returned by the for loop is actually the key and not the value.
So you could try this:
var testElements = document.getElementsByClassName('test');
for (var key in testElements) {
var sortable = testElements[key];
console.log("---- " + sortable)
sortable.setAttribute('class', '');
}
However, this would fail as there are many properties defined on the value returned by getElementsByClassName, which not all return an element.
You can see them all by doing the following:
for (var key in document.getElementsByClassName('test')) {
console.log(key);
}
This will output something like this:
0
1
2
test1
test2
test3
length
item
namedItem
You can see that not only does the returned value contain the numerical indexes, it also has the ID's as properties and also an item and namedItem property.
Unfortunatety, your for-loop also doesn't work as you are changing the class name and getElementsByClassName returns a "live" collection, which means that once you change the class, it is removed from the collection.
You can work around this with a simple loop:
var elements = document.getElementsByClassName("test");
while (elements.length > 0) {
elements[0].setAttribute("class", "");
}
This solution was taken from: Javascript For Loop execution on dom element
getElementsByClassName returns an array of all the elements.
For-in only iterates over objects, not arrays.

GetElementByID - Multiple IDs

doStuff(document.getElementById("myCircle1" "myCircle2" "myCircle3" "myCircle4"));
This doesn't work, so do I need a comma or semi-colon to make this work?
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes. You have several different options:
You could implement your own function that takes multiple ids and returns multiple elements.
You could use document.querySelectorAll() that allows you to specify multiple ids in a CSS selector string .
You could put a common class names on all those nodes and use document.getElementsByClassName() with a single class name.
Examples of each option:
doStuff(document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4"));
or:
// put a common class on each object
doStuff(document.getElementsByClassName("circles"));
or:
function getElementsById(ids) {
var idList = ids.split(" ");
var results = [], item;
for (var i = 0; i < idList.length; i++) {
item = document.getElementById(idList[i]);
if (item) {
results.push(item);
}
}
return(results);
}
doStuff(getElementsById("myCircle1 myCircle2 myCircle3 myCircle4"));
This will not work, getElementById will query only one element by time.
You can use document.querySelectorAll("#myCircle1, #myCircle2") for querying more then one element.
ES6 or newer
With the new version of the JavaScript, you can also convert the results into an array to easily transverse it.
Example:
const elementsList = document.querySelectorAll("#myCircle1, #myCircle2");
const elementsArray = [...elementsList];
// Now you can use cool array prototypes
elementsArray.forEach(element => {
console.log(element);
});
How to query a list of IDs in ES6
Another easy way if you have an array of IDs is to use the language to build your query, example:
const ids = ['myCircle1', 'myCircle2', 'myCircle3'];
const elements = document.querySelectorAll(ids.map(id => `#${id}`).join(', '));
No, it won't work.
document.getElementById() method accepts only one argument.
However, you may always set classes to the elements and use getElementsByClassName() instead. Another option for modern browsers is to use querySelectorAll() method:
document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4");
I suggest using ES5 array methods:
["myCircle1","myCircle2","myCircle3","myCircle4"] // Array of IDs
.map(document.getElementById, document) // Array of elements
.forEach(doStuff);
Then doStuff will be called once for each element, and will receive 3 arguments: the element, the index of the element inside the array of elements, and the array of elements.
getElementByID is exactly that - get an element by id.
Maybe you want to give those elements a circle class and getElementsByClassName
document.getElementById() only takes one argument. You can give them a class name and use getElementsByClassName() .
Dunno if something like this works in js, in PHP and Python which i use quite often it is possible.
Maybe just use for loop like:
function doStuff(){
for(i=1; i<=4; i++){
var i = document.getElementById("myCiricle"+i);
}
}
Vulgo has the right idea on this thread. I believe his solution is the easiest of the bunch, although his answer could have been a little more in-depth. Here is something that worked for me. I have provided an example.
<h1 id="hello1">Hello World</h1>
<h2 id="hello2">Random</h2>
<button id="click">Click To Hide</button>
<script>
document.getElementById('click').addEventListener('click', function(){
doStuff();
});
function doStuff() {
for(var i=1; i<=2; i++){
var el = document.getElementById("hello" + i);
el.style.display = 'none';
}
}
</script>
Obviously just change the integers in the for loop to account for however many elements you are targeting, which in this example was 2.
The best way to do it, is to define a function, and pass it a parameter of the ID's name that you want to grab from the DOM, then every time you want to grab an ID and store it inside an array, then you can call the function
<p id="testing">Demo test!</p>
function grabbingId(element){
var storeId = document.getElementById(element);
return storeId;
}
grabbingId("testing").syle.color = "red";
You can use something like this whit array and for loop.
<p id='fisrt'>??????</p>
<p id='second'>??????</p>
<p id='third'>??????</p>
<p id='forth'>??????</p>
<p id='fifth'>??????</p>
<button id="change" onclick="changeColor()">color red</button>
<script>
var ids = ['fisrt','second','third','forth','fifth'];
function changeColor() {
for (var i = 0; i < ids.length; i++) {
document.getElementById(ids[i]).style.color='red';
}
}
</script>
For me worked flawles something like this
doStuff(
document.getElementById("myCircle1") ,
document.getElementById("myCircle2") ,
document.getElementById("myCircle3") ,
document.getElementById("myCircle4")
);
Use jQuery or similar to get access to the collection of elements in only one sentence. Of course, you need to put something like this in your html's "head" section:
<script type='text/javascript' src='url/to/my/jquery.1.xx.yy.js' ...>
So here is the magic:
.- First of all let's supose that you have some divs with IDs as you wrote, i.e.,
...some html...
<div id='MyCircle1'>some_inner_html_tags</div>
...more html...
<div id='MyCircle2'>more_html_tags_here</div>
...blabla...
<div id='MyCircleN'>more_and_more_tags_again</div>
...zzz...
.- With this 'spell' jQuery will return a collection of objects representing all div elements with IDs containing the entire string "myCircle" anywhere:
$("div[id*='myCircle']")
This is all! Note that you get rid of details like the numeric suffix, that you can manipulate all the divs in a single sentence, animate them... Voilá!
$("div[id*='myCircle']").addClass("myCircleDivClass").hide().fadeIn(1000);
Prove this in your browser's script console (press F12) right now!
As stated by jfriend00,
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes.
However, here's some example code I created which you can give one or a comma separated list of id's. It will give you one or many elements in an array. If there are any errors, it will return an array with an Error as the only entry.
function safelyGetElementsByIds(ids){
if(typeof ids !== 'string') return new Error('ids must be a comma seperated string of ids or a single id string');
ids = ids.split(",");
let elements = [];
for(let i=0, len = ids.length; i<len; i++){
const currId = ids[i];
const currElement = (document.getElementById(currId) || new Error(currId + ' is not an HTML Element'));
if(currElement instanceof Error) return [currElement];
elements.push(currElement);
};
return elements;
}
safelyGetElementsByIds('realId1'); //returns [<HTML Element>]
safelyGetElementsByIds('fakeId1'); //returns [Error : fakeId1 is not an HTML Element]
safelyGetElementsByIds('realId1', 'realId2', 'realId3'); //returns [<HTML Element>,<HTML Element>,<HTML Element>]
safelyGetElementsByIds('realId1', 'realId2', 'fakeId3'); //returns [Error : fakeId3 is not an HTML Element]
If, like me, you want to create an or-like construction, where either of the elements is available on the page, you could use querySelector. querySelector tries locating the first id in the list, and if it can't be found continues to the next until it finds an element.
The difference with querySelectorAll is that it only finds a single element, so looping is not necessary.
document.querySelector('#myCircle1, #myCircle2, #myCircle3, #myCircle4');
here is the solution
if (
document.getElementById('73536573').value != '' &&
document.getElementById('1081743273').value != '' &&
document.getElementById('357118391').value != '' &&
document.getElementById('1238321094').value != '' &&
document.getElementById('1118122010').value != ''
) {
code
}
You can do it with document.getElementByID Here is how.
function dostuff (var here) {
if(add statment here) {
document.getElementById('First ID'));
document.getElementById('Second ID'));
}
}
There you go! xD

select an array of elements and use them

Using this syntax:
var position = array($('#ipadmenu > section').attr('data-order'));
I cannot get my code to work. I have never used arrays before so im kind of lost on how to use them. (especially in jquery).
How would I make an array of all section elements and associate the value of data-order to that list. Example:
first section - data-order:1
second section - data-order:2
etc and then use that info afterwards.
Thank you!
Since .attr just gets one attribute -- the first one found by the jQuery selector -- you need to build your array element by element. One way to do that is .each (you can also use .data to extract data attributes):
var position = new Array;
$('#ipadmenu > section').each(function() {
position.push($(this).data('order'));
});
alert(position[0]); // alerts "1"
This will be an indexed array, not an associative array. To build one of those (which in JavaScript is technically an object, not any kind of array) just change the inner part of your .each loop:
var position = {};
$('#ipadmenu > section').each(function(i) {
position["section"+i] = $(this).data('order');
});
The resulting object position can now be accessed like:
alert(position['section1']); // alerts "1"
A different approach involves using jQuery.map, but since that only works on arrays, not jQuery objects, you need to use jQuery.makeArray to convert your selection into a true array first:
var position = $.map($.makeArray($('#ipadmenu > section')), function() {
return $(this).data('order');
} ); // position is now an indexed array
This approach is technically shorter than using .each, but I find it less clear.
Javascript:
var orders = [];
$('#ipadmenu > section').each(function() {
orders.push($(this).data('order'))
});
HTML:
<div id="ipadmenu">
<section data-order="1">1</section>
<section data-order="2">2</section>
</div>
You will want to do something like this:
// Get the elements and put them in an array
var position = $('#ipadmenu section').toArray();
console.log(position);
// Loop through the array
for (var i = 0; i < position.length; i++){
// Display the attribute value for each one
console.log("Section " + i + ": " + $(position[i]).attr('data-order'));
}
Working example here: http://jsfiddle.net/U6n8E/3/

Categories

Resources