I am looking to create a grid of 3x3 text input boxes, relative to an existing square div, using pure JavaScript. Preferably I would like to construct the grid of a single 1D array that cycles through every third box (if not, then an array of an array of input boxes would do - I hope this makes sense). This is what my code looks like at the moment, but only three of the boxes show when I cycle the array length (if I don't then the array extends linearly across beyond the div confines):
var row0 = new Array(9);
for (var i = 0; i < 9; ++i)
{
row0[i] = document.createElement('input');
row0[i].style.position = "absolute";
row0[i].type = "text";
row0[i].style.marginLeft = 35px *i % 105 + "px";
row0[i].style.width = "35px";
row0[i].style.height = "35px";
document.getElementById('block1').appendChild(row0[i]);
}
How can I get the grid to display correctly?
I would use a combination of javascript and CSS
DEMO http://jsfiddle.net/x8dSP/3010/
JS
window.onload = function () {
var parent_div = document.createElement("div")
parent_div.id = "parent"
document.body.appendChild(parent_div);
var x = 0;
while (x < 9) {
var child_input = document.createElement("input")
child_input.className = "child"
document.getElementById(parent_div.id).appendChild(child_input);
x++;
}
}
CSS
div {
width: 150px;
}
input {
display: inline-block;
width: 30px;
height: 30px;
margin: 5px;
}
Related
I'm making a simple tic tac toe game as my introduction to JS and I ran into a problem almost immediately. I have a div with the class="container", and I use JS to create 9 more div elements inside it.
I have created the div elements with and put them in the cells[] array with no problem. The problem arrises when i try to access .style from the array elements.
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) {
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} //this line is where the problem is
i++;
}
I have gone about this using addEventHandler() too, still with me not being able to access the .style property. When I type it in it doesn't show up on that autofill thing VSCode does.
Help?
Ps. I have noticed the cells[] array can't always access it's elements when inside a block.
This issue is due to how closures work in JavaScript.
Here's a demo with your current code (plus some CSS to make it clear what's happening):
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) { // actually, the problem is here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} // ...here...
i++; // ...and here
}
div:not([class]) {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
Note that the next div is always highlighted, not the one that was clicked.
Because you increment i within the block itself, that value is captured by the onclick callback, so it's always 1 higher than it should be.
Instead, you need to increment i within the parentheses as the third setup statement for the loop itself.
Here's the fix:
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9; ++i) { // increment here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function() { cells[i].style.backgroundColor = "red"; }
// ...not here
}
div {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}
.setWidth {
width: 100px;
height: 100px;
border: 1px solid black;
}
<div class="container"></div>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}
i've been trying to make a list of names. the names are inputed by enter click.
after that it should fill an array which later will be used to shuffle them.
as the enter is clicked im trying to add each array child to a styled div.
that's what i tryed so far -
var values = [];
document.getElementById("inputtext").onkeypress = function(event){
if (event.keyCode == 13 || event.which == 13){
var inp = document.getElementById('inputtext');
values.push(inp.value);
inp.value = "";
for(var i = 0; i < values.length; i += 1) {
var udiv = document.createElement("div");
udiv.className = "idiv";
udiv.innerHTML = document.getElementById("inputtext").value;
document.getElementsByClassName('addednames')[0].appendChild(udiv);
}
}
}
i'm not sure that's even the right way hope for more guidance.
thanks in advance
With inp.value = "" you are re-setting the input's value but you are trying to access the value inside the loop. Instead, you can use the array value to create the element:
var values = [];
document.getElementById("inputtext").onkeypress = function(event){
if (event.keyCode == 13 || event.which == 13){
document.getElementsByClassName('addednames')[0].innerHTML = ''; //Clear the previously created div
var inp = document.getElementById('inputtext');
values.push(inp.value);
inp.value = "";
values.sort(() => Math.random() - 0.5); //shuffle the array
for(var i = 0; i < values.length; i += 1) {
var udiv = document.createElement("div");
udiv.className = "idiv";
udiv.innerHTML = values[i];
document.getElementsByClassName('addednames')[0].appendChild(udiv);
}
}
}
.idiv{
border: 1px solid lightgray;
margin: 3px 0;
padding: 5px;
}
<input id="inputtext"/>
<div class="addednames"></div>
There are a few minor issues with your code:
-The for loop. What it'd do is every time you enter a new input, you'll get all the previous inputs appended to the div.
-Using a className to access an element. Why don't you just use an ID instead? That'd eliminate potential issues in the future if you decided to add more elements with that same class.
-Using the var keyword. Try using let instead. Here's a good post on the reason why: What's the difference between using "let" and "var"?
Other than that it's all good.
I'm trying to print an element, in my case an hr tag some number of times according to the length of a word. This code is for a hangman game I'm trying to recreate. I have looked up similar questions and its not quite what I'm lookin for.
This is my javascript code so far.
var words = ['Quaffle', 'Bludger', 'Golden Snitch', 'Time-Turner',
'Pensieve', 'Mirror of Erised'];
function getRandomWord(){
var randomIndex = words[Math.floor(Math.random()* words.length)];
alert(randomIndex);
}
function printDashes(){
var dashes = document.getElementById("dash")
}
getRandomWord()
printDashes()
I'm not sure what to add after retrieving the element. Can someone guide me on how to go about this?
You can also create div's so you can enter letters when the user inputs a character. I've attached an example below.
UPDATE: Added example code to update the dashes with letters based on word
var elem = document.getElementById('container');
var guess = document.getElementById('guess');
var word = "Hello";
// draw empty dashes
var drawDashes = function(numberOfDashes) {
for (var i = 0; i < numberOfDashes; i++) {
var el = document.createElement('div');
el.classList = 'dash';
// we draw an empty character inside so that the element
// doesn't adjust height when we update the dash later with a
// letter inside
el.innerHTML = ' ';
elem.appendChild(el);
}
}
// update dash with a letter based on index
var updateDash = function(index, letter) {
elem.children[index].innerHTML = letter;
}
guess.addEventListener('keyup', function(evt) {
// split the word up into characters
var splitWord = word.split('');
// check to see if the letter entered matches any of the
// words characters
for (var i = 0; i < splitWord.length; i++ ) {
// it is important we convert them to lowercase or
// else we might get a mismatch because of case-sensitivity
if (evt.key.toLowerCase() === splitWord[i].toLowerCase()) {
// update dash with letter based on index
updateDash(i, evt.key.toLowerCase());
}
}
// clear out the value
this.value = '';
});
drawDashes(word.length);
body {
font-family: sans-serif;
}
.dash {
height: 50px;
width: 50px;
margin: 0 10px;
display: inline-block;
border-bottom: 2px solid black;
font-size: 32px;
font-weight: bold;
text-align: center;
}
#guess {
height: 50px;
width: 50px;
padding: 0;
font-size: 32px;
text-align: center;
}
<div id="container"></div>
<h4>Type a letter</h4>
<input id="guess" type="text"/>
Say your word is in some variable named myWord.
Get the length of the word by doing:
var myWordLen = myWord.length;
Then you can create HTML elements using Javascript createElement method and appending child elements, information etc as needed. But since you want as many elements as the length of a word, use a loop. Eg:
for(var i=0; i < myWordLen; i++)
{
var tr1 = document.createElement("hr");
var someEle = document.getElementById("someID");
someEle.appendChild(tr1);
}
What about this way?
myElement.innerHTML = `<...>`.repeat(words.length)
Problem
I tried to randomly generate the position of two images( the images of the characters) in a table td, but sometimes they wouldn't show. One of them or both would just disappear. Try to loading more times (from 1 to 5) the pen to let the bug occur.
Pen
Here is all the code: penHere
Interested functions
How the table\map is building?
it's a 2d array random generated, something like this:
map = [[1,1,1,1,0],
[1,0,0,0,0],
[1,0,1,1,1],
[1,0,0,0,1],
[1,1,1,0,1]]
After I build the map in the table with this one:
function mapGenerate(map){
//loop the 2d array map and change the number with the appropriate img
for(var i = 0; i < map.length; i++) {
var innerArrayLength = map[i].length;
for(var j = 0; j<innerArrayLength; j++){
if(map[i][j] === 0){
map[i][j]="<div class=\"tile\"><img class=\"walkable\" src=\"https://image.ibb.co/bGanFz/floor_Resized.png\"></div>";
}else{
map[i][j]="<img class=\"nonWalkable\" src=\"https://image.ibb.co/m9s1az/volcanoresize.png\">";
}
;
}
$("#tableGame").append("<tr><td>"+ map[i].join('</td><td>') + "</td></tr>")
}
}
with the function below i select the coordinate ( they are corrects, i check it several times in the console)
function placeCharAndItem(char){
let rowCoord= mapA.length;
let cellCoord = mapA[1].length;
//this object is to save 2 random number, the row and the cell
let coord={
row: Math.floor(Math.random() * rowCoord),
cell: Math.floor(Math.random() * cellCoord)
};
//I need this 2 variables to check if the tiles is a correct one
let toCheck = mapA[coord.row][coord.cell];
let check= toCheck.search('nonWalkable');
//if it's not correct(you found the sub-string "non-
//walkable"), this while loop have to generate random new
//coordinates.
while(check != -1){
coord.row=Math.floor(Math.random() * rowCoord);
coord.cell=Math.floor(Math.random() * cellCoord);
toCheck = mapA[coord.row][coord.cell];
check= toCheck.search('nonWalkable');
};
place(coord, char);
};
and finally, after i have 2 valid coordinates i can show the character:
function place(coord, char){
console.log('sei entrato nella funzione place');
var charImage = $("<img>").attr("src", char.image).addClass('char');
var row = $($("#tableGame tr")[coord.row]);
var cell = $($("td", row)[coord.cell]);
var tile = $($(".tile", row)[coord.cell]);
tile.prepend(charImage);
};
these are the css regarding the table and the image char:
#tableGame .td{
position: relative;
}
.char{
z-index: 1000;
}
#tableGame .char {
position: absolute;
}
table{
background-color: black;
border-collapse: collapse;
border: 2px solid white;
box-shadow: 1px 1px 30px white;
}
tr{
border: 0px;
padding: 0px;
margin:0px;
}
td{
border: 0px;
padding: 0px;
margin:0px;
}
I don't understand why sometimes one or both of the images, disappear, any kind of help will be really appreciated.
Assume the map =
[[1,1,1,1,0],
[1,0,0,0,0],
[1,0,1,1,1],
[1,0,0,0,1],
[1,1,1,0,1]]
and coord.row = 0, coord.cell = 4, then $(".tile", row) would be a jQuery object within only 1 .tile. It would set tile to undifined and won't prepend the image.
function place(coord, char){
console.log('sei entrato nella funzione place');
var charImage = $("<img>").attr("src", char.image).addClass('char');
var row = $($("#tableGame tr")[coord.row]);
var cell = $($("td", row)[coord.cell]);
var tile = $($(".tile", row)[coord.cell]);
tile.prepend(charImage);
};
So I think you can replace var tile = $($(".tile", row)[coord.cell]); with var tile = $(".tile", cell);.
function place(coord, char){
console.log('sei entrato nella funzione place');
var charImage = $("<img>").attr("src", char.image).addClass('char');
var row = $($("#tableGame tr")[coord.row]);
var cell = $($("td", row)[coord.cell]);
// will out of bounds if the coord.cell is greater than the jQuery object $(".tile", row)
// var tile = $($(".tile", row)[coord.cell]);
var tile = $(".tile", cell);
tile.prepend(charImage);
};
Fairly new to Javascript and trying a more complex script (to me, anyway).
The end-game for this script is the following:
Element tagged with onclick=(runscript) will prompt script to load a text file of site names/links, separated by commas.
Script loads text file into an array.
First loop iterates through array, separating the main array into two new arrays based on even/odd array position. (ex. Site name is 0, link is 1, name is 2, link is 3, etc.)
Second loop iterates through the site name array, creating a new div element for each value in the array.
Second loop also creates new anchor element, appending it to the div element.
Second loop sets div's class, anchor's href, and appends the new div to a container div.
I feel like I'm making a few noob mistakes and my lack of exposure to Javascript is keeping me from seeing them. I cut out the first two steps to test steps 3-6 instead.
This is what I've managed to come up with so far.. any nudge in the right direction would be awesome.
Thanks!
var main = ["Google", "http://google.com", 'Gmail', 'http://gmail.com', 'Hotmail', 'http://hotmail.com', 'Battle.net', 'http://battle.net', 'Steam', 'http://steampowered.com'];
function getSites() {
var site = new Array();
var link = new Array();
for (var i = 0; i <= main.length; i++) {
if (i % 2 == 0) {
link.push(main[i]);
} else {
site.push(main[i]);
}
}
for ($i = 1; i <= site.length; i++) {
var divElement = document.createElement("div");
var anchorElement = document.createElement("a");
divElement.appendChild(anchorElement);
divElement.className = "boxin";
anchorElement.href = link[i];
divElement.innerHTML = (site[i]);
linkContainer.appendChild(divElement);
}
}
getSites();
boxin {
height: 20px;
background-color: green;
}
#linkContainer div
{
border:solid 1px black;
margin:5px;
}
<div id="linkContainer"></div>
You have a bug in the second iteration, you are initializing a new variable $i, but the condition is checking for i<=site.length which will be false since the value of i is updated to main.length at the end of the first loop
But you really don't need to use 2 loop to solve the problem, you can use a single loop as below. Also you need to set the label text as the content of anchor element not of the div
var main = ["Google", "http://google.com", 'Gmail', 'http://gmail.com', 'Hotmail', 'http://hotmail.com', 'Battle.net', 'http://battle.net', 'Steam', 'http://steampowered.com'];
function getSites() {
for (var i = 0; i < main.length; i += 2) {
var divElement = document.createElement("div");
var anchorElement = document.createElement("a");
divElement.appendChild(anchorElement);
divElement.className = "boxin";
anchorElement.href = main[i + 1];
anchorElement.innerHTML = (main[i]);
linkContainer.appendChild(divElement);
}
}
getSites();
boxin {
height: 20px;
background-color: green;
}
#linkContainer div {
border: solid 1px black;
margin: 5px;
}
<div id="linkContainer"></div>
Do you really need them to be in an array? I think an object would work much better.
var sites = {
"Google": "http://google.co.uk",
"Gmail": "http://gmail.com"
};
Then you could loop through the object and achieve what you wanted.
Try it : i'm change your code little bit... below code 100% workable...
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="../js/jquery-1.7.1.min.js"></script>
<style type="text/css">
boxin {
height: 20px;
background-color: green;
}
#linkContainer div {
border: solid 1px black;
margin: 5px;
}
</style>
</head>
<body>
<div>
<div id="linkContainer"></div>
</div>
<script type="text/javascript">
var main = ["Google", "http://google.com", 'Gmail', 'http://gmail.com', 'Hotmail', 'http://hotmail.com', 'Battle.net', 'http://battle.net', 'Steam', 'http://steampowered.com'];
function getSites() {
var site = new Array();
var link = new Array();
for (var i = 0; i <= main.length; i++) {
if (i % 2 == 0) {
link.push(main[i]);
} else {
site.push(main[i]);
}
}
for (var i = 0; i < site.length; i++) {
var divElement = document.createElement("div");
var anchorElement = document.createElement("a");
divElement.appendChild(anchorElement);
divElement.className = "boxin";
anchorElement.href = link[i];
divElement.innerHTML = (site[i]);
document.getElementById("linkContainer").appendChild(divElement);
}
}
getSites();
</script>
</body>
</html>