Access child elements generated by a template - javascript

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>

Related

toggle div using for loops

just wondering what went wrong.. i have two div named click_1 and click_2.. and i want to toggle the div named hide corresponding with their numbers.. lets say click_1 with hide_1 and click_2 with hide_2.. but when i ran the code only click_1 is functioning .. what seems to be wrong... newbie here.. recently learned jquery
<div id='click_1'>
<div id='hide_1'></div>
</div>
<div id='click_2'>
<div id='hide_2'></div>
</div>
<script>
function toggle_div(id_A,id_B){
for(var i=0; i<3; i++){
var new_A = id_A + i;
var new_B = id_B + i;
$(new_A).click(function(){
$(new_B).toggle();
});
}
}
toggle_div('click_','hide_');
</script>
The issue is because your id selectors are missing the # prefix:
toggle_div('#click_', '#hide_');
However you should note that you will also need to use a closure for this pattern to work otherwise the new_B element will always be the last one referenced in the for loop.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='click_1'>
click 1
<div id='hide_1'>hide 1</div>
</div>
<div id='click_2'>
click 2
<div id='hide_2'>hide 2</div>
</div>
<script>
function toggle_div(id_A, id_B) {
for (var i = 1; i < 3; i++) {
var new_A = id_A + i;
var new_B = id_B + i;
(function(a, b) {
$(a).click(function() {
$(b).toggle();
})
})(new_A, new_B);
}
}
toggle_div('#click_', '#hide_');
</script>
As you can see this is very verbose, rather complicated and hardly extensible. A much better approach is to use generic classes and DOM traversal to repeat the same logic on common HTML structures.
To achieve this put common classes on the elements to be clicked and the elements to toggle. Then in the single click event handler you can use the this keyword to reference the element which was clicked, then find() the element to toggle within that. Something like this:
$(function() {
$('.click').click(function() {
$(this).find('.hide').toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="click">
click 1
<div class="hide">hide 1</div>
</div>
<div class="click">
click 2
<div class="hide">hide 2</div>
</div>
<div class="click">
click 3
<div class="hide">hide 3</div>
</div>
Also note that this pattern means that you can have an infinite number of .click elements with matching .hide content without ever needing to update your JS code.
It is better not to use for loop for click event ! If you have id like that your can handle by that clicked id split ....
$("[id^='click_']").on("click",function () {
$('#hide_'+this.id.split('_')[1]).toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='click_1'>
Click1
<div id='hide_1'>hide1</div>
</div>
<div id='click_2'>
Click2
<div id='hide_2'>hide2</div>
</div>

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! :)

Which is the fastest method to add values with Jquery in HTML elements?

With pure HTML and then adding the value via jquery:
<div id="leftAxis">
<div class="leftQuadrant">
<div id="oneval" class="insideQuadrant"></div>
</div>
<div class="leftQuadrant">
<div id="twoVal" class="insideQuadrant"></div>
</div>
<div class="leftQuadrant">
<div id="threeVal" class="insideQuadrant"></div>
</div>
</div>
fillLeftAxis: function() {
var data = ['one', 'two', 'three'],
IdHtml = ['#oneVal', '#twoVal', '#threeVal'];
for(var i=0; i<IdHtml.length; i++) {
$(IdHtml[i]).html(data[i]);
}
};
Or directly construct the HTML elements with the value in it and append it later to the container with jquery:
<div id="leftAxis">
</div>
fillLeftAxis: function() {
var data = ['one', 'two', 'three'],
html = '';
for(var i=0; i<data.length; i++) {
html += '<div class="leftQuadrant"><div id="' + data[i] + 'Val" class="insideQuadrant">' + data[i] + '</div></div>';
}
$('#leftAxis').html(html);
};
You can use Document.querySelectorAll() to select all elements with class "insideQuadrant" instead of using jQuery, that is an external library with a lot of methods that you probably do not need all of them in your script (or project).
Than you can iterate over all the aray of elements with Array.prototype.forEach().
Code:
(function () {
var data = ['one', 'two', 'three'];
document
.querySelectorAll('.insideQuadrant')
.forEach(function (element, index) {
element.textContent = data[index];
});
})();
<div id="leftAxis">
<div class="leftQuadrant">
<div class="insideQuadrant"></div>
</div>
<div class="leftQuadrant">
<div class="insideQuadrant"></div>
</div>
<div class="leftQuadrant">
<div class="insideQuadrant"></div>
</div>
</div>
Notice: that for this case there is no need to use element id attributes because that will require more querys to the DOM.
the second way.
the first way causes Dom Tree refreshing each loop, and that causes heavy performance expending. not suggested.
see more details about Dom rending and UI Thread in browsers.

Loop through child and get attribute

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>

How to get the total instance of the :contains() Selector using an Array with multiple matches in a DIV?

This is a follow-up query for How to get the total instance of the :contains() Selector
I have this array loop issue on getting the total match using contains:selector...
Here are my variables -
var filterarray = ["Content1", "goes"];
<div id="content" style="display:none">Content1 goes here</div>
<div id="content" style="display:none">Content1 goes here too</div>
<div id="content" style="display:none">Content1 goes here again</div>
<div id="content" style="display:none">extra node</div>
Here's my script -
totalSum = 0;
for (i=0;i<filterarray.length;i++){
$( "div[id^=content]:contains('"+ filterarray[i] +"')").css( "display", "block" );
totalSum += $( "div[id^=content]:contains('"+ filterarray[i] +"')").length;
}
$("#results").append("Total Results: " +totalSum);
The results shows = 6, wherein it should only be 3 because the div is already in "block". I think the count goes for each "Content1" = 3 and "goes" = 3, total of 6.
QUESTION: Is there a way to show only 3 and ignore if there are multiple matches (or duplicates) within a DIV instance?
This might help you: http://api.jquery.com/jquery.unique/
http://jsfiddle.net/xb14h1ev/1/
HTML:
<div class="content" style="display:none">Content1 goes here</div>
<div class="content" style="display:none">Content1 goes here too</div>
<div class="content" style="display:none">Content1 goes here again</div>
<div class="content" style="display:none">extra node</div>
<div id="results"></div>
JS:
var filterarray = ["Content1", "goes"];
$(function(){
totalSum = 0;
var divs = [];
for (i=0;i<filterarray.length;i++){
$( "div.content:contains('"+ filterarray[i] +"')").css( "display", "block" );
$.merge(divs, $( "div.content:contains('"+ filterarray[i] +"')"));
}
totalSum = $.unique(divs).length;
$("#results").append("Total Results: " +totalSum);
});
First advice use classes instead of ids! Because id means UNICAL IDENTIFICATOR. Read about this note.
So assume you have next html nodes
<div class="content" style="display:none">Content1 goes here</div>
<div class="content" style="display:none">Content1 goes here too</div>
<div class="content" style="display:none">Content1 goes here again</div>
<div class="content" style="display:none">extra node</div>
Iterate all nodes with content class.
var nodes = $(".content");
var filterarray = ["Content1", "goes"];
var total = 0;
for(var i = 0; i < nodes.length; i++){
var current = $(nodes[i]);
var text = current.text();
var res = filterarray.reduce(function(p, a){
return p && (text.indexOf(a) != -1);
}, true);
if(res) total++;
}
console.log(total)
Demo

Categories