Javascript OOP get Children with getElementsByClassName method - javascript

I have a problem for getting children using getElementsByClassName method.
I'm using OOP way just like Jquery Does.
"use strict";
var $, i;
(function() {
$ = function(el) {
return new obj$(el);
};
var obj$ = function(el) {
var firstChar = el.charAt(0),
cl = document.getElementsByClassName(el.slice(1));
switch (firstChar) {
case ".":
for (i = 0; i < this.length; i++) {
this[i] = cl[i];
}
break;
}
};
obj$.prototype = {
find : function(child) {
for (i = 0; i < this.length; i++) {
this[i].getElementsByClassName(child)[0];
}
return this;
},
html : function(data) {
for (i = 0; i < this.length; i++) {
this[i].innerHTML = data;
}
return this;
}
};
})();
var x = $(".parent").find("child").html("replace!");
console.log(x);
<div class="parent">
this is parent 1
<p class="child">test 1</p>
</div>
<div class="parent">
this is parent 2
<p class="child">test 2</p>
</div>
<div class="parent">
this is parent 3
<p class="child">test 3</p>
</div>
jsFiddle : https://jsfiddle.net/Lng5mn3o/
It doesn't work.

I have updated fiddle for you - https://jsfiddle.net/Lng5mn3o/3/
The main thing what i changed in your jsfiddle example, i created this['elements'] to store matched elements and used it length in loop rest was ok in your code
// define blank array
this['elements'] = new Array();
// store elements
this['elements'][i] = cl[i];
// loop over that elements
for (i = 0; i < this['elements'].length; i++) {

Related

How to add ID to <a href> on click using JavaScript

I have an HTML like this
How add ID to HTML href with javascript
<div class="tab">
exp
</div>
<div class="tab">
exp
</div>
<div class="tab">
exp
</div>
<script>
var els = document.getElementsByClassName("tab");
// loops els
for(var i = 0, x = els.length; i < x; i++) {
els[i].onclick = function(){
x = document.querySelector(".tab> a")
// do something
x.id = "expid";
}
}
</script>
I want to add the id to each tag when I click this. Pls help me. Thks so much
<div class="tabs">
... your html code.
</div>
const tabs = document.querySelector('.tabs')
tabs.addEventListener('click', event => {
const aTag = event.target
if (aTag.tagName !== 'A') return
aTag.id = `EXPID#${getIndexIn(aTag, tabs)}`
})
function getIndexIn(element, parent): number
What's the meaning to be it?
Your call to document.querySelector() always returns the first .tab > a link in the document. You can this.querySelector() to return the link in the DIV that you clicked on instead.
I've changed the code to use a class rather than ID, since you shouldn't have duplicate IDs.
Loop through all the DIVs. If it's the DIV that the user clicked on, add the class, otherwise remove it.
var els = document.getElementsByClassName("tab");
// loops els
for (var i = 0, x = els.length; i < x; i++) {
els[i].onclick = function() {
for (var j = 0; j < els.length; j++) {
x = els[j].querySelector("a");
if (els[j] == this) {
x.classList.add("expid");
} else {
x.classList.remove("expid");
}
}
}
}
.expid {
background-color: yellow;
}
<div class="tab">
exp
</div>
<div class="tab">
exp
</div>
<div class="tab">
exp
</div>
const anchors = document.getElementsByTagName('a');
const ids= [1,2,3,4,5];
let index =0 ;
for(let a of anchors ){
a.href=ids[index++]
}
you can try this way it's a cool and easiest what I do with pure js

Three js loops just in one

Hey i just wanted to do one loop which has in three buttons and three drop down lists. But I must created three list because when I connect them connect also drop down lists. My three loops looks like:
var arrow = document.getElementsByClassName('list_arrow');
var list = document.getElementsByClassName('list_panel');
for (var i = 0; i < arrow.length; i++) {
arrow[0].addEventListener('click', function() {
for (var i = 0; i < list.length; i++) {
list[0].classList.toggle('list_panel_open');
}
});
}
for (var i = 0; i < arrow.length; i++) {
arrow[2].addEventListener('click', function() {
for (var i = 0; i < list.length; i++) {
list[2].classList.toggle('list_panel_open');
}
});
}
for (var i = 0; i < arrow.length; i++) {
arrow[1].addEventListener('click', function() {
for (var i = 0; i < list.length; i++) {
list[1].classList.toggle('list_panel_open');
}
});
}
And how can I write this just in one loop?
You don't need the loop within the loops either:
for (var i = 0; i < arrow.length; i++) {
arrow[i].addEventListener('click', function() {
list[i].classList.toggle('list_panel_open');
// since all of the `i` numbers are the same
});
}
You should not combine 2 sets of queried elements like that. You are not guaranteed that the index in the array is the same everywhere. Instead set a attribute on the button(data-id). In the onClickElement handler I get the data-id and use it to toggle the target element.
var q = document.querySelectorAll.bind(document);
function toggleElement(id){
q("#" + id)[0].classList.toggle('hidden');
}
function onClickElement(){
var toggleId = this.getAttribute('data-id');
toggleElement(toggleId);
}
q('.arrow').forEach(function(element){
element.addEventListener('click', onClickElement);
});
.hidden{
display: none;
}
<button class="arrow" data-id="p1">1</button>
<button class="arrow" data-id="p2">2</button>
<button class="arrow" data-id="p3">3</button>
<br>
<br>
<div id="p1" class="panel hidden">Panel 1</div>
<div id="p2" class="panel hidden">Panel 2</div>
<div id="p3" class="panel hidden">Panel 3</div>

Get index of class

I'm trying to get the index of an element in a class. For example if I have a class called myClass with 5 elements, and the fourth element has an id of fourth, I want to get the index number of #fourth from the class.
I tried using indexOf like this:
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
console.log(myClass.indexOf(fourth));
But I get an error saying:
Uncaught TypeError: myClass.indexOf is not a function
JSFiddle
Code Snippet
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
console.log(myClass.indexOf(fourth));
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass" id="fourth"></div>
<div class="myClass"></div>
I then tried creating my own function that gets the index from the class:
function indexInClass(node) {
var className = node.className;
var num = 0;
for (var i = 0; i < className.length; i++) {
if (className[i] === node) {
return num;
}
num++;
}
return -1;
}
But I get undefined when I use it.
How can I get the index of the class?
JSFiddle
Code Snippet
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
function indexInClass(node) {
var className = node.className;
var num = 0;
for (var i = 0; i < className.length; i++) {
if (className[i] === node) {
return num;
}
num++;
}
return -1;
}
console.log(myClass[indexInClass(fourth)]);
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass" id="fourth"></div>
<div class="myClass"></div>
getElementsByClassName returns an HTML collection, not an array, thus you cannon use indexOf on it.
Iterating over the elements is the way to go, but the problem with your custom function was this:
for (var i = 0; i < className.length; i++) {
You were iterating over className, which is a string containing your node's class name, while instead you should be iterating over your element collection myClass.
Here's your custom function fixed:
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
function indexInClass(node) {
var className = node.className;
var num = 0;
for (var i = 0; i < myClass.length; i++) {
if (myClass[i] === node) {
return num;
}
num++;
}
return -1;
}
console.log(myClass[indexInClass(fourth)]);
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass" id="fourth"></div>
<div class="myClass"></div>
UPDATE
Thanks for the answer! I want to create a function that I can use anywhere, meaning, not specific to myClass. How can I achieve that?
Here's a sligthly optimized version of your function:
function indexInClass(collection, node) {
for (var i = 0; i < collection.length; i++) {
if (collection[i] === node)
return i;
}
return -1;
}
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
alert("The ID is: " + indexInClass(myClass, fourth));
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass" id="fourth"></div>
<div class="myClass"></div>
UPDATE 2
Is there a way to do it without the collection argument? For example, is there a way to get the class from the id?
function indexInClass(node) {
var collection = document.getElementsByClassName(node.className);
for (var i = 0; i < collection.length; i++) {
if (collection[i] === node)
return i;
}
return -1;
}
var fourth = document.getElementById('fourth');
alert("The ID is: " + indexInClass(fourth));
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass"></div>
<div class="myClass" id="fourth"></div>
<div class="myClass"></div>
Be careful with .className because it will work properly if the node has one class. If you expect more, you'd need to extract the common one, either from className or classList.
getElementsByClassName returns an HTMLCollection, which does not have the indexOf array methods.
If you have access to Array.from, then the simple solution is to use it to convert the collection to an array and call indexOf:
Array.from(document.getElementsByClassName('myClass'))
.indexOf(fourth); //3
If you can't use Array.from, then Array.prototype.slice.call should work:
Array.prototype.slice.call(document.getElementsByClassName('myClass'))
.indexOf(fourth); //3
Your custom function has the right idea, you're just iterating over the wrong variable. Fiddle
var myClass = document.getElementsByClassName('myClass');
var fourth = document.getElementById('fourth');
function indexInClass(node) {
var className = node.className;
var num = 0;
for (var i = 0; i < myClass.length; i++) {
if (myClass[i] === node) {
return num;
}
num++;
}
return -1;
}
console.log(indexInClass(fourth));

Improve code "content changer"

Im trying to improve my as I call it "contenthandler". What it does is that it changes different articles when I click different buttons. Im happy on how it works, but I feel this is not the best practise and I want some advices on how to maybe shorten it even more or use any other way to do this.
Im not intrested in any jQuery or other libaries at the moment.
document.addEventListener("click", function(e){
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className;
switch (buttonClick){
case "one":
test(article);
article[0].style.display = "";
break;
case "two":
test(article);
article[1].style.display = "";
break;
case "three":
test(article);
article[2].style.display = "";
break;
}
function test(article){
for (var i = 0; i < article.length; i++){
article[i].style.display = "none";
}
}
});
//html
<ul>
<li class="buttonNav"><h2 class="one">Show 1</h2></li>
<li class="buttonNav"><h2 class="two">Show 2</h2></li>
<li class="buttonNav"><h2 class="three">Show 3</h2></li>
</ul>
<article class="test" style="display: none">1</article>
<article class="test" style="display: none">2</article>
<article class="test" style="display: none">3</article>
[Edit]
I remade the script from the answer I got, but I made a small change to it and made it dynamic so I do not need to hard code the "menu" in the script file.
var getClassName = document.querySelectorAll("h2");
var classNamesArray = [];
for (var i = 0; i < getClassName.length; i++){
classNamesArray.push(getClassName[i].className.toString());
};
document.addEventListener("click", function (e) {
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className,
// Maintain list of class names in an order
validClassNames = classNamesArray,
index = -1;
for (var i = 0; i < validClassNames.length; i++) {
if (buttonClick === validClassNames[i]) {
index = i;
break;
}
}
if (index >= 0) {
test(article);
article[index].style.display = "";
}
});
function test(article) {
for (var i = 0; i < article.length; i++) {
article[i].style.display = "none";
}
}
One approach I can think of is
document.addEventListener("click", function (e) {
var article = document.getElementsByClassName("test"); // Article becomes an array.
var buttonClick = e.target.className,
// Maintain list of class names in an order
validClassNames = ["one", "two", "three"],
index = -1;
for (var i = 0; i < validClassNames.length; i++) {
if (buttonClick === validClassNames[i]) {
index = i;
break;
}
}
if (index >= 0) {
test(article);
article[index].style.display = "";
}
});
function test(article) {
for (var i = 0; i < article.length; i++) {
article[i].style.display = "none";
}
}
Also move the function definition to outside of the event handler.
Fiddle

JS function should affect all divs with same class

My function only works with the first element.
What do I have to change so that all elements with the class .folder are affected by the function update.
<div class="folder"></div>
<div class="folder"></div>
<div class="folder"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var radioButtons = document.getElementsByName('colorOut');
for(var i = 0; i < radioButtons.length; i++) {
radioButtons[i].addEventListener('change', update, false);
}
function update() {
var paragraph = document.querySelector('.folder');
paragraph.className = 'folder';
for(var i = 0; i < radioButtons.length; i++) {
if (radioButtons[i].checked) {
paragraph.classList.add(radioButtons[i].value);
}
}
}
update();
});
</script>
You have this:
document.getElementsByName
that's the wrong syntax, you need:
document.getElementsByClassName

Categories