Loop through child and get attribute - javascript

I'm trying to create a div which should replace the select element (because the real one is not necessary in that case) and I try to get the data-select attribute of each option (which represented by an a tag) but I probably do something wrong and I'm getting null. that's my code - HTML:
<div class="select" data-after="C">
<i data-select-value="">Date & Time</i>
<div class="options">
Date & Time
Alphabetical
Modified
</div>
</div>
<div class="select" data-after="C">
<i data-select-value="">Delete</i>
<div class="options">
Delete
Edit
Unpublish
</div>
</div>
JS:
var selectbox = document.getElementsByClassName('select');
for(var i = 0; i < selectbox.length; i++) {
selectbox[i].onclick = function() {
var elechild = this.childNodes;
var x = 0;
for(x; x < elechild.length; x++) {
elechild[x].onclick = function() {
console.log(this.getAttribute('data-select'));
}
}
}
}
How can I solve this and get each attribute (please, no jQuery)?
(btw please excuse my english if I had any misspellings)
Thank you very much!

Basically, you can get all elements using querySelectorAll in javascript. https://developer.mozilla.org/de/docs/Web/API/Document/querySelectorAll
Try this:
var selectors = document.querySelectorAll('.options a');
for (var x = 0; x < selectors.length; x++) {
selectors[x].onclick = function() {
console.log(this.getAttribute('data-select'));
}
}
<div class="select" data-after="C">
<i data-select-value="">Date & Time</i>
<div class="options">
Date & Time
Alphabetical
Modified
</div>
</div>
<div class="select" data-after="C">
<i data-select-value="">Delete</i>
<div class="options">
Delete
Edit
Unpublish
</div>
</div>

Use this:
var options = document.querySelectorAll('.select .options a');
for (var x = 0; x < options.length; x++) {
options[x].onclick = function() {
console.log(this.getAttribute('data-select'));
}
}

You really had overthought that a bit. You only need to gather up the links and loop through them. You might have noticed that in your code, you had to click twice for anything to happen - - that was because you were applying a click event to ALL the children of the select div elements as well as the select div elements, which included the option div.
Also, it's better to not use the onXyz event properties of DOM objects and instead use the W3C DOM Event standard, which uses addEventListener as an event callback registration method. This allows for a more standard and more robust event registration / de-registration model.
// Just get the anchors that are children of your options element:
var selectAnchors = document.querySelectorAll(".options a");
// Just loop through the anchors. No need to loop the divs
for(var x = 0; x < selectAnchors.length; x++) {
selectAnchors[x].addEventListener("click", function() {
console.log(this.getAttribute('data-select'));
});
}
<div class="select" data-after="C">
<i data-select-value="">Date & Time</i>
<div class="options">
Date & Time
Alphabetical
Modified
</div>
</div>
<div class="select" data-after="C">
<i data-select-value="">Delete</i>
<div class="options">
Delete
Edit
Unpublish
</div>
</div>

Related

Targeting an specific row to make an accordion arrow spin in vanilla JS

Hi im working on animating an arrow in an accordion but it only animates the first row no matter which one i pick. I know its a target issue but can make this work. some help would be great!!
code pen here https://codepen.io/al-web-dev/pen/bGRXdyL
<div class="myDiv">
<div class="row">
<div class="col-4">Test</div>
<div class="col-4 cheese">test 1</div>
<div class="col-4">
<i class="fa fa-arrow-up" aria-hidden="true"></i>
</div>
</div>
<div class="row">
<div class="col-4">Test</div>
<div class="col-4 cheese">test 2</div>
<div class="col-4">
<i class="fa fa-arrow-up" aria-hidden="true"></i>
</div>
</div>
</div>
var myDiv = document.getElementsByClassName("row");
for (var i = 0; i < myDiv.length; i++) {
myDiv[i].addEventListener("click", function (event) {
let toggleAble = document.querySelector(".fa-arrow-up");
let cheese = document.querySelector(".cheese");
event.target.classList.toggle("yello");
event.target.classList.toggle("arrow-down");
});
}
The code in your codepen and your example given here is different. I suggest settling on one version of the code if you're gonna ask for help.
The problem you were facing in your codepen example had to do with var toggleAble. You were query-selecting by a classname. .querySelector will only pick the first element from a list of elements it finds. That is why you've had only the first arrow react. Change document before your query selector method to myDiv[i] - the element you're looking for the arrow in. Like so:
for (let i = 0; i < myDiv.length; i++) {
myDiv[i].addEventListener("click", function (event) {
var toggleAble = myDiv[i].querySelector(".fa-arrow-up");
toggleAble.classList.toggle("arrow-down");
});
}
Oh and for some reason you've renamed the function parameter to myDiv, an already declared array of elements. I've changed it back to event for you.

Removing Attribute hidden from All DOM Elements Except That Whose Index is given Using Javascript Function Not Working

My Function does not work when i call it.
When I Query All Elements And loop over them. I cant get any effect on the UI.
I need to add attribute hidden from all .question and remove .hidden from the one whose index is passed to the Js function. classes when i call the function.
Here is the HTML.
<div class="col-md-12 mb-12 question" hidden="hidden" id="D1">
1
</div>
<div class="col-md-12 mb-12 question" hidden="hidden" id="D2">
2
</div>
<div class="col-md-12 mb-12 question" hidden="hidden" id="D3">
3
</div>
<div class="col-md-12 mb-12 question" hidden="hidden">
4
</div>
Calling the lines in the If condition alone without the loop works.
What could i not be doing right here.
function hideothersexcept(index){
var ALLQNS = $('.question');
for (i = -1; i < ALLQNS.length; i++) {
if (index == i) {
$('#' + getid(index)).removeAttr('hidden')
} else {
ALLQNS[index].setAttribute("hidden", "hidden");
}
}
}
function getid(elm) {
var ALLQNS = $('.question');
k = ALLQNS[elm].getAttribute("id");
return k;
}
Try following code its more clean and succinct then manually looping through all divs and more importantly it works :)
function hideothersexcept(index){
$('.question').each(function(elIndex, el){
if(elIndex == index){
$(el).removeAttr('hidden');
}else{
$(el).attr('hidden', 'hidden');
}
});
}
hideothersexcept(1);
It will hide all other dive except div containing number 2.
NOTE: indexing is zero-based :)
Please let me know if it does not work.

Selecting #2 element inside every div X

I'm trying to make a script which will change the content of every occurence like this:
<div id="random numbers">
<div class="column-1"></div>
<div class="column-1">this value I want to change</div>
<div class="column-1"></div>
</div>
there's many of those^
so far, this is the code I'm trying to make use of:
var elements = document.querySelectorAll('column-1');
for ( var i=elements.length; i--; ) {
elements[ i ].InnerHTML = "test";
}
but this isn't working, and I'm really just trying to piece together some code that will replace the content of the #2 column-1 of every <div id="random numbers">
I appreciate any help here, thanks in advance
There are two problems with your above code. First, your .querySelectorAll() should be targeting the class; you need to specify the full stop. Second, the i in .innerHTML needs to be lowercase.
After these two bugs have been fixed, you can only apply the change to every second element by running a condition based on a modulo of 2 using i % 2 as follows:
var elements = document.querySelectorAll('.column-1');
for (var i = 0; i < elements.length; i++) {
if (i % 2) {
elements[i].innerHTML = "OVERRIDDEN";
}
}
<div id="random numbers">
<div class="column-1">Should STAY</div>
<div class="column-1">Should CHANGE</div>
<div class="column-1">Should STAY</div>
</div>
If you're specifically trying to target the <a> tags, you can do that directly with querySelectorAll('.column-1 a') itself, using .outerHTML if you want to replace the <a> tag itself. Note that this doesn't require a conditional:
var elements = document.querySelectorAll('.column-1 a');
for (var i = 0; i < elements.length; i++) {
elements[i].outerHTML = "OVERRIDDEN";
}
<div id="random numbers">
<div class="column-1">Should STAY</div>
<div class="column-1">Should CHANGE</div>
<div class="column-1">Should STAY</div>
</div>
Hope this helps! :)

Access child elements generated by a template

In my application I'm generating HTML with a Go template. I pass a list to a template that resembles this:
<div id="myList">
{{ Loop }}
<div id="{{.loopIndex}}">
{{ End loop }}
</div>
I now want to access the individual children in JavaScript according to ID. These are not 'elements', so I can't use the HTML DOM getAttribute() method, or access element.id.
I want to do something like this:
var listElement = document.getElementById("myList");
var listElements = listElement.childNodes;
for (i=0; i < listElements.length; i++) {
alert(listElements[i].id);
}
How would I do this? Is there any way to convert the objects in my list to DOM Elements? The example I gave is a lot simpler than my actual code, but it would follow the same approach, I imagine.
You could use getElementsByTagName:
var listElement = document.getElementById("myList");
var listElements = listElement.getElementsByTagName('div'); // could also use listElement.children;
for (i = 0; i < listElements.length; i++) {
alert(listElements[i].id);
}
<div id="myList">
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
</div>
Or just children:
var listElements = listElement.children;
After retrieving the list element with document.getElementById('myList') and assigning it to list, you can retrieve its children with list.getElementById(n) where n is the id. (Or you could continue to use document.getElementById if the element IDs are unique in the document, as they are supposed to be.)
Demonstration:
function print(s) {
document.write(s + '<br />');
}
var list = document.getElementById('myList');
for (var i = 1; i <= 3; ++i) {
var child = list.getElementById(i);
print(child.innerHTML);
}
<div id="myList">
<div id="1"> one </div>
<div id="2"> two </div>
<div id="3"> three </div>
</div>
You can try it with document.querySelector, works fine with all browsers and ie 9
See a demo on jsfiddle
var listItems = document.querySelectorAll("#myList .list-item");
for(var i=0; i < listItems.length; i++){
console.info(listItems[i].id);
}
<div id="myList">
<div class="list-item" id="1" >item 1</div>
<div class="list-item" id="2" >item 2</div>
<div class="list-item" id="3" >item 3</div>
</div>

using jquery accordion collapse only working on one section

So in my div i have a data-bind which will display multiple headers with content within. I want to use jQuery in order for me to collapse and expand but with what i have currently regardless of what header i am clicking it only collapses and expands the first header.
How can i alter what i have so that it could collapse and expand any header clicked and not just the first one?
<div class="accordion-group elements-by-unit" style="display:none" id="listView" data-bind="foreach: Types">
<div class="text_x-large header">
<span data-bind="text:Name()"></span>
<span class="userCount">(<span data-bind="text:UserCount()"></span>)</span>
<span class="icon-minus-sign" data-toggle="collapse"></span>
</div>
<div class="collapse in" data-bind="template: { name: 'list', foreach: $data.Users }"></div>
</div>
<script type="text/html" id="list">
<h3 id="letter" data-bind="text: Letter"></h3>
<div class="smoke_hover">
<span class="h2"><small data-bind="text: Name"></small></span>
</div>
</script>
Javascript
<script type="text/javascript">
(function ($) {
Views.User.Init({
url: '#url',
id:#ViewBag.SectionID,
roleUser:#ViewBag.UserSettings
});
var togglerArr = [];
var contentArr = [];
$('.icon-minus-sign').each(function(){
togglerArr.push($(this));
});
$('.collapse').each(function(){
contentArr.push($(this));
});
for (var t = 0; t < togglerArr.length; t++) {
togglerArr[t][0].dataset.target = "#rUsers-" + t;
}
for (var c = 0; c < contentArr.length; c++) {
contentArr[c][0].id = "#rUsers-" + c;
}
})(jQuery);
</script>
ID passed in data-target of your span.icon-minus-sign has to correspond with the ID of the div.colapse that you want to collapse.
Because all your span.icon-minus-sign are targeting all the divs outputted (because all of them have the same #rUsers id) it is bind to the first element it finds, and that is the first div#rUsers.
To go around this, dynamically add IDs, with incrementing numbers would be the best, and add it to both data-target and id. In your case only solution I see is:
Javascript
var togglerArr = [];
var contentArr = [];
$(".icon-minus-sign").each(function(){
togglerArr.push($(this));
});
$(".collapse").each(function(){
contentArr.push($(this));
});
for (var t = 0; t < togglerArr.length; t++) {
togglerArr[t][0].dataset.target = "#rUsers-" + t;
}
for (var c = 0; c < contentArr.length; c++) {
contentArr[c][0].id = "#rUsers-" + c;
}
And modified html (I removed data-target and coresponding id, as we are setting those in script)
<div class="accordion-group elements-by-unit" id="listView" data-bind="foreach: Types">
<div class="text_x-large header">
<span data-bind="text:Name()"></span>
<span class="userCount">(<span data-bind="text:UserCount()"></span>)</span>
<span class="icon-minus-sign" data-toggle="collapse"></span>
</div>
<div class="collapse in" data-bind="template: { name: 'list', foreach: $data.Users }"></div>
Please let me know if it works for you! Also make sure all .js files are called in right order.
Is this what you are looking for?
$('.header').click(function()
{
$(this).siblings('.collapse').slideToggle();
})
I used siblings() to find the siblings of the header with class .collapse Also used slideToggle() so you don't have to check if the content is visible or not(automatically slideUp and slideDown)
jsFiddle

Categories