I'm trying to dynamically create a html list that update when new information arrives.
Here is my code :
setlast();
function setlast() {
last = [
"xyyxx", "yxyxx", "xxxxy", "yyxxy", "yxyxy"]
};
setInterval(function() {
last[0] = Math.random();
last[1] = Math.random();
last[2] = Math.random();
last[3] = Math.random();
last[4] = Math.random();
}, 2000);
createHtml();
function createHtml() {
setTimeout(function(){
ul = document.createElement("ul");
document.body.appendChild(ul);
ul.setAttribute("id", "lyl");
for(w=0; w<5; w++) {
li = document.createElement("li");
ul.appendChild(li);
}
updateT();
},3500);
}
function updateT() {
setInterval(function() {
li.innerHTML = last[w];
},2000);
}
#listwrapper {
margin-top: 2%;
width : 100%;
}
li {
display : inline;
float : left;
padding : 10px;
}
Doing like above, I get undefined.
If I do it like below, the code works but each li do not update every time Math.random generates a new number.:
setlast();
function setlast() {
last = [
"xyyxx", "yxyxx", "xxxxy", "yyxxy", "yxyxy"]
};
setInterval(function() {
last[0] = Math.random();
last[1] = Math.random();
last[2] = Math.random();
last[3] = Math.random();
last[4] = Math.random();
}, 2000)
createHtml();
function createHtml() {
setTimeout(function(){
ul = document.createElement("ul");
document.body.appendChild(ul);
ul.setAttribute("id", "lyl");
for(w=0; w<5; w++) {
li = document.createElement("li");
ul.appendChild(li);
li.innerHTML = last[w];
}
},3500)
}
#listwrapper {
margin-top: 2%;
width : 100%;
}
li {
display : inline;
float : left;
padding : 10px;
}
So my question is: how can I get the list to display and update every time a new number is generated ?
Thanks a lot.
setlast();
function setlast() {
last = [
"xyyxx", "yxyxx", "xxxxy", "yyxxy", "yxyxy"]
};
setInterval(function() {
last[0] = Math.random();
last[1] = Math.random();
last[2] = Math.random();
last[3] = Math.random();
last[4] = Math.random();
}, 2000);
createHtml();
function createHtml() {
setTimeout(function(){
ul = document.createElement("ul");
document.body.appendChild(ul);
ul.setAttribute("id", "lyl");
for(w=0; w<5; w++) {
li = document.createElement("li");
ul.appendChild(li);
}
updateT();
},3500);
}
function updateT() {
setInterval(function() {
list = ul.childNodes;
for (var i = 0; i < list.length; i++) {
list[i].innerHTML = last[i];
}
},2000);
}
#listwrapper {
margin-top: 2%;
width : 100%;
}
li {
display : inline;
float : left;
padding : 10px;
}
This works. Notes:
Create variables without keywords let or var makes them global which is a bad thing. Variables should be accessible only where its supposed to. See this post.
The above code will fail if the number of elements in the last list is less then the number of li elements appended to ul.
Here is a working example using only pur javascript :
/**
* Update The HTML
*
* #param {Array} last - ensure the array exist by passing it as an argument
*/
function updateHtml(last) {
const ul = document.querySelector('#toUpdate');
// Empty existing li node
ul.innerHTML = ''
for (let i = 0; i < last.length; i++) {
// create and append li elements
const li = document.createElement('li')
li.innerHTML = last[i]
ul.appendChild(li);
}
}
setInterval(function() {
// call with random stuff
updateHtml([
Math.random(),
Math.random(),
Math.random(),
Math.random(),
Math.random()
])
}, 2000)
// first call with strings
updateHtml([
"xyyxx", "yxyxx", "xxxxy", "yyxxy", "yxyxy"
]);
#listwrapper {
margin-top: 2%;
width: 100%;
}
li {
display: inline;
float: left;
padding: 10px;
}
<div id="main">
<ul id="toUpdate">
</ul>
</div>
There is many things to say about DOM Update but most of all what I've done is to exctract the update function to specialize it so updateHtml manipulate the DOM according to the 'last' argument.
Please note that this is a one way data binding. You can do more by using more complex structures and patterns like Observable.
Hope that help
Related
I have coded an infinite scroll. When the user scrolls it will load an additional 20 items which makes it a long list.
I want the scroll to loads new items and clear the previous items.
var listElm = document.querySelector('#infinite-list');
// Add 20 items.
var nextItem = 1;
var loadMore = function() {
for (var i = 0; i < 20; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
loadMore();
}
});
// Initially load some items.
loadMore();
#infinite-list {
/* We need to limit the height and show a scrollbar */
width: 200px;
height: 300px;
overflow: auto;
/* Optional, only to check that it works with margin/padding */
margin: 30px;
padding: 20px;
border: 10px solid black;
}
/* Optional eye candy below: */
li {
padding: 10px;
list-style-type: none;
}
li:hover {
background: #ccc;
}
<ul id='infinite-list'>
</ul>
If you empty the list before that, would it be ok?
var listElm = document.querySelector('#infinite-list');
// Add 20 items.
var nextItem = 1;
var loadMore = function() {
listElm.innerHTML = ''
for (var i = 0; i < 20; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight ) {
loadMore();
}
});
// Initially load some items.
loadMore();
#infinite-list {
/* We need to limit the height and show a scrollbar */
width: 200px;
height: 300px;
overflow: auto;
/* Optional, only to check that it works with margin/padding */
margin: 30px;
padding: 20px;
border: 10px solid black;
}
/* Optional eye candy below: */
li {
padding: 10px;
list-style-type: none;
}
li:hover {
background: #ccc;
}
<ul id='infinite-list'>
</ul>
You can empty the list every time loadMore() is called.
var listElm = document.querySelector('#infinite-list');
// Add 20 items.
var nextItem = 1;
var loadMore = function() {
//Here we empty the list to remove the old results
listElm.innerHTML = ''
//And then load the new items
for (var i = 0; i < 20; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight ) {
loadMore();
}
});
// Initially load some items.
loadMore();
I am writing a javascript code which will sort arrays in ascending order. But whenever my code meets the correct condition which is arr[1] < arr[2], it stops the loop and prompts the message Congratulations!! This Group is Sorted By the way, I am using jquery also because I made a little game that you can sort all the numbers to ascending order and check if it is sorted or not.
I am not sure if the click event is responsible for the loop to stop. I am really confused with this. Can someone help me?
Here is the code snippet from my project:
HTML
<ul id="sort">
<!--Generated Numbers using javascript-->
</ul>
JAVASCRIPT
$(document).ready(function(){
$("#sort").sortable();
$("#sort").disableSelection();
// var elemArr = document.getElementsByClassName("sort-ui");
// var arr = jQuery.makeArray(elemArr);
// arr = arr.map(data => data.innerHTML);
var arr = [];
function generateNum(){
var min=1;
var max=12;
return Math.floor(Math.random() * (+max - +min)) + +min;
// document.write("Random Number Generated : " + random );
}
function storeToArray() {
var i = 0;
var ul = document.getElementById("sort");
var li;
while(i < 12) {
var rec = generateNum();
arr[i] = rec;
li = document.createElement("li");
li.appendChild(document.createTextNode(arr[i]));
ul.appendChild(li);
++i;
}
}
storeToArray();
$(".btn-check").on("click", function(){
var elemArr = document.getElementsByTagName("li");
var arrCheck = jQuery.makeArray(elemArr);
arrCheck = arrCheck.map(data => data.innerHTML);
var int;
var len = arrCheck.length;
console.log(arrCheck);
for(int = 0; int < len-1; i++) {
if(arrCheck[int] > arrCheck[int+1]){
alert("This Group is Not Sorted");
} else {
alert("Congratulations!! This Group is Sorted");
}
}
});
});
CSS (For you to visualize)
#sort {
list-style: none;
width: 430px;
border: 1px solid;
padding: 20px;
margin: 0 auto;
height: 315px;
}
#sort li {
display: inline-block;
float: left;
width: 100px;
height: 100px;
background: yellow;
font: 600 16px/100px "Arial";
text-align: center;
margin: 0;
border: 3px solid white;
}
.button-c {
width: 200px;
margin: 0 auto;
}
There is mistake in for loop i++ for(int = 0; int < len-1; i++) , It should be int++
let arrCheck = [1, 3 , 3, 4]
let len = arrCheck.length
for(let int = 0; int < len-1; int++) {
if(arrCheck[int] > arrCheck[int+1]){
alert("This Group is Not Sorted");
} else {
alert("Congratulations!! This Group is Sorted");
}
}
Your implementation of the sort function was incorrect. You didn't use the break keyword and your numbers were in string format, so you need to parse them for comparison.
function isSorted(arrCheck) {
var sortVal = true;
var len = arrCheck.length;
console.log(arrCheck);
for(int = 0; int < len-1; int++) {
if(parseInt(arrCheck[int]) > parseInt(arrCheck[int+1])) {
sortVal = false;
break;
}
}
return sortVal;
}
I want to add 10 points when blue box goes into brown box.
I tried to set score = 0 and points to add = 10 but it doesn't work.
I alert '+10 points' and it shows me the alert so I guess the problem is the DOM ?!?
Any suggestions ?
Thanks !
let moveCounter = 0;
let score = 0;
let obs = 10;
document.getElementById('score').textContent = '0';
var grid = document.getElementById("grid-box");
for (var i = 1; i <= 49; i++) {
var square = document.createElement("div");
square.className = 'square';
square.id = 'square' + i;
grid.appendChild(square);
}
var obstacles = [];
while (obstacles.length < 10) {
var randomIndex = parseInt(49 * Math.random());
if (obstacles.indexOf(randomIndex) === -1) {
obstacles.push(randomIndex);
var drawObstacle = document.getElementById('square' + randomIndex);
$(drawObstacle).addClass("ob")
}
}
var playerOne = [];
while (playerOne.length < 1) {
var randomIndex = parseInt(49 * Math.random());
if (playerOne.indexOf(randomIndex) === -1) {
playerOne.push(randomIndex);
var drawPone = document.getElementById('square' + randomIndex);
$(drawPone).addClass("p-0")
}
}
var addPoints = $('#score');
$('#button_right').on('click', function() {
if ($(".p-0").hasClass("ob")) {
alert('add +10 points !!!')
addPoints.text( parseInt(addPoints.text()) + obs );
}
moveCounter += 1;
if ($(".p-0").hasClass("ob")) {
}
$pOne = $('.p-0')
$pOneNext = $pOne.next();
$pOne.removeClass('p-0');
$pOneNext.addClass('p-0');
});
#grid-box {
width: 400px;
height: 400px;
margin: 0 auto;
font-size: 0;
position: relative;
}
#grid-box>div.square {
font-size: 1rem;
vertical-align: top;
display: inline-block;
width: 10%;
height: 10%;
box-sizing: border-box;
border: 1px solid #000;
}
.ob {
background-color: brown;
}
.p-0 {
background-color: blue;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div id="grid-box">
</div>
<div class="move">
<button id="button_right">right</button><br>
</div>
<div id="score">
</div>
Thank you very much! I am new to JavaScript/ JQuery
Thank you very much!
You are trying to change the HTML inside of the div with id "score".
Selecting the css element using $("#id") retrieves the DOM element and not its contents so adding the score directly to it has no consequences.
What you want to do is: update the score variable and then set the HTML inside the div to the score value.
So instead of just:
addPoints += obs
you should
score += obs
addPoints.html(score)
I would like to know how can I define a bigger variable for a set of variables that I have in javascript: showFootnotesPanel();, showReferencesPanel();, showImagesPanel();, showInformationPanel();.
Would it be something like this?
function showPanel() {
var x = [showFootnotesPanel();showReferencesPanel();showImagesPanel();showInformationPanel();]
}
Update:
I have this function that used to open a side panel on the right side and color the content:
var els = document.getElementsByClassName('change-color'),
target = document.getElementsByClassName('resources'),
changeColor = function(a) {
elements = document.getElementsByClassName("note");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i])
elements[i].style.backgroundColor = "";
}
target = a.getAttribute('href');
element = document.querySelector('[data-id="' + target.substring(1, target.length) + '"]');
element.style.backgroundColor = a.getAttribute('data-color');
};
for (var i = els.length - 1; i >= 0; --i) {
els[i].onclick = function() {
showFootnotesPanel();
changeColor(this);
}
Now I have 4 side panels that need to respond to the same script, and I thought that by defining something like showPanel() is showFootnotesPanel() or showReferencesPanel() or showImagesPanel() or showInformationPanel() I might simplify things, so the last line of the script would be this instead just:
els[i].onclick = function(){showPanel();changeColor(this);}
Update 2:
Or is it possible to do this with the logical operator OR?
els[i].onclick = function(){showFootnotesPanel(); || showReferencesPanel(); || showImagesPanel(); || showInformationPanel();changeColor(this);}
Update 3:
This is the new script that I am using to hide and show the panels:
function showPanel(myPanel) {
var elem = document.getElementById(myPanel);
if (elem.classList) {
console.log("classList supported");
elem.classList.toggle("show");
} else {
var classes = elem.className;
if (classes.indexOf("show") >= 0) {
elem.className = classes.replace("show", "");
} else {
elem.className = classes + " show";
}
console.log(elem.className);
}
}
function hideOthers(one, two, three, four) {
if (one > "") {
var elem1 = document.getElementById(one);
var classes = elem1.className;
elem1.className = classes.replace("show", "");
}
if (two > "") {
var elem2 = document.getElementById(two);
var classes = elem2.className;
elem2.className = classes.replace("show", "");
}
if (three > "") {
var elem3 = document.getElementById(three);
var classes = elem3.className;
elem3.className = classes.replace("show", "");
}
if (four > "") {
var elem4 = document.getElementById(four);
var classes = elem4.className;
elem4.className = classes.replace("show", "");
}
return;
}
And this is the script that calls the panels and highlights the text on them:
var els = document.getElementsByClassName('change-color'),
target = document.getElementsByClassName('resources'),
changeColor = function(a) {
elements = document.getElementsByClassName("note");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i])
elements[i].style.backgroundColor = "";
}
target = a.getAttribute('href');
element = document.querySelector('[data-id="' + target.substring(1, target.length) + '"]');
element.style.backgroundColor = a.getAttribute('data-color');
};
for (var i = els.length - 1; i >= 0; --i) {
els[i].onclick = function() {
hideOthers('footnotes-section', 'references-section', 'images-section', 'information-section');
showPanel('references-section');
changeColor(this);
}
}
Thank you!
Updated with a final solution.
In javascript you can declare variables by this way:
var text = ""; // String variable.
var number = 0; //Numeric variable.
var boolValue = true; //Boolean variable.
var arrayValue = []; // Array variable. This array can contain objects {}.
var obj = {}; // Object variable.
Check this version of your code.
// var text = ""; => String variable.
// var number = 0; => Numeric variable.
// var boolValue = true; => Boolean variable.
// var arrayValue = []; => Array variable. This array can contain objects {}.
// var obj = {}; => Object variable.
// This section of code is only to explain the first question.
(function() {
function showFootnotesPanel() {
return 10; // Random value.
}
function showReferencesPanel() {
return 30; // Random value.
}
function showImagesPanel() {
return 50; // Random value.
}
function showInformationPanel() {
return 90; // Random value.
}
function showPanel() {
return [
showFootnotesPanel(), // Index = 0
showReferencesPanel(), // Index = 1
showImagesPanel(), // Index = 2
showInformationPanel() // Index = 3
];
}
var bigVariable = showPanel(); // bigVariable is array of numeric values.
// Using logical operator to check status of variable about this demo code.
if (bigVariable[0] === 10 || bigVariable[1] === 30) {
console.log("Hey, with these values can show the FootnotesPanel and ReferencesPanel.");
} else {
console.log("With the current values can't show anything...");
}
console.log(bigVariable);
})();
// https://jsfiddle.net/dannyjhonston/t5e8g22b/
// This section of code attempts to answer the question of this post.
(function() {
// This function can be executed when the page is loaded.
function showPanel(panels) {
var panel, panelVisible = "";
var selPanels = document.getElementById("selPanels");
// In panels array...
for (var i = 0; i < panels.length; i++) {
// panels[0] = "ReferencesPanel";
panel = document.getElementById(panels[i]); // Get in the DOM tag context of the panel to set in the variable "panel".
panelVisible = panel.getAttribute("data-visible"); // HTML5 data attribute.
if (panelVisible == "true") {
panel.setAttribute("class", "show");
} else {
panel.setAttribute("class", "hide");
}
}
}
// This function is for set panel visibilty.
function setPanel(panelId, status) {
panel = document.getElementById(panelId);
panel.setAttribute("data-visible", status);
// Calling the showPanel function to check in the DOM.
showPanel(["ReferencesPanel", "InformationPanel", "ImagesPanel", "FootnotesPanel"]);
}
// Binding the change event to the select tag.
selPanels.addEventListener("change", function() {
// Executes setPanel function with panelId and true to update the data-visible attribute in the DOM.
setPanel(this.options[this.selectedIndex].value, "true");
});
// Executes showPanel function with array argument with panels Id. You need to specify every panel that want to handle.
showPanel(["ReferencesPanel", "InformationPanel", "ImagesPanel", "FootnotesPanel"]);
})();
#global {
border: solid 1px #6291AD;
}
.tools {
background-image: linear-gradient(#FFFFFF, #8999CE);
}
#global div[data-visible] {
height: 80px;
padding: 5px 0;
}
#global div p {
padding: 10px;
}
#ReferencesPanel {
background-image: linear-gradient(#FFFFFF, #FD9A9A);
float: left;
width: 20%;
}
#InformationPanel {
background-image: linear-gradient(#FFFFFF, #A1C7F1);
float: left;
width: 80%;
}
#ImagesPanel {
background-image: linear-gradient(#C6E9FB, #FFF);
width: 100%;
}
#FootnotesPanel {
background-image: linear-gradient(#C6E999, #FFF);
width: 100%;
}
.clear {
clear: both;
}
.show {
display: block;
}
.hide {
display: none;
}
<div id="global">
<div class="tools">Show Panel:
<br />
<!-- Demo -->
<select id="selPanels">
<option value="">[SELECT]</option>
<option value="ReferencesPanel">ReferencesPanel</option>
<option value="InformationPanel">InformationPanel</option>
<option value="ImagesPanel">ImagesPanel</option>
<option value="FootnotesPanel">FootnotesPanel</option>
</select>
</div>
<!-- You need to set data-visible attribute with true or false to show or hide a panel. -->
<div id="ReferencesPanel" data-visible="false">
<p>References Panel</p>
</div>
<div id="InformationPanel" data-visible="false">
<p>Information Panel</p>
</div>
<div class="clear"></div>
<div id="ImagesPanel" data-visible="false">
<p>Images Panel</p>
</div>
<div id="FootnotesPanel" data-visible="false">
<p>Foot notes Panel</p>
</div>
</div>
I dont understand your question exactly, but if you want to define a variable that contains other variables then you can use an object.
e.g:
var footNotesPanel = true;
var referencesPanel = true;
var imagesPanel = true;
var showPanels = {
footNotesPanel: footNotesPanel,
referencesPanel: referencesPanel,
imagesPanel: imagesPanel
}
/*
Option 2 - for showing/hiding side panels
1 ) create all your panels as they would appear, with all the data, but hide them with display:none;
2 ) call show panel function to show a panel.
*/
var showPanel(panel_id) {
var panel_element = $("#" + panel_id); /*panel that you want to show ( is hidden atm but somewhere on the page */
if (!panel_element.length) {
return false; //no panel with this id currently on page
} else {
//check the panel id and do some custom editing if needed, eg.
if (panel_id == "main_side_panel") {
//add some additional classes to body element etc
}
panel_element.show();
//Or Another option that you probably are looking for is below
if (panel_id == "footnotes_panel") {
showFootnotesPanel();
} else if (panel_id == "images_panel") {
showImagesPanel();
}
}
}
// And use it like this:
<div id="footnotes_panel" onclick="showPanel('footnotes_panel')"></div>
// Or simply get the element id from `event.target` and use `showPanel()` without arguments.
I don't want to use jQuery, or any other 3rd party library!
Not working proof of concept:
<div id="Wrapper"></div>
<script>
function Build()
{
for (var i = 0 ; i < 10 ; i++)
{
var elem = document.createElement("div");
elem.setAttribute("onclick", "OnClickEvent(" + i + ")");
elem.textContent = "Hi";
document.getElementById("Wrapper").appendChild(elem);
}
}
function OnClickEvent(elementNum)
{
alert("Hi! I am " + elementNum);
}
Build();
</script>
fiddle: http://jsfiddle.net/qyzrQ/
In real life:
I'm dynamically creating a table based on ajax callback, each row contains an image button and another table. This image button should be able to hide or show corresponding inner table.
Frustrating. I was able to solve it myself.
It is enough to add (even before inserrting it into DOM):
element.setAttribute("onclick","functionName("+param+")");
Here is what i wanted to get: http://jsfiddle.net/YhY4Q/6/
And prototype (in case fiddle got deleted):
html:
<section id="Table" class="table">
<header class="row">
<div class="cell">header</div>
</header>
<script>
function ToggleShow(id) {
var elem = document.getElementById(id);
if (elem.classList.contains("invisible")) {
elem.classList.remove("invisible");
} else {
elem.classList.add("invisible");
}
}
</script>
<section id="TableWrapper">
</section>
</section>
javascript:
function ToggleShow(id) {
var elem = document.getElementById(id);
if (elem.classList.contains("invisible")) {
elem.classList.remove("invisible");
} else {
elem.classList.add("invisible");
}
}
function Build() {
var parent = document.getElementById("TableWrapper");
for (var id = 0; id < 10; id++) {
var row = document.createElement("div");
row.appendChild(HeaderRowBuilder(id));
row.appendChild(InnerTableBuilder(id));
parent.appendChild(row);
}
}
function HeaderRowBuilder(id) {
var header = document.createElement("header");
header.classList.add("row");
header.appendChild(HeaderCellBuilder(id));
var strongEle = document.createElement("strong");
strongEle.classList.add("cell");
strongEle.classList.add("cell2");
strongEle.textContent = "Something else";
header.appendChild(strongEle);
return header;
}
function HeaderCellBuilder(id) {
var div = document.createElement("div");
div.classList.add("cell");
div.appendChild(HeaderImageBuilder(id));
return div;
}
function HeaderImageBuilder(id) {
var img = document.createElement("img");
img.setAttribute("alt", "extended");
img.setAttribute("onclick", "ToggleShow('InnerTable_" + id + "')");
return img;
}
function InnerTableBuilder(id) {
var div = document.createElement("div");
div.setAttribute("id", "InnerTable_" + id);
div.textContent = "More rows, I don't care about them right now";
return div;
}
Build();
and css:
.table {
display: table;
}
.table .cell {
display: table-cell;
}
.table .cell2 {
border: 1px solid black;
width: 100%;
}
.table .spacer {
min-width: 40px;
max-width: 40px;
}
.table .cell3 {
min-width: 50px;
max-width: 50px;
}
.table .row {
display: table-row;
}
.invisible {
display: none;
}