Add multiple colspans that line up in HTML - javascript

I'm building a calendar scheduler where I am hoping to add multiple tasks to one employee row. Whenever I try to add multiple tasks to the same time span, the spans no longer line up. Here is an example of how it looks now: . What would be the best practice to add tasks to the same day columns while keeping a task like "Slaughter them" similar?
HTML Script:
<script>
var sysDate = new Date();
var sysDay = new Date();
var sysMonth = new Date();
var dayCount = sysDay.getDay();
var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
let employee;
let typeofKey;
let empArry = [];
let x = 1;
let y = 0;
let trInc= 0;
var drawTable = '<table id = wholeTable>';
drawTable += "<thead>";
drawTable += "<tr>";
drawTable += "<th style='color:white;'>Employee Name<\/th>";
let today = new Date();
let dd = today.getDate();
let mm = today.getMonth()+1; //January is 0!
let mmN = mm;
let yyyy = today.getFullYear();
let oneWeekAhead = new Date();
let nextWeek = (today.getDate()+10) + 10;
/* If next week falls into the next month, print correctly */
if (nextWeek > 30 && (mmN == 9 || mmN == 4 || mmN == 6 || mmN == 11)) {
mmN++;
nextWeek -= 30;
}
else if (nextWeek > 31 && (mmN == 1 || mmN == 3 || mmN == 5 || mmN == 7 || mmN == 8 || mmN == 10 || mmN == 12)) {
mmN++;
nextWeek -= 31;
}
else if (nextWeek > 28 && mmN == 2) {
mmN++;
nextWeek -= 28;
}
/* Formatting of the dates at the top of the table */
if(dd < 10) {
dd = '0'+ dd;
}
if(nextWeek < 10) {
nextWeek = '0' + nextWeek;
}
if(mmN < 10) {
mmN = '0' + mmN
}
if(mm < 10) {
mm = '0' + mm;
}
let edate = yyyy + mmN + nextWeek;
/* Finds the logged earliest and latest dates */
let startDate1 = yyyy.toString() + mm.toString() + dd.toString();
let startDate = parseInt(startDate1);
let endDate = parseInt(edate);
let startDateN = 20180501;
let endDateN = 20180531;
/* Change the strings of dates to ints for calculation of start and end date of the table */
if( localStorage.length > 0){
for (var key in localStorage) {
typeofKey = (typeof localStorage[key]);
if (typeofKey == 'string' || typeofKey instanceof String ){
emp1 = JSON.parse(localStorage.getItem(key));
if ("Task" in emp1) {
for (let i = 0; i < emp1.Task.length; i++) {
startDateN = parseInt(emp1.Task[i]['Task Start Date'].substr(0,4) + emp1.Task[i]['Task Start Date'].substr(5,2) + emp1.Task[i]['Task Start Date'].substr(8,2));
endDateN = parseInt(emp1.Task[i]['Task End Date'].substr(0,4) + emp1.Task[i]['Task End Date'].substr(5,2) + emp1.Task[i]['Task End Date'].substr(8,2));
if(endDateN > endDate) {
endDate = endDateN;
}
if(startDateN < startDate) {
startDate = startDateN;
}
}
}
}
}
}
let numStr = null;
let numStrDay = null;
let finalDay = null;
let finalDayF = null;
let colCount = 0;
/* Correctly print the months and days at the top of the table */
for (let i = startDate; i <= endDate +1; i++) {
numStr = (i.toString()).substr(4,2);
numStrDay = (i.toString()).substr(6,2);
if(numStr == '09' || numStr == '04' || numStr == '06' || numStr == '11') {
if(numStrDay == '31') {
i += 69;
}
else {
finalDay = i.toString()
finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
colCount++;
}
}
else if(numStr == '01' || numStr == '03' || numStr == '05' || numStr == '07' || numStr == '08' || numStr == '10' || numStr == '12') {
if(numStrDay == '32') {
i += 68;
}
else {
finalDay = i.toString()
finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
colCount++;
}
}
else if(numStr == '02') {
if(numStrDay == '29') {
i += 71;
}
else {
finalDay = i.toString()
finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
colCount++;
}
}
else {
finalDay = i.toString()
finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
colCount++;
}
x++;
}
drawTable += "</tr>";
drawTable += "</thead>";
drawTable += '<tbody class="dragscroll">';
//drawTable += "<tr id =" + trInc + ">";
//trInc++;
//counters for the employee and date rows/col
x=0;
y=1;
// counter for the main table
let z =1;
for (var key in localStorage) {
typeofKey = (typeof localStorage[key]);
//cols of the employee names
if(typeofKey == 'string' || typeofKey instanceof String ){
drawTable += "<tr id =" + trInc + ">";
trInc++;
employee = JSON.parse(localStorage.getItem(key));
drawTable += "<td class = employ id =emp" + x + '-' + y + ">" + employee['Employee Name'] + "</td>";
// rows and cols of the main table and date
for (let j = 0; j < colCount; j++) {
drawTable += "<td class =" + z + '-' + y + "></td>";
z++;
}
// set z to one to start the main tables x at 1 for off by one error
z=1;
//reset x for each row
x=0;
drawTable += '</tr>';
y++;
}
}
drawTable += '<tr>';
var noRows = 14 - localStorage.length;
for(; noRows >= 0; noRows--){
drawTable += "<td class = employ id =emp" + x + '-' + y + ">" + "" + "</td>";
// rows and cols of the main table and date
for (let j = 0; j < colCount; j++) {
drawTable += "<td class =" + z + '-' + y + "></td>";
z++;
}
// set z to one to start the main tables x at 1 for off by one error
z=1;
//reset x for each row
x=0;
drawTable += '</tr>';
y++;
}
drawTable += "</tbody>";
drawTable += "</table>";
document.write(drawTable);
</script>
CSS:
table {
/* border: 0.0625em solid black; */
table-layout: fixed;
position: relative;
width: auto;
overflow: hidden;
border-collapse: collapse;
box-shadow: 0 0 20px rgba(0,0,0,0.1);
}
html, body{
height: 100%;
width: 100%;
background: linear-gradient(45deg, #e1e1e1, #f6f6f6);
}
/*thead*/
thead {
position: relative;
display: block; /*seperates the header from the body allowing it to be positioned*/
width: 1535px;
overflow: visible;
/* border: 1px solid black; */
}
td, th {
padding: 0.75em 1.5em;
text-align: left;
}
thead th {
min-width: 140px;
max-width: 140px;
height: 35px;
text-align: center;
}
thead th:nth-child(1) { /*first cell in the header*/
position: relative;
display: float;
min-width: 140px;
background-color: #202020;
}
/*tbody*/
tbody {
position: relative;
display: block; /*seperates the tbody from the header*/
width: 1535px;
height: 475px;
overflow: scroll;
}
tbody td {
background-color: white;
min-width: 140px;
max-width: 140px;
border: 2px solid #474747;
white-space: nowrap;
}
tbody tr td:nth-child(1) { /*the first cell in each tr*/
position: relative;
/*display: block; seperates the first column from the tbody*/
height: 40px;
min-width: 140px;
max-width: 140px;
}
.dragscroll {
overflow-y: hidden;
margin-right: 0;
height: 600px;
}
.days {
background-color: #31bc86;
color: white;
text-align: center;
}
.employ {
background-color: #2ea879;
color: white;
text-align: center;
}
#taskDiv {
position: absolute;
border: 2px solid black;
}
#days, #emp{
background-color: #071833;
color: white;
}
::-webkit-scrollbar {
width: 20px;
}
/* Track */
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px black;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #071833;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #1caf8f
}
JS:
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
$(document).ready(function(){
let typeofKey;
let empArry = [];
let employee;
let myTable = document.getElementById('wholeTable');
let colFill = false;
let color = null;
//cols of the employee names
for (var i = 0; i < localStorage.length; i++){
empArry.push(localStorage.key(i))
}
// loop through the local storage and pull the data
for(let j = 0; j < empArry.length; j++){
color = getRandomColor();
employee = JSON.parse(localStorage.getItem(empArry[j]));
// If employee has any task
if("Task" in employee){
// while employee has task in his array
for(let taskIndex = 0; taskIndex < employee.Task.length; taskIndex++){
for(let k = 1; k < myTable.rows[0].cells.length; k++) {
if(myTable.rows[0].cells[k].innerHTML == employee.Task[taskIndex]["Task Start Date"]) {
colFill = true;
}
if(colFill == true) {
myTable.rows[j+1].cells[k].innerHTML += '<div style="background-color:' + color + '">' + employee.Task[taskIndex]["Task Name"] + '</br></div>';
}
if(myTable.rows[0].cells[k].innerHTML == employee.Task[taskIndex]["Task End Date"]) {
colFill = false;
}
}
}
}
}
});
JSFiddle: https://jsfiddle.net/py5gzw0b/1/#&togetherjs=eM8xgAd5eV

Set the vertical-align CSS property for those table cells to top;
td {
vertical-align:top;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align

If you need each item to be on its own row [along with all identical tasks] and perfectly aligned there, then you would need to create row 1, and insert only the Slaughter tasks, followed by creating row 2, inserting only the Cry tasks. This would then ensure that they would all correctly line up with one another, although it would take up more space as a result.

Another solution besides creating a row for each task would be to use jQuery to find the "max top of the task" and setting all instances at that top. Since they take the same space it should be doable and more flexible BUT you're in for some css-positioning fun.
To be more specific, you should :
1/ Add an unique identifier to each task : <div id_task="1" style=...
2/ Loop on each instance to find max top value :
maxTop=0;
$('[id_task=1]').each(function(){
newTop=$(this).position().top;
if(newTop>maxTop)maxTop=newTop;
});
3/ Use maxTop to set all id_task=1 to the same top, probably set these divs to relative too : $('[id_task=1]').css({'top':maxTop,'position':'relative');
4/ Enjoy fine-tuning this to close in on your desired goal, it'll take a while ^^
I made the code quickly as an example, there's no guarantee to it.

Take a look at this:
var cols = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
var employees = [
{
Name: 'Jason',
Task:[
{'Task Start Date':'Mon','Task End Date':'Thu','Task Name':'Do nothing'},
{'Task Start Date':'Thu','Task End Date':'Fri','Task Name':'Do a bit'},
{'Task Start Date':'Sat','Task End Date':'Sun','Task Name':'Do everything'}
]
},
{
Name: 'Timmy',
Task:[
{'Task Start Date':'Mon','Task End Date':'Sun','Task Name':'On vacation'},
{'Task Start Date':'Sat','Task End Date':'Sun','Task Name':'Still on vacation'},
]
}
]
function RowCompound(employee,columns){
var tasks = employee.Task
var spans = []
var max_rows = 1
var rowmap = []
var rows = []
function calcSpans(){
for(var i=0;i<tasks.length;i++){
var cspan = null
for(var u=0;u<columns.length;u++){
if(tasks[i]['Task Start Date']==columns[u]){
cspan = {row:0,start:u,task:tasks[i]}
}
if(cspan && tasks[i]['Task End Date']==columns[u]){
cspan.end = u
spans.push(cspan)
cspan = null
}
}
if(cspan){
cspan.end = columns.length-1
spans.push(cspan)
}
}
}
function solveConflicts(){
var conflict = true
while(conflict){
conflict = false
for(var i=0;i<spans.length;i++){
for(var u=i+1;u<spans.length;u++){
if(spans[i].row!=spans[u].row) continue
if(spans[i].start>spans[u].end || spans[i].end<spans[u].start) continue
conflict = true
max_rows = Math.max(max_rows,++spans[u].row + 1)
}
}
}
}
function createRowMap(){
for(var u=0;u<max_rows;u++){
var row = []
for(var i=0;i<columns.length;i++){
var empty = true
for(var k=0;k<spans.length;k++){
if(spans[k].row!=u) continue
if(i==spans[k].start){
empty = false
var span = spans[k].end-spans[k].start+1
row.push({task:spans[k].task,colspan:span,rowspan:1})
i += span-1
break
}
}
if(empty)
row.push({task:null,colspan:1,rowspan:1})
}
rowmap.push(row)
}
}
function buildDom(){
for(var i=0;i<rowmap.length;i++){
var row = document.createElement('tr')
for(var u=0;u<rowmap[i].length;u++){
if(rowmap[i][u].rowspan==0) continue
var cell = document.createElement('td')
cell.colSpan = rowmap[i][u].colspan
cell.rowSpan = rowmap[i][u].rowspan
if(rowmap[i][u].task){
cell.innerHTML = rowmap[i][u].task['Task Name']
cell.className = 'busy'
}
row.appendChild(cell)
}
rows.push(row)
}
var head = document.createElement('td')
head.rowSpan = max_rows
head.innerHTML = employee.Name
rows[0].prepend(head)
}
calcSpans()
solveConflicts()
createRowMap()
buildDom()
return rows
}
// example use
employees.forEach(function (emp){
var result_rows = RowCompound(emp,cols)
for(var i in result_rows){
document.getElementById('table').appendChild(result_rows[i])
}
})
table{
width: 100%;
border-collapse: collapse;
}
table td{
border: solid 1px #ccc;
width: 50px;
}
table td.busy{
background-color: dodgerblue;
color: white;
}
<table id="table">
<thead>
<th>Employee</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
<th>Sun</th>
</thead>
</table>
What this does is:
Create virtual spans for each task
If the spans overlap, push them one row lower
Create multiple rows utilizing the rowSpan attribute
Append the said rows to the table
You're gonna need to rewrite your code a little for this to work, but i think its the way to go.
Please note, the createRowCompound function requires the columns of the table as array in order to create the layout. See the example use.
Questions?

This is more of a conceptual answer/idea, but I think that you might be able to use the Isotope javascript layout library with the "vertical" layout mode:
https://isotope.metafizzy.co/layout-modes.html
You can disable all kinds of animations, so in that sense, this would be a shortcut to the "css positioning fun" that #Nomis mentions in the answer above. There's also the https://masonry.desandro.com library by the same person - might be worth a look.

Related

How to create multidimentional array in html tables

I created tables in which each cells will change its class between clicked cells.
When I create this table, I would like to get clicked history array.
In the current state,history array is stored in clicked array.
clicked array is like
array=[1,4,6,9]
but My desired result is like
array=[[1,2,3,4],[6,7,8,9]]
or
array=[[1,4],[6,9]]
I mean in each class change,I would like to get parent keys for manipulation.
If you have some opinion, please let me know.
const $days = $("td");
const range = [-1, -1];
let clicked =[];
$(function() {
$("td").click(function() {
if (range[0] > -1 && range[1] > -1) { // RESET
range[0] = -1;
range[1] = -1;
}
if (range[0] > -1 && range[1] < 0) { // SET END
range[1] = $days.index(this);
$days.slice(range[0],range[1]+1).addClass('is-active');
}
if (range[0] < 0 && range[1] < 0) { // SET START
range[0] = $days.index(this);
}
let clickedID=$days.index(this);
clicked.push(clickedID);
console.log("Array of clicked cells",clicked);
});
});
td {
transition-duration: 0.5s;
border: solid black 1px;
cursor: pointer;
}
div {padding: 5px;}
table {border-collapse: collapse;}
.aqua{background-color: aqua;}
td:hover {
background-color:yellow;}
.is-active{
background-color:aqua;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id=calendar></div>
<script>
let html = ''
html += '<table>';
let i = 0;
for (let w = 0; w < 10; w++) {
html += '<tr>';
for (let d = 0; d < 10; d++) {
i = i + 1;
html += '<td>' + '<div>' + i + '</div>' + '</td>'
}
html += '</tr>';
}
html += '</table>'
document.querySelector('#calendar').innerHTML = html;
</script>
Will this help?
let sets = []
clicked.forEach((item,i) => {
if (i===0 || i%2===0) sets.push([])
sets[sets.length-1].push(item)
})
let html = ''
html += '<table>';
let i = 0;
for (let w = 0; w < 10; w++) {
html += '<tr>';
for (let d = 0; d < 10; d++) {
i = i + 1;
html += '<td data-layer=0>' + '<div>' + i + '</div>' + '</td>'
}
html += '</tr>';
}
html += '</table>'
document.querySelector('#calendar').innerHTML = html;
const $days = $("td");
const range = [-1, -1];
let clicked = [];
$(function() {
$("td").click(function() {
if (range[0] > -1 && range[1] > -1) { // RESET
range[0] = -1;
range[1] = -1;
}
if (range[0] > -1 && range[1] < 0) { // SET END
range[1] = $days.index(this);
$days.slice(range[0], range[1] + 1).addClass('is-active');
}
if (range[0] < 0 && range[1] < 0) { // SET START
range[0] = $days.index(this);
}
let clickedID = $days.index(this);
clicked.push(clickedID)
let sets = []
clicked.forEach((item,i) => {
if (i===0 || i%2===0) sets.push([])
sets[sets.length-1].push(item)
})
console.log("Array of clicked cells", sets);
// $(".is-active").each((i,td) => console.log(td.innerText))
});
});
td {
transition-duration: 0.5s;
border: solid black 1px;
cursor: pointer;
}
div {
padding: 5px;
}
table {
border-collapse: collapse;
}
.aqua {
background-color: aqua;
}
td:hover {
background-color: yellow;
}
.is-active {
background-color: aqua;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id=calendar></div>

Forcing a click where i want

Run my snippet code before you read my question and click on some cells, so you can understand my question better!!
I got Player A = vertical and Player B = horizontal, As you can see, Each click gives turns between each player, moving the green background around some cells, how i can force the players only to be able to click the cells that have green behind them?
note: i tried using $(selector).trigger('click'); (JQuery)
var isCol = 0;
var CellPoint = 0;
var board = [];
var P1 = {
points: 0
};
var P2 = {
points: 0
};
for (r = 0; r < 7; r++) {
var line = [];
for (c = 0; c < 7; c++) {
line.push(RandomGenerator(50, 500));
}
board.push(line);
}
function prs(curr, c, r) {
CellPoint = parseInt($(curr).text());
showTable(curr, c, r);
isCol = (isCol + 1) % 2;
clr = isCol ? 'blue' : 'red';
$(curr).text('S');
$('#turn').css("color", clr)
.text(`Player ${(isCol+1)} turn`);
if (CellPoint) {
if (isCol) {
P1.points += CellPoint;
} else {
P2.points += CellPoint;
}
$('#p1').text(`Player 1: ${P1.points}`);
$('#p2').text(`Player 2: ${P2.points}`);
} else {
console.log('selected S');
}
}
function toColor(col, row, chosen_col, chosen_row) {
var ret = false;
switch (isCol) {
case 0:
if (row == chosen_row) {
ret = true;
}
break;
case 1:
if (col == chosen_col) {
ret = true;
}
break;
}
return ret;
}
function showTable(c, chosen_col, chosen_row) {
if(c!==-1){board[chosen_row][chosen_col] = 'S';}
var str = "";
str += "<table border=1>";
for (row = 0; row < 7; row++) {
str += "<tr>";
for (let col = 0; col < 7; col++) {
str += "<td onclick='prs(this, " + col + "," + row + ")'";
if(board[row][col]=='S'){
str += " class=uniqueCell";
} else{
if (toColor(col, row, chosen_col, chosen_row)) {
str += " class='grn' ";} }
str += ">";
if(board[row][col]=='S') {
str += 'S';
} else str += board[row][col];
str += "</td>";
}
str += "</tr>";
}
str += "</table>";
document.getElementById("ff").innerHTML = str;
}
function RandomGenerator(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
showTable(-1);
var getUnique = function() {
var tdElements = document.querySelectorAll('#ff td');
tdElements[
RandomGenerator(0, tdElements.length)
].classList.add('uniqueCell');
// update the text of the cell using the class
document.querySelector('.uniqueCell').textContent = 'S';
};
getUnique();
td {
border: 2px solid black;
width: 10px;
height: 10px;
text-align: center;
}
td:hover {
background-color: lightgreen;
}
.grn {
background-color: green;
color: white;
}
.turn1 {
background-color: green;
color: red;
}
.turn0 {
background-color: green;
color: blue;
}
.uniqueCell {
background-color: tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div><span id='p1' style='color:red;'>Player1: </span> X <span style='color:blue;' id='p2'>Player2: </span></div>
<p id='turn'>Player 1 turn</p>
<div id="ff"></div>
I would suggest to use pointer-events. I have added JavaScript logic as well as modified CSS little bit.
in JavaScript I am checking for class .grn, if its available then allowing click everywhere. But if .grn is available then only td with .grn class will be clickable.
See below JavaScript logic.
if(document.querySelectorAll(".grn").length>0){
document.getElementById("tbl").classList.add("preventclick");
}else{
document.getElementById("tbl").classList.remove("preventclick");
}
See the Snippet below:
var isCol = 0;
var CellPoint = 0;
var board = [];
var P1 = {
points: 0
};
var P2 = {
points: 0
};
for (r = 0; r < 7; r++) {
var line = [];
for (c = 0; c < 7; c++) {
line.push(RandomGenerator(50, 500));
}
board.push(line);
}
function prs(curr, c, r) {
CellPoint = parseInt($(curr).text());
showTable(curr, c, r);
isCol = (isCol + 1) % 2;
clr = isCol ? 'blue' : 'red';
$(curr).text('S');
$('#turn').css("color", clr)
.text(`Player ${(isCol+1)} turn`);
if (CellPoint) {
if (isCol) {
P1.points += CellPoint;
} else {
P2.points += CellPoint;
}
$('#p1').text(`Player 1: ${P1.points}`);
$('#p2').text(`Player 2: ${P2.points}`);
} else {
console.log('selected S');
}
}
function toColor(col, row, chosen_col, chosen_row) {
var ret = false;
switch (isCol) {
case 0:
if (row == chosen_row) {
ret = true;
}
break;
case 1:
if (col == chosen_col) {
ret = true;
}
break;
}
return ret;
}
function showTable(c, chosen_col, chosen_row) {
if(c!==-1){board[chosen_row][chosen_col] = 'S';}
var str = "";
str += "<table id='tbl' border=1>";
for (row = 0; row < 7; row++) {
str += "<tr>";
for (let col = 0; col < 7; col++) {
str += "<td onclick='prs(this, " + col + "," + row + ")'";
if(board[row][col]=='S'){
str += " class=uniqueCell";
} else{
if (toColor(col, row, chosen_col, chosen_row)) {
str += " class='grn' ";
}
}
str += ">";
if(board[row][col]=='S') {
str += 'S';
} else str += board[row][col];
str += "</td>";
}
str += "</tr>";
}
str += "</table>";
document.getElementById("ff").innerHTML = str;
if(document.querySelectorAll(".grn").length>0 || document.querySelectorAll(".uniqueCell").length > 1){
document.getElementById("tbl").classList.add("preventclick");
}
}
function RandomGenerator(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
showTable(-1);
var getUnique = function() {
var tdElements = document.querySelectorAll('#ff td');
tdElements[
RandomGenerator(0, tdElements.length)
].classList.add('uniqueCell');
// update the text of the cell using the class
document.querySelector('.uniqueCell').textContent = 'S';
};
getUnique();
table#tbl.preventclick td{
pointer-events: none;
}
td {
border: 2px solid black;
width: 10px;
height: 10px;
text-align: center;
}
td:hover {
background-color: lightgreen;
}
.grn {
background-color: green;
color: white;
}
table#tbl.preventclick td.grn{
pointer-events: auto;
}
.turn1 {
background-color: green;
color: red;
}
.turn0 {
background-color: green;
color: blue;
}
.uniqueCell {
background-color: tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div><span id='p1' style='color:red;'>Player1: </span> X <span style='color:blue;' id='p2'>Player2: </span></div>
<p id='turn'>Player 1 turn</p>
<div id="ff"></div>
Update:
I have added || document.querySelectorAll(".uniqueCell").length > 1 in if condition document.querySelectorAll(".grn").length>0 to fix issue mentioned in comment : there's little problem, try clicking on all the cells, in some cases, where there is no selectable numbers, i can click on anywhere on the S cells

HTML/Javascript multiplication table that takes inputs and highlights the answer on table

As the title states, I need to make a multiplication table using JS and HTML that takes two user inputs and highlights the answer on the table. I have the table made, I'm just struggling with how to take the user inputs from the ids "leftOp" and "rightOp" and highlighting the answer on the table.
var color_td;
document.write("<table border='1px'>");
for(var i = 1; i < 11; i++) {
document.write("<tr style='height:30px;'>");
for(var j = 1; j < 11; j++) {
if(j == 1 || i == 1) {
color_td = "#ccc";
}
else {
color_td = "#fff";
}
document.write("<td style='width:30px;background-color:" + color_td + "'>" + i*j + "</td>");
}
document.write("</tr>");
}
document.write("</table>");
<input type='text' id='leftOp' value=''>
<input type='text' id='rightOp' value=''>
I tried a simple answer with your code style.
Just bind the event "onkeyup" of your inputs to a function that highlight the result cell.
To identify each cell, I add an id and a class to each one. The id is a concatenation of the two indexes and the class difference between border cells and other cells.
To hightlight the rersult cell, you use the inputs values and build the id of the result cell with them.
Don't forget to reset the cells colors on each invocation.
var color_td;
document.write("<table border='1px'>");
for (var i = 1; i < 11; i++) {
var id;
var cellClass;
document.write("<tr style='height:30px;'>");
for (var j = 1; j < 11; j++) {
id = 'cell-' + i + '-' + j;
if (j == 1 || i == 1) {
color_td = "#ccc";
cellClass = "border-cell";
}
else {
color_td = "#fff";
cellClass = "result-cell";
}
document.write("<td class='" + cellClass + "' id='" + id + "' style='width:30px;background-color:" + color_td + "'>" + i * j + "</td>");
}
document.write("</tr>");
}
document.write("</table>");
function inputChange() {
var left = document.getElementById('leftOp').value;
var right = document.getElementById('rightOp').value;
if (!left || !right || left > 10 || left < 1 || right > 10 || left < 1) {
return;
}
var cells = document.getElementsByClassName('result-cell');
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
cell.style.backgroundColor = '#fff';
}
var cells = document.getElementsByClassName('border-cell');
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
cell.style.backgroundColor = '#ccc';
}
var resultCell = document.getElementById('cell-' + left + '-' + right);
resultCell.style.backgroundColor = '#5fc047';
}
<input type='text' id='leftOp' value='' onkeyup="inputChange()">
<input type='text' id='rightOp' value='' onkeyup="inputChange()">
Important tip: Doesn't use document.write when creating elements and appending new things to DOM, use the correct API for that, such as document.createElement that you can manage the elements much better. In my code below I'm using it to show you as example.
After creating the table, you'll need a function to get the values and the do the verifications and Maths. Also, add the operands i and j (example: "i_j") as the id of each <td> (take care to not have any repeated id), that way you'll have an easy way to found the td you should highlight.
Also, you should have some way to clear the background color of the td which is already highlighted, for that I used an auxiliar function called cleanTds.
Take a look:
var color_td;
let table = document.createElement("table");
document.body.appendChild(table);
for(var i = 1; i < 11; i++) {
let tr = document.createElement("tr");
tr.style.height = "30px"
table.appendChild(tr);
var color_class;
for(var j = 1; j < 11; j++) {
if(j == 1 || i == 1) {
color_class = "grayBg";
}
else {
color_class = "whiteBg";
}
let td = document.createElement("td");
td.className = "tdClass " + color_class;
td.id = i +"_"+ j;
td.style.background = color_td;
td.textContent = i * j;
tr.appendChild(td);
}
}
document.getElementById("calc").onclick = (ev) => {
cleanTds()
let val1 = document.getElementById("leftOp").value;
let val2 = document.getElementById("rightOp").value;
if (val1 == null || val1 == ""){ val1 = 0}
if (val2 == null || val2 == ""){ val2 = 0}
let tdResult = document.getElementById(val1 + "_" + val2)
if (tdResult != null){
tdResult.style.background = "green";
}
}
function cleanTds(){
let tds = document.querySelectorAll("td");
for (var td of tds){
td.style.background = ""
}
}
.tdClass{
height: 30px;
width: 30px;
border: 1px solid;
}
.grayBg{
background: #ccc;
}
.whiteBg{
background: #fff;
}
<input type='text' id='leftOp' value=''>
<input type='text' id='rightOp' value=''>
<button id="calc">Calculate</button>
This should get you started. it's triggered when the enter key is pressed
var color_td;
document.write("<table border='1px'>");
for(var i = 1; i < 11; i++) {
document.write("<tr style='height:30px;'>");
for(var j = 1; j < 11; j++) {
var idName = 'R'+i + 'C' + j;
if(j == 1 || i == 1) {
color_td = "#ccc";
}
else {
color_td = "#fff";
}
document.write("<td id='"+idName + "'style='width:30px;background-color:" + color_td + "'>" + i*j + "</td>");
}
document.write("</tr>");
}
document.write("</table>");
left = document.getElementById("leftOp");
right = document.getElementById("rightOp");
document.getElementById("rightOp")
.addEventListener("keyup", function(event) {
event.preventDefault();
if (event.keyCode === 13) {
left = document.getElementById("leftOp");
right = document.getElementById("rightOp");
var idName = 'R' + leftOp.value + 'C' + rightOp.value;
document.getElementById(idName).style.backgroundColor = "lightblue";
}
});
<input type='text' id='leftOp' value=''>
<input type='text' id='rightOp' value='' >

Using jQuery to Generate a Grid of DIVs, but Get Wierd Behavior if it Isn't 10 x 10

I'm using jQuery to generate a grid of divs that I will then style to become the board of a game. It works fine when I set the grid to 10 x 10, but when I increase the number of squares, even by one, the second column from the left either doesn't display at all (although the html is fine), or it extends from the bottom of the grid down instead of up.
I've tried messing with the stylesheet and pretty much every variable in the code to no avail. Any help would be appreciated.
$(document).ready(function() {
var row_count = 11;
var base = document.getElementById('base');
var square = '<div class="square"></div>';
var col_count = 11; // Sets the number of columns
while (col_count >= 0) { //Outer loops controls the columns.
row_count = 11; // sets the number of rows
while (row_count >= 0) {
$('<div class="square" id = "in_col' + '_' + col_count + '_' + row_count + '"></div>', {
"class": "square"
}).appendTo('#base');
row_count--;
}
col_count--;
}
// These two values, for posx and posy are the positioning
// coordinates for the squares of the grid
var posx = 10;
var posy = 10;
var col = 0; // Initiates the column counter for the below while loop
while (col <= 11) { // must match var col_count above
$.each($('div[id^="in_col_' + col + '"]'), function() {
$(this).css('top', posy);
$(this).css('left', posx);
posy += 41;
});
posy = 10;
posx += 41;
col++;
}
});
.square {
border: 1px solid black;
height: 40px;
width: 40px;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='base'>
</div>
Fiddle of example
I refactored the code a bit, using for loops instead so we don't have to keep track of iteration variables. I also used float: left; on the tiles and clear: both; whenever we want to wrap down to a new line.
Javascript
$(document).ready(function() {
var col_count = 11; //Sets the number of columns
var row_count = 11; //sets the number of rows
var base = $('#base');
var square = '<div class="square"></div>';
for(var i = 0; i < col_count; i++){
for(var j = 0; j < row_count; j++){
var tile = $(square);
if(j === 0) tile.addClass('newRow');
base.append(tile);
}
}
});
CSS
.square {
border: 1px solid black;
height: 40px;
width: 40px;
float: left;
margin-top: -1px;
margin-left: -1px;
}
.newRow {
clear: both;
}
fiddle: https://jsfiddle.net/e0g6y9th/
Problem is in $.each($('div[id^="in_col_' + col + '"]'), function() {
col_10 is called 2 times. Change it to $.each($('div[id^="in_col_' + col + '_"]'), function() {, a more restrictive regex
$(document).ready(function() {
var row_count = 11;
var base = document.getElementById('base');
var square = '<div class="square"></div>';
var col_count = 11; // Sets the number of columns
while (col_count >= 0) { //Outer loops controls the columns.
row_count = 11; // sets the number of rows
while (row_count >= 0) {
$('<div class="square" id = "in_col' + '_' + col_count + '_' + row_count + '"></div>', {
"class": "square"
}).appendTo('#base');
row_count--;
}
col_count--;
}
// These two values, for posx and posy are the positioning
// coordinates for the squares of the grid
var posx = 10;
var posy = 10;
var col = 0; // Initiates the column counter for the below while loop
while (col <= 11) { // must match var col_count above
$.each($('div[id^="in_col_' + col + '_"]'), function() {
$(this).css('top', posy);
$(this).css('left', posx);
posy += 41;
});
posy = 10;
posx += 41;
col++;
}
});
.square {
border: 1px solid black;
height: 40px;
width: 40px;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='base'>
</div>
The selector in your $.each loop is matching columns multiple times. A simple solution will be to zero-pad the numbers in your ids:
function pad(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
Then change
$('<div class="square" id = "in_col' + '_' + col_count + '_' + row_count + '"></div>', {
"class": "square"
}).appendTo('#base');
To
$('<div class="square" id = "in_col' + '_' + pad(col_count,3) + '_' + pad(row_count,3) + '"></div>', {
"class": "square"
}).appendTo('#base');
And
$.each($('div[id^="in_col_' + col + '"]'), function() {
to
$.each($('div[id^="in_col_' + pad(col,3) + '"]'), function() {
Here's a working fiddle: https://jsfiddle.net/xc9gyv8p/4/
Here's my take
fiddle
$(document).ready(function() {
var row_count = 11;
var col_count = 11;
var x = 0;
var y = 0;
var offX = 41;
var offY = 41;
for(var i = 0; i < col_count; i++){
$('#base').append('<div id="col_'+i+'" class="col" style="left:'+x+'px"><div>');
x += offX;
y = 0;
for(var j = 0; j < row_count; j++){
$('#col_'+i).append('<div class="square" id="row_'+j+'" style="top:'+y+'px"></div>');
y += offY;
}
}
});
.col{
position: absolute;
}
.square {
border: 1px solid black;
height: 40px;
width: 40px;
position: absolute;
}
Yours is more a mathematical problem. My version is much easier to understand, here is a fiddle.
go row by row and column by column in each row. so var i is each row and var j is each column in the row (starting every time by 1 and count up till reach var col_count.
$(document).ready(function() {
var row_count = 11;
var col_count = 11;
var size = 41;
var base = document.getElementById('base');
for (var i=1; i<=row_count; i++) {
for (var j=1; j<=col_count; j++) {
$('<div class="square" id = "in_col' + '_' + j + '_' + i + '"></div>')
.addClass('square')
.css({
'left': j*size,
'top': i*size
})
.appendTo('#base');
}
}
});
to select each elements in column 1 use div[id^="in_col_1_"]. I would recommend you to work with data attributes by changing the code to:
$(document).ready(function() {
var row_count = 11;
var col_count = 11;
var size = 41;
var base = document.getElementById('base');
for (var i=1; i<=row_count; i++) {
for (var j=1; j<=col_count; j++) {
$('<div class="square" id = "in_col' + '_' + j + '_' + i + '"></div>')
.addClass('square')
.attr('data-col', j)
.attr('data-row', i)
.css({
'left': j*size,
'top': i*size
})
.appendTo('#base');
}
}
});
so you can easily select elements in row 1 by div[data-row="1"] and column 1 by div[data-col="1"]. Have a look at this fiddle.
insted for running while loop backward run it forward, it will fix your problem
var row_count = 0;
var col_count = 0; // Sets the number of columns
while (col_count <= 10){ //Outer loops controls the columns.
row_count = 0; // sets the number of rows
while (row_count <= 10) { // Inner loop controls the cells in each column.
$('<div class="square" id = "in_col' + '_' + col_count + '_' + row_count +'"></div>', {"class":"square"}).appendTo('#base');
row_count++;
}
col_count++;
}
IrkenInvader, thanks, I went with your solution, much cleaner than what I had originally and obviates the need for the bit of code (the regex in the jQuery selector) that was causing the problem.
$(document).ready(function(){
var col_count = 11;// Sets the number of columns
var row_count = 11; //sets the number of rows
var base = $('#base');
for(var i = 0; i < col_count; i++) {
for (var j = 0; j < row_count; j++) {
var square = '<div class="square" id = "in_col' + '_' + j + '_' + i +'"></div>';
var tile = $(square);
if (j === 0) tile.addClass('newRow');
base.append(tile);
}
}
});

Merge two HTML tables using Javascript Objects as data feed?

I am going to have multiple arrays of arrays and I want to make objects from the array and then merge it into one table. I already did that, however I need help using the object to make one larger table?
If a key exists in one object but not the others the value can just be blank for the object the key doesnt exist. I am able to make multiple different tables but how can I merge them to make the table one larger one?
var data =[["default_PROJECT","Allow","Connect","Allow","AddComment","Allow","Write",
"Allow","ViewComments","Allow","ExportData","Allow","ExportImage","Allow","ViewUnderlyingData","Allow","Read","Allow","ShareView","Allow","Filter"],
["Allow","ExportImage","Allow","Write","Allow","ViewComments",
"Allow","ShareView","Allow","Filter","Allow","ExportData","Allow","Connect","Allow",
"Read","Allow","ViewUnderlyingData","Allow","AddComment","Allow","ViewComments","Deny","ExportData","Allow",
"AddComment","Deny","Write","Allow","Read","Deny","ExportXml","Deny","ShareView","Allow","Connect","Allow","ChangeHierarchy","Allow",
"WebAuthoring","Deny","ViewUnderlyingData","Deny","Filter","Deny","ExportImage"]];
var result = [];
for(var i = 0, len = data.length; i < len; i++) {
var list = data[i];
result[i] = { name: list[0] };
for (var j = list.length - 1; j >= 1; j = j - 2) {
var key = list[j];
var value = list[j - 1];
if( result[i][key] !== "Deny" ) {
result[i][key] = value;
}
}
}
console.log(result);
var resultElement = document.getElementById('result1');
var tpl = '';
for(var t = 0, tLen = result.length; t < tLen; t++) {
var item = result[t];
tpl+= '<table align=center style="width:25%;">' +
'<thead>' +
'<tr><td colspan="2">Project: ' + item.name + '</td></tr>' +
'<tr><th>Permission</th><th>Value</th></tr>' +
'</thead>' +
'<tbody>'
;
for(var key in item) {
if(!item.hasOwnProperty(key) || key === 'name') { continue; }
if(item[key] == "Allow"){
tpl += '<tr style="background-color:greenyellow;"><td>'+ key +'</td><td>'+ item[key] +'</td></tr>';
}
else{
tpl += '<tr style="background-color:red;"><td>'+ key +'</td><td>'+ item[key] +'</td></tr>';
}
}
}
resultElement.innerHTML = tpl;
table { text-align: left; width: 100%; margin-bottom: 50px; border-collapse: collapse;}
td, th { width: 50%; border: 1px solid black; line-height: 1; padding:2px 10px;}
[colspan="2"] { color: blue; font-weight: bolder;text-transform: uppercase; text-align: center;}
<div id="result1"></div>
http://jsfiddle.net/h2s17hac/
This merges the two tables.
Fiddle
var data =[["default_PROJECT","Allow","Connect","Allow","AddComment","Allow","Write",
"Allow","ViewComments","Allow","ExportData","Allow","ExportImage","Allow","ViewUnderlyingData","Allow","Read","Allow","ShareView","Allow","Filter"],
["test_PROJECT", "Allow","ExportImage","Allow","Write","Allow","ViewComments",
"Allow","ShareView","Allow","Filter","Allow","ExportData","Allow","Connect","Allow",
"Read","Allow","ViewUnderlyingData","Allow","AddComment","Allow","ViewComments","Deny","ExportData","Allow",
"AddComment","Deny","Write","Allow","Read","Deny","ExportXml","Deny","ShareView","Allow","Connect","Allow","ChangeHierarchy","Allow",
"WebAuthoring","Deny","ViewUnderlyingData","Deny","Filter","Deny","ExportImage"]];
function makeObjects(data){
result = [];
for(var i = 0, len = data.length; i < len; i++) {
var list = data[i];
result[i] = { Name: list[0] };
for (var j = list.length - 1; j >= 1; j = j - 2) {
var key = list[j];
var value = list[j - 1];
if( result[i][key] !== "Deny" ) {
result[i][key] = value;
}
}
}
return result;
}
function sortObject(obj) {
return Object.keys(obj).sort().reduce(function (result, key) {
result[key] = obj[key];
return result;
}, {});
}
function getKeys(data){
var keys = [];
for(i=0; i<data.length; i++){
key = Object.keys(data[i]);
for(j =0; j<key.length; j++){
if(keys.indexOf(key[j]) == -1){
keys.push(key[j]);
}
}
}
return keys;
}
function addMissingKeys(keys, data){
var filtData = [];
for(i=0; i<data.length; i++){
for(j=0; j<keys.length; j++){
if(data[i][keys[j]] == undefined){
data[i][keys[j]] = "";
}
}
}
for(num=0; num<data.length; num++){
filtData.push(sortObject(data[num]));
}
return filtData;
}
var dataa = makeObjects(data);
var keys = getKeys(dataa);
var filtData = addMissingKeys(keys, dataa);
console.log(filtData);
var resultElement = document.getElementById('result1');
var tpl = '<table align=center style="width:75%;">';
for(var t = 0, tLen = filtData.length; t < tLen; t++) {
var item = filtData[t];
tpl+= '<tr><td>' + item.Name + '</td>';
for(var key in item) {
if(!item.hasOwnProperty(key) || key === 'Name') { continue; }
if(item[key] != "") {
if(item[key] == "Allow"){
tpl += '<td style="background-color:greenyellow;">'+ key +':<br>'+ item[key] +'</td>';
}
else{
tpl += '<td style="background-color:red;">'+ key +':<br>'+ item[key] +'</td>';
}
} else {
tpl += '<td></td>';
}
}
tpl += '</tr>';
}
tpl += '</table>';
resultElement.innerHTML = tpl;
table { text-align: left; width: 100%; margin-bottom: 50px; border-collapse: collapse;}
td, th { width: 50%; border: 1px solid black; line-height: 1; padding:2px 10px;}
[colspan="2"] { color: blue; font-weight: bolder;text-transform: uppercase; text-align: center;}
<div id="result1"></div>
<div id="test"></div>

Categories

Resources