Need help adjusting the grid size based on user input - javascript

Need help!
simply put I am creating a grid that is x * x. the "x" variable is going to be whatever the user inputs.
Where I am struggling is I need be able to click a button and have a prompt widow come up, collect the number the user enters, and then use that number as an argument for a function I created to build the grid.
As you can probably tell by my question, I am fairly new to coding. So the simpler the solution the better for me to understand.
Thanks a ton!
const div = document.querySelector('#container')
const clearButton = document.querySelector('.button-clear');
const resizeButton = document.querySelector('.button-resize')
createGrid = gridNumber => {
if (gridNumber === undefined) {
gridNumber = 16;
} else gridNumber = gridNumber;
let gridSize = gridNumber * gridNumber;
for (i = 0; i < gridSize; i++) {
let squares = document.createElement('div');
squares.classList.add('squares');
div.style.gridTemplateRows = `repeat(${gridNumber}, 1fr)`;
div.style.gridTemplateColumns = `repeat(${gridNumber}, 1fr)`;
div.appendChild(squares);
}
let boxes = document.querySelectorAll('.squares');
boxes.forEach(box => box.addEventListener('mouseover', () => {
box.style.backgroundColor = "gray";
}));
}
resetGrid = () => {
let boxes = document.querySelectorAll('.squares');
boxes.forEach(box => {
box.style.backgroundColor = 'white';
})
}
createGrid();
clearButton.addEventListener('click', resetGrid);

Just prompt for the value and call the function again. Check for undefined in case user didn't enter anything.
const div = document.querySelector('#container')
const clearButton = document.querySelector('.button-clear');
const resizeButton = document.querySelector('.button-resize')
createGrid = gridNumber => {
if (gridNumber === undefined) {
gridNumber = 16;
} else gridNumber = gridNumber;
let gridSize = gridNumber * gridNumber;
for (i = 0; i < gridSize; i++) {
let squares = document.createElement('div');
squares.classList.add('squares');
div.style.gridTemplateRows = `repeat(${gridNumber}, 1fr)`;
div.style.gridTemplateColumns = `repeat(${gridNumber}, 1fr)`;
div.appendChild(squares);
}
let boxes = document.querySelectorAll('.squares');
boxes.forEach(box => box.addEventListener('mouseover', () => {
box.style.backgroundColor = "gray";
}));
}
resetGrid = () => {
let boxes = document.querySelectorAll('.squares');
boxes.forEach(box => {
box.style.backgroundColor = 'white';
})
}
createGrid(4);
clearButton.addEventListener('click', resetGrid);
resizeButton.addEventListener('click', function() {
var value = prompt("enter size: ", 16);
if (typeof value === 'undefined') {
return
}
createGrid(value)
});
.squares {
border: 1px solid black;
width: 20px;
height: 20px;
float: left;
}
<div id="container">
</div>
<button class="button-clear">clear</button>
<button class="button-resize">resize</button>

Related

Javascript and Google Sheet - Display only one element of array

I'm learning javascript, hence my question might be a bit silly/simple.
Following a tutorial on Udemy, I was able to display a spreadsheet from Google Sheet in my website, using javascript to retrieve all rows contained in the document and pass them to a container in an HTML page.
This is great.
Now I would like to visualise only one row at a time, at a specific interval.
After some search I realised I can do this by using getElementById in conjunction with .innerHTML within a loop but I can't figure out what I am supposed to pass and where.
So, here is the HTML I'm using
<!DOCTYPE html>
<html><head><title>Testing Data from Sheets</title></head>
<body>
<div class="output"></div>
<script src="sheets.js"></script>
</body>
</html>
And here is the JS
const sheetID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const base = `https://docs.google.com/spreadsheets/d/${sheetID}/gviz/tq?`;
const sheetName = 'quotes';
let qu = 'Select D';
const query = encodeURIComponent(qu);
const url = `${base}&sheet=${sheetName}&tq=${query}`;
const data = [];
document.addEventListener('DOMContentLoaded', init);
const output = document.querySelector('.output');
function init() {
console.log('ready');
fetch(url)
.then(res => res.text())
.then(rep => {
//console.log(rep);
const jsData = JSON.parse(rep.substr(47).slice(0, -2));
console.log(jsData);
const colz = [];
jsData.table.cols.forEach((heading) => {
if (heading.label) {
colz.push(heading.label.toLowerCase().replace(/\s/g, ''));
}
})
jsData.table.rows.forEach((main) => {
//console.log(main);
const row = {};
colz.forEach((ele, ind) => {
//console.log(ele);
row[ele] = (main.c[ind] != null) ? main.c[ind].v : '';
})
data.push(row);
})
maker(data);
})
}
function maker(json) {
const div = document.createElement('div');
div.style.display = 'grid';
output.append(div);
let first = true;
json.forEach((el) => {
//console.log(ele);
const keys = Object.keys(el);
div.style.gridTemplateColumns = `repeat (${keys.length} ,'1fr')`;
if (first) {
first = false;
keys.forEach((heading) => {
const ele = document.createElement('div');
//ele.textContent = heading.toLocaleUpperCase();
ele.style.background = 'black';
ele.style.color = 'white';
ele.style.fontFamily = 'Helvetica';
div.append(ele);
})
}
keys.forEach((key) => {
const ele = document.createElement('div');
//ele.style.border = '1px solid #ddd';
ele.textContent = el[key];
ele.style.background = 'black';
ele.style.color = 'white';
ele.style.fontFamily = 'Helvetica';
div.append(ele);
})
console.log(keys);
})
}
Thanks heaps for helping!
I tried using the following from other messages I've found on the forum:
var i = 0; // the index of the current item to show
setInterval(function() { // setInterval makes it run repeatedly
document
.getElementById('output')
.innerHTML = jsData[i++];
if (i == jsData.length) i = 0;
}, 1000);

Don't know how to reload window and have different output -Modifying DOM

I have a simple HTML document of three pictures like this-
Now I need to modify the code so that the deleting of images
starts from the beginning, reload the page, and the result like-
Here is code:
export default () => {
const button = document.querySelector('#b1');
const listener = e => {
const images = document.getElementsByTagName('img');
// for(let i = 0; i <= images.length; i++) {
for(let i = images.length - 1; i >= 0; i--) {
const image = images[i];
if(image.alt) {
let text = document.createTextNode(image.alt);
image.parentNode.replaceChild(text, image);
}
}
const style = `
color: yellow;
border: 2px solid yellow;
`;
button.setAttribute('style', style);
button.style.backgroundColor = 'red';
button.disabled = true;
button.textContent = 'Disabled';
};
// button.onclick = listener;
button.addEventListener('click', listener);
};
Does anybody know what to do?
I tried
for(let i = images.length - 1; i >= 0; **i=i-2**) {
const image = images[i];
if(image.alt) {
let text = document.createTextNode(image.alt);
image.parentNode.replaceChild(text, image);
}
}
And I get the desired look(like in the resulting picture), but I need to reload the page and get the output as shown in the resulting picture.

Input value does not replace global scope

Input value does not replace global scope. I'm trying to have a default number on a variable. I would like to enter a number into an input on the browser and then update that variable.
// VARIABLES
const container = document.querySelector('.container');
const unsplashURL = 'https://source.unsplash.com/random/';
let rows = 3
const input = document.querySelector('#number')
const button = document.querySelector('.button')
for (let i = 0; i < rows * 3; i++) {
const img = document.createElement('img')
img.src = `${ unsplashURL }${ getRandomSize() }`
container.appendChild(img)
}
button.addEventListener('click', (e) => {
e.preventDefault()
let rows = input.value
input.value = ''
})
// FUNCTIONS
function getRandomSize() {
return `${ getRandomNr() }x${ getRandomNr() }`
}
function getRandomNr() {
return Math.floor(Math.random() * 11) + 300
}
#phil_Hinch, here are the problems you have.
JavaScript code is not re-running automatically. You need to define function like setupGrid and call this function every time after you update rows.
On button click listener, you wrote let rows = input.value. Which means new variable rows declared for that code block. This will not update let rows = 3. You need to remove let to update global rows.
Please check following example
// VARIABLES
const container = document.querySelector('.container');
const unsplashURL = 'https://source.unsplash.com/random/';
let rows = 3
const input = document.querySelector('#number')
const button = document.querySelector('.button')
function setupGrid() {
container.innerHTML = ''
for (let i = 0; i < rows * 3; i++) {
const img = document.createElement('img')
img.src = `${ unsplashURL }${ getRandomSize() }`
container.appendChild(img)
}
}
button.addEventListener('click', (e) => {
e.preventDefault()
rows = input.value
input.value = ''
setupGrid()
})
// FUNCTIONS
function getRandomSize() {
return `${ getRandomNr() }x${ getRandomNr() }`
}
function getRandomNr() {
return Math.floor(Math.random() * 11) + 300
}
setupGrid();
.container {
width: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 1rem;
}
.container img {
width: 80%;
}
<div class="container">
</div>
<input id="number" type="number" />
<button class="button">update</button>

next and prev button functionality with pagination

I want to add to my pagination the next and prev button functionality so i can also move the pages through them. in my code i only manage to display the next or prev page and see the content from the second page on click but without also moving the selected number of the button from 1 to 2, or the next page if there are more and so on. same for the prev. also, if i cannot go next/prev i want to have the next/prev button disabled.
any help with this, please?
here is what i have till now:
window.onload = function(){
var data = {
"headings": {
"propBook": "Book",
"propAuthor": "Author",
"propYear": "Year",
},
"items": [{
"fields": {
"propBook": "The Great Gatsby",
"propAuthor": "F Scott Fitzgerald",
"propYear": "1925",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
},
{
"fields": {
"propBook": "The Grapes of Wrath",
"propAuthor": "John Steinbeck",
"propYear": "1939",
},
"button": {
"name": "View book",
"propURL": ""
}
},
{
"fields": {
"propBook": "A Wild Sheep Chase",
"propAuthor": "Haruki Murakami",
"propYear": "1982",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
}
]
}
const HEADINGS = data.headings;
const ITEMS = data.items;
const TABLE_WRAPPER = document.querySelector('.book-component .table-wrapper');
const TABLE = document.createElement('table');
TABLE.setAttribute('class', 'pagination');
TABLE.setAttribute('data-pagecount', 2);
TABLE_WRAPPER.appendChild(TABLE);
for (const field in data) {
const TABLE_ROW = document.createElement('tr');
TABLE_ROW.setAttribute('id', 'myRow');
if (field == 'headings') {
for (const child in HEADINGS) {
const HEADER_CELL = document.createElement('th');
TABLE_ROW.appendChild(HEADER_CELL);
HEADER_CELL.setAttribute('class', 'sort-cta');
HEADER_CELL.innerText = HEADINGS[child];
TABLE.appendChild(TABLE_ROW);
}
} else if (field == 'items') {
for (const child in ITEMS) {
const TABLE_ROW = document.createElement('tr');
let item = ITEMS[child].fields;
let btn = ITEMS[child].button;
for (const row in item) {
const TABLE_DATA = document.createElement('td');
TABLE_ROW.appendChild(TABLE_DATA);
TABLE_DATA.innerText = item[row];
TABLE.appendChild(TABLE_ROW);
}
if (btn.propURL !== '') {
let link = document.createElement('a');
link.setAttribute('href', btn.propURL);
link.innerHTML = btn.name;
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
} else {
let link = document.createElement('span');
link.innerHTML = 'Reserved';
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
}
}
}
}
let perPage = 10;
function genTables() {
let tables = document.querySelectorAll('.pagination');
tables.forEach((table) => {
perPage = parseInt(table.dataset.pagecount);
createFooters(table);
createTableMeta(table);
loadTable(table);
});
}
// based on current page, only show the elements in that range
function loadTable(table) {
let startIndex = 0;
if (table.querySelector('th')) startIndex = 1;
const START = parseInt(table.dataset.currentpage) * table.dataset.pagecount + startIndex;
const END = START + parseInt(table.dataset.pagecount);
const TABLE_ROWS = table.rows;
for (var x = startIndex; x < TABLE_ROWS.length; x++) {
if (x < START || x >= END) TABLE_ROWS[x].classList.add('inactive');
else TABLE_ROWS[x].classList.remove('inactive');
}
}
function createTableMeta(table) {
table.dataset.currentpage = '0';
}
function createFooters(table) {
const COUTING_WRAPPER = document.createElement('div');
COUTING_WRAPPER.setAttribute('class', 'counting-wrapper');
const COUNTING_MSG = document.createElement('p');
COUTING_WRAPPER.appendChild(COUNTING_MSG);
let TABLE_WRAP = document.querySelector('.table-wrapper');
TABLE_WRAP.appendChild(COUTING_WRAPPER);
let hasHeader = false;
if (table.querySelector('th')) hasHeader = true;
let ROWS = table.rows.length;
if (hasHeader) ROWS = ROWS - 1;
let NUM_PAGES = ROWS / perPage;
let pager = document.createElement('div');
// add an extra page
if (NUM_PAGES % 1 > 0) NUM_PAGES = Math.floor(NUM_PAGES) + 1;
pager.className = 'pager';
let nextPage = document.createElement('button');
nextPage.innerHTML = 'next';
nextPage.className = 'item';
let prevPage = document.createElement('button');
prevPage.innerHTML = 'prev';
prevPage.className = 'item';
pager.appendChild(prevPage);
pager.appendChild(nextPage);
nextPage.addEventListener('click', () => {
table.dataset.currentpage = parseInt(table.dataset.currentpage) + 1;
loadTable(table);
});
prevPage.addEventListener('click', () => {
table.dataset.currentpage = parseInt(table.dataset.currentpage) - 1;
loadTable(table);
})
for (var i = 0; i < NUM_PAGES; i++) {
var page = document.createElement('button');
page.innerHTML = i + 1;
page.className = 'pager-item';
page.dataset.index = i;
if (i == 0) page.classList.add('selected');
page.addEventListener('click', function () {
var items = pager.querySelectorAll('.pager-item');
for (var x = 0; x < items.length; x++) {
items[x].classList.remove('selected');
}
this.classList.add('selected');
table.dataset.currentpage = this.dataset.index;
loadTable(table);
});
pager.appendChild(page);
}
// insert page at the top of the table
table.parentNode.insertBefore(pager, table);
}
genTables();
};
tr.inactive {
display: none;
}
.table-wrapper {
display: flex;
flex-direction: column-reverse;
}
.pager {
display: flex;
justify-content: center;
padding: 0;
margin-top: 10px;
font-weight: 800;
}
.pager-item.selected {
outline: none;
border-color: #0077cc;
background: #0077cc;
color: #fff;
cursor: default;
}
<div class="book-component">
<div class="table-wrapper">
</div>
</div>
Your loadTable function is updating the DOM based on the current state of your application. You can extend this to set the disabled state of the prev/next buttons, and to set the selected class of the page number button.
Here's an example where the button state is set by the loadTable function. The click event handlers should only update the current page (ie. set the state of the app). Then you can do your rendering of the state in the loadTable function.
// based on current page, only show the elements in that range
function loadTable(table) {
let startIndex = 0;
if (table.querySelector('th')) startIndex = 1;
const START = parseInt(table.dataset.currentpage) * table.dataset.pagecount + startIndex;
const END = START + parseInt(table.dataset.pagecount);
const TABLE_ROWS = table.rows;
for (var x = startIndex; x < TABLE_ROWS.length; x++) {
if (x < START || x >= END) TABLE_ROWS[x].classList.add('inactive');
else TABLE_ROWS[x].classList.remove('inactive');
}
// You should move this calculation outside of the function
const ROWS = table.rows.length - 1;
const NUM_PAGES = Math.ceil(ROWS / perPage);
const prevPage = document.getElementsByName('pagination-prev-button')[0];
const nextPage = document.getElementsByName('pagination-next-button')[0];
const isNextDisabled = +table.dataset.currentpage >= NUM_PAGES - 1;
const isPrevDisabled = +table.dataset.currentpage === 0;
if (isNextDisabled) {
nextPage.setAttribute('disabled', true);
} else {
nextPage.removeAttribute('disabled');
}
if (isPrevDisabled) {
prevPage.setAttribute('disabled', true);
} else {
prevPage.removeAttribute('disabled');
}
const items = document.querySelectorAll('.pager-item');
for (var x = 0; x < items.length; x++) {
if (x === +table.dataset.currentpage) {
items[x].classList.add('selected');
} else {
items[x].classList.remove('selected');
}
}
}
Here's the full working example.
https://jsfiddle.net/aloshea/r68gtvmc/

Cannot read property 'classList' of undefined when using it for DIVs

Me again. I modified the code a bit but
I have an error.
Cannot read property 'classList' of undefined. It happens at:
slides[this.current].classList.remove("visible");
const innerDiv1 = document.createElement("div");
innerDiv1.id = "innerDivID1";
//innerDiv1.classList.add("innerDivClass");
innerDiv1.classList.add("visible");
innerDiv1.innerText = "1";
const innerDiv2 = document.createElement("div");
innerDiv2.id = "innerDivID2";
innerDiv2.classList.add("innerDivClass");
//innerDiv2.classList.add("visible");
innerDiv2.innerText = "2";
const innerDiv3 = document.createElement("div");
innerDiv3.id = "innerDivID3";
innerDiv3.classList.add("innerDivClass");
//innerDiv3.classList.add("visible");
innerDiv3.innerText = "3";
rightButton() {
let next = document.getElementById("next");
next.addEventListener("click", () => {
this.nextSlide();
});
}
nextSlide() {
const slides = document.querySelectorAll(
"#outsideCaroussel, .innerDivClass"
);
for (let i = 0; i <= slides.length; i++) {
if ((slides.className = "visible")) {
slides[this.current].classList.remove("visible");
slides[this.current].classList.add("innerDivClass");
}
if ((slides.className = "innerDivClass")) {
slides[this.current].classList.add("visible");
slides[this.current].classList.remove("innerDivClass");
}
this.current++;
console.log(slides);
console.log(this.current);
}
Note.
this.current = 0 {at the beginning of the code, the index of the current shown div}
On your code this.current will go outside your sliders divs in this case you have to use the index i
nextSlide() {
const slides = document.querySelectorAll(
"#outsideCaroussel, .innerDivClass"
);
// It should check less than slides.length, on equality slides[i] would be exceeding bound
for (let i = 0; i < slides.length; i++) {
if ((slides.className = "visible")) {
slides[i].classList.remove("visible");
slides[i].classList.add("innerDivClass");
}
if ((slides.className = "innerDivClass")) {
slides[i].classList.add("visible");
slides[i].classList.remove("innerDivClass");
}
}
}

Categories

Resources