How to update created elements? - javascript

I have this simple function that will create a paragraph.
function appendElements() {
const input = document.getElementById("myInput");
const createDiv = document.createElement("div");
createDiv.classList.add("myDiv");
const createP = document.createElement("P");
createP.classList.add("myParagraph");
createP.innerHTML = input.value;
createDiv.appendChild(createP);
const div = document.getElementById("examplediv");
div.appendChild(createDiv);
}
And another function that will sum the innerHTML of the divs, and create a div element for the result.
function calculateSum() {
let div = document.getElementsByClassName("myParagraph");
let array = new Array;
for (var i = 0; i <div.length; i++) {
array.push(div[i].innerHTML);
}
let numberedArray = array.map((i) => Number(i));
const sumArray = numberedArray.reduce(function(a, b){
return a + b;
}, 0);
const createElement = document.createElement("div");
createElement.innerHTML = sumArray;
document.getElementById("divForAvg").appendChild(createElement);
}
And the last function that will change the innerHTML of the paragraph element when clicked.
function editELement() {
const input2 = document.getElementById("myInput2")
let items = document.getElementsByClassName("myParagraph");
for(var i = 0; i < items.length; i++){
items[i].onclick = function(){
items[i].innerHTML = input2.value;
}
}
}
So basically when I create some paragraphs and execute the second function, the second function will calculate the sum of the paragraphs and create a div with the sum inside.
What I want is when I remove one of the paragraph elements or edit them, I want the previously created divs to update(recalculate the sum), I have literally no idea on how to do this.

Let's try this using event delegation. I have interpreted what I think you are looking for (note: it's exemplary, but it may give you an idea for your code) and reduced your code a bit for the example. Note the 2 different ways to create new elements (insertAdjacentHTML and Object.assign).
You can play with the code #Stackblitz.com.
document.addEventListener("click", handle);
function handle(evt) {
if (evt.target.id === "create") {
return appendInputValueElement();
}
if (evt.target.classList.contains("remove")) {
return removeThis(evt.target);
}
if (evt.target.id === "clear") {
document.querySelector("#accumulated ul").innerHTML = "";
return true;
}
}
function appendInputValueElement() {
const input = document.querySelector(".myInput");
const div = document.querySelector("#exampleDiv");
exampleDiv.insertAdjacentHTML("beforeEnd", `
<div class="myDiv">
<button class="remove">remove</button>
<span class="myParagraph">${input.value || 0}</span>
</div>
`);
calculateSum();
}
function removeThis(elem) {
elem.closest(".myDiv").remove();
calculateSum();
}
function calculateSum() {
const allParas = [...document.querySelectorAll(".myParagraph")];
const sum = allParas.reduce( (acc, val) => acc + +val.textContent, 0);
document.querySelector("#accumulated ul")
.append(Object.assign(document.createElement("li"), {textContent: sum}));
document.querySelector(".currentSum").dataset.currentSum = sum;
if (sum < 1) {
document.querySelector("#accumulated ul").innerHTML = "";
}
}
.currentSum::after {
content: ' 'attr(data-current-sum);
color: green;
font-weight: bold;
}
.myParagraph {
color: red;
}
.accSums, .currentSum, .myDiv {
margin-top: 0.3rem;
}
<div>
A number please: <input class="myInput" type="number" value="12">
<button id="create">create value</button>
</div>
<div class="currentSum" data-current-sum="0">*Current sum</div>
<p id="exampleDiv"></p>
<div id="accumulated">
<div class="accSums">*Accumulated sums</div>
<ul></ul>
<button id="clear">Clear accumulated</button>
</div>

i've changed calculateSum you can call it when you edited paragraph. If summParagraph doesn't exists then we create it.
function calculateSum() {
let div = document.getElementsByClassName("myParagraph");
let array = new Array;
for (var i = 0; i <div.length; i++) {
array.push(div[i].innerHTML);
}
let numberedArray = array.map((i) => Number(i));
const sumArray = numberedArray.reduce(function(a, b){
return a + b;
}, 0);
if (!document.getElementById("summParagraph")) {
const createElement = document.createElement("div");
createElement.setAttribute("id", "summParagraph");
document.getElementById("divForAvg").appendChild(createElement);
}
document.getElementById("summParagraph").innerHTML = summArray;
}

Related

How to find/remove last text portion of innerHTML

I have a <div> element that contains both html elements and text. I want to find/remove the last or the last nth or the nth text only portion of it.
So for example
<div id="foo">
<span id="bar">abcdefg</span>
<span id="baz">z</span>
</div>
If I had a method to delete the last text character, the first call would delete z and the second call would delete g. Or if I had a method to find the 4th character, it would return d.
It sounds like you only care about the text nodes, so probably something like this so you can just delete the nth character:
var div = document.getElementById("foo");
const getTextNodes = (el, nodes) => {
nodes = nodes || [];
for (var i = 0; i < el.childNodes.length; i++) {
var curNode = el.childNodes[i];
if (curNode.nodeName === "#text") {
if (curNode.textContent.trim().length) {
nodes.push(curNode);
}
} else {
getTextNodes(curNode, nodes);
}
}
return nodes;
}
console.log(getTextNodes(div).map((el) => el.textContent));
const deleteNthCharacter = (el, n) => {
n--; // since we want to be "1 indexed"
const nodes = getTextNodes(el);
let len = 0;
for (let i = 0; i < nodes.length; i++) {
const curNode = nodes[i];
if (len + curNode.textContent.length > n) {
curNode.textContent = curNode.textContent.substring(0, n - len) + curNode.textContent.substring(n + 1 - len);
break;
} else {
len += curNode.textContent.length;
}
}
}
deleteNthCharacter(div, 2);
deleteNthCharacter(div, 7);
<div id="foo">
<span id="bar">abcdefg</span>
<span id="baz">z</span>
</div>
If I understood your question correctly this should do the trick:
function deleteLastChar(targetId){
const target = document.getElementById(targetId);
let lastWithText = -1;
//find last child that has text set
target.childNodes.forEach((child, iter) => {
if(child.innerText != undefined && child.innerText.length > 0){
lastWithText = iter;
}
});
// exit if no valid text node was found
if(lastWithText === -1)
return;
const lastNode = target.childNodes[lastWithText];
lastNode.innerText = lastNode.innerText.slice(0, -1);
}
deleteLastChar("foo")
deleteLastChar("foo")
deleteLastChar("foo")
deleteLastChar("foo")
<div id="foo">
<span id="bar">abcdefg</span>
<span id="baz">z</span>
</div>
If I understand the question this is probably what you're looking for
let x = document.getElementById('foo').children;
function erase() {
for (let i = x.length - 1; i >=0; i--) {
if(x[i].textContent.length > 0) {
const textC = x[i].textContent;
x[i].textContent = textC.substring(0, textC.length - 1);
return;
}
}
}
<div id="foo">
<span id="bar">abcdefg</span>
<span id="baz">z</span>
</div>
<button onclick="erase()">Erase</button>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="foo">
<span id="bar">abcdefg</span><br>
<span id="baz">z</span><br><br>
<div id="result"></div>
<div id="result2"></div>
</div>
<script type="text/javascript">
var s = function(x){
return document.querySelector(x)
}
log = console.log;
var span1 = s("#bar")
var span2 = s("#baz")
var result = s("#result")
var result2 = s("#result2")
var res = span1.innerText.charAt(4)
// with the charAt method
result.innerText = " Result is : " +res+"\n\n"
// with regular Expression
var reg = /e/
result2.innerText = " Result2 is : " +span1.innerText.match(reg)
</script>
</body>
</html>

Adding the result of separate results

Thanks in advance for any replies. I am new to JavaScript and have got this far in calculating 2 results that I require. My question is how do I add both results together?
Please see first result below:
$(document).ready(function() {
function checkSum(e) {
var result = 0;
$(".checksum").each(function() {
var i = 0;
if ($(this).val() != "") {
i = parseFloat($(this).val());
}
result = result + i;
});
$("#resultsum").html(result * 60.60);
}
checkSum();
$(".checksum").bind("keyup", checkSum);
});
and this is the second:
$(document).ready(function() {
function checkSum2(e) {
var result2 = 0;
$(".checksum2").each(function() {
var j = 0;
if ($(this).val() != "") {
j = parseFloat($(this).val());
}
result2 = result2 + j;
});
$("#resultsum2").html(result2 * 14.88);
}
checkSum2();
$(".checksum2").bind("keyup", checkSum2);
});
Just add one line in the end of functions:
$("#resultsum3").html($("#resultsum").text() + $("#resultsum2").text());
$(document).ready(function() {
function checkSum(e) {
var result = 0;
$(".checksum").each(function() {
var i = 0;
if ($(this).val() != "") {
i = parseFloat($(this).val());
}
result = result + i;
});
$("#resultsum").html(result * 60.60);
$("#resultsum3").html($("#resultsum").text() + $("#resultsum2").text());
}
checkSum();
$(".checksum").bind("keyup", checkSum);
function checkSum2(e) {
var result2 = 0;
$(".checksum2").each(function() {
var j = 0;
if ($(this).val() != "") {
j = parseFloat($(this).val());
}
result2 = result2 + j;
});
$("#resultsum2").html(result2 * 14.88);
$("#resultsum3").html($("#resultsum").text() + $("#resultsum2").text());
}
checkSum2();
$(".checksum2").bind("keyup", checkSum2);
});
I've combined your snippets in to one to remove the redundant code you have. This approach will allow you to add more checksums in future (.checksum3?) and also makes sure your calculation logic is same for all.
The result is calculated in to new element whenever any of the checksums change. Try the snippet below:
// function to calculate checksum
// used for both individual results as well as for total
function calcChecksum(elements) {
let result = 0;
elements.each( function(index, ele) {
result = result + (parseFloat($(ele).val()) || 0)
});
return result;
}
// update total result
function updateTotal() {
let total = calcChecksum($('.result'));
$('#resultsum_total').val(total);
}
$(document).ready(function() {
// generate function for each set of checksum inputs
function genCheckSumFn(inputSel, outputSel, multiplier) {
return () => {
const result = calcChecksum($(inputSel));
$(outputSel).val(result * multiplier);
updateTotal();
}
}
//checkSum bindings
$(".checksum").bind("keyup",
genCheckSumFn('.checksum','#resultsum',60.60)
);
$(".checksum2").bind("keyup",
genCheckSumFn('.checksum2','#resultsum2',14.88)
);
// trigger initial calculation
$(".checksum").trigger('keyup');
$(".checksum2").trigger('keyup');
});
.checksum,
.checksum2{
display: block;
}
.box {
padding:10px 0px;
}
.box div {
margin-top:5px;
}
.box.results input {
color: #FFA500;
border:0px;
font-size: 14px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box">
Checksum
<input class="checksum" value="10">
<input class="checksum" value="5">
Checksum(2)
<input class="checksum2" value="20">
<input class="checksum2" value="15">
<div>
<div class="box results">
<div> Resultsum:
<input id="resultsum" class="result" readonly> </div>
<div> Resultsum(2):
<input id="resultsum2" class="result" readonly> </div>
<div> Resultsum(Total): <input id="resultsum_total" readonly> </div>
</div>

How to generate same elements in multiple divs?

I have been trying to create onlick function in multiple divs by using shot codes in javascript but I end up creating multiple javascript codes with different ids and onclick function.
I tried for loop function but it didn't work as well.
function copy() {
document.getElementById("label").innerHTML = document.getElementById("mySelect").value;
}
function copy2() {
document.getElementById("label2").innerHTML = document.getElementById("mySelect2").value;
}
function copy3() {
document.getElementById("label3").innerHTML = document.getElementById("mySelect3").value;
}
function copy4() {
document.getElementById("label4").innerHTML = document.getElementById("mySelect4").value;
}
function copy5() {
document.getElementById("label5").innerHTML = document.getElementById("mySelect5").value;
}
function copy6() {
document.getElementById("label6").innerHTML = document.getElementById("mySelect6").value;
}
function copy7() {
document.getElementById("label7").innerHTML = document.getElementById("mySelect7").value;
}
function copy8() {
document.getElementById("label8").innerHTML = document.getElementById("mySelect8").value;
}
function copy9() {
document.getElementById("label9").innerHTML = document.getElementById("mySelect9").value;
}
function copy10() {
document.getElementById("label10").innerHTML = document.getElementById("mySelect10").value;
}
try this concept and adjust your code.
for(var i = 1; i < 3; i++) {
document.getElementById("label"+i).innerHTML = document.getElementById("mySelect"+i).innerHTML;
}
<div id="mySelect1">Up above the world so high</div>
<div id="mySelect2">like a diamond in the sky</div>
<div id="label1"></div>
<div id="label2"></div>
It is really hard to understand this question but can you not just make one function with a parameter? And loop the function with a for-loop if necessary.
function copy(id) {
id = id || ""; //empty string if id is undefined
document.getElementById("label" + id).innerHTML = document.getElementById("mySelect" + id).value;
}
function copyClick() {
for(var i = 0; i < 10; i++){
copy(i);
}
}
<button onclick="copyClick">Copy!</button>
Or if you have multiple buttons the copyClick function is not necessary.
<button onclick="function(){ copy(0) }">Copy 0!</button>
<button onclick="function(){ copy(1) }">Copy 1!</button>
...

How to beat a JavaScript condition riddle?

I am using a foreach loop in php to load data from a mysql table. I'm using the data ID's loaded from the data base and applying it to the button values.
The buttons come in two colors, green and white. The buttons represent likes for liking comments or posts.
The total existing number of likes starts at 6 (div id="total")
white buttons
If button 1 has color of white and you click it, total likes (6) will increase by 1. If you click button 1 again, total likes (7) will decrease by 1.
If button 1, button 2, and button three are clicked, total likes (6) increases by 3 ( 1 for each button). If button 1, button 2 and button 3 are clicked again, the total likes (9) will decrease by 3.
The Puzzle
Green buttons
How do I make it so, When a green button is clicked, the total (6) decrease by 1, and if the button is clicked again, it should increase by 1. Unlike white buttons.
If Green button 3, 5 and 6 are clicked, the total (6) should decease by 3. if the same buttons are clicked again, total (6) increases by 3.
Here is my code
var colorcode = "rgb(116, 204, 49)";
var buttonid = str;
var elem = document.getElementById(buttonid);
var theCSSprop = window.getComputedStyle(elem, null).getPropertyValue("background-color");
var initialtotal = parseInt(document.getElementById("total").innerHTML, 10);
var likes = new Array();
function showUser(str) {
////// 1st condition /////
if (theCSSprop == colorcode) {
if (likes[value] == 0 || !likes[value]) {
likes[value] = 1;
} else {
likes[value] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum--
}
}
}
////// 2nd condition /////
else {
if (likes[str] == 0 || !likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum++
}
}
}
var tot = initialtotal + sum;
document.getElementById("total").innerHTML = tot;
}
<div id="total" style="width:100px;padding:50px 0px; background-color:whitesmoke;text-align:center;">6 </div>
<!---------------------------------------------------------------------------------------------------------------------->
<button id="5" value="5" onclick="showUser(this.value)">LIKE </button>
<button id="346" value="346" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="128" value="128" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="687" value="687" onclick="showUser(this.value)">LIKE </button>
<button id="183" value="183" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="555" value="555" onclick="showUser(this.value)">LIKE </button>
<!---------------------------------------------------------------------------------------------------------------------->
Instead of passing this.value to showUser(), just pass this. That way, the function can get the value and the style directly, without having to call getElementById() (you're not passing the ID). Then you need to set theCSSprop inside the function, so it's the property of the current button.
To make green buttons alternate direction from increment to decrement, you need a global variable that remembers what it did the last time the function was called.
Also, you don't need to write if(likes[str] == 0 || !likes[str]), since 0 is faley. Just write if(!likes[str]).
var colorcode = "rgb(116, 204, 49)";
var likes = new Array();
var greenIncr = -1;
function showUser(elem) {
var initialtotal = parseInt(document.getElementById("total").innerHTML, 10);
////// 1st condition /////
var str = elem.value;
var theCSSprop = window.getComputedStyle(elem, null).getPropertyValue("background-color");
if (theCSSprop == colorcode) {
if (!likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum += greenIncr;
}
}
greenIncr = -greenIncr; // revese the direction of green button
}
////// 2nd condition /////
else {
if (!likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum++
}
}
}
var tot = initialtotal + sum;
document.getElementById("total").innerHTML = tot;
}
<div id="total" style="width:100px;padding:50px 0px; background-color:whitesmoke;text-align:center;">6 </div>
<!---------------------------------------------------------------------------------------------------------------------->
<button id="5" value="5" onclick="showUser(this)">LIKE </button>
<button id="346" value="346" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="128" value="128" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="687" value="687" onclick="showUser(this)">LIKE </button>
<button id="183" value="183" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="555" value="555" onclick="showUser(this)">LIKE </button>
<!---------------------------------------------------------------------------------------------------------------------->
First naive implementation can look like this
class Counter {
constructor(initial) {
this.initial = initial
this.white = [false, false, false]
this.green = [false, false, false]
}
changeGreen(index) {
this.green[index] = !this.green[index]
}
changeWhite(index) {
this.white[index] = !this.white[index]
}
get total() {
return this.initial + this.white.reduce((total, current) => total + current, 0) + this.green.reduce((total, current) => total - current, 0)
}
}
let counter = new Counter(6)
const render = counter => {
document.querySelector('#total').innerHTML = counter.total
}
render(counter)
;['#first', '#second', '#third'].map((selector, index) => {
document.querySelector(selector).addEventListener('click', e => {
e.target.classList.toggle('pressed')
counter.changeWhite(index)
render(counter)
})
})
;['#fourth', '#fifth', '#sixth'].map((selector, index) => {
document.querySelector(selector).addEventListener('click', e => {
e.target.classList.toggle('pressed')
counter.changeGreen(index)
render(counter)
})
})
.green {
background: #00aa00
}
.pressed {
border-style: inset
}
<div id="total">0</div>
<p>
<button id="first">First</button>
<button id="second">Second</button>
<button id="third">Third</button>
<button id="fourth" class="green">Fourth</button>
<button id="fifth" class="green">Fifth</button>
<button id="sixth" class="green">Sixth</button>
</p>
But after all I've finished with something like
class Counter {
constructor(initial, strategy) {
this.initial = initial;
this.elements = [];
this.strategy = typeof strategy === 'function' ? strategy : () => {}
}
addElement(content, type, next) {
const element = {
content: content,
type: type,
state: false
};
this.elements.push(element);
return next(element, this.elements.length - 1);
}
toggleElementState(index) {
this.elements[index].state = !this.elements[index].state
}
get total() {
return this.strategy(this.initial, this.elements)
}
}
const initialize = () => {
Counter.WHITE = Symbol('white');
Counter.GREEN = Symbol('green');
const counter = new Counter(6, (initial, buttons) => {
return initial +
buttons.filter(button => button.type === Counter.WHITE).reduce((total, current) => total + Number(current.state), 0) +
buttons.filter(button => button.type === Counter.GREEN).reduce((total, current) => total - Number(current.state), 0)
});
const render = counter => {
document.querySelector('#total').innerHTML = counter.total
};
const createButton = (element, index) => {
const button = document.createElement('button');
button.setAttribute('data-id', index);
button.classList.add(element.type === Counter.GREEN ? 'green' : 'none');
button.textContent = element.content;
document.querySelector('#buttons').appendChild(button)
};
const addButton = (type, ...selectors) => {
selectors.forEach(selector => counter.addElement(selector, type, createButton));
};
render(counter);
addButton(Counter.WHITE, '#first', '#second', '#third');
addButton(Counter.GREEN, '#fourth', '#fifth', '#sixth');
addButton(Counter.WHITE, '#first', '#second', '#third');
document.querySelector('#buttons').addEventListener('click', function(e) {
e.target.classList.toggle('pressed');
counter.toggleElementState(parseInt(e.target.dataset.id));
render(counter)
})
};
document.addEventListener('DOMContentLoaded', initialize);
.green {
background: #00aa00
}
.pressed {
border-style: inset
}
<div id="total">0</div>
<p id="buttons">
</p>

How can put an id text in a text box by click on it?

I want that when I click on id it sends my value in id=arxidia and when I click again on mounoxilo it removes it.
<div class="poutsa" id="mounoxilo1" value="vizia1">etsi1</div>
<div class="poutsa" id="mounoxilo2" value="vizia2">etsi2</div>
<div class="poutsa" id="mounoxilo3" value="vizia3">etsi3</div>
<div class="poutsa" id="mounoxilo4" value="vizia4">etsi4</div>
<input type="text" id="arxidia">
using jquery
jQuery("#mounoxilo").click(function(){
if(jQuery("#arxidia").val() == "") {
jQuery("#arxidia").val(jQuery("#mounoxilo").attr("value"));
} else {
jQuery("#arxidia").val("");
}
}
Not using jQuery:
document.getElementById('mounoxilo').onclick = function(e) {
var inputEl = document.getElementById('arxidia');
if(inputEl.value) {
inputEl.value = "";
} else {
inputEl.value = this.getAttribute('value');
}
}
EDIT 1
JSFiddle: http://jsfiddle.net/XwAY5/
For the edited question it's like this:
var divEls = document.getElementsByClassName('poutsa');
for(var i = 0; i < divEls.length; i++) {
divEl = divEls[i];
divEl.onclick = function(e) {
var inputEl = document.getElementById('arxidia');
if(inputEl.value == this.getAttribute('value')) {
inputEl.value = "";
} else {
inputEl.value = this.getAttribute('value');
}
}
}
JSFiddle: http://jsfiddle.net/XwAY5/2/
EDIT 2
Appearently, the input should be able to hold multiple values, so I came up with this: http://jsfiddle.net/XwAY5/3/

Categories

Resources