Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a currency converter for a gaming marketplace that I'm working on, I want the user to be able to generate the image in javascript. I'm not sure if this makes sense or not, but I have the majority of it done, I just need the images to show rather than broken image boxes
I've tried changing the path that the image is meant to be drawn from but I don't really know javascript too well
const data = [
{
currency: 'btc',
we_buy: 0.58,
we_sell: 0.77,
img_path: 'null',
icon: 'fab fa-btc'
},
{
currency: 'usd',
we_buy: 0.67,
we_sell: 0.82,
img_path: './united-states.svg',
icon: 'fas fa-dollar-sign'
},
{
currency: 'gbp',
we_buy: 0.50,
we_sell: 0.68,
img_path: './united_kingdom.svg',
icon: 'fas fa-pound-sign'
},
{
currency: 'eur',
we_buy: 0.59,
we_sell: 0.76,
img_path: './european-union.svg',
icon: 'fas fa-euro-sign'
}
];
const imagesContainer = document.getElementById("currencies");
let selectedCurrency = null;
var selectCurrency = function (index) {
const element = data[index];
selectedCurrency = data[index];
document.getElementById("currency-selected").innerHTML = `Currency selected: ${element.currency}`;
document.getElementById("data_icon").className = element.icon;
};
(() => {
for (let i = 0; i < data.length; i++) {
imagesContainer.innerHTML += `<div class="currency" onclick=selectCurrency(${i})><img id=${i} src=${data[i].img_path}></div>`;
}
selectCurrency(0);
const amount = document.getElementById("amount");
amount.onkeyup = () => {
const output_we_buy = document.getElementById("output_we_buy");
const output_we_sell = document.getElementById("output_we_sell");
if (amount.value === '') {
output_we_buy.innerHTML = 0;
output_we_sell.innerHTML = 0;
return;
}
if (!isNaN(amount.value)) {
output_we_buy.innerHTML = `${(+amount.value * selectedCurrency.we_buy).toFixed(2)}`;
output_we_sell.innerHTML = `${(+amount.value * selectedCurrency.we_sell).toFixed(2)}`;
}
}
})();
<div class="container-fluid">
<div class="currencies-container">
<div class="currencies" id="currencies">
</div>
<div class="currency-selected" id="currency-selected">
No currency selected.
</div>
<div class="output">
<div class="row">
<div class="col-6 input-group">
<input type="number" class="form-control" aria-label="Amount of GP in Millions" placeholder="Amount of GP (in millions)"
id="amount">
<div class="input-group-append">
<span class="input-group-text"><i id="data_icon"></i></span>
<span class="input-group-text" id="output_we_buy">.00</span>
<span class="input-group-text" id="output_we_sell">.00</span>
</div>
</div>
</div>
</div>
</div>
</div>
I expect images stored in my directory to be shown for the currency selection
I didn't specify the folder - rookie mistake
Related
I am building a simple javascript picture quiz for a project. I have only written the function for show question and possible answers but for some reason when i call the quiz the images aren't loading and i am getting an error re failing to load the resource. The img files work perfectly fine otherwise and i have tried both .png & .jpg and both display the same error.
I have a few elements to add in to the JS like checkAnswer and Display score but i need the images to work as they are the answer buttons.
Corresponding HTML
<section id="quiz">
<div id="quiz-question-card" class="container welcome-card shadow-lg text-dark mb-3 d-flex justify-content-center">
<div class="card-body">
<h3 class="question-title">Question</h3>
<p id="question-text"></p>
</div>
</div>
<div class="container d-flex justify-content-center">
<div id="answer-btns" class="row row-cols-1 row-cols-sm-2 row-cols-md-4">
</div>
</div>
Javascript two sample questions and answers & function;
let spQuiz = [
{
question: "What planet is closest to the Sun?",
answers: [
"../img/venus.png",
"../img/mercury.png",
"../img/mars.png",
"../img/earth.png"
],
correctAnswer: '1'
},
{
question: "Which planet has the highest mountain in our solar system, a volcano named Olympus Mons?",
answers: [
"../img/mars.png",
"../img/jupiter.png",
"../img/neptune.png",
"../img/earth.png"
],
correctAnswer: '0'
},
];
let newQuestion = 0;
function displayQuestion () {
let question = spQuiz[newQuestion];
document.getElementById("question-text").innerHTML = question.question;
let answers = question.answers;
for (let i = 0; i < answers.length; i++) {
let answer = answers[i];
let img = document.createElement("img");
img.src = answers;
img.onclick = function() {
checkAnswer(i);
};
document.getElementById("answer-btns").appendChild(img);
}
}
displayQuestion();
I am building a trivia app that loads random questions (from a series of objects I have stored in a Javascript file). Each question has four answers, 3 of them being wrong and 1 right. I am trying to get the possible answers for each question to load into the buttons. Right now all the buttons are loading the first item of the array for each question.
How is this done? I have experimented with forEach and a few other array methods, and I am thinking that the answers must be iterated over and then something with the indexes of each.
<div class="answers-container">
<button id="answers-btn-1" class="answers-btn"></button>
<button id="answers-btn-2" class="answers-btn"></button>
<button id="answers-btn-3" class="answers-btn"></button>
<button id="answers-btn-4" class="answers-btn"></button>
</div>
randomQuestion.answers.forEach(answer => {
answersButton1.innerHTML = answer.text;
answersButton2.innerHTML = answer.text;
answersButton3.innerHTML = answer.text;
answersButton4.innerHTML = answer.text;
});
Also, is there a way to consolidate the code with one answer-btn?
What I understand from your descriptions this could be a possible solution:
randomQuestions.answer.forEach((answer, index) => {
document.getElementById(`answers-btn-${index + 1}`).textContent = answer;
});
Example pure JS to control random answers list and use in buttons:
let answersUsed = [];
let answers = [
'All variables in JavaScript are object data types',
'Netscape is the software company that developed JavaScript',
'isNan function returns true if the argument is not a number',
'JavaScript is a client-side and server-side scripting language',
'Negative Infinitycan be derived by dividing negative number by zero'
];
function getRandomAnswer() {
let answerUsed = answers[Math.floor(Math.random() * answers.length)];
answersUsed.push(answerUsed);
const index = answers.indexOf(answerUsed);
if (index > -1) {
answers.splice(index, 1);
}
return answerUsed;
}
answers.forEach(answer => {
document.getElementById("answers-btn-1").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-2").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-3").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-4").innerHTML = getRandomAnswer();
});
button {
margin: 8px;
display: block;
}
<div class="answers-container">
<button id="answers-btn-1" class="answers-btn"></button>
<button id="answers-btn-2" class="answers-btn"></button>
<button id="answers-btn-3" class="answers-btn"></button>
<button id="answers-btn-4" class="answers-btn"></button>
</div>
You can do this by building a list of options and setting the innerHTML of a select element or build an input[type="radio"] for each answer.
const randomQuestion = {answers: [{text: 'one'},{text: 'two'},{text: 'three'},{text: 'four'}]}
const opts = ['<option disabled>Choose one</option>']
randomQuestion.answers.forEach(answer => {
opts.push(`<option value="${answer.text}">${answer.text}</option>`)
});
const answerSelect = document.querySelector('#answer-select')
answerSelect.innerHTML = opts.join("\n")
answerSelect.size = opts.length // shows all options
answerSelect.value = ""
const radio_opts = []
randomQuestion.answers.forEach(answer => {
radio_opts.push(`<label><input type="radio" name="answerRadio" value="${answer.text}" />${answer.text}</label>`)
});
document.querySelector('#answers-container').innerHTML = radio_opts.join("\n")
<select class="answer-select" name="answer" id="answer-select">
<option>answer</option>
</select>
<div class="answers-container" id="answers-container">
<input type="radio" name="answerRadio">
</div>
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 10 months ago.
Improve this question
I am working on a simple "Green Light, Red light" game using Angular, and I am storing players with their score and maxScore using localStorage.
I can already read each property from the array stored in the localStorage, but now I am stuck on modifying those values once I click a button.
This is the test array I am currently working with:
[{"name":"test1","score":3,"maxScore":8},{"name":"test2","score":10,"maxScore":22}]
This array is stored with a single key named "players", so it is an array of players.
My component looks like this:
game.component.ts
export class GameComponentComponent implements OnInit {
highScoreLS: number = this.getHighScoreData();
scoreLS: number = this.getScoreData();
highScore: number = 0;
score: number = 0;
state: string = 'RUN';
faArrowRightFromBracket = faArrowRightFromBracket;
faShoePrints = faShoePrints;
constructor() {}
ngOnInit(): void {}
addPoint() {
this.score++;
if (this.score > this.highScore) {
this.highScore = this.score;
}
this.changeHighScore();
this.changeScore();
}
removePoint() {
this.score--;
if (this.score < 0) {
this.score = 0;
}
this.changeHighScore();
this.changeScore();
}
changeState() {
if (this.state === 'RUN') {
this.state = 'PAUSE';
} else {
this.state = 'RUN';
}
}
getScoreData() {
let localStorageItem = JSON.parse(localStorage.getItem('players') || '[]');
let item = localStorageItem.find(
(item: { name: string }) => item.name === 'test1'
);
let sc = item.score;
return sc;
}
getHighScoreData() {
let localStorageItem = JSON.parse(localStorage.getItem('players') || '[]');
let item = localStorageItem.find(
(item: { name: string }) => item.name === 'test1'
);
let hs = item.maxScore;
return hs;
}
changeHighScore() {
let localStorageItem = JSON.parse(localStorage.getItem('players') || '[]');
let item = localStorageItem.find(
(item: { name: string }) => item.name === 'test1'
);
item.maxScore = this.highScore;
localStorage.setItem('players', JSON.stringify(item));
}
changeScore() {
let localStorageItem = JSON.parse(localStorage.getItem('players') || '[]');
let item = localStorageItem.find(
(item: { name: string }) => item.name === 'test1'
);
item.score = this.score;
localStorage.setItem('players', JSON.stringify(item));
}
}
And the html looks like this:
game.component.html
<div class="navbar navbar-dark bg-dark">
<div class="container">
<h2>Hi! 👋</h2>
<a class="navbar-brand" routerLink=""
><fa-icon [icon]="faArrowRightFromBracket"></fa-icon
></a>
</div>
</div>
<div class="container flex vh-100">
<div class="row m-3">
<h3>HIGH SCORE: {{ highScoreLS }}</h3>
</div>
<div class="row m-3">
<div class="card p-3">
<h3>{{ state }}</h3>
</div>
</div>
<div class="row m-3">
<h3>SCORE: {{ scoreLS }}</h3>
</div>
<div class="row m-3">
<div class="col">
<button class="btn btn-outline-success" (click)="addPoint()">
<fa-icon [icon]="faShoePrints"></fa-icon>
Left
</button>
<button class="btn btn-outline-success" (click)="removePoint()">
Right
<fa-icon [icon]="faShoePrints"></fa-icon>
</button>
</div>
</div>
</div>
The problem is, when I click the button to add or remove a point, it deletes the whole array of players, and creates a new one like the following:
{"name":"test1","score":0,"maxScore":1}
I have been working for a couple of days with localStorage so I do not know exactly what I am missing or what I am doing wrong.
My idea is to edit those values, score and maxScore, but I can't figure it out how.
EDIT
The first time I click on add a point, it edits only the maxScore, but once. The next time I click, it gives me this error:
ERROR TypeError: localStorageItem.find is not a function
at GameComponentComponent.changeScore (game-component.component.ts:83:33)
at GameComponentComponent.addPoint (game-component.component.ts:34:10)
You're calling localStorage.setItem with just the single item and not the whole array so every subsequent "finds" you're trying will fail.
Try this instead:
localStorage.setItem('players', JSON.stringify(localStorageItem));
Though I have to say, there's loads of duplicate code in just that one component. You should read some articles on data structures and state management.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have an html element like this,
<div class='myparent'>
<div>
<div class="pdp-product-price">
<span> 650 rupees</span>
<div class="origin-block">
<span> 1,500 rupees</span>
<span>-57%</span>
</div>
</div>
</div>
</div>
I need to create a json of this 'myparent' div.
{
"div": {
"div": {
"div": {
"span": {},
"div": {
"span": {},
"span": {}
}
}
}
}
}
Is there a way to do this in javascript?
You can use children property of HTMLElement
Then iterate over parent recursively and get subtree.
But be aware that you cannot assign two values with the same key. Therefore, you can use an index when assigning subtree like
"div": {
"span_1": {},
"span_2": {},
}
Hope the below snippet will give you a clue.
const parent = document.getElementById('parent')
const tree = {};
const getTree = (elem) => {
const subtree = {};
for(let child of elem.children){
subtree[child.tagName.toLowerCase()] = getTree(child)
}
return subtree;
}
tree[parent.tagName.toLowerCase()] = getTree(parent);
console.log(tree);
<div id="parent" class='myparent'>
<div>
<div class="pdp-product-price">
<span> 650 rupees</span>
<div class="origin-block">
<span> 1,500 rupees</span>
<span>-57%</span>
</div>
</div>
</div>
</div>
Recursive function that builds the json. To ensure no issues with the keys (that have a possibility to be duplicates) the following was added :n where n is the index of the element.
function htmlToObject(targetElement) {
return Array
.from(targetElement.children)
.reduce((acc, cur, i) => {
acc[`${cur.tagName}:${i}`.toLowerCase()] = htmlToObject(cur);
return acc;
}, {});
}
const startElement = document.getElementsByClassName("myparent")[0];
const res = {
[startElement.tagName.toLowerCase()]: htmlToObject(startElement)
};
console.log(res);
<div class='myparent'>
<div>
<div class="pdp-product-price">
<span> 650 rupees</span>
<div class="origin-block">
<span> 1,500 rupees</span>
<span>-57%</span>
</div>
</div>
</div>
</div>
I am working on a browser game. I have lots of upgrades, crafting, planets, etc that I generate with jS (1 box (or square?) PER EACH item). Here is a mini snippet from my game, displaying my current method of generating HTML
JSFiddle example
I do a simple loop and insert as many boxes as there are upgrades
for(i = 0; i < 9; i ++)
Then, I put a gigantic HTML code block in a function, and use arrays to identify upgrades ID, name, info...
Is this a good practice to generate loads of HTML content? If not, what can I do to improve it?
Also, I started "coding" a game with one main goal to learn JS. If you have better solutions, but they include a lib (jQuery, etc) then you can post it, but I'm going pure jS here. Thanks!
-- Update --
I've been learning lots of JS in the past year. #DoXicK provided a great example a while ago but I didn't understand it then. This is the final rendering method I come up with, thanks to his examples, and I guess I'll stick with it:
JS:
const game = {};
// make our life easier
const $ = key => document.getElementById(key);
const render = (key, str) => $(key).insertAdjacentHTML("beforeend", str);
// a function that returns upgrades html content
const html = self => `
<div class="some-class" id="${self.id}">
<h2>${self.name}</h2>
<p>${self.damage}</p>
</div>
`;
// object containing each upgrades template
const template = {
laserGun: {
id: "laserGun",
name: "Laser Gun",
damage: 10
},
plasmaGun: {
id: "plasmaGun",
name: "Plasma Gun",
damage: 30
}
};
// Upgrade class
class Upgrade {
constructor(upg) {
this._id = upg.id;
this._name = upg.name;
this._damage = upg.damage;
}
get id() {return this._id;}
get name() {return this._name;}
get damage() {return this._damage;}
generate() {
// find div with upgrade id, and inject it's html content inside
render("upgrade", html(this));
}
static make(key) {
game.upgrade[key] = new Upgrade(template[key]);
game.upgrade[key].generate();
}
}
let laserGun = Upgrade.make("laserGun");
HTML:
<div class="upgrade-container" id="upgrade">
I hope you find it helpful!
As i already explained in comments, your code will become quite unmaintainable if you keep it as spaghetti code like that.
I've made an updated example which does the exact same thing as you did, just with a bit of updated javascript and by making a javascript-component out of your "template".
https://jsfiddle.net/7L8e5kmg/3/
class UpgradeBlock {
constructor(props) {
this.props = props;
}
render() {
let { Id, Name, Info, Res } = this.props;
// basically:
// let Id = this.props.Id;
// let Name = this.props.Name;
// etc
return (`
<div class="hud-item" id="${Id}">
<img src="client/img/${Id}.png" id="${Id}Img" />
<div class="hud-tooltip f16 fwhite">
<div class="hud-tt-header-container">
<div class="hud-tt-info-container">
<div class="col-full">${Name}</div>
<div class="col-half">
<img style="vertical-align: text-bottom;" src="img/${Res}16.png" />
<span id="${Id}Cost"></span>
</div>
<div class="col-half">
+<span id="${Id}dmgPerLv"></span>
<img style="vertical-align: text-bottom;" src="client/img/character/dps16.png" />
</div>
</div>
<div class="hud-tt-lv-container">
<canvas id="${Id}Bar" width="64px" height="64px"></canvas>
</div>
</div>
<hr/>
<div class="hud-tt-info-container">
<div class="col-half fwhite f16">
<img style="vertical-align: text-bottom" src="client/img/character/dps16.png" />
<span id="${Id}Dmg"></span>
</div>
<div class="col-half fgrey f10"><span class="fwhite f16" id="${Id}ofTotal"></span> of total</div>
<div class="col-full fgrey f10">${Info}</div>
<div class="col-full f10" id="${Id}click"></div>
</div>
</div>
</div>
`)
}
}
You use it by doing:
let upgrade = {
Id: 'id',
Name: 'name',
Info: 'info',
Res: 'res'
};
let html = new UpgradeBlock(upgrade).Render()
For people that do react: yes, it is intended to steer that way.