I'm trying to display all elements of an array, by iterating through the arrray, but after I chose the file (from the input), the element in page changes to : "unidentified". Why?
function getElement() {
console.log('sfgsdf')
document.getElementById('files').onchange = function() {
console.log('sfgsdf')
let file = this.files[0];
let reader = new FileReader();
reader.readAsText(file);
reader.onload = function() {
variableIs = this.result
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function display(asd) {
const usingSplit = asd.split(' ')
lengthOf = usingSplit.length
for (var i = 0;i < lengthOf;i++) {
sleep(1000).then(() => {
document.getElementById('test').innerHTML = usingSplit[i];
});
}
}
display(variableIs);
}
}
}
getElement()
The HTML code is just this simple one :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1 id="test">TEST</h1>
<script src="test4.js"></script>
</body>
</html>
The problem is the var inside the for loop.
You should use let instead due to the way both work.
Read this post to understand their difference:
What is the difference between "let" and "var"?
The way you're using the sleep function is not gonna work since they will execute at the same time.
You can solve this by using async await.
function delay(ms = 0) {
return new Promise(resolve => setTimeout(resolve, ms))
}
const inputFile = document.getElementById('files')
const test = document.getElementById('test')
function init() {
inputFile.onchange = async function() {
const file = this.files[0];
const content = await file.text()
const splitText = content.split(' ')
for (let i = 0; i < splitText.length; i++) {
test.innerHTML = splitText[i]
// Here we are actually waiting in the for loop since this is an async function
await delay(1000)
}
}
}
init()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1 id="test">TEST</h1>
<input id="files" type="file">
</body>
</html>
Related
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TV Show Search</title>
<script src="https://cdn.jsdelivr.net/npm/axios#1.1.2/dist/axios.min.js"></script>
</head>
<body>
<h1>TV Show Search</h1>
<form id="searchForm">
<input type="text" placeholder="TV Show title" name="query">
<button>Search</button>
</form>
<script src="app.js"></script>
</body>
</html>
The result of displayed image in the browser
The below code is searching the picture element data in api and it will display the picture after searching it, My goal is while the first searched picture displayed and when i'm trying to search for the different element the previous displayed picture should be deleted. Right now when i search it prints from where the last picture displayed in the browser.
const form = document.querySelector('#searchForm');
const input = document.querySelector('.name');
form.addEventListener('submit', async function(e) {
e.preventDefault();
const searchTerm = form.elements.query.value;
const config = {params: {q: searchTerm}}
const res = await axios.get(`https://api.tvmaze.com/search/shows`, config)
form.elements.query.value = ''
// console.log(res.data[0].show.image.medium);
// form.elements.query.value = '';
// const img = document.createElement('IMG');
// img.src = res.data[0].show.image.medium;
// document.body.append(img)
makeImages(res.data)
})
const makeImages = (shows) => {
for(let result of shows){
if(result.show.image) {
const img = document.createElement('IMG');
img.src = result.show.image.medium;
document.body.append(img);
}
}
}
You should add a new container for images.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TV Show Search</title>
<script src="https://cdn.jsdelivr.net/npm/axios#1.1.2/dist/axios.min.js"></script>
</head>
<body>
<h1>TV Show Search</h1>
<form id="searchForm">
<input type="text" placeholder="TV Show title" name="query">
<button>Search</button>
</form>
<div id="results-container"></div><!-- new container -->
<script src="app.js"></script>
</body>
</html>
Then the first thing you should do in makeImages is clear all the children inside the container.
const form = document.querySelector('#searchForm');
const input = document.querySelector('.name');
form.addEventListener('submit', async function(e) {
e.preventDefault();
const searchTerm = form.elements.query.value;
const config = {params: {q: searchTerm}}
const res = await axios.get(`https://api.tvmaze.com/search/shows`, config)
form.elements.query.value = ''
// console.log(res.data[0].show.image.medium);
// form.elements.query.value = '';
// const img = document.createElement('IMG');
// img.src = res.data[0].show.image.medium;
// document.body.append(img)
makeImages(res.data)
})
const makeImages = (shows) => {
let container = document.querySelector('#results-container');
container.empty(); // remove all previous images
for(let result of shows){
if(result.show.image) {
const img = document.createElement('IMG');
img.src = result.show.image.medium;
container.append(img); // add images to the container instead of adding them directly to the body.
}
}
}
I'm trying to make a web framework and one feature will be a key-value state management tool. I need the second <script> tag to only run after ./script.js loads in.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./framework.js"></script>
</head>
<body>
<p f-text="name"></p>
<script>
Framework.store('name', 'Joe');
</script>
</body>
</html>
framework.js:
document.querySelectorAll('*').forEach((element) => {
if (element.hasAttribute('f-text')) {
const textValue = element.getAttribute('f-text');
const key = window.fStore.find((x) => x.key === textValue);
element.innerHTML = key.value;
}
});
window.Framework = {
store: (key, value?) => {
if (!value) {
const foundKey = window.fStore.find((x) => x.key === key);
return foundKey.value;
}
window.fStore = [...window.fStore, { key: key, value: value }];
}
}
Error:
SyntaxError: Unexpected token ')'
at /framework.js:12:22
ReferenceError: Framework is not defined
at /:12:5
You need to wait that your script is loaded, you can use this
window.addEventListener('load', function() {
Framework.store('name', 'Joe');
})
I have a similar class structure and it doesn't work for me, I've already tried several things and can't fix the problem. As you can see, the constructors are executed correctly and also the method executed in the last constructor. However, when I create HTML content, it doesn't paint it. Why and how could you solve this?
class AutoComplete{
constructor(){
console.log("constructor autocomplete")
this.table = new Table();
}
}
class Table{
constructor(){
console.log("constructor table")
this.arr = []
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => {
data.map(d => this.arr.push(d))
});
this.fill();
}
fill = () => {
console.log("fill");
const content = document.querySelector("#content");
// doesn't work
this.arr.forEach( ct => {
const div = document.createElement("div");
div.innerText = ct.body;
content.appendChild(div);
//content.innerHTML += div;
});
}
}
let autoc = new AutoComplete();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
</head>
<body>
<div id="content"></div>
</body>
</html>
This is happening because you need to call this.fill() within the .then() callback function. Otherwise. this.fill is called before you get data back from the API.
Demo:
class AutoComplete{
constructor(){
console.log("constructor autocomplete")
this.table = new Table();
}
}
class Table{
constructor(){
console.log("constructor table")
this.arr = []
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => {
data.map(d => this.arr.push(d));
this.fill();
})
// this.fill()
}
fill = () => {
console.log("fill");
const content = document.querySelector("#content");
// doesn't work
this.arr.forEach(ct => {
const div = document.createElement("div");
div.innerText = ct.body;
content.appendChild(div);
//content.innerHTML += div;
});
}
}
let autoc = new AutoComplete();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
</head>
<body>
<div id="content"></div>
</body>
</html>
The button should replace all the letters (a, b, c) with 'test', but it only replaces the last (c).
If I replace the line of code inside of updateHTML() with the commented line, the code works as intended. Can someone explain what the difference is and why the lines of code work differently.
My js and html files:
let names = ["a", "b", "c"];
let objs = [];
let container;
let form;
class Class {
constructor(name) {
this.name = name;
this.buildHTML();
}
buildHTML() {
container.innerHTML += `
<div id="${this.name}">
${this.name}
</div>`
this.inner_container = document.getElementById(this.name);
}
updateHTML() {
this.inner_container.innerHTML = "test";
// document.getElementById(this.name).innerHTML = "test";
}
}
function main() {
container = document.getElementById("container");
for (var name in names) {
objs.push(new Class(names[name]));
}
form = document.getElementById("form");
form.addEventListener('submit', eventHandler_submit_form);
}
function eventHandler_submit_form(event) {
event.preventDefault();
for (var obj in objs) {
objs[obj].updateHTML();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Sample Text</title>
</head>
<body onload="main()">
<form id="form">
<button type="submit">Submit</button>
</form>
<div id="container"></div>
</body>
</html>
Here is my HTML and JS code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2-d0</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>2-D0</h2>
<div id="heading">
<textarea id="text"></textarea>
<button id="button">Add</button>
</div>
<div id="lists">
</div>
<script src="functions.js"></script>
</body>
</html>
Here is my Javascript code
'use strict'
const buttonclick = document.getElementById('button')
const list = document.getElementById('lists')
const a = "<span><button class = 'rbutton'>X</button></span>" //list-item button
const clickhandler = () => {
const text = document.getElementById('text')
//creating a list element
if(text.value != ''){
let Newdiv = document.createElement('div')
// appending elements
Newdiv.innerHTML = text.value + a
list.appendChild(Newdiv)
let b = document.getElementsByClassName('rbutton')
if(b !=[]){
for(let i = 0; i < b.length; i++){
b[i].addEventListener('click', function(){
b[i].parentElement.parentElement.remove();
console.log(b)
})
}
}
//reseting the textarea value
text.value = ''
}
}
buttonclick.addEventListener('click', clickhandler)
An error in shown on delete a item: Cannot read property 'parentElement' of undefined at HTMLButtonElement. .
Can someone please explain what is wrong in my code and what does the error mean.
thankyou
On every click of the button you are attaching event handlers to the whole group again.
On the first iteration, 1st button has one delete handler.
On second iteration, 1st button has 2 event handler(one for buttons[0] and one for buttons[1]), and 2nd has one.
So on.
Use this. It will always point to the element to the event on which the event handler is attached:
this.parentElement.parentElement.remove();
Another way is to simply use this.parentElement.parentElement.remove()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2-d0</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>2-D0</h2>
<div id="heading">
<textarea id="text"></textarea>
<button id="button">Add</button>
</div>
<div id="lists">
</div>
<script>
"use strict";
const buttonclick = document.getElementById('button');
const list = document.getElementById('lists');
const a = "<span><button class = 'rbutton'>X</button></span>"; //list-item button
const clickhandler = () => {
const text = document.getElementById('text');
//creating a list element
if(text.value != '') {
let Newdiv = document.createElement('div');
// appending elements
Newdiv.innerHTML = text.value + a;
list.appendChild(Newdiv);
let b = document.getElementsByClassName('rbutton');
for(let i = 0; i < b.length; i++) {
b[i].addEventListener('click', function() {
this.parentElement.parentElement.remove();
});
}
//reseting the textarea value
text.value = '';
}
}
buttonclick.addEventListener('click', clickhandler);
</script>
</body>
</html>
You should use window.event.target.parentElement... to get the button instead of b[i].parentElement....
"use strict";
const buttonclick = document.getElementById('button');
const list = document.getElementById('lists');
const a = "<span><button class = 'rbutton'>X</button></span>"; //list-item button
const clickhandler = () => {
const text = document.getElementById('text');
//creating a list element
if(text.value != '') {
let Newdiv = document.createElement('div');
// appending elements
Newdiv.innerHTML = text.value + a;
list.appendChild(Newdiv);
let b = document.getElementsByClassName('rbutton');
for(let i = 0; i < b.length; i++) {
b[i].addEventListener('click', function() {
window.event.target.parentElement.parentElement.remove();
});
}
//reseting the textarea value
text.value = '';
}
}
buttonclick.addEventListener('click', clickhandler);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2-d0</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>2-D0</h2>
<div id="heading">
<textarea id="text"></textarea>
<button id="button">Add</button>
</div>
<div id="lists">
</div>
</body>
</html>