let state = {}
var Playername;
At the start of the code the var Playername is created.
if (nextTextNodeId == 60) {
var InputName = document.getElementById('name').value;
let Playername = InputName;
alert(Playername);
if (Playername == "Andrew") {
ToggleInputOff()
state = Object.assign(state, option.setState)
showTextNode(4)
return;
}
else if (Playername == "") {
state = Object.assign(state, option.setState)
showTextNode(3)
return;
}
else {
ToggleInputOff()
state = Object.assign(state, option.setState)
showTextNode(5)
return;
}
return ToggleInputOff()
}
The alert Playername displays the inputted name in the alert box correctly, however when i go to use this variable later in the project it comes up as undefined.
{
id: 5,
text: "Welcome " + Playername + " let us start the day!",
options: [
{
text: "Let's go",
nextText: 6
}
]
},
The text nodes are accessed through this function and displayed on the screen
function showTextNode(textNodeIndex) {
const textNode = textNodes.find(textNode => textNode.id === textNodeIndex)
textElement.innerText = textNode.text
while (optionButtonsElement.firstChild) {
optionButtonsElement.removeChild(optionButtonsElement.firstChild)
}
textNode.options.forEach(option => {
if (showOption(option)) {
const button = document.createElement('button')
button.innerText = option.text
button.classList.add('btn')
button.addEventListener('click', () => selectOption(option))
optionButtonsElement.appendChild(button)
}
})
}
Whenever this text node is accessed the output is
Welcome Undefined let us start the day!
Related
I have this interval code:
const interval = setInterval(function() {
run(); //Load Divs
$('.parentDiv').remove(); //Remove Divs
}, 10000); //Loop in 10 Seconds
The issue is that this is NOT SMOOTH at all. Is there a better way to refresh the divs with data than to delete them and remake them?
You can see the current code on this test site https://footballify.net/test/. It is not smooth.
code:
//Pull API Data for UTC
var run = async () => {
const res = await fetch(`https://v3.football.api-sports.io/fixtures?date=${isoStr}`, {
headers: {
'X-RapidAPI-Host': "v3.football.api-sports.io",
"X-RapidAPI-Key": "e54f3d3972ca8251c1259694b49948de"
},
});
//Parse JSON
const json = (await res.json())?.response;
//Map desiredOrder onto API Call
const ordered = desiredOrder.map((id) => json.filter(({ league }) => league?.id === id));
//Remove any Null Values
const filtered = ordered.filter(e => e.length);
//arrLeagues created to avoid duplicate leagues
let arrLeagues = [];
console.log(filtered)
//Loop through leagues
for (i = 0; i < filtered.length-1; i++) {
//Loop through games of Leagues
for (x=0; x<filtered[i].length;x++){
//Create Parent Div For Data
let parent = document.createElement("div")
parent.className = 'parentDiv'
//League Duplication not allowed
if (arrLeagues.includes(filtered[i][x].league.id)) {
} else {
arrLeagues.push(filtered[i][x].league.id)
//League Name
let league = document.createElement("div")
league.className = 'league'
league.innerHTML = filtered[i][x].league.name + `<img class='flag' src=${filtered[i][x].league.flag}>`
parent.appendChild(league)
}
//Home Container
let child1 = document.createElement("div")
child1.className = 'childDiv'
//Game Status
let gameStatus = document.createElement("div")
gameStatus.className = 'status'
gameStatus.innerHTML = filtered[i][x].fixture.status.short
parent.appendChild(gameStatus)
//Home Name
let homeTeamName = document.createElement("div")
homeTeamName.className = 'team1'
homeTeamName.innerHTML = filtered[i][x].teams.home.name
parent.appendChild(homeTeamName)
//Home Score
let homeTeamScore = document.createElement("div")
homeTeamScore.className = 'score1'
parent.appendChild(homeTeamScore)
//Away Container
let child2 = document.createElement("div")
child2.className = 'childDiv'
//Away Name
let awayTeamName = document.createElement("div")
awayTeamName.className = 'team2'
awayTeamName.innerHTML = filtered[i][x].teams.away.name
parent.appendChild(awayTeamName)
//Away Score
let awayTeamScore = document.createElement("div")
awayTeamScore.className = 'score2'
parent.appendChild(awayTeamScore)
//Push all Data to DOM
document.querySelector('.parentContainer').appendChild(parent);
if (String(filtered[i][x].fixture.status.short) === 'NS') {
homeTeamScore.innerHTML = 0
homeTeamScore.classList.add('hide')
awayTeamScore.innerHTML = 0
awayTeamScore.classList.add('hide')
} else if (String(filtered[i][x].fixture.status.short) === 'CANC') {
homeTeamScore.classList.add('hide')
homeTeamScore.innerHTML = 0
awayTeamScore.classList.add('hide')
awayTeamScore.innerHTML = 0
gameStatus.innerHTML = 'NA'
} else if (String(filtered[i][x].fixture.status.short) === 'FT') {
homeTeamScore.classList.remove('hide')
homeTeamScore.innerHTML = filtered[i][x].goals.home
awayTeamScore.classList.remove('hide')
awayTeamScore.innerHTML = filtered[i][x].goals.away
} else if (String(filtered[i][x].fixture.status.short) === 'HT') {
homeTeamScore.classList.remove('hide')
homeTeamScore.classList.add('live')
homeTeamScore.innerHTML = filtered[i][x].goals.home
awayTeamScore.classList.remove('hide')
awayTeamScore.classList.add('live')
gameStatus.classList.add('live')
awayTeamScore.innerHTML = filtered[i][x].goals.away
} else if (String(filtered[i][x].fixture.status.short) == '1H') {
homeTeamScore.classList.remove('hide')
homeTeamScore.classList.add('live')
homeTeamScore.innerHTML = filtered[i][x].goals.home
awayTeamScore.classList.remove('hide')
awayTeamScore.classList.add('live')
awayTeamScore.innerHTML = filtered[i][x].goals.away
gameStatus.classList.add('live')
gameStatus.innerHTML = filtered[i][x].fixture.status.elapsed + "′"
} else if (String(filtered[i][x].fixture.status.short) == 'ET') {
homeTeamScore.classList.remove('hide')
homeTeamScore.classList.add('live')
homeTeamScore.innerHTML = filtered[i][x].goals.home
awayTeamScore.classList.remove('hide')
awayTeamScore.classList.add('live')
awayTeamScore.innerHTML = filtered[i][x].goals.away
gameStatus.classList.add('live')
gameStatus.innerHTML = filtered[i][x].fixture.status.elapsed + "′"
} else if (String(filtered[i][x].fixture.status.short) == '2H') {
homeTeamScore.classList.remove('hide')
homeTeamScore.classList.add('live')
homeTeamScore.innerHTML = filtered[i][x].goals.home
awayTeamScore.classList.remove('hide')
awayTeamScore.classList.add('live')
awayTeamScore.innerHTML = filtered[i][x].goals.away
gameStatus.classList.add('live')
gameStatus.innerHTML = filtered[i][x].fixture.status.elapsed + "′"
} else {}
//If Home Wins
if (filtered[i][x].teams.home.winner == true) {
homeTeamName.classList.add('winner')
awayTeamName.classList.add('loser')
homeTeamScore.classList.add('winner')
awayTeamScore.classList.add('loser')
} else if (filtered[i][x].teams.away.winner == true) {
//If Away Wins
awayTeamName.classList.add('winner')
homeTeamName.classList.add('loser')
awayTeamScore.classList.add('winner')
homeTeamScore.classList.add('loser')
//Match Not Started or Cancelled
} else if (filtered[i][x].fixture.status.short == 'NS' || 'CANC'){
homeTeamName.classList.add('winner')
homeTeamScore.classList.add('winner')
awayTeamScore.classList.add('winner')
awayTeamName.classList.add('winner')
} else {
//Draw
homeTeamName.classList.add('loser')
awayTeamName.classList.add('loser')
homeTeamScore.classList.add('loser')
awayTeamScore.classList.add('loser')
}
}
}
};
run();
so it is a fetch of data along with appending the data do dom
Try this:
const interval = setInterval(async function() {
if ($('.parentDiv').length) { // Check if the parent div exists
$('.parentDiv').remove(); // Remove the div
}
await run(); // Fire the run function to create a new div with new data
}, 10000);
Edit:
I think the problem with my above answer is that there is still a delay: The time that it takes for your code to both get the data from your API and build your div with all of its child elements. With this in mind, try deleting the div within the `run()` function right before a new div is created. This way, all of the processing can be done while the old data is still visible. Try this:
Interval code:
const interval = setInterval(async function() {
await run();
});
Run function:
$('.parentDiv').remove(); // Remove the old div
//Push all Data to DOM
document.querySelector('.parentContainer').appendChild(parent);
I have an input form field that outputs text on submit to another created input, essentially an editable todo list. I have tried to make the input text value auto grow, but cannot figure out how to do it. Right now the user has to scroll over to see the rest of the text on each list item. This should not be.
What I tried:
I have tried creating a span and attaching editableContent but that makes my input text disappear.
I have tried setting an attribute on max-length on the created input but cannot get it to work. What is the best way to accomplish auto growing the text input value?
Here is the full codepen
const createTodoText = (todo) => {
const itemText = document.createElement("INPUT");
// const itemText = document.createElement("span");
// itemText.contentEditable
// itemText.contentEditable = 'true'
itemText.classList.add("todoText");
itemText.value = todo.name;
itemText.addEventListener("click", (e) => {
e.currentTarget.classList.add("active");
});
// update todo item when user clicks away
itemText.addEventListener("blur", (e) => {
todo.name = e.currentTarget.value;
renderTodos();
});
return itemText;
};
There you go: -
// select DOM elements
const todoForm = document.querySelector(".todo-form");
const addButton = document.querySelector(".add-button");
const input = document.querySelector(".todo-input");
const ul = document.getElementById("todoList");
let todos = [];
todoForm.addEventListener("submit", function (e) {
e.preventDefault();
addTodo(input.value);
});
const addTodo = (input) => {
if (input !== "") {
const todo = {
id: Date.now(),
name: input,
completed: false
};
todos.push(todo);
renderTodos();
todoForm.reset();
}
};
const renderTodos = (todo) => {
ul.innerHTML = "";
todos.forEach((item) => {
let li = document.createElement("LI");
// li.classList.add('item');
li.setAttribute("class", "item");
li.setAttribute("data-key", item.id);
const itemText = createTodoText(item);
const cb = buildCheckbox(item);
const db = buildDeleteButton(item);
// if (item.completed === true) {
// li.classList.add('checked');
// }
li.append(cb);
li.append(db);
li.append(itemText);
ul.append(li);
});
};
const createTodoText = (todo) => {
const itemText = document.createElement("span");
itemText.setAttribute('role','textbox');
itemText.setAttribute('contenteditable',"true");
itemText.classList.add("todoText");
itemText.innerHTML = todo.name;
itemText.addEventListener("click", (e) => {
e.currentTarget.classList.add("active");
});
// update todo item when user clicks away
itemText.addEventListener("blur", (e) => {
todo.name = e.target.textContent;
renderTodos();
});
return itemText;
};
const buildCheckbox = (todo) => {
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.name = 'checkbox';
cb.classList.add('checkbox');
cb.checked = todo.completed;
// checkbox not staying on current state ??
cb.addEventListener('click', function (e) {
if (e.target.type === 'checkbox') {
// todo.completed = e.target.value;
todo.completed = e.currentTarget.checked
e.target.parentElement.classList.toggle('checked');
}
});
return cb;
};
const buildDeleteButton = (todo) => {
const deleteButton = document.createElement("button");
deleteButton.className = "delete-button";
deleteButton.innerText = "x";
deleteButton.addEventListener("click", function (e) {
// duplicates children sometimes ??
const div = this.parentElement;
div.style.display = "none";
todos = todos.filter((item) => item.id !== todo.id);
});
return deleteButton;
};
// //------ Local Storage ------
function addToLocalStorage(todos) {}
function getFromLocalStorage() {}
// getFromLocalStorage();
This is the Javscript code part. In createTodoText, you can see the changes i've made. It's working according to what you want. What i've done is simple used 'span' instead of 'input'.
How about trying something like
if (todo.name.length) {itemText.size = todo.name.length;}
I want to be able to access the "const history" outside in the historyInfo function so I don't have to call the historyInfo() function inside the selectOption function. The main problem is that there are two addEventListeners calling the showOption function where the historyInfo function is called. I just want the buyItemPanelbtn click to call the historyInfo function.
function showbrookton(brooktonIndex){
const brookton = Brookton.find(brookton => brookton.id === brooktonIndex)
textElement.innerText = brookton.text //fill text element
titleElement.innerText = brookton.title //title element
while (optionButtonsElement.firstChild) { //removes all buttons
optionButtonsElement.removeChild(optionButtonsElement.firstChild)
}
brookton.options.forEach(option => { //option is options and the funtion is performed on each option
if(showOption(option) && (option.text)) { //
const button = document.createElement('button')
button.innerText = option.text
button.classList.add('btn')
button.addEventListener('click', () => {
selectOption(option);
})
optionButtonsElement.appendChild(button)
}
if(option.backText){ //this goes back to previous page
const backOption = option.backText;
backButton.addEventListener('click', () => showbrookton(backOption))
} //else close window
})
}
function showOption(option){
return option.requiredState == null || option.requiredState(state)
}
function selectOption(option){
const nextbrooktonId = option.nextText
const history = option.historyText;
if (nextbrooktonId == "buyItem"){
buyItemPanel();
function buyItemPanel(){
const buyItemName = option.text;
buyItemPanelName.innerText = buyItemName
buyItemPanelPrice.innerText = "Price: " + option.price
buyPanelType.innerText = option.type
historyInfo(history);
showBuyItemPanel()
}
function historyInfo(history) {
$(HistoryPanel).append("<div>" + history + "</div>");
}
buyItemPanelbtn.addEventListener('click', () => selectOption());
const Brookton = [
{
id: "Bakery",
title: "Bakery",
text: 'Choose a Location to visit.',
options: [
{
text: 'Bread',
type: 'Food',
price: '$4',
historyText: "You bought bread",
nextText: "buyItem",
}
]
}
]
Declare the history variable outside as
.
var history;
and then in the selectOption function
history = option.historyText;
Code:
var history;
function selectOption(option) {
history = option.historyText;
historyInfo(history);
return showBuyItemPanel()
}
showbrookton(nextbrooktonId)
}
function historyInfo(history) {
$(HistoryPanel).append("<div>" + history + "</div>");
}
This seems to have solved the problem. I declared Newoption globally and then set it to the parameter option inside the selectOption function. I was then able to make a const 'history' inside the historyInfo function.
var Newoption;
function showOption(option){
return option.requiredState == null || option.requiredState(state)
}
function selectOption(option){
Newoption = option;
const nextbrooktonId = option.nextText
// const history = option.historyText;
if (nextbrooktonId == "buyItem"){
buyItemPanel();
function buyItemPanel(){
const buyItemName = option.text;
buyItemPanelName.innerText = buyItemName
buyItemPanelPrice.innerText = "Price: " + option.price
buyPanelType.innerText = option.type
showBuyItemPanel()
}
function historyInfo(){
const history = Newoption.historyText;
$(HistoryPanel).append("<div>" + history + "</div>");
updateScroll();
}
// click buy button
buyItemButton.addEventListener("click", () => {
closeItemBuyWindow();
closeLocationsMenu();
historyInfo();
});
I am trying to make a text based game based on a tutorial on Youtube. I have a div called "HistoryPanel" where I want divs to be appended containing a string from an object property "historyText" when "buyItemPanelbtn" is clicked. While I have managed to achieve this when I click the button again it will append the div twice and three times if I click again after that and so on. Can someone show me how to make it only append once each time the button is clicked?
I have included the code and the object that the code is relevant to. I haven't included the other objects because there are a lot and they are not relevant to this problem.
const textElement = document.getElementById('text');
const titleElement = document.getElementById('title');
const buyItemPanelBackground = document.getElementById('buyItemPanelBackground');
const buyItemPanel = document.getElementById('buyItemPanel');
const buyItemPanelName = document.getElementById('buyPanelName');
const buyItemPanelPrice = document.getElementById('buyPanelPrice');
const buyPanelType = document.getElementById('buyPanelType');
const buyItemPanelbtn = document.getElementById('buyItemPanelbtn');
const buyItemNevermind = document.getElementById('buyItemNevermind');
const backButton = document.getElementById('backButton');
const closeMenuButton = document.getElementById('closeMenuButton');
const optionButtonsElement = document.getElementById('option-buttons');
//home screen
const HistoryPanel = document.getElementById('HistoryPanel');
// home screen buttons
const homeScreen = document.getElementById('homeScreen');
const menuScreen = document.getElementById('menuScreen');
const homeLocationsButton = document.getElementById('homeLocationsButton');
let state = {}
function startGame() {
state = {}
showbrookton("Bakery");
}
//close locations menu
function closeLocationsMenu(){
menuScreen.style.display = "none";
homeScreen.style.display = "block";
}
//close item buy window
function closeItemBuyWindow(){
buyItemPanelBackground.style.display = "none";
}
//hide buy item window when click nevermind
buyItemNevermind.addEventListener("click", closeItemBuyWindow);
// click buy button
buyItemPanelbtn.addEventListener("click", () => {
closeItemBuyWindow();
closeLocationsMenu();
});
//display locations menu
homeLocationsButton.addEventListener("click", () => {
menuScreen.style.display = "block";
homeScreen.style.display = "none";
startGame();
});
//close locations menu
closeMenuButton.addEventListener("click", closeLocationsMenu);
// when clicking an item
function showBuyItemPanel(){
buyItemPanelBackground.style.display = "block";
}
function showbrookton(brooktonIndex){
const brookton = Brookton.find(brookton => brookton.id === brooktonIndex)
textElement.innerText = brookton.text //fill text element
titleElement.innerText = brookton.title //title element
while (optionButtonsElement.firstChild) { //removes all buttons
optionButtonsElement.removeChild(optionButtonsElement.firstChild)
}
brookton.options.forEach(option => { //option is options and the funtion is performed on each option
if(showOption(option) && (option.text)) { //
const button = document.createElement('button')
button.innerText = option.text
button.classList.add('btn')
button.addEventListener('click', () => selectOption(option))
optionButtonsElement.appendChild(button)
}
if(option.backText){ //this goes back to previous page
const backOption = option.backText;
backButton.addEventListener('click', () => showbrookton(backOption))
} //else close window
})
}
function showOption(option){
return option.requiredState == null || option.requiredState(state)
}
function selectOption(option){
const nextbrooktonId = option.nextText
const history = option.historyText
if (nextbrooktonId == "buyItem"){
const buyItemName = option.text;
buyItemPanelName.innerText = buyItemName
buyItemPanelPrice.innerText = "Price: " + option.price
buyPanelType.innerText = option.type
const history = option.historyText;
buyItemPanelbtn.addEventListener('click', () => {
$(HistoryPanel).append("<div>" + history + "</div>")
})
return showBuyItemPanel()
}
state = Object.assign(state, option.setState) //this overrides the current state with the new ones
showbrookton(nextbrooktonId)
}
const Brookton = [
{
id: "Bakery",
title: "Bakery",
text: 'Choose a Location to visit.',
options: [
{
text: 'Bread',
type: 'Food',
price: '$4',
historyText: "You bought bread",
nextText: "buyItem",
}
]
}
]
I wrote a function that trigger on input and get data from API. I need to store last input.value in localStorage and then set input.value to one in localStorage on reload. Everything is fine except when I reload the page I have value that I need but I have to click space then backspace f.e. to render things. I would like to ask where should I pass the getter from localStorage so it will trigger the function on reload, but won't break the listener for input. There is full code underneath :
let country;
let cities = [];
const citiesDiv = document.getElementById("cities");
const countryPicker = document.getElementById("country-picker");
const getData = async () => {
const response = await fetch(
`https://api.openaq.org/v1/cities?country=${country}&limit=10¶meter=no2&order_by=parameter`
);
const data = await response.json();
cities = data.results;
console.log(cities);
citiesDiv.innerHTML = "";
renderCities(cities);
};
countryPicker.value = JSON.parse(localStorage.getItem("inputValue"));
countryPicker.addEventListener("input", function(e) {
if (e.target.value.toLowerCase() === "poland".toLowerCase()) {
country = "PL";
} else if (e.target.value.toLowerCase() === "spain".toLowerCase()) {
country = "ES";
} else if (e.target.value.toLowerCase() === "germany".toLowerCase()) {
country = "DE";
} else if (e.target.value.toLowerCase() === "france".toLowerCase()) {
country = "FR";
}
localStorage.setItem("inputValue", JSON.stringify(e.target.value));
getData();
});
function renderCities(cities) {
cities.forEach(function(city) {
const p = document.createElement("p");
const button = document.createElement("button");
button.classList.add("accordion");
const div = document.createElement("div");
div.classList.add("panel");
const citiesDiv = document.getElementById("cities");
button.textContent = city.city;
citiesDiv.appendChild(button);
citiesDiv.appendChild(div);
div.appendChild(p);
p.textContent = "Lorem ipsum";
});
const acc = document.getElementsByClassName("accordion");
let i;
for (i = 0; i < acc.length; i++) {
console.log(i);
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
}
Refactor your code in order to make the function that fetches and renders data to be reusable for two cases:
when user changes the input.
when the page is loaded.
Replace the following part
countryPicker.value = JSON.parse(localStorage.getItem("inputValue"));
countryPicker.addEventListener("input", function(e) {
if (e.target.value.toLowerCase() === "poland".toLowerCase()) {
country = "PL";
} else if (e.target.value.toLowerCase() === "spain".toLowerCase()) {
country = "ES";
} else if (e.target.value.toLowerCase() === "germany".toLowerCase()) {
country = "DE";
} else if (e.target.value.toLowerCase() === "france".toLowerCase()) {
country = "FR";
}
localStorage.setItem("inputValue", JSON.stringify(e.target.value));
getData();
});
with
countryPicker.value = JSON.parse(localStorage.getItem("inputValue"));
fetchAndRender(countryPicker.value);
countryPicker.addEventListener("input", e => fetchAndRender(e.target.value));
function fetchAndRender(value) {
if (value.toLowerCase() === "poland".toLowerCase()) {
country = "PL";
} else if (value.toLowerCase() === "spain".toLowerCase()) {
country = "ES";
} else if (value.toLowerCase() === "germany".toLowerCase()) {
country = "DE";
} else if (value.toLowerCase() === "france".toLowerCase()) {
country = "FR";
}
localStorage.setItem("inputValue", JSON.stringify(value));
getData();
}