Creating multiple spans in the same javascript function - javascript

var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function() {
var text = reader.result;
var output = document.getElementById('output');
const lines = text.split('\n');
lines.forEach((line) => {
const div = output.appendChild(document.createElement('div'));
const textSplitAroundAt = line.split('Microsoft');
textSplitAroundAt.forEach((text, i) => {
div.appendChild(document.createTextNode(text));
if (i === textSplitAroundAt.length - 1) return;
const span = div.appendChild(document.createElement('span'));
span.textContent = 'Microsoft';
span.className = 'colorMicrosoft';
});
});
document.getElementById('populateAt').textContent = text.split('#').length - 1;
document.getElementById('populateMicrosoft').textContent = text.split('Microsoft').length - 1;
document.getElementById('populateGoogle').textContent = text.split('Google').length - 1;
};
reader.readAsText(input.files[0]);
};
.colorMicrosoft
{
color: blue;
background-color: red;
}
.colorGoogle
{
color: red;
background-color: blue;
}
.colorAt
{
color: blue;
background-color: green;
}
<center>
<h1>.TXT Log Parser</h1>
</center>
<center>
<div>I would like the number of times '#' symbol appears here: <span id="populateAt"> ... </span></div>
<div>I would like the number of times 'Microsoft' symbol appears here: <span id="populateMicrosoft"> ... </span></div>
<div>I would like the number of times 'Google' symbol appears here: <span id="populateGoogle"> ... </span></div>
</center>
<center>
<h2><input type='file' accept='text/plain' onchange='openFile(event)'></h2>
</center>
<br/>
<div id='output'>...</div>
As long can see if the below code snippet, I am loading a text file into a div.
Currently I can tally the number of times a specific strings show up.
Additionally, I can change the color of each 'Microsoft' string via span.
However, I cannot seem to add multiple spans for 'Google' and '#'
Should I use an array, and if so, how?

You can check line for occurrence of each of three words, without using array
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function() {
var text = reader.result;
var output = document.getElementById('output');
const lines = text.split('\n');
lines.forEach((line) => {
const div = output.appendChild(document.createElement('div'));
var textSplit = line.split('Microsoft');
line = textSplit.join('<span class="colorMicrosoft">Microsoft</span>');
textSplit = line.split('Google');
line = textSplit.join('<span class="colorGoogle">Google</span>');
textSplit = line.split('#');
line = textSplit.join('<span class="colorAt">#</span>');
div.innerHTML += line;
});
document.getElementById('populateAt').textContent = text.split('#').length - 1;
document.getElementById('populateMicrosoft').textContent = text.split('Microsoft').length - 1;
document.getElementById('populateGoogle').textContent = text.split('Google').length - 1;
};
reader.readAsText(input.files[0]);
};
.colorMicrosoft
{
color: blue;
background-color: red;
}
.colorGoogle
{
color: red;
background-color: blue;
}
.colorAt
{
color: blue;
background-color: green;
}
<center>
<h1>.TXT Log Parser</h1>
</center>
<center>
<div>I would like the number of times '#' symbol appears here: <span id="populateAt"> ... </span></div>
<div>I would like the number of times 'Microsoft' symbol appears here: <span id="populateMicrosoft"> ... </span></div>
<div>I would like the number of times 'Google' symbol appears here: <span id="populateGoogle"> ... </span></div>
</center>
<center>
<h2><input type='file' accept='text/plain' onchange='openFile(event)'></h2>
</center>
<br/>
<div id='output'>...</div>

Related

How to delete DOM element and related array index at same time?

Edit: Never mind...I give up...I'm done with studying web dev...
I have an array (myLibrary) of "book" objects that are pushed into said array when a user submits input from a form.
let myLibrary = [];
function Book(title, author, pages, read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
}
function addToLibrary() {
let Newbook = new Book(
titleInput.value,
authorInput.value,
pagesInput.value,
readInput.checked
);
myLibrary.push(Newbook);
}
Upon submitting, a card is also generated on the DOM displaying the information from the form. I also add a delete button on each dynamically generated card. I am able to delete the card itself using an event listener (in bold), but I am unable to also delete the related object in the array.
function renderBookCard() {
const newCard = document.createElement("div");
const removeBook = document.createElement("img");
const bookTitleDiv = document.createElement("div");
const titleLabel = document.createElement("p");
const dynamicTitle = document.createElement("p");
const authorDiv = document.createElement("div");
const authorLabel = document.createElement("p");
const dynamicAuthor = document.createElement("p");
const pagesDiv = document.createElement("div");
const pagesLabel = document.createElement("p");
const dynamicPages = document.createElement("p");
const readDiv = document.createElement("div");
const dynamicRead = document.createElement("p");
//
MainBookContainer.appendChild(newCard);
newCard.appendChild(removeBook);
removeBook.classList.add("trash");
removeBook.setAttribute(
"src",
"./Images/delete_FILL0_wght400_GRAD0_opsz48.svg"
);
newCard.classList.add("book-card-container");
newCard.appendChild(bookTitleDiv);
bookTitleDiv.classList.add("book-title");
newCard.appendChild(titleLabel);
titleLabel.textContent = `Title:`;
newCard.appendChild(dynamicTitle);
newCard.appendChild(authorDiv);
authorDiv.classList.add("book-author");
newCard.appendChild(authorLabel);
authorLabel.textContent = `Author:`;
newCard.appendChild(dynamicAuthor);
newCard.appendChild(pagesDiv);
pagesDiv.classList.add("book-pages");
newCard.appendChild(pagesLabel);
pagesLabel.textContent = `Pages:`;
newCard.appendChild(dynamicPages);
newCard.appendChild(readDiv);
readDiv.classList.add("book-read");
newCard.appendChild(dynamicRead);
//
let i;
for (i = 0; i < myLibrary.length; i++) {
dynamicTitle.textContent = myLibrary[i].title;
dynamicAuthor.textContent = myLibrary[i].author;
dynamicPages.textContent = myLibrary[i].pages;
if (!readInput.checked) {
dynamicRead.textContent = "Unread";
} else {
dynamicRead.textContent = "Read";
}
}
//
**newCard.addEventListener("click", function (e) {
if (e.target.classList.contains("trash")) {
newCard.remove();
myLibrary.splice([i], 1);**
}
});
}
How am I able to delete the card and the related object in the array? I hope I was able to ask in a clear way. If not I apologize.
Here is my example. I think it might help you.
*If you have many elements to append to your HTML feel free to use insertAdjacentHTML or other methods, this will help you easily to organize your code.
*In my case, I use the filter method to update my list.
let bookList = [];
const addBook = document.querySelector("#add_book");
const bookWrap = document.querySelector("#book_wrap");
addBook.addEventListener("click", () => {
const bookName = document.querySelector("#book_name");
const bookAuthor = document.querySelector("#book_author");
bookList.push({
book_name: bookName.value,
book_author: bookAuthor.value
})
const bookTemplate = `
<div class="book">
<div>
<h2>${bookName.value}</h2>
<p>${bookAuthor.value}</p>
</div>
<div>
<button id="trash_${bookName.value}">Trash</button>
</div>
</div>`;
bookWrap.insertAdjacentHTML("beforeend", bookTemplate);
// console.log(bookList)
document.querySelector(`#trash_${bookName.value}`)
.addEventListener("click", (e) => {
e.target.closest(".book").remove();
bookList = [...bookList.filter(item => item.book_name !== e.target.id.split("_")[1])]
// console.log(bookList)
})
bookName.value = null;
bookAuthor.value = null;
})
.book-wrap {
min-width: 250px;
min-height: 200px;
border-radius: 10px;
border: 1px solid black;
margin: 20px 0;
padding: 20px;
}
.book {
display: flex;
justify-content: space-between;
width: 200px;
gap: 40px;
margin-bottom: 20px;
}
h2,
p{
margin: 0;
}
p {
color: #999;
}
<div>
<div style="margin-bottom: 10px;">
<label for="book_name">Book name:</label><br/>
<input id="book_name" type="text" />
</div>
<div style="margin-bottom: 10px;">
<label for="book_author">Author name:</label><br/>
<input id="book_author" type="text" />
</div>
<div>
<button id="add_book">Add Book</button>
</div>
<div id="book_wrap" class="book-wrap"></div>
</div>
Hope this might help you.
Enjoy the journey into Web dev.

Display slider when you hover over array elements and give value to the array elements

I have done the part where you have to generate the array elements when you enter them from textbox, what I struggle with now is to display a slider on hover over each array element and give the array element a value, also what I struggle with is to delete each generated array element individually, my delete function deletes the entire array on click not just the single element I click.
Here is how it should look like:
enter image description here
Here is my code so far:
let names = [];
let nameInput = document.getElementById("name");
let messageBox = document.getElementById("display");
function insert ( ) {
names.push( nameInput.value );
clearAndShow();
}
function remove()
{
var element = document.getElementById("display");
element.parentNode.removeChild(element);
}
function clearAndShow () {
let printd=""
nameInput.value = "";
messageBox.innerHTML = "";
names.forEach(function(element){
if(element != ''){
var _span = document.createElement('span');
_span.style.borderStyle = "solid"
_span.style.borderColor = "blue"
_span.style.width = '50px'
_span.style.marginLeft = "5px"
_span.appendChild(document.createTextNode(element))
messageBox.appendChild(_span)
printd +="''" + element + "''" + "," + " ";
document.getElementById("labelprint").innerHTML=(printd)
}
})
}
h3 {
color: rgb(0, 174, 255);
}
.container {
border: solid 2px;
display: block;
margin-left: 200px;
margin-right: 200px;
margin-top: 50px;
}
<div class="container">
<form>
<h1>Enter Search</h1>
<input id="name" type="text" />
<input type="button" value="Search" onclick="insert()" />
</form>
<br/>
<div onclick="remove(this)" id="display"></div>
<br/>
<label >You have Selected: </label>
<h3 id="labelprint"></h3>
</div>
I am not being rude I just got confused on how you stated your message but what I think you are saying is to do this:
var names = [];
var nameInput = document.getElementById("name");
var messageBox = document.getElementById("display");
function insert ( ) {
names.push( nameInput.value );
// add value to array val: names[names.length - 1] = PutValueHere
clearAndShow();
}
function remove(this){
document.getElementById("display").parentNode.firstChild.remove(); // If you want it to remove the last child with the id 'display' then do .parentNode.lastChild.remove()
//if you are trying to remove the last val in the array do this: names.splice(names.length-1,1) for the first do this names.splice(0,1)
}
function clearAndShow () {
var printd=""
nameInput.value = "";
messageBox.innerHTML = "";
names.forEach(function(element){
if(element != ''){
var _span = document.createElement('span');
_span.id = '_spanId'
$('_spanId').css('border-style',solid');
$('_spanId').css('border-color',blue');
$('_spanId').css('width',50+'px');
$('_spanId').css('margin-left',5+'px');
_span[0].appendChild(document.createTextNode(element))
messageBox[0].appendChild(_span)
printd += "''" + element + "'', ";
document.getElementById("labelprint").innerHTML = printd
}
})
}
I have tried to implement something that i hope it's close to what are you looking for:
HTML:
<div class="container">
<form>
<h1>Add new slider</h1>
<input id="sliderName" type="text" />
<input type="button" value="Add" onclick="insertSlider()" />
</form>
<div id="display"></div>
</div>
CSS:
h3 {
color: rgb(0, 174, 255);
}
.container {
border: solid 2px;
display: block;
margin-left: 200px;
margin-right: 200px;
margin-top: 50px;
}
JS:
let messageBox = document.getElementById("display");
function deleteFn(id) {
const element = document.getElementById(id)
if(element) element.outerHTML="";
}
function onChangeSlideId(id){
const elementSlide = document.getElementById('slider-'+id+'')
if(elementSlide){
const value = elementSlide.value
const elementSlideText = document.getElementById('slider-value-'+id+'')
elementSlideText.innerText = '('+value+')'
}
}
function insertSlider(){
const name = document.getElementById("sliderName")
const nameValue = name.value
const newLabel = document.createElement('label')
newLabel.setAttribute('for',nameValue)
newLabel.innerText = nameValue
const newSlider = document.createElement('input')
newSlider.setAttribute('id','slider-'+nameValue+'')
newSlider.setAttribute('type','range')
newSlider.setAttribute('name',nameValue)
newSlider.setAttribute('onchange','onChangeSlideId("'+nameValue+'")')
const sliderValue = document.createElement('span')
sliderValue.setAttribute('id','slider-value-'+nameValue+'')
sliderValue.innerText = '('+newSlider.value+')'
const newContainer = document.createElement('div')
newContainer.setAttribute('id',nameValue)
newContainer.setAttribute('style','display: grid')
newContainer.appendChild(newSlider)
newContainer.appendChild(newLabel)
newContainer.appendChild(sliderValue)
const newDeleteButton = document.createElement('input')
newDeleteButton.setAttribute('type', 'button')
newDeleteButton.setAttribute('value', 'Delete ' + nameValue + '')
newDeleteButton.setAttribute('onclick', 'deleteFn("'+nameValue+'")')
newContainer.appendChild(newDeleteButton)
messageBox.appendChild(newContainer)
}
You can try it by yourself in this codepen

Word count limit for multiple textarea tags

I have this script to limit the words on a textarea but I want to use the same function to a form that contains multiple textarea tags.
What is the best way to reuse this and make an independent word counter and limiter for every textarea tag in the same form?
Thanks a lot in advance.
var wordLimit = 5;
var words = 0;
var jqContainer = $(".my-container");
var jqElt = $(".my-textarea");
function charLimit()
{
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
}
jqElt.on("keyup", charLimit);
charLimit();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
<div>
You can use a generic function ($this) is the textarea element changed.
For relative elements, you can use the function .next(selector)
Also you can read parameters from attributes (maxwords for example).
var jqContainer = $(".my-container");
function charLimit()
{
var words = 0;
var jqElt=$(this);
var wordLimit = jqElt.attr("maxwords");
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
jqElt.next('.words-left').text(Math.max(wordLimit-words, 0));
}
$(".my-textarea", jqContainer).on("keyup", charLimit).keyup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea id="text1" class="my-textarea" maxwords="5"></textarea>
<span class="words-left"></span> words left
<textarea id="text1" class="my-textarea" maxwords="10"></textarea>
<span class="words-left"></span> words left
<div>
You can wrap your logic up in a function and reuse that function.
See example:
function wordCounter(container, limit) {
var wordLimit = limit;
var jqContainer = $(container);
var jqElt = $("textarea", jqContainer);
function charLimit()
{
var words = 0;
var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = jqElt.val()[trimmed.length];
jqElt.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
}
jqElt.on("keyup", charLimit);
charLimit();
}
wordCounter(".my-container1", 5);
wordCounter(".my-container2", 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container1">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
</div>
<div class="my-container2">
<textarea class="my-textarea"></textarea>
<span class="words-left"></span> words left
</div>
Note that you had an issue in your example where the div tag wasn't closed.
if you need to use that same implementation you could add an id to each text area you are going to put in the form, then add an attribute for= to the corresponding spans pointing to the corresponding text area like this:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
<textarea id="textarea-1" class="my-textarea" onkeyup="charLimit(this)"></textarea>
<span for="textarea-1" class="words-left"></span> words left
<textarea id="textarea-2" class="my-textarea" onkeyup="charLimit(this)"></textarea>
<span class="words-left" for="textarea-2"></span> words left
<div>
var wordLimit = 5;
var words = 0;
var jqContainer = $(".my-container");
function charLimit(elem)
{
var elm = $(elem)
var words = 0;
var wordmatch = elm.val().match(/[^\s]+\s+/g);
words = wordmatch?wordmatch.length:0;
if (words > wordLimit) {
var trimmed = elm.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = elm.val()[trimmed.length];
elm.val(trimmed + lastChar);
}
$('.word-count', jqContainer).text(words);
$('[for='+ elm.attr('id') +']', jqContainer).text(Math.max(wordLimit-words, 0));
}
This is how I will normally do it:
Create a function that handles the word count refreshMaxWords()
Create a hook that can be tied up with the element <textarea data-max-words="5"></textarea>
(function($) {
var refreshMaxWords = function ($el) {
var wordLimit = parseInt($el.data('max-words')) || false,
wordmatch = $el.val().match(/[^\s]+\s+/g),
words = wordmatch ? wordmatch.length : 0,
// You can change how to get the "words-left" div here
$wordsLeft = $el.parent().find('.words-left');
if (wordLimit !== false) {
if (words > wordLimit) {
var trimmed = $el.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
var lastChar = $el.val()[trimmed.length];
$el.val(trimmed + lastChar);
}
}
if ($wordsLeft.length > 0) {
$wordsLeft.html(Math.max(wordLimit - words, 0));
}
};
$(function () {
$(document).on('keyup.count-words', '[data-max-words]', function (e) {
refreshMaxWords($(this));
});
});
})(jQuery);
This is with assumption of HTML that looks like the following:
<div class="form-group">
<label>Input #1</label>
<textarea class="form-control" data-max-words="5"></textarea>
<p class="help-block"><span class="words-left">5</span> words left.</p>
</div>
<div class="form-group">
<label>Input #2</label>
<textarea class="form-control" data-max-words="10"></textarea>
<p class="help-block"><span class="words-left">10</span> words left.</p>
</div>
The benefits of this approach are:
Cleaner code structure
This can be reused on your other projects.
Notes:
You don't really need to wrap the javascript in
(function($) {
// your code here
})(jQuery);
I like doing it because it ensures that there won't be any conflict by accident.

object.style.display throwing message error on console

UPDATE so here is a better code for you. I cut it down to have only what's strictly necessary for you to reproduce the problem.
// change the color of the button when mousedown/up
let button = document.getElementsByClassName('button');
for(i = 0; i < button.length; i++){
button[i].onmousedown = function() {
this.style.backgroundColor = "#a3a3a3";
};
button[i].onmouseup = function() {
this.style.backgroundColor = "#808080";
};
}
let buttonLg = document.getElementsByClassName('button-lg');
for(i = 0; i < buttonLg.length; i++){
buttonLg[i].onmousedown = function() {
this.style.backgroundColor = "#a3a3a3";
};
buttonLg[i].onmouseup = function() {
this.style.backgroundColor = "#808080";
};
}
let button2 = document.getElementsByClassName('button2');
for(i = 0; i < button2.length; i++){
button2[i].onmousedown = function() {
this.style.backgroundColor = "#ffe299";
};
button2[i].onmouseup = function() {
this.style.backgroundColor = "#ffca47";
};
}
// show the numbers typed or result
let result = document.getElementById('result');
let preview = [];
let buttonAc = document.getElementById('ac');
let plusMinus = document.getElementById('plus-minus');
let plusMinus2 = document.getElementById('plus-minus2');
let buttonN7 = document.getElementById('seven');
let buttonN72 = document.getElementById('seven2');
let buttonN8 = document.getElementById('eight');
let buttonN82 = document.getElementById('eight2');
let buttonN9 = document.getElementById('nine');
let buttonN92 = document.getElementById('nine2');
// button AC erasing result and changing outlook to C when other buttons are clicked
// number 0 disapear when there is only zero and when a key is clicked
buttonAc.onclick = function () {
buttonAc.innerHTML = "AC";
preview = [];
result.innerHTML = 0;
}
// concatenation of the buttons numbers without any commas
buttonN7.onclick = function () {
document.getElementById('ac').innerHTML = "C";
buttonN7 = 7;
preview.push(buttonN7);
const a = preview.join('');
result.innerHTML = a;
}
buttonN8.onclick = function () {
document.getElementById('ac').innerHTML = "C";
buttonN8 = 8;
preview.push(buttonN8);
const a = preview.join('');
result.innerHTML = a;
}
buttonN9.onclick = function () {
document.getElementById('ac').innerHTML = "C";
buttonN9 = 9;
preview.push(buttonN9);
const a = preview.join('');
result.innerHTML = a;
}
// positive to negative value and vice versa with the plus, minus key
plusMinus.onclick = function(){
let a = preview.join('');
let b = parseInt(a, 10);
let c = b * -1;
result.innerHTML = c;
plusMinus.style.display = "none";
plusMinus2.style.display = "block";
//this code below works
//document.getElementById('nine').style.display = "none";
//that one does not work
buttonN9.style.display = "none";
buttonN92.style.display = "block";
}
plusMinus2.onclick = function(){
let a = preview.join('');
let b = parseInt(a, 10);
let c = b * -1;
result.innerHTML = b;
plusMinus2.style.display = "none";
plusMinus.style.display = "block";
}
buttonN92.onclick = function(){
result.innerHTML = 0;
preview = [];
//this code below works
//document.getElementById('nine').style.display = "block";
//that one does not work
buttonN9.style.display = "block";
buttonN92.style.display = "none";
}
h1 {
padding: 30px;
}
.result {
font-size: 80px;
border: 2px solid #000;
color: #f9f9f9;
padding-right: 20px;
background-color: #696969;
}
.row1 {
border: 2px solid #000;
}
.button,
.button2,
.button-lg {
width: 25%;
}
p {
cursor: pointer;
}
#ac,
#plus-minus,
#plus-minus2,
#percentage,
#seven,
#eight,
#nine,
#seven2,
#eight2,
#nine2 {
font-size: 40px;
background-color: #808080;
color: #f9f9f9;
height: 140px;
padding-top: 50px;
margin-bottom: 0px;
border-right: 1px solid #696969;
}
#ac,
#plus-minus,
#percentage,
#seven,
#eight,
#nine {
display: block;
}
#plus-minus2,
#seven2,
#eight2,
#nine2 {
display: none;
}
#division,
#multiplication{
font-size: 40px;
background-color: #ffca47;
color: #f9f9f9;
height: 140px;
margin-bottom: 0px;
padding-top: 50px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>Calculator</title>
</head>
<body>
<h1 class="text-center">Calculator</h1>
<div class="container">
<div class="row">
<div class="col-xl-12">
<h5 id="result" class="card-title text-right result">0</h5>
</div>
</div>
<div class="row">
<div class="col-xl-12">
<div class="card-group row1">
<p id="ac" class="card-text text-center button">AC</p>
<p id="plus-minus" class="card-text text-center button">+ | -</p>
<p id="plus-minus2" class="card-text text-center button">+ | -</p>
<p id="percentage" class="card-text text-center button">%</p>
<p id="division" class="card-text text-center button2">/</p>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-12">
<div class="card-group row2">
<p id="seven" class="card-text text-center button">7</p>
<p id="seven2" class="card-text text-center button">7</p>
<p id="eight" class="card-text text-center button">8</p>
<p id="eight2" class="card-text text-center button">8</p>
<p id="nine" class="card-text text-center button">9</p>
<p id="nine2" class="card-text text-center button">9</p>
<p id="multiplication" class="card-text text-center button2">X</p>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="script.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>
So here is the idea: It's a calculator, so I opened my calculator from my iMac and I just checked the behavior to try to reproduce it.
What you can do:
- clicking on the number, showing them on the screen result.
- Clicking on AC make the button change to C and clear the screen result.
- Clicking on %, / and X makes nothing yet.
- Clicking on "+|-" swap the number to it's minus.
Here is what I'm trying to do. Normally, when you click the "+|-" key several time, it's going from negative to positive etc. ... and, normally if you click on a number it should go back to 0. I tried first with an external button to test and then I used the key 9 to see if it will work fine, with that code here:
document.getElementById('nine').style.display = "block"; //or none
It works perfectly! But, when I throw that code instead (I marked them up on the whole snippet to you identify them better)
buttonN9.style.display = "block"; //or none
BADABOOM, red alert on the console.
I've tried everything on every sens since hours; return my brain as much as I can; I'm still doing it. This evening, I must go somewhere with my wife. It's going to be hard to not think about it.
I will be honest with you, the calculator from the iPhone does not have the same behavior. If you fire 1,2,3 then +|- it goes -123. If you fire again 7, it goes -1237. So, maybe I mess up my brain too much, but I want to do it :)
Simply put all your code that accesses the DOM in a window.onload() handler, like this:
<script>
window.onload = function() {
let plusMinus = document.getElementById('plus-minus');
let buttonN9 = document.getElementById('nine');
// other variable initialization
plusMinus.onclick = function() {
buttonN9.style.display = "none";
// other handler code logic
}
// other event handlers
};
</script>
This way, you are sure the DOM is ready before accessing or manipulating it.
Also, from the html file in your Github repository here; you included several external scripts (including jquery) after your script. Except these scripts depend on your own script - which is not likely, you should always place your own script last after other external scripts that your code may likely depend on.
UPDATE: There are issues with firing window.onload from within the body tag. see the answer on this post. In addition to my previous answer, try putting your scripts in the header tag like this:
<head>
<!-- Place other external scripts here -->
<script src='myscript.js'></script>
</head>
So, here is the solution. As a beginner, i made first some mistakes, i was repeating the functions. I've created for each behavior one function. The main problem is i wanted to get to an index thru an array without using any loop. The loop for made the deal and now it's behaving as i want ...
The list of the buttons did not change. What you have:
- A function to handle a reset button.
- A function to handle the value of the numbers buttons
- A function to the positive/negative number
- A function to reset the positive/negative number in case you click on one number.
This is how behave the calculator that i have so i'm just trying to do the exactly same thing. Thanks a lot for your help !
function buttonResetHandler(button){
button.onclick = function (){
button.innerHTML = "AC";
preview = [];
result.innerHTML = 0;
}
}
buttonResetHandler(buttonAc);
// concatenation of the buttons numbers without any commas
function buttonNumberHandler(button, value){
button.onclick = function(){
buttonAc.innerHTML = "C";
button = value;
preview.push(button);
const a = preview.join('');
result.innerHTML = a;
}
}
buttonNumberHandler(buttonN0, 0);
buttonNumberHandler(buttonN1, 1);
buttonNumberHandler(buttonN2, 2);
buttonNumberHandler(buttonN3, 3);
buttonNumberHandler(buttonN4, 4);
buttonNumberHandler(buttonN5, 5);
buttonNumberHandler(buttonN6, 6);
buttonNumberHandler(buttonN7, 7);
buttonNumberHandler(buttonN8, 8);
buttonNumberHandler(buttonN9, 9);
// positive to negative value and vice versa with the plus, minus key
function buttonPlusMinusHandler(button1, button2, button3, button4){
button1.onclick = function(){
let a = preview.join('');
let b = parseInt(a, 10);
let c = b * -1;
result.innerHTML = c;
button1.style.display = "none";
button2.style.display = "block";
for(i = 0; i < button3.length; i++){
button3[i].style.display = "none";
}
for(i = 0; i < button4.length; i++){
button4[i].style.display = "block";
}
if(result.innerHTML == c){
button2.onclick = function(){
result.innerHTML = b;
button2.style.display = "none";
button1.style.display = "block";
}
}
}
}
buttonPlusMinusHandler(plusMinus, plusMinus2, allButtonsN, allButtonsN2);
function buttonNumberResetPlusMinus(button, button2){
for(i = 0; i < button.length; i++){
button[i].onclick = function(){
preview = [];
result.innerHTML = 0;
for(i = 0; i < button2.length; i++){
button[i].style.display = "none";
button2[i].style.display = "block";
}
}
}
}
buttonNumberResetPlusMinus(allButtonsN2, allButtonsN);

Using InnerHTML on 144 different cells

I am creating a tile based game using tables. In each td cell,
<td>
<div id="image" style="display:none; display: fixed; right: 5; top:2;"><img src="http://thumb7.shutterstock.com/display_pic_with_logo/339217/339217,1272881114,1/stock-vector-hand-drawing-of-typical-house-along-the-canal-near-bangkok-in-thailand-52242874.jpgAttap"/></div>
<input id ="attap" type="submit" value="Show Div" onclick="showDiv(); if(submitted)this.disabled = true" />
<div id="welcomeDiv" style="display:none;"> <input type="submit" name="answer" value="Show Div" onclick="showDiv3(); if(submitted)this.disabled = true" /></div>
<div id="welcomeDiv3" style="display:none;"> <input type="submit" name="answer" value="Show Div" onclick="showDiv4(); if(submitted)this.disabled = true"" /></div>
<div id= "welcomeDiv4" style="display:none;"><input type="submit" name="answer" value="Show Div" onclick="showDiv5(); if(submitted)this.disabled = true"" /> </div>
</td>
Javascipt:
function showDiv() {
document.getElementById('welcomeDiv').style.display = "block";
document.getElementById('image').style.display = "block";
submitted = true;
populationred +=20;
document.getElementById('population').innerHTML = populationred;
}
function showDiv3() {
document.getElementById('welcomeDiv3').style.display = "block";
document.getElementById("image").innerHTML = "'<img src='http://www.sgshophouses.com/images/Shophouses1.jpg'>'"
submitted = true;
populationred +=50;
document.getElementById('population').innerHTML = populationred;
}
function showDiv4() {
document.getElementById('welcomeDiv4').style.display = "block";
document.getElementById('image').innerHTML = "'<img src='http://singaporepropertylaunch.com.sg/wp-content/uploads/2015/04/HDB-resale-prices-fall-1.0.gif'>'"
submitted = true;
populationred +=100;
document.getElementById('population').innerHTML = populationred;
}
function showDiv5() {
document.getElementById('image').innerHTML = "'<img src='www.realestatechannel.com/assets_c/2010/06/Austonian-Condo-Tower-thumb- 120x238.jpg'>'"
submitted = true;
populationred +=200;
document.getElementById('population').innerHTML = populationred;
}
I need to repeat this for 144 cells. However, the problem is that when 1 button is clicked, the image will show up only at the first cell, hence the tedious way of solving this issue is to rename all the divs differently for every cell. Is there any more efficient ways?
You can refer here: www2.hci.edu.sg/t0104448b/cells.html for a "fiddle".
Shilly's comment had the right idea. I'm not entirely sure what your goal is but this is what I did, that looks reasonably what you're after. It should get you started.
There's only one click handler, on the <table> itself. It's effectively delegating the click. This saves memory because you're not creating a copy/closure for every cell. It costs some performance due to the delegating nature but for click handlers, it's generally okay. For mouseover handlers, that's another subject.
Using a <template> tag effectively gives you a DocumentFragment to work with and markup as HTML, instead of doing it in JavaScript (which can be tedious).
We clone that document fragment 144 times, injecting the proper description ('ShopHouse', 'HDB Flat', 'Condo', etc.) into each stamp of the template. Each clone is appended to a document fragment. Once our document fragment is done being modified, we inject it into the DOM via board.appendChild(frag);.
var board = document.getElementById('board');
var cellTmpl = document.getElementById('template-cell');
var cellTmplContent = cellTmpl.content;
var frag = document.createDocumentFragment(); // for performance
var submitted = false; // not sure what you intend to use this for
var descriptions = [ 'ShopHouse', 'HDB Flat', 'Condo' ]; // ... etc.
var cells = [];
for (var r = 0; r < 12; r++) {
var row = [];
cells.push(row);
var tr = document.createElement('tr');
frag.appendChild(tr);
for (var c = 0; c < 12; c++) {
var clone = document.importNode(cellTmplContent, true);
var index = r * 12 + c;
var description = index < descriptions.length ? descriptions[index] : 'Unknown place';
clone.querySelector('p.description').innerText = description;
tr.appendChild(clone);
row.push(clone);
}
}
board.appendChild(frag);
board.addEventListener('click', function(e) {
var button = e.target;
var td = button.parentElement;
var img = td.querySelector('img');
var p = td.querySelector('p.description');
button.disabled = true;
img.style.display = 'block';
p.style.display = 'block';
submitted = true;
});
// could do something with `cells` variable if you like. It's a two dimensional array of <td> elements
td {
background: #ccc;
border: 1px solid #000;
}
td > img {
display: none;
zoom: 0.2;
}
p.description {
display: none;
}
<table id="board">
</table>
<template id="template-cell">
<td>
<img src="http://thumb7.shutterstock.com/display_pic_with_logo/339217/339217,1272881114,1/stock-vector-hand-drawing-of-typical-house-along-the-canal-near-bangkok-in-thailand-52242874.jpgAttap"/>
<button>Show</button>
<p class="description"></p>
</td>
</template>

Categories

Resources