I'm trying to build a program to run a function every time I press a button, and output the returned value. To do this, I use the following HTML:
<h2>Test Results:</h2>
<strong><span id='runs'>0</span> tests</strong><br>
<div id='testResults'>
<button id='test' onClick='this.parentNode.innerHTML = initiatePlanB()'>Begin</button>
</div>
Here's the javascript:
var tests = document.getElementById('runs');
var inner = document.getElementById('testResults').innerHTML;
//Here's the part I can't figure out
var wo = inner.replace(??????, '');
var out = wo + '<br><strong>Test #' + String(Number(tests.innerText) + 1) + '</strong><br>';
tests.innerText = Number(tests.innerText) + 1;
//More stuff here
return out;
Basically, I need either a regex expression, or some other function that can remove any html tag and it's contents.
Why not just find all buttons using getElementsByTagName('button')
and then remove them all?
var testCount = 0;
var tests = document.getElementById('runs');
var inner = document.getElementById('testResults')
function initiatePlanB() {
var buttons = inner.getElementsByTagName('button');
if (buttons) {
for (var i = 0; i < buttons.length; i++) {
buttons[i].remove();
}
}
testCount++;
inner.insertAdjacentHTML('beforeend', '<br><strong>Test #' + testCount + '</strong><br>');
tests.innerText = testCount;
//More stuff here
}
<h2>Test Results:</h2>
<strong><span id='runs'>0</span> tests</strong><br>
<div id='testResults'>
<button id='test' onClick='initiatePlanB()'>Begin</button>
</div>
Though you should probably just hide the buttons, or disable them.
Related
I've written code using Javascript to format the following section of a webpage based on the values:
<div class="col-md-auto mx-auto">
<h3>Average price</h3>
<p id="avgPrice"></p>
<br>
<div>Average change</div>
<div class="change" id = "avgChange"></div>
</div>
<div class="col-md-auto mx-auto">
<h3>Max price</h3>
<p id="maxPrice"></p>
<br>
<div>Max change</div>
<div class="change" id="maxChange"></div>
</div>
(The values for the text within each of the id's are getting pulled from a database, and appear correctly on the webpage when I start the server)
Here is my Javascript to format the HTML based on positive/negative values:
function changeFormatter() {
var elements = document.getElementsByClassName("change");
for (var i = 0; i < elements.length; i++) {
var change = elements[i]; //this is where the problem is
console.log(change);
if (change > 0) {
elements[i].innerHTML = "▴ " + change + "%";
elements[i].classList.add("text-success");
}
if (change < 0) {
elements[i].innerHTML = "▾ " + change + "%";
elements[i].classList.add("text-danger");
}
}
}
This code is being called by the following eventlistener:
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
getData(); //gets values from database and adds them to HMTL
changeFormatter();
});
The issue is the line where I'm defining the var change. The output of the console.log on the line below it shows the text I want is there, see image below:
But no matter what I try I cannot get the text contained within this div. I've tried elements[i].value, .textContent, .innerHTML, .innerText, parseFloat(elements[i].innerHTML)... but they all return 'undefined' when I try and log them. I would really appreciate any suggestions!
Output of console.log(elements[i], elements[i].innerHTML)
.innerHTML should be correct as seen here: https://jsfiddle.net/awLynp28/3/. All I did was copy your script, have it run on page load (since it looks like you have something like that in there, I am assuming your function is getting called after the data is fully called in), and change
var change = parseFloat(elements[i].innerHTML);
document.addEventListener('DOMContentLoaded', function() {
var elements = document.getElementsByClassName("change");
for (var i = 0; i < elements.length; i++) {
var change = parseFloat(elements[i].innerHTML); //this is where I put innerHTML
console.log(change);
if (change > 0) {
elements[i].innerHTML = "▴ " + change + "%";
elements[i].classList.add("text-success");
}
if (change < 0) {
elements[i].innerHTML = "▾ " + change + "%";
elements[i].classList.add("text-danger");
}
}
}, false);
just try to run this code in two ways:
1) run this code below;
2) enable for loop then run it
<html>
<head>
<script>
function toggle(){
//console.log('hi');
var samplediv = document.getElementById('samplediv');
samplediv.innerHTML = '';
var i = 1;
//for(var i = 0; i < 3; ++i){
samplediv.innerHTML +=
"<div id=\'jh"+ i + "\'>Hi This is "+i+"</div>" +
"<div id=\'edit" + i + "\' style=\'display:none\'>Edit "+i+"</div>" ;
document.getElementById('jh'+i).addEventListener("click", function(){document.getElementById('edit'+i).style.display="block";});
/*
(function(i){
//console.clear();
var key = i;
i += "";
document.getElementById('jh0').addEventListener("click", function(){document.getElementById('edit0').style.display="block";});
//document.getElementById('jh'+key).addEventListener("click", function(){document.getElementById('edit'+key).style.display="none";}, true);
//console.log(i, key);
}(i));
*/
//}
}
</script>
</head>
<body>
<div id="samplediv" >over here</div>
<script>toggle();</script>
</body>
</html>
I'm trying to add addEventLister on every divs using for. I'm sure this is kind of call by reference error. I know there are ways to add events such as on attribute method. Also adding a number of similar listeners is inefficient but I have to make them as you can see.
I've made a IIFE to make key be a value but failed. Do you have any idea to solve this problem?(No jQuery please)
JSFiddle
You will change method which You use to adding new elements.
I replaced innerHTML += to document.createElement for each new item.
var jh = document.createElement('div');
jh.id = 'jh'+i;
jh.innerText = 'Hi This is '+i;
var edit = document.createElement('div');
edit.id = 'edit'+i;
edit.style.display = 'none';
edit.innerText = 'Edit '+i;
samplediv.appendChild(jh).appendChild(edit);
Variable i on click event is visible with last value, so You must get index from other source (from id for example).
document.getElementById('jh'+i).addEventListener("click", function(){
var jhIndex = this.id.split('jh')[1];
document.getElementById('edit'+jhIndex).style.display= 'block';
});
http://jsfiddle.net/rfnslyr/CRqXm/1/
I have the following fiddle which extracts CSS classes and ID's, and posts them to console. I want to type a name into the top box, paste some code, and have it generate a separate set of unique css ID's and classes into a new instance of the #classes instance (which has uin0CE + a bunch of classes in it).
I have that posting to console done, I just don't know how to "spawn" a new instance of the the #classes section on submit every time I add a new name to #codeName and code to #codeInput.
index.html
<div id="container">
<input id="codeName" class="boxsizingBorder"></input><br>
<textarea id="codeInput" class="boxsizingBorder"></textarea><br>
<button id="submitCode">submit</button>
<div id="classes">
<div class="pageTitle">uin0CE</div>
<div class="cssClassesIDs">
ui-icon-nodisc,redDotClass,translate,test,ui-hide-label,ui-grid-a,ui-block-a,ui-block-b,alignRight,ui-grid-solo,ui-disabled,companyFieldset,longbutton,icon-map-marker,locationIcon,icon-phone,contactIcon,legalBlock,legal,legalDivider,signInInfoIcon,icon-info-sign,ui-icon-alt
</div>
</div>
</div>
<script src="functions.js"></script>
functions.js
$(function() {
$('#submitCode').click(function() {
var CSS_CLASSES = [];
var CSS_IDS = [];
var el = document.createElement( 'div' );
var text = $("#codeInput").val();
el.innerHTML = text;
var nodes = el.getElementsByTagName('*');
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.id.length > 0) {
CSS_IDS.push.apply(CSS_IDS, node.id.split(" "));
}
if (node.className.length > 0) {
CSS_CLASSES.push.apply(CSS_CLASSES, node.className.split(" "));
}
}
var uniqueNames = [];
$.each (CSS_CLASSES, function(i, el){
if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
console.log(uniqueNames + " --- " + uniqueNames.length);
});
});
Edit: I added this to your fiddle:
//Added this section here
var name = $('#codeName').val();
var code = uniqueNames;
$('#classes').empty();
$('#classes').append('<div class="pageTitle">'+name+'</div>');
$('#classes').append('<div class="cssClassesIDs">'+code+'</div>');
Here's the updated fiddle: http://jsfiddle.net/CRqXm/4/
I'm hoping I'm following your question correctly, but this seems to be what you're looking for.
folks! Today I created this script that has the following functionality:
add new items to array
list all items from the array
remove an item from the array
There are two functions:
addToFood() - adds the value of input to the array and updates
innerHTML of div
removeRecord(i) - remove a record from the array and updates
innerHTML of div
The code includes 3 for loops and you can see it at - http://jsfiddle.net/menian/3b4qp/1/
My Master told me that those 3 for loops make the solution way to heavy. Is there a better way to do the same thing? Is it better to decrease the loops and try to use splice? Thanks in advance.
HTML
<!-- we add to our foodList from the value of the following input -->
<input type="text" value="food" id="addFood" />
<!-- we call addToFood(); through the following button -->
<input type="submit" value="Add more to food" onClick="addToFood();">
<!-- The list of food is displayed in the following div -->
<div id="foods"></div>
JavaScript
var foodList = [];
function addToFood () {
var addFood = document.getElementById('addFood').value;
foodList.push(addFood);
for (i = 0; i < foodList.length; i++) {
var newFood = "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML += newFood;
}
function removeRecord (i) {
// define variable j with equal to the number we got from removeRecord
var j = i;
// define and create a new temporary array
var tempList = [];
// empty newFood
// at the end of the function we "refill" it with the new content
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
if(i != j) {
// we add all records except the one == to j to the new array
// the record eual to j is the one we've clicked on X to remove
tempList.push(foodList[i]);
}
};
// make redefine foodList by making it equal to the tempList array
// it should be smaller with one record
foodList = tempList;
// re-display the records from foodList the same way we did it in addToFood()
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
You should use array.splice(position,nbItems)
function removeRecord (i) {
foodList.splice(i, 1); // remove element at position i
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> "
+ foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
http://jsfiddle.net/3b4qp/5/
Now using JQuery:
$(function(){
$(document).on('click','input[type=submit]',function(){
$('#foods')
.append('<div>X '
+ $('#addFood').val() + '</div>');
});
$(document).on('click','.item',function(){
$(this).parent().remove();
});
});
http://jsfiddle.net/jfWa3/
Your problem isn't the arrays, your problem is this code:
node.innerHTML += newFood;
This code is very, very, very slow. It will traverse all exising DOM nodes, create strings from them, join those strings into one long string, append a new string, parse the result to a new tree of DOM nodes.
I suggest to use a framework like jQuery which has methods to append HTML fragments to existing DOM nodes:
var parent = $('#foods');
...
for (var i = 0; i < foodList.length; i++) {
parent.append( "<a href='#' onClick='removeReco..." );
That will parse the HTML fragments only once.
If you really must do it manually, then collect all the HTML in a local string variable (as suggested by JohnJohnGa in his answer) and then assign innerHTML once.
Here's some tips to, at least, make your code more portable (dunno if it will be better performance wise, but should be, since DOM Manipulation is less expensive)
Tips
First separate your event handle from the HTML
Pass the "new food" as a function paramater
Tie the array elements to the DOM using the ID
Instead of rerendering everything when something changes (using innerHTML in the list), just change the relevant bit
Benefits:
You actually only loop once (when removing elements from the array).
You don't re-render the list everytime something changes, just the element clicked
Added bonus: It's more portable.
Should be faster
Example code:
FIDDLE
HTML
<div id="eventBinder">
<!-- we add to our foodList from the value of the following input -->
<input id="addFood" type="text" value="food" />
<!-- we call addToFood(); through the following button -->
<button id="addFoodBtn" value="Add more to food">Add Food</button>
<!-- The list of food is displayed in the following div
-->
<div id="foods"></div>
</div>
JS
// FoodList Class
var FoodList = function (selectorID) {
return {
foodArray: [],
listEl: document.getElementById(selectorID),
idCnt: 0,
add: function (newFood) {
var id = 'myfood-' + this.idCnt;
this.foodArray.push({
id: id,
food: newFood
});
var foodDom = document.createElement('div'),
foodText = document.createTextNode(newFood);
foodDom.setAttribute('id', id);
foodDom.setAttribute('class', 'aFood');
foodDom.appendChild(foodText);
this.listEl.appendChild(foodDom);
++this.idCnt;
},
remove: function (foodID) {
for (var f in this.foodArray) {
if (this.foodArray[f].id === foodID) {
delete this.foodArray[f];
var delFood = document.getElementById(foodID);
this.listEl.removeChild(delFood);
}
}
}
};
};
//Actual app
window.myFoodList = new FoodList('foods');
document.getElementById('eventBinder').addEventListener('click', function (e) {
if (e.target.id === 'addFoodBtn') {
var food = document.getElementById('addFood').value;
window.myFoodList.add(food);
} else if (e.target.className === 'aFood') {
window.myFoodList.remove(e.target.id);
}
}, false);
Here is another sugestion:
function remove(arr, index) {
if (index >= arr.lenght) { return undefined; }
if (index == 0) {
arr.shift();
return arr;
}
if (index == arr.length - 1) {
arr.pop();
return arr;
}
var newarray = arr.splice(0, index);
return newarray.concat(arr.splice(1,arr.length))
}
I have following html:
<div id="note">
<textarea id="textid" class="textclass">Text</textarea>
</div>
How can I get textarea element? I can't use document.getElementById("textid") for it
I'm doing it like this now:
var note = document.getElementById("note");
var notetext = note.querySelector('#textid');
but it doesn't work in IE(8)
How else I can do it? jQuery is ok
Thanks
If jQuery is okay, you can use find(). It's basically equivalent to the way you are doing it right now.
$('#note').find('#textid');
You can also use jQuery selectors to basically achieve the same thing:
$('#note #textid');
Using these methods to get something that already has an ID is kind of strange, but I'm supplying these assuming it's not really how you plan on using it.
On a side note, you should know ID's should be unique in your webpage. If you plan on having multiple elements with the same "ID" consider using a specific class name.
Update 2020.03.10
It's a breeze to use native JS for this:
document.querySelector('#note #textid');
If you want to first find #note then #textid you have to check the first querySelector result. If it fails to match, chaining is no longer possible :(
var parent = document.querySelector('#note');
var child = parent ? parent.querySelector('#textid') : null;
Here is a pure JavaScript solution (without jQuery)
var _Utils = function ()
{
this.findChildById = function (element, childID, isSearchInnerDescendant) // isSearchInnerDescendant <= true for search in inner childern
{
var retElement = null;
var lstChildren = isSearchInnerDescendant ? Utils.getAllDescendant(element) : element.childNodes;
for (var i = 0; i < lstChildren.length; i++)
{
if (lstChildren[i].id == childID)
{
retElement = lstChildren[i];
break;
}
}
return retElement;
}
this.getAllDescendant = function (element, lstChildrenNodes)
{
lstChildrenNodes = lstChildrenNodes ? lstChildrenNodes : [];
var lstChildren = element.childNodes;
for (var i = 0; i < lstChildren.length; i++)
{
if (lstChildren[i].nodeType == 1) // 1 is 'ELEMENT_NODE'
{
lstChildrenNodes.push(lstChildren[i]);
lstChildrenNodes = Utils.getAllDescendant(lstChildren[i], lstChildrenNodes);
}
}
return lstChildrenNodes;
}
}
var Utils = new _Utils;
Example of use:
var myDiv = document.createElement("div");
myDiv.innerHTML = "<table id='tableToolbar'>" +
"<tr>" +
"<td>" +
"<div id='divIdToSearch'>" +
"</div>" +
"</td>" +
"</tr>" +
"</table>";
var divToSearch = Utils.findChildById(myDiv, "divIdToSearch", true);
(Dwell in atom)
<div id="note">
<textarea id="textid" class="textclass">Text</textarea>
</div>
<script type="text/javascript">
var note = document.getElementById('textid').value;
alert(note);
</script>
Using jQuery
$('#note textarea');
or just
$('#textid');
$(selectedDOM).find();
function looking for all dom objects inside the selected DOM.
i.e.
<div id="mainDiv">
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<div id="innerDiv">
link
<p>Paragraph 3</p>
</div>
</div>
here if you write;
$("#mainDiv").find("p");
you will get tree p elements together. On the other side,
$("#mainDiv").children("p");
Function searching in the just children DOMs of the selected DOM object. So, by this code you will get just paragraph 1 and paragraph 2. It is so beneficial to prevent browser doing unnecessary progress.