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.
Related
I am a beginner in JavaScript and I can't figure out the following problem: I am trying to create a simple JavaScript Movie List. I have 10 lists on the Movie List. I tried to show all of the lists with for loop, but it doesn't work.
Here's the code:
function renderModal() {
for (let i = 0; i < listMovies.length; i++) {
let movieData = listMovies[i];
document.getElementById("poster").src = movieData.img;
document.getElementById("title").innerHTML = movieData.name;
document.getElementById("genre").innerHTML = movieData.genre;
document.getElementById("rating-num").innerHTML = "Rating: "+ movieData.rating + "/10";
document.getElementById("movie-desc").innerHTML = movieData.desc;
document.getElementById("imdb-page").href = movieData.link;
return movieData;
}
}
What do I have to do?
Help me to fix it!.
You can use template tag for list and render it into target element.I am showing an example.
Movie list
<div id="movieList"></div>
template for list
<template id="movieListTemplate">
<div class="movie">
<img src="" class="poster" alt="">
<div class="title"></div>
<div class="genre"></div>
<div class="rating-num"></div>
<div class="movie-desc"></div>
<div class="imdb-page"></div>
</div>
</template>
Javascript code:
if (listMovies.length > 0) {
const movileListTemplate = document.getElementById('movieListTemplate')
const movieRenederElement = document.getElementById('movieList')
for(const movie of listMovies) {
const movieEl = document.importNode(movileListTemplate.content, true)
movieEl.querySelector('.poster').src = movie.img
movieEl.querySelector('.title').textContent = movie.name
//use all queryselector like above
}
}
Your return movieData; will stop the loop dead. Not that running it more than once will change anything since you change the same elements over and over. IDs must be unique.
Here is a useful way to render an array
document.getElementById("container").innerHTML = listMovies.map(movieData => `<img src="${movieData.img}" />
<h3>${movieData.name}</h3>
<p>${movieData.genre}</p>
<p>Rating: ${movieData.rating}/10</p>
<p>${movieData.desc}
IMDB
</p>`).join("<hr/>");
With return movieData, the for loop will ends in advance.You should put it outside the for loop.
I have been trying to display JSON data from one page to another on click using local storage.
For example, a user clicks on an specific image of a book which then takes them to book.html where the image and the name of the book is shown (from the json file)
FIGMA PROTOTYPE - https://www.figma.com/proto/VAFgj0JQVX0YLt3WyZ12el/Untitled?node-id=5%3A5&scaling=min-zoom
script.js
const petsData = [{
name: "Story Book",
species: "Jean Lumier", //THIS IS THE JSON FILE
photo: "a.jpg"
},
{
name: "Barksalot",
species: "Dog",
href:"href.img,
photo: "https://learnwebcode.github.io/json-example/images/dog-1.jpg"
},
];
function petTemplate(pet) {
return `
<div class ="image-grid">
<div class="animal">
<img class="pet-photo " src="${pet.photo}" >
<div class="olay" onclick="location.href='${pet.href}';" style="cursor: pointer;">
<div id="mydiv">
<h2 class="pet-name">${pet.name}
<h1 class="species">${pet.species}
</div>
<div></div></div>
</div>
</div>
`;
}
Thank you.
I set this up as a one page demo: https://stackblitz.com/edit/web-platform-uzc5rj
Since your JSON does not have IDs, you can reference the position in the array in your book.html link. Like this:
<a href='book.html?book=1'><img of book /></a>
Then in book.html
<div id='book_details'></div>
<script>
let bookData = localStorage.getItem('bookData');
bookData = JSON.parse(bookData)
const urlParams = new URLSearchParams(window.location.search);
const bookPos = urlParams.get('book');
let book = bookData[bookPos]
let bookHtml = `
<div class ="book-html">
<h1>${book.name} </h1>
<p>${book.species} </p>
</div>
`;
document.getElementById('book_details').innerHTML = bookHtml;
</script>
so im making this web app with api from https://www.football-data.org/
so i make the template for the api content with the dom. but there's one part that are not being shown
function showStanding(data) {
let standings = ``;
const standingElement = document.getElementById("standings");
/* Jika dilihat melalui console.log, seharusnya kakak me looping data.standings[0].table, karena
disitulah object team berada
*/
data.standings[0].table.forEach((standing) => {
console.log(standing);
standings += `
<div class="standing__team">
<div class="favtim">
<img src="${standing.team.crestUrl.replace(
/^http:\/\//i, 'https://')}" alt="Logo team" />
<h3><a class="link" href="#team?id=${standing.team.id}">${standing.team.name}</a></h3>
<h3 class="point">Point: <span>${standing.points}</span></h3>
</div>
</div>
`;
});
// di line ke 23 dan 24 seharusnya competition, bukan competitions
standingElement.innerHTML = `
<div class="standing__header blue lighten-3">
<h1>${data.competition.name}</h1>
<p class="standing__header--place">${data.competition.area.name}</p>
<p class="standing__header--time">${data.season.startDate} - ${data.season.endDate}</p>
</div>
`;
document.querySelectorAll(".link").forEach(function (link) {
link.addEventListener("click", function (e) {
urlTeamParam = e.target.getAttribute("href").substr(9);
loadpage();
});
});
}
so this is the code for the templating the api
the result
so in the result there are a element which is base on the url. but there's one part that are not showing
so i tried to console.log() it and it appear on the console. how can i show it in the browser window?
the console
can you help me how to solve this problem?
I am new in Unit Test JS. I want create test in jasmine. I dynamically create element HTML in JS.
data.map((channel) => {
const { url, width, height } = channel.thumbnails.medium;
const { title, customUrl } = channel;
const { subscriberCount, videoCount, viewCount } = channel.statistics;
output += `
<li class="channel-wrraper">
<a href='${customUrl}' target="_blank">
<img src='${url}' alt="img-channel" height='${width}' width='${height}' class="channel-img">
</a>
<p class="channel-title">${title}</p>
<div class="channel-statistic">
<div class="statistic-wrraper">
<span class="statistic-name">subscribers:</span>
<span class="subscirber-count">${formatNumber(subscriberCount)}</span>
</div>
<div class="statistic-wrraper">
<span class="statistic-name">videos:</span>
<span class="video-count">${formatNumber(videoCount)}</span>
</div>
<div class="statistic-wrraper">
<span class="statistic-name">views:</span>
<span class="veiw-count">${formatNumber(viewCount)}</span>
</div>
</div>
</li>`
});
channelsList.innerHTML = output;
Then some element will be ordered. This is sort function:
const list = document.querySelector('.channels-list');
const sortNumber = (selector) => {
[...list.children]
.sort((a,b) => a.querySelector(selector).innerText.replace(/,/g, '') - b.querySelector(selector).innerText.replace(/,/g, ''))
.map(node => list.appendChild(node))
}
I read about JSDOM and I watched the tutorials in which they tested the DOM, however, these elements were in the html file...
I want test function sortNumber
But I don`t know how start this task..
You can try using jsdom-global, then you will have document.body setup for you:
require('jsdom-global')()
// you can now use the DOM
document.body.innerHTML = 'put your html here'
An alternative will be to use jest, which comes with JSDOM configured as default
There's a page with some HTML as follows:
<dd id="fc-gtag-VARIABLENAMEONE" class="fc-content-panel fc-friend">
Then further down the page, the code will repeat with, for example:
<dd id="fc-gtag-VARIABLENAMETWO" class="fc-content-panel fc-friend">
How do I access these elements using an external script?
I can't seem to use document.getElementByID correctly in this instance. Basically, I want to search the whole page using oIE (InternetExplorer.Application Object) created with VBScript and pull through every line (specifically VARIABLENAME(one/two/etc)) that looks like the above two into an array.
I've researched the Javascript and through trial and error haven't gotten anywhere with this specific page, mainly because there's no tag name, and the tag ID always changes at the end. Can someone help? :)
EDIT: I've attempted to use the Javascript provided as an answer to get results, however nothing seems to happen when applied to my page. I think the tag is ALSO in a tag so it's getting complicated - here's a major part of the code from the webpage I will be scanning.
<dd id="fc-gtag-INDIAN701" class="fc-content-panel fc-friend">
<div class="fc-pic">
<img src="http://image.xboxlive.com/global/t.58570942/tile/0/20400" alt="INDIAN701"/>
</div>
<div class="fc-stats">
<div class="fc-gtag">
<a class="fc-gtag-link" href='/en-US/MyXbox/Profile?gamertag=INDIAN701'>INDIAN701</a>
<div class="fc-gscore-icon">3690</div>
</div>
<div class="fc-presence-text">Last seen 9 hours ago playing Halo 3</div>
</div>
<div class="fc-actions">
<div class="fc-icon-actions">
<div class="fc-block">
<span class="fc-buttonlabel">Block User</span>
</div>
</div>
<div class="fc-text-actions">
<div class="fc-action"> </div>
<span class="fc-action">
View Profile
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Compare Games
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Send Message
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Send Friend Request
</span>
</div>
</div>
</dd>
This then REPEATS, with a different username (the above username is INDIAN701).
I tried the following but clicking the button doesn't yield any results:
<script language="vbscript">
Sub window_onLoad
Set oIE = CreateObject("InternetExplorer.Application")
oIE.visible = True
oIE.navigate "http://live.xbox.com/en-US/friendcenter/RecentPlayers?Length=12"
End Sub
</script>
<script type="text/javascript">
var getem = function () {
var nodes = oIE.document.getElementsByTagName('dd'),
a = [];
for (i in nodes) {
(nodes[i].id) && (nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i]));
}
alert(a[0].id);
alert(a[1].id);
}
</script>
<body>
<input type="BUTTON" value="Try" onClick="getem()">
</body>
Basically I'm trying to get a list of usernames from the recent players list (I was hoping I wouldn't have to explain this though :) ).
var getem = function () {
var nodes = document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i].id.split('-')[2]));
}
alert(a[0]);
};
please try it by clicking here!
var getem = function () {
var nodes = document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i]));
}
alert(a[0].id);
alert(a[1].id);
};
try it out on jsbin
<body>
<script type="text/javascript">
window.onload = function () {
var outputSpan = document.getElementById('outputSpan'),
iFrame = frames['subjectIFrame'];
iFrame.document.location.href = 'http://live.xbox.com/en-US/friendcenter/RecentPlayers?Length=1';
(function () {
var nodes = iFrame.document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i].id.split('-')[2]));
}
for (var j in a) if (a.hasOwnProperty(j)) {
outputSpan.innerHTML += (a[j] + '<br />');
}
})();
};
</script>
<span id="outputSpan"></span>
<iframe id="subjectIFrame" frameborder="0" height="100" width="100" />
</body>
What does "I can't seem to use document.getElementsByID correctly in this instance" mean? Are you referring to the fact that you are misspelling getElementByID?
So...something like this (jQuery)?
var els = [];
$('.fc-content-panel.fc-friend').each(function() {
els.push(this));
});
Now you have an array of all the elements that have both of those classes.