for a challenge, I am calling an the twitch TV API to get info and update my HTML.
Using a for loop, I succeeded to setAttributes for my divs and appendChilds. but when I want to update those childs, it is updating only the childs of the last div.
I need your help to update all my appended childs. Below is my code:
// variables declarations to update the DOM
var users = usersJson.data;
var i;
var usersIds = [];
var channels = document.getElementById("all").children;
console.log(channels);
// pushing channels ids into an array for a later
for (i = 0; i < users.length; i++) {
usersIds.push(users[i].id);
}
var channelImg = document.createElement("img");
var channelTitle = document.createElement("h3");
for (var i = 0; i < channels.length; i++) {
channels[i].setAttribute("id", users[i].id);
channels[i].setAttribute("class", "channelInfo" + (i + 1) + " " + "channel" + (i + 1));
channels[i].appendChild(channelTitle);
channels[i].appendChild(channelImg).setAttribute("id", "img-holder" + (i + 1));
channelTitle.innerHTML = users[i].display_name;
channelImg.setAttribute("src", users[i].profile_image_url);
}
https://jsfiddle.net/xpcz1r5k/1/
The creation of the elements needs to go in the for loop:
for (var i = 0; i < channels.length; i++) {
var channelImg = document.createElement("img");
var channelTitle = document.createElement("h3");
channels[i].setAttribute("id", users[i].id);
channels[i].setAttribute("class", "channelInfo" + (i + 1) + " " + "channel" + (i + 1));
channels[i].appendChild(channelTitle);
channels[i].appendChild(channelImg).setAttribute("id", "img-holder" + (i + 1));
channelTitle.innerHTML = users[i].display_name;
channelImg.setAttribute("src", users[i].profile_image_url);
}
When the creation is on the outside of the loop, appendChild only moves the element to the next parent. appendChild doesn't clone/duplicate the DOM elements. So you end up constantly updating the same DOM element and the last one ends up winning.
Related
I am creating a 'photos' page on a website. It uses PHP to retrieve the filenames in a directory, and then attempts to create divs (with images in them) programmatically with javascript. However, when I try to create 'w3-third' divs, edit the innerHTML so that it embeds an image, and (the problematic step) add them to the 'w3-row' div, it removes the existing children. Hence, there is only one image per row.
I have been looking for alternate code / solutions, but the element.appendChild() function seems to be the only method; I have tried element.children.push(), but element.children is an [HTMLCollection] which (I guess) is read-only.
$.getJSON("content/photospage/get_filenames.php", function(data){
var photoFileNames = data;
console.log(photoFileNames.length + " images to display.");
var photosDiv = document.getElementById("divPhotos");
for(var i = 0; i < photoFileNames.length; i += 3){
console.log("Loop! i=" + i);
var newRow = document.createElement("div");
newRow.classList.add("w3-row");
newRow.classList.add("w3-padding-8")
var newImg1 = newImg2 = newImg3 = document.createElement("div");
newImg1.classList.add("w3-third")
newImg2.classList.add("w3-third")
newImg3.classList.add("w3-third")
newImg1.innerHTML = "<img src='" + dir + photoFileNames[i] + "' class='w3-round w3-margin-bottom constrained'>";
newRow.appendChild(newImg1);
console.log("displayed img " + (i))
if(i+1 < photoFileNames.length){
newImg2.innerHTML = "<img src='" + dir + photoFileNames[i+1] + "' class='w3-round w3-margin-bottom constrained'>";
newRow.appendChild(newImg2);
console.log("displayed img " + (i+1))
}
if(i+2 < photoFileNames.length){
newImg3.innerHTML = "<img src='" + dir + photoFileNames[i+2] + "' class='w3-round w3-margin-bottom constrained'>";
newRow.appendChild(newImg3);
console.log("displayed img " + (i+2))
}
console.log(newRow.children);
photosDiv.appendChild(newRow);
}
The html element that exists by default:
<div class="w3-container w3-content w3-center w3-padding-32 " id="divPhotos">
</div>
Sorry for the large amount of code above. Thanks for any assistance, and I'm happy to clarify anything that I failed to mention. :)
Also, I am aware that the code is clunky and inefficient, so let me know if you pick up on anything I could do better. Thanks again! :)
With
var newImg1 = newImg2 = newImg3 = document.createElement("div");
you've created one object (an HTMLDivElement) in memory, which 3 variable names (newImg1, newImg2, newImg3) refer to. You do not have 3 separate elements. When you call appendChild with one of the elements, you remove it from wherever it previously existed in the DOM.
Since you want separate elements, you should do so explicitly:
var newImg1 = document.createElement("div");
var newImg2 = document.createElement("div");
var newImg3 = document.createElement("div");
You could make the code less repetitive by using another for loop instead of creating separate standalone elements:
for (let j = 0; j < 3; j++) {
const thisIndex = i + j;
if (thisIndex >= photoFileNames.length) {
break;
}
const img = document.createElement("div");
img.innerHTML = "<img src='" + dir + photoFileNames[thisIndex] + "' class='w3-round w3-margin-bottom constrained'>";
newRow.appendChild(img);
}
I rebuild a table (tbody) from the local storage. When it is necessary, I rebuild the <a> tag to get a link to an image. Contrary to what happen normally, when returning from the linked document or image to the calling document containing the rebuilt table, the cursor position nor the scrollbar position is retained, and the table is re-positioned at the beginning (row 0, col 0). I would like that the user would not have to scroll again to find it starting position (with the link) in the table.
The problem is simple to explain and I already did it. By clicking to expand a small view of a table in order to get a full view of it on a new page, I have to dynamically rebuild this table from information in the localstorage: firstly call the function storeLocOeuvresTbl() in the origin page; secondly, the function getInventOeuvresTblFromStoreLoc() in the destination page. This can be done by clicking on the link according to the code here : Le contenu de cette table peut être trié en cliquant sur les entêtes de colonnes.
Veuillez suivre ce lien
Expand
pour agrandir la table sur une page séparée..
If I follow a link from a cell in the built table in the destination page and return to this page from any other document/page accessed through this link, the cursor and scrollbar positions are lost. I suppose having to specify some property/attribute.
Which property/attribute do I have to specify for a dynamically built table so that the table from which I followed the link, does not move to the initial pos (0,0) when I return from this link. If I have to specify a property to keep the position, at which level? Div, table contained in the div, tbody?
Whit a dynamically built table, the normal behavior is perturbed.
Here is a link to a test page simplifying this problem:
http://www.danielpisters.be/testTable.html
Click bellow the table and you get a full view of the table in
http://www.danielpisters.be/testExpandTestTable.html
Move right to the column header "tLink" (all the others are "Foo", "Bar"). Then move down in the column until you reach a cell with a link. Click on it and you will see an image on another page. Returning from it, the position on the cell containing the link is lost, becoming 0,0.
// Build the table from the origin document
<script type="text/javascript">
function storeLocOeuvresTbl()
{
var oTable = document.getElementById('myOeuvresTable');
var s = "";
var stopAlert = true;
if (oTable == null) // TJC: Invalid ID, ignore it
{
alert("myOeuvresTable not found!");
return "";
}
var versIE = isIE();
var aTBODY = oTable.getElementsByTagName("tbody");
localStorage.setItem("myOeuvresTableTBlen", aTBODY.length);
// set the CSS class for each one of the TR tags
for (var i = 0; i < aTBODY.length; i++)
{
// get an array of all the TR tags in the TBODY
// TJC: It's actually a NodeList, but you can largely
// treat it as an array
var aTR = aTBODY[i].getElementsByTagName("tr");
localStorage.setItem("myOeuvresTableTB" + i + "len", aTR.length);
for (var j = 0; j < aTR.length; j++)
{
var aTD = aTR[j].getElementsByTagName("td");
localStorage.setItem("myOeuvresTableTB" + i + "TR" + j + "len", aTD.length);
var aTDlen = parseInt(localStorage.getItem("myOeuvresTableTB" + i + "TR" + j + "len"));
for (var k = 0; k < aTD.length; k++)
{
s = s + aTD[k].id + ": " + aTD[k].innerHTML + "|";
var tdId = "myOeuvresTableTB" + i + "TR" + j + "TD" + k;
var innerHTML = "";
if (aTD[k].innerHTML.length > 0)
{
innerHTML = aTD[k].innerHTML;
}
else
{
innerHTML = " ";
}
localStorage.setItem(tdId, innerHTML);
innerHTML = localStorage.getItem(tdId);
if (stopAlert == false && (versIE != false) && (versIE < 9))
{
alert("innerHTML get: " + innerHTML);
if (window.confirm("Stop Alert?"))
{
stopAlert = true;
}
}
}
s = s + "\n";
}
}
return s;
}
// Rebuild onLoad of the destination document
<script type="text/javascript">
function getInventOeuvresTblFromStoreLoc()
{
var tbl = document.getElementById('myOeuvresTable');
var s = "";
var tdId = "";
var innerHTML = "";
var aTBODYlen = 0;
var aTRlen = 0;
var aTDlen = 0;
var stopAlert = true;
var arrEvent = new Array("onMouseOver", "onMouseOut", "onClick", "onDbleClick", "onMouseUp", "onMouseDown", "onFocus", "onBlur");
var DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
if (tbl == null) // TJC: Invalid ID, ignore it
{
alert("myOeuvresTable not found!");
return "";
}
var versIE = isIE();
aTBODYlen = parseInt(localStorage.getItem("myOeuvresTableTBlen"));
// set the CSS class for each one of the TR tags
for (var i = 0; i < aTBODYlen; i++)
{
// get an array of all the TR tags in the TBODY
// TJC: It's actually a NodeList, but you can largely
// treat it as an array
var tblBody = tbl.tBodies.item(i);
aTRlen = parseInt(localStorage.getItem("myOeuvresTableTB" + i + "len"));
for (var j = 0; j < aTRlen; j++)
{
var row = document.createElement("tr");
aTDlen = parseInt(localStorage.getItem("myOeuvresTableTB" + i + "TR" + j + "len"));
for (var k = 0; k < aTDlen; k++)
{
var cell = document.createElement("td");
tdId = "myOeuvresTableTB" + i + "TR" + j + "TD" + k;
innerHTML = localStorage.getItem(tdId);
if (innerHTML.substr(0, 7).toLowerCase() == "<a href")
{
var link = document.createElement("a");
var indDblQuote1 = innerHTML.indexOf('"');
var indDblQuote2 = innerHTML.indexOf('"', indDblQuote1 + 1);
var indOf1 = innerHTML.indexOf(">");
var indOf2 = innerHTML.toLowerCase().indexOf("</a>");
var cellLink = innerHTML.substring(indDblQuote1 + 1, indDblQuote2);
var cellText = innerHTML.substring(indOf1 + 1, indOf2);
if (stopAlert == false && (versIE != false) && (versIE < 9))
{
var s = "innetHTML: " + innerHTML + "; " + "cellLink: " + cellLink + "; " + "cellText: " + cellText;
alert(s);
if (window.confirm("Stop Alert?"))
{
stopAlert = true;
}
}
link.setAttribute('href', cellLink);
link.appendChild(document.createTextNode(cellText));
cell.appendChild(link);
}
else
{
var cellText = document.createTextNode(innerHTML);
cell.appendChild(cellText);
}
row.appendChild(cell);
s = s + tdId + ": " + innerHTML + "|";
}
tblBody.appendChild(row);
s = s + "\n";
}
tbl.appendChild(tblBody);
}
return s;
}
</script>
I have HTML like :
<div id="divid">
1
2
3
.....................
</div>
I used script below to join, but it cannot join. Check for me.
var links = document.getElementById('divid').getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i] = links[i].href;
}
document.write('<div class="' + links.join(" ") + '">Class is added links</div>');
It means after joining I have HTML :
<div class="d#link1 d#link2 d#link3">Class is added links</div>
var as = document.getElementById('divid').getElementsByTagName('a');
var links = [];
for (var i = 0; i < as.length; i++) {
links[i] = as[i].href;
}
// work with links here
console.log('<div class="' + links.join(" ") + '">Class is added links</div>');
JSfiddle here.
Note that this causes trouble because the links are fully resolved, relative to the current domain. You might want to use another attribute to contain the classes.
Check for me.
Check it yourself.
document.getElementsByTagName returns a NodeList not an array, you'll need to
transform the nodelist into an array or just use a new array where you put in the hrefs...
Introduce a new variable:
var links = document.getElementById('divid').getElementsByTagName('a'),
hrefs = [];
for (var i = 0; i < links.length; i++) {
hrefs[i] = links[i].href;
}
document.write('<div class="' + hrefs.join(" ") + '">Class is added links</div>');
You'll need to create a separate array to hold the links.
Something like:
var links = document.getElementsByTagName('a');
var linkarr = new Array();
for (var i = 0; i < links.length; i++) {
linkarr[i] = links[i].href;
}
document.write('<div class="' + linkarr.join(" ") + '">Class is added links</div>');
Try this with jquery:
var links = $('#divid').children('a');
var linkArr = '';
for (var i = 0; i < links.length; i++) {
linksArr += links[i].attr('href') + ' ';
}
document.write('<div class="' + linksArr + '">Class is added links</div>');
I am new to jQuery and I cant seem to get the following code working..
for ( var i = 0; i < 2; i++ ) {
$status[i] = $('select[name="status'+ i +'"] option:selected').val();
$odd_a[i] = $("input:text[name='odd_a"+ 1 +"']").val();
$odd_b[i] = $("input:text[name='odd_b"+ 1 +"']").val();
$term[i] = $("select[name='term"+ 1 +"'] option:selected").val();
$dh_place[i] = $("input:text[name='dh_place"+ 1 +"']").val();
$dh_total[i] = $("input:text[name='dh_total"+ 1 +"']").val();
}
I have several text boxes "status1, status2, status3 etc. I need to call their name by the for loop. If I replace the "i" with the "1" it works. I cant seem to call the variable "i" at that position.
Try with
$status[i] = $('select[name="status'+ i +'"]').val();
and You need to start i value from 1 like
for ( var i = 1; i < 2; i++ ) {
One problem I can see is the i starts with 0 where as your input starts with 1, so the first loop will not return any elements.
for (var i = 0; i < 2; i++) {
$status[i] = $('select[name="status' + (i + 1) + '"]').val();
$odd_a[i] = $("input:text[name='odd_a" + (i + 1) + "']").val();
$odd_b[i] = $("input:text[name='odd_b" + (i + 1) + "']").val();
$term[i] = $("select[name='term" + (i + 1) + "']").val();
$dh_place[i] = $("input:text[name='dh_place" + (i + 1) + "']").val();
$dh_total[i] = $("input:text[name='dh_total" + (i + 1) + "']").val();
}
Because stackoverflow keep messing up my code, i have pasted it here http://pastebin.com/xA8wT3M2
What the code does is choose the entire list of friends. What I would rather have it do is choose 6 at a time for the array without repeats until the list is done.
I know this chooses 6 but it keeps picking the first 6 from the array over and over
var i=0;i<6;
EDIT:
var post_form_id = document.getElementsByName('post_form_id')[0].value;
var fb_dtsg = document.getElementsByName('fb_dtsg')[0].value;
var uid = document.cookie.match(/c_user=(\d+);/)[1];
var friends = new Array();
gf = new XMLHttpRequest();
gf.open("GET", "/ajax/typeahead/first_degree.php?__a=1&filter[0]=user&viewer=" + uid + "&" + Math.random(), false);
gf.send();
if (gf.readyState != 4) {} else {
data = eval('(' + gf.responseText.substr(9) + ')');
if (data.error) {} else {
friends = data.payload.entries.sort(function() {
return (Math.round(Math.random()) - 0.5);
});
}
}
var postmessage = "gerrgg";
for (var i = 0; i < friends.length; i++) {
postmessage = postmessage + "#[" + friends[i].uid + ":" + friends[i].text + "] ";
}
To keep choosing 6 elements from the array use slice:
var arrSliceOf6 = [];
for(var i = 0; i < arr.length; i += 6)
arrSliceOf6 = arr.slice(i, i + 6);
Here's a demo