Show when element is found in array - javascript

I am creating a word search solver and used the find() method to detect when a value is inside an array.
The values of the table are placed in two arrays, one for rows, one for columns.
Right now, my program detects if a value is in the table or not.
However, how could I highlight each value found in the table when the word is found?
Code:
//GENERATE TABLE
const table = document.querySelector('table');
function GenerateTable(x, y) {
for (let column = 0; column < x; column++) {
const newRow = table.insertRow();
for (let row = 0; row < y; row++) {
newRow.insertCell().appendChild(document.createElement('INPUT'));
}
}
let cells = document.querySelectorAll('td > input');
for (const x of cells) {
x.maxLength = 1;
x.type = 'text';
const index = [...cells].indexOf(x);
x.onkeyup = function() {
if (this.value != '' && cells[index + 1]) {
cells[index + 1].focus();
}
}
}
}
GenerateTable(5, 5)
//FIND WORDS
const input = document.getElementById('inputSearch');
function SubmitSearch() {
console.clear();
//Find Rows
const arrayX = [];
for (const row of table.rows) {
for (const cell of row.cells) {
const valueCell = cell.firstChild.value.toLowerCase();
arrayX.push(valueCell)
}
}
const values = chunkArray(arrayX, table.rows[0].cells.length);
const valuesX = values.map(x => x.join(''));
const foundX = valuesX.find(e => e.includes(input.value.toLowerCase()));
//Find Columns
const arrayY = [];
for (let a = 0; a < values.length; a++) {
for (let b in values) {
arrayY.push(values[b][a]);
}
}
let valuesY = chunkArray(arrayY, table.rows[0].cells.length);
valuesY = valuesY.map(x => x.join(''));
const foundY = valuesY.find(e => e.includes(input.value.toLowerCase()));
console.log(`Rows values: ${JSON.stringify(valuesX)}`);
console.log(`Columns values: ${JSON.stringify(valuesY)}`);
if (foundX || foundY) {
console.log(`Word found!`);
} else {
console.log('Word not found')
}
}
function chunkArray(x, chunk) {
const array = [];
while (x.length) {
array.push(x.splice(0, chunk));
}
return array;
}
<table></table>
<br>
<input type="text" id="inputSearch">
<button id="search" onclick="SubmitSearch()"> Find Words </button>
An example to illustrate my objective would be:
Thanks so much!
Please note that diagonal and reversed search is not to be taken in consideration in my program

You were looking for the index of the arrays,
Array.prototype.find returns the item if it finds it
Array.prototype.findIndex returns the index if it finds it and -1 otherwise
Because of Array indexing you have to add 1 to the return value of Array.prototype.findIndex
If the word was found on the column, the row wouldn't have the valid index and vice-versa.
So I used the index I got from the Array.prototype.findIndex and used it get the word in that row or column then I used String.prototype.search to get the index from which the word that was found started from and returned that as the row (or column) number
// I would advise you stop using inline event handlers (onevent)
const button = document.getElementById('search');
const table = document.querySelector('table');
function GenerateTable(x, y) {
for (let column = 0; column < x; column++) {
const newRow = table.insertRow();
for (let row = 0; row < y; row++) {
newRow.insertCell().appendChild(document.createElement('INPUT'));
}
}
let cells = document.querySelectorAll('td > input');
for (const x of cells) {
x.maxLength = 1;
x.type = 'text';
const index = [...cells].indexOf(x);
x.onkeyup = function() {
if (this.value != '' && cells[index + 1]) {
cells[index + 1].focus();
}
}
}
}
GenerateTable(5, 5)
//FIND WORDS
const input = document.getElementById('inputSearch');
function SubmitSearch() {
console.clear();
//Find Rows
const arrayX = [];
const searchWord = input.value.toLowerCase(); // We use this a lot so its best to store it in a value
[...document.querySelectorAll('td.found')].forEach(cell => cell.classList.remove('found')); // To reset the styles for the cells
for (const row of table.rows) {
for (const cell of row.cells) {
const valueCell = cell.firstChild.value.toLowerCase();
arrayX.push(valueCell)
}
}
const values = chunkArray(arrayX, table.rows[0].cells.length);
const valuesX = values.map(x => x.join(''));
let foundX = valuesX.findIndex(e => e.includes(searchWord));
//Find Columns
const arrayY = [];
for (let a = 0; a < values.length; a++) {
for (let b in values) {
arrayY.push(values[b][a]);
}
}
let valuesY = chunkArray(arrayY, table.rows[0].cells.length);
valuesY = valuesY.map(x => x.join(''));
let foundY = -1;
if (foundX < 0) foundY = valuesY.findIndex(e => e.includes(searchWord));
console.log(`Rows values: ${JSON.stringify(valuesX)}`);
console.log(`Columns values: ${JSON.stringify(valuesY)}`);
if (foundY > -1 || -1 < foundX) {
console.log(`Word found!`);
if (foundX < 0) {
foundX = valuesY[foundY].search(searchWord);
// I got the rows and selected the rows the word were found in, then iterated through its children picking out the column to get its cell and added the class found with styling
[...table.rows].slice(foundX, foundX + searchWord.length).forEach(row => row.children[foundY].classList.add('found'));
}
if (foundY < 0) {
foundY = valuesX[foundX].search(searchWord);
// I got the columns, then selected the particular row the word was found in, then iterated through its children and added the class found with styling
[...table.rows[foundX].children].slice(foundY, foundY + searchWord.length).forEach(col => col.classList.add('found'));
}
} else console.log('Word not found');
}
function chunkArray(x, chunk) {
const array = [];
while (x.length) {
array.push(x.splice(0, chunk));
}
return array;
}
td.found {
border: 2px solid yellow;
}
td.found input {
border: none;
outline: none;
}
<table></table>
<br>
<input type="text" id="inputSearch">
<button id="search" onclick="SubmitSearch()"> Find Words </button>

Related

How to sort a long data html table with javascript?

I have a problem with coding the sorting code for my database. With few data there is no problem but at this time I have to sort about 4000 data and it lasts about 20s, too long time.
By my check, the operation which lasts too much is insertBefore(...,...) function.
Can you please help me?
function sorting(list) {
var list_data = [];
var list_id = [];
for (var i = 0; i < list.length; i++) {
list_data[i] = Date.parse(list[i].cells[1].innerHTML);
list_id[i] = parseInt(list[i].cells[12].innerHTML);
}
//ordino gli array
for (var i = 0; i < list.length; i++) {
for (var j = 0; j < list.length-1; j++) {
if (list_data[j] > list_data[j+1]) {
tmp = list_data[j];
list_data[j] = list_data[j+1];
list_data[j+1] = tmp;
tmp = list_id[j];
list_id[j] = list_id[j+1];
list_id[j+1] = tmp;
}
}
}
//ordinato lista_id
var j = 0;
for (var i = 0; i < list.length; i++) {
j=i;
while (list_id[i] != parseInt(list[j].cells[12].innerHTML)) {
j++;
}
var target = list[i];
var newElement = list[j];
target.parentNode.insertBefore(newElement, target);
}
}
I have my table with 13 columns 0-12. The thirteenth column contains hidden cells with id of the data. I started with a bubblesort and then changed in this because i thought it could work better, but it still lasts 20s to sort. How suggested in comments I'm starting to think that a sort by server is better, but I don't know how to implement
I don't think it's the sorting. Created a snippet with time-logging, so you can see that a 5000 items long list's sorting is not that much of a problem.
Try setting up your project so that you control the data & only output the results (the snippet is a very simple example of that).
const tbody = document.getElementById('tbody')
let sortDesc = false
const rowHtml = (rowData) => {
return `
<tr>
<td>
${ rowData.first }
</td>
<td>
${ rowData.second }
</td>
</tr>
`
}
const setTable = (data) => {
tbody.innerHTML = ''
tbody.innerHTML = data.map(rowData => {
return rowHtml(rowData)
}).join('')
}
const sortData = (data, desc) => {
return data.sort((a, b) => {
if (desc) {
return b.first - a.first
} else {
return a.first - b.first
}
})
}
renderTable = (data) => {
console.time('sort data')
const d = sortData(data, sortDesc)
console.timeEnd('sort data')
sortDesc = !sortDesc
console.time('set table')
setTable(d)
console.timeEnd('set table')
}
let data = [];
(function() {
console.time('create items')
for (let i = 0; i < 5000; i++) {
data.push({
first: i,
second: `${ i }-${ i }`,
})
}
console.timeEnd('create items')
renderTable(data)
})();
const btnSort = document.getElementById('btnSort')
btnSort.addEventListener('click', function() {
renderTable(data)
})
<button id="btnSort">SORT</button><br />
<table id="table">
<tbody id="tbody"></tbody>
</table>
You can see from the time-logs that the real "expensive" stuff is actually putting out the HTML ("set table" in this case takes ~100 times as much time as "sort data").

Want to delete the dynamically appended card from object array using splice method but the loop iteration is getting wrong values

I am making a task planner using classes.
These tasks are saved in the form of dynamically appended cards.
I am adding three cards in the array in class CardManager.
When I am selecting a card to delete by pressing a delete button the id is retrieved correctly, but in the last delfunc function which has a for loop, I am getting wrong array length.
So splice is not working.
The problem is in the loop of last function called delfunc().
class Card {
constructor(id, cname, pic, description, assignee, dDate, st) {
this.id = id;
this.cname = cname;
this.pic = pic;
this.description = description;
this.assignee = assignee;
this.dDate = dDate;
this.st = st;
// this.info=info;
}
}
class CardManager {
constructor() {
this.cardArr = [];
this.currentId = 1;
}
addcard(cname, pic, description, assignee, dDate, st) {
const nCard = new Card(this.currentId++, cname, pic, description, assignee, dDate, st); //creates
an instance of class card
this.cardArr.push(nCard);
}
}
const cardDeck = new CardManager(); //create an instance of card manager to access the members
// cardDeck.addcard("laundry","test","testing","Saeed","thursday","to do");
let tname = document.querySelector("#text1"); //accepting user input from form
let tdes = document.querySelector("#des");
let assignee = document.querySelector("#assignee");
let dDate = document.querySelector("#dDate");
let sTatus = document.querySelector("#stAtus");
let addButton = document.querySelector("#addButton");
addButton.onclick = function () {
alert("here i am card deck");
cardDeck.addcard(tname.value, "test", tdes.value, assignee.value, dDate.value, sTatus.value);
$('#myModal').modal('hide');
}
let btn1 = document.querySelector("#btn1");
let buttonCount = 1;
btn1.onclick = function displayListHtml() {
let html = "";
alert(cardDeck.cardArr.length);
for (let i = 0; i < cardDeck.cardArr.length; i++) {
html = `<div class="card">
<h1>${cardDeck.cardArr[i].cname}</h1>
<img src="sample.jpg" alt="Denim Jeans" style="width:100%">
<p>${cardDeck.cardArr[i].description}</p>
<p>${cardDeck.cardArr[i].assignee}</p>
<p>${cardDeck.cardArr[i].dDate}</p>
<p>${cardDeck.cardArr[i].st}</p>
<p>${cardDeck.cardArr[i].id}</p>
<p><button class="delete btn btn-primary" id="dbutton_${cardDeck.cardArr[i].id}">
Delete</button></p>
<p><button class="Edit btn btn-primary" id="ebutton_${cardDeck.cardArr[i].id}">
Edit</button></p>
</div>`;
buttonCount++;
}
const taskcontainer = document.querySelector("#taskcontainer");
const element = document.createRange().createContextualFragment(html);
element.querySelector("button.delete")
.addEventListener("click", delfunc);
element.querySelector("button.Edit")
.addEventListener("click", edifunc);
// element.addEventListener("click",yourClickEventHandler);
taskcontainer.append(element);
}
function delfunc() {
alert("i am in delete function");
const taskElement = event.target.closest(".delete"); //see line 74.
let delIdArr = taskElement.id.split("_"); //spliting the id by underscore. i.e . dbuton_id
let retreiveId = delIdArr[1];
for (let j = 0; j < this.cardDeck.cardArr.length; j++) {
if (retreiveId === j) {
this.cardDeck.cardArr.splice(retreiveId, 1);
}
}
}
Here is minimal version your concern. But looks like splice call doing as expected.
const del = (cardArr, retreiveId) => {
for (let j = 0; j < cardArr.length; j++) {
if (retreiveId === j) {
cardArr.splice(retreiveId, 1);
}
}
};
const cardArr = [2, 3, 4];
// delete the index 1
del(cardArr, 1);
console.log(cardArr);
// Case where delete index out of array index
const a = [1];
del(a, 1)
console.log(a);
function delfunc() {
alert("I am in delete function");
const taskElement = event.target.closest(".delete");//see line 74.
let delIdArr = taskElement.id.split("_");
let retrieveId = delIdArr[1];
var arr=[];
for (let j = 1; j <= cardDeck.cardArr.length; j++ ) {
if (retrieveId == j) {
arr = cardDeck.cardArr.splice(retreiveId, 1);
}

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/

Trying to print out step by step in a recursive function without printing them out all at once in Javascript

I'm trying to make an N-Queens visualizer and I hooked up my solver to the html doc. My issue is that I'm trying to display everything step by step with intervals of 1 second each for the place function, rather than showing the completed solutions right away.
In other words, I want to show each move done step by step.
My placing function, is also hooked up to the tables on the DOM so when it's being placed on the board, it also places it on the html table.
function place(board, row, col, val, table) {
const newRow = board[row].split('');
newRow[col] = val;
board[row] = newRow.join('');
//place on DOM as well
table.childNodes[row].childNodes[col].innerHTML = val;
}
and the code I have for my solver is this
function solver(board, row, col, solutions) {
if (col === board.length) {
solutions.push([...board]);
return;
}
const currentTable = listOfTables[solutions.length];
for (let i = 0; i < board.length; i++) {
if (canPlace(board, i, col)) {
place(board, i, col, 'Q', currentTable);
solver(board, row, col + 1, solutions);
place(board, i, col, '.', currentTable);
}
}
}
I was trying to wrap a setTimeout inside the solver function but that still runs the code all at once, when the timeout hits.
The currentTable variable is the used to know which of the tables in the DOM is currently going to be in use.
Here's the CodePen with all the code if anyone needs it https://codepen.io/vvus/pen/KKVKMrq?editors=1111
you can adjust the code bellow to your liking
you add the display="none" to all your tables and then you deactivate the attribute in a time interval using this code
var i=0
setInterval(() => {
for(z=i;z<listOfTables.length;z++) {
const x=document.getElementsByClassName('new-table')[z]
if (x.style.display === "none") {
x.style.display = "";
i++
}
break
}
}, 3000);
so your final code may look like this
const button = document.getElementById("button-click");
const selection = document.getElementById("selection");
let tablesContainer = document.getElementById("tables-container");
let listOfTables = tablesContainer.childNodes;
button.addEventListener("click", () => {
console.log(nQueens(Number(selection.value)));
listOfTables = tablesContainer.childNodes;
// add this code to your eventlistner or anywhre you want to show something in time interval
var i=0
setInterval(() => {
for(z=i;z<listOfTables.length;z++) {
const x=document.getElementsByClassName('new-table')[z]
console.log(z)
if (x.style.display === "none") {
x.style.display = "";
i++
}
break
}
}, 3000);
});
selection.addEventListener("change", (e) => {
let numOfTables = e.target.value;
if (numOfTables === 1) numOfTables = 1;
else if (numOfTables === 4) numOfTables = 3;
else if (numOfTables === 8) numOfTables = 93;
const rowsCols = e.target.value;
for (let allTables = 1; allTables < numOfTables; allTables++) {
const newTable = document.createElement("table");
newTable.classList = "new-table";
newTable.style.display="none"// add this attribute to all your tables
for (let i = 0; i < rowsCols; i++) {
const row = document.createElement("tr");
for (let j = 0; j < rowsCols; j++) {
const th = document.createElement("th");
th.innerHTML = ".";
row.appendChild(th);
}
newTable.appendChild(row);
}
tablesContainer.appendChild(newTable);
}
});

How to change the element of a cell with the value of the element next to it in Javascript?

In table like the one below in the code snippet I would like that once clicked an item, I want to change the name of the selected cell to the next name corresponding to the sequence like in the array. [square, triangle, circle, oval, pentagon] So if I click "square", now the name appearing on it should be "triangle".
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for(var i=0; i < cells; i++){
// track row length and insert new ones when necessary
// also creates the first row
if(i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<table id="grid">
</table>
"I want the value to change to the next in the sequence" (clarification from a comment that it isn't the element to the right that matters, it's the sequence in the array)
OK, so I would probably use a (delegated) click handler attached to the table element. Get the value of the clicked td element and look it up in the card array, then from there get the next item from the array. Maybe a little something like this:
document.getElementById('grid').addEventListener("click", function(e) {
if (e.target.nodeName.toLowerCase() === "td") {
var currentIndex = card.findIndex(function(shape) {
return shape.name === e.target.innerHTML;
});
e.target.innerHTML = card[(currentIndex + 1) % card.length].name;
}
});
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for(var i=0; i < cells; i++){
// track row length and insert new ones when necessary
// also creates the first row
if(i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<table id="grid">
</table>
I have used the array .findIndex() method to find the item in the array, so if you want to support IE you'll need a polyfill, or of course you could just use a for loop or whatever.
You can access cells by their cellIndex property. So once you have the cell that was clicked on, get the cell to the right (if it exists) and update the innerHTML of the clicked on cell.
function changeName(e){
// Get the element that was clicked on
var cell = e.target;
var row, index;
// If it's a td, update the innerHTML
if (cell && cell.tagName.toLowerCase() == 'td') {
// Get the row that the cell is in
row = cell.parentNode;
// Get index of cell to right
index = cell.cellIndex + 1;
// Make sure cell to right exists
if (row.cells[index]) {
// Update clicked on cell
cell.innerHTML = row.cells[index].innerHTML;
}
}
}
window.onload = function(){
document.querySelector('table').addEventListener('click',changeName);
}
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Here is a more concise version:
window.onload = function() {
document.querySelector('table').addEventListener('click',
function(e) {
var cell = e.target;
var next = cell.cellIndex === undefined? null : cell.parentNode.cells[cell.cellIndex + 1];
if (next)
cell.innerHTML = next.innerHTML
});
};
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Edit
Updated to loop through the names in succession
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function getNextCard(name) {
}
window.onload = function() {
document.querySelector('table').addEventListener('click',
function(e) {
var node = e.target;
var name = node.textContent;
var index;
if (node.tagName.toLowerCase() == 'td') {
index = (card.findIndex(function(obj){
return obj.name == name;
}) + 1) % card.length;
node.textContent = card[index].name;
}
});
};
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Please feel free to optimize this solution. Hope this works for you and this is what you want :)
var card = [{
name: 'square'
},
{
name: 'triangle'
},
{
name: 'circle'
},
{
name: 'oval'
},
{
name: 'pentagon'
}
];
function onCellClick(td) {
value = td.innerHTML.trim();
for (var i = 0; i < card.length; i++) {
var index;
if (card[i].name === value) {
index = i + 1;
if (card.length - 1 === i) {
index = 0
}
td.innerHTML = card[index].name;
break;
}
}
}
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for (var i = 0; i < cells; i++) {
// track row length and insert new ones when necessary
// also creates the first row
if (i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.onclick = function() {
onCellClick(this);
};
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="grid">
</table>

Categories

Resources