Dynamicaly fill table td based on array of elements - javascript

I need to fill the background of table td based on td values. Below is the sample code i wrote for filling the td cell value.
applySchedules = function(schedules){
$.map(schedules, function(value, index){
$('#'+value.start).css('background', 'green');
});
}
var temp = [{start:9, end:10}, {start:13, end:14}]
applySchedules(temp);
tr {
border-width:2px;
outline:solid;
}
td {
border-width:2px;
width:60px;
outline:solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table>
<tr>
<td id="8">8AM</td>
<td id="9">9AM</td>
<td id="10">10AM</td>
<td id="11">11AM</td>
<td id="12">12PM</td>
<td id="13">1PM</td>
<td id="14">2PM</td>
<td id="15">3PM</td>
<td id="16">4PM</td>
<td id="17">5PM</td>
<td id="18">6PM</td>
<td id="19">7PM</td>
<td id="20">8PM</td>
</tr>
</table>
Basically i will get json array of time slots that are occupied for the given day. The problem comes when the slot span more than or less than 1hour. The time slots are allotted in multiple's 30 mins.
Like {start:10,end:11.30},{start:12,end:12.30},{start:14.30,end:15}
Looking for some pointers how to handle these kind of cases.
Sample Output :

I would advise:
increase number of spans such way, that there would be your 30 minute item
Don't use just numbered ID's -> it is not a very good way
$(function(){
var applySchedules = function(schedules){
$.map(schedules, function( value,index){
var startHour = value.start.split(":")[0];
var endHour = value.end.split(":")[0];
var halfStart = value.start.split(":")[1];
var halfEnd = value.end.split(":")[1];
var startContainer = $('#time'+ padLeft( startHour, 2));
var endContainer = $('#time'+ padLeft( endHour, 2));
if( parseInt( halfStart )){
startContainer.append( $("<div />").addClass("start") );
}
if( parseInt( halfEnd )){
endContainer.append( $("<div />").addClass("end") );
}
if( ( parseInt(endHour) - parseInt(startHour) ) > 0){
for( var i = 1; i < parseInt(endHour) - parseInt(startHour); i++ ){
$('#time'+ padLeft( (parseInt(startHour) + i)+"", 2)).append( $("<div />").addClass("full") );
}
}
});
}
function padLeft(str,size,padwith) {
if(size <= str.length) {
return str;
} else {
return Array(size-str.length+1).join(padwith||'0')+str
}
}
var initTime = function(){
for( var i =0; i< 24; i++ ){
var $item;
if( i < 12 ){
$item = $("<td/>").text( padLeft(i+"",2)+":00 AM" );
}else if( i == 12 ){
$item = $("<td/>").text( padLeft( (i)+"",2)+":00 PM" );
} else {
$item = $("<td/>").text( padLeft( (i-12)+"",2)+":00 PM" );
}
$item.attr("id", "time" + padLeft(i+"",2));
$("#timeContainer").append($item);
}
}
var temp=[{start:"9:00",end:"9:30"}, {start:"13:00",end:"13:30"}, { start:"14:00", end:"14:30"}, {start:"15:30", end:"18:30"}]
initTime();
applySchedules(temp);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<style>
tr{border-width:2px; outline:solid;}
td{border-width:2px; width:60px; outline:solid; position:relative;}
div.start {
width: 50%;
background: green;
position: absolute;
height: 100%;
top: 0;
right: 0;
z-index:-1;
}
div.end {
width: 50%;
background: green;
position: absolute;
height: 100%;
top: 0;
left: 0;
z-index:-1;
}
div.full{
width: 100%;
background: green;
position: absolute;
height: 100%;
top: 0;
z-index:-1;
}
</style>
<body>
<table>
<tr id="timeContainer">
</tr>
</table>
</body>
UPDATED ANSWER
Some first approach to code

If you are adamant on using your current setup, might I suggest using CSS gradients:
...
$('#'+value.start).css('background','repeating-linear-gradient(to right, #00FF33, #00FF33 23px, #FFFFFF 23px, #FFFFFF 46px)');
...
46px is the width of the <td> in the fiddle, this would probably have to be generated dynamically. The second two values are half of the width of the whole <td> which creates a gradient covering only half of the whole <td>. You can then split this into smaller section by doing more complicated maths but I suggest referring to https://css-tricks.com/stripes-css/ for more information on this trick.
Here's the fiddle:
http://jsfiddle.net/85mJN/190/

Related

How to change index in html element

In my code, each class will be toggled by clicking them.
I would like to understand the data,class-index, in my code,class-index is changed and class will be changed aligned with this.
But when I look at developer tool, class-index dosen't seems to be changed.
<td class="classC" data-class-index="0">Value 1</td>
<td class="classB" data-class-index="0">Value 1</td>
Considering this, I add undo button,it works as a reverse of toggle,but it didn't work well.
How can I fix it?
$(function(){
var classArray = ['classA','classB','classC'];
var arrLen = classArray.length;
$("#our_calendar td").click(function() {
var classIndex = $(this).data('class-index');
$(this).removeClass(classArray[classIndex]);
if(classIndex < (arrLen-1)) {
classIndex++;
} else {
//reset class index
classIndex = 0;
}
$(this).addClass(classArray[classIndex]);
$(this).data('class-index',classIndex);
});
$("#undo").on('click',function() {
var classIndex = $(this).data('class-index');
$(this).removeClass(classArray[classIndex]);
classIndex--;
$(this).addClass(classArray[classIndex]);
$(this).data('class-index',classIndex);
})
});
.classA {
background-color: aqua;
}
.classB {
background-color: yellow;
}
.classC {
background-color: red;
}
td {
transition-duration:0.4s ;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="our_calendar">
<tr><td class="classA" data-class-index="0">Value 1</td></tr>
</table>
<button id="undo">undo</button>
With regard to the DOM not being updated, this is expected behaviour as the data() method only updates jQuery's internal cache of data attributes. It does not update the data attributes held in the relevant elements in the DOM.
With regard to your issue, the main problem is because you're using this within the #undo click handler. That will refer to the clicked button, not the td with the class on it. You just need to target the right element.
Also note that the classIndex logic can be simplified by using the modulo operator. Try this:
$(function() {
let classArray = ['classA', 'classB', 'classC'];
let arrLen = classArray.length;
let $td = $("#our_calendar td");
$td.click(function() {
let classIndex = $td.data('class-index');
$td.removeClass(classArray[classIndex]);
classIndex = ++classIndex % classArray.length;
$td.addClass(classArray[classIndex]);
$td.data('class-index', classIndex);
});
$("#undo").on('click', function() {
let classIndex = $td.data('class-index');
$td.removeClass(classArray[classIndex]);
classIndex = (--classIndex + classArray.length) % classArray.length;
$td.addClass(classArray[classIndex]);
$td.data('class-index', classIndex);
});
});
.classA { background-color: aqua; }
.classB { background-color: yellow; }
.classC { background-color: red; }
td { transition-duration: 0.4s; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="our_calendar">
<tr>
<td class="classA" data-class-index="0">Value 1</td>
</tr>
</table>
<button id="undo">undo</button>

Create table with Javascript

I'm creating some kind of "Mario puzzle" all in one file for now.
I managed to create a table using window prompt. I don't know how to make height and width fixed so it will be the same size as the pictures on the top.
Later on, I will make an option to select a picture and insert it in the blank square. Any advice please?
After the user inputs rows and columns:
Playing around and making something, you get the point
Code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mario</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
table,td {
border: 1px solid grey;
border-collapse: collapse;
margin: 10px;
background-color: silver;
}
img {
display: block;
}
</style>
</head>
<body>
<table>
<tr>
<td><img src="images/sprite1.gif" alt="sprite1.gif"></td>
<td><img src="images/sprite2.gif" alt="sprite2.gif"></td>
<td><img src="images/sprite3.gif" alt="sprite3.gif"></td>
<td><img src="images/sprite4.gif" alt="sprite4.gif"></td>
<td><img src="images/sprite5.gif" alt="sprite5.gif"></td>
<td><img src="images/sprite6.gif" alt="sprite6.gif"></td>
<td><img src="images/sprite7.gif" alt="sprite7.gif"></td>
<td><img src="images/sprite8.gif" alt="sprite8.gif"></td>
<td><img src="images/sprite9.gif" alt="sprite9.gif"></td>
<td><img src="images/sprite10.gif" alt="sprite10.gif"></td>
<td><img src="images/sprite11.gif" alt="sprite11.gif"></td>
<td><img src="images/sprite12.gif" alt="sprite12.gif"></td>
<td><img src="images/sprite13.gif" alt="sprite13.gif"></td>
<td><img src="images/sprite14.gif" alt="sprite14.gif"></td>
<td><img src="images/sprite15.gif" alt="sprite15.gif"></td>
<td><img src="images/sprite16.gif" alt="sprite16.gif"></td>
</tr>
</table>
<script type="text/javascript">
var r = window.prompt("Please enter rows:"); //vrstica tr
while(r<5 || r>20){
r = window.prompt("Wrong, enter a number between 5 and 20:");
}
var c = window.prompt("Please enter columns:"); //stoplec td
while(c<10 || c>40){
c = window.prompt("Wrong, enter a number between 10 and 40:");
}
document.write('<table>');
for(i=1;i<=r;i++) {
document.write("<tr>");
for(j=1;j<=c;j++) {
document.write("<td>"+" "+"</td>");
}
document.write("</tr>");
}
document.write('</table>');
</script>
</body>
</html>
As mentioned, do not use document.write. Create the elements in memory and then append to the DOM when ready.
As for height and width; 1) set the inline style of the tds or 2) apply height and width CSS.
Make sure that wherever you set the dimensions, to make it the same as the images above. Option #2 is the preferred approach.
Option #1
function el( tagName ) {
return document.createElement( tagName );
}
var rows = 5;
var cols = 10;
var table = el( 'table' );
for ( var i = 0; i < rows; i++ ) {
var tr = el( 'tr' );
for ( var j = 0; j < cols; j++ ) {
var td = el( 'td' );
td.style.width = '20px';
td.style.height = '20px';
tr.appendChild( td );
}
table.appendChild( tr );
}
document.body.appendChild( table );
td {
border: 1px solid #ccc;
}
Option #2
function el( tagName ) {
return document.createElement( tagName );
}
var rows = 5;
var cols = 10;
var table = el( 'table' );
for ( var i = 0; i < rows; i++ ) {
var tr = el( 'tr' );
for ( var j = 0; j < cols; j++ ) {
tr.appendChild( el( 'td' ) );
}
table.appendChild( tr );
}
document.body.appendChild( table );
td {
border: 1px solid #ccc;
width: 20px;
height: 20px;
}

Allowing different widths of columns in rows

I am trying to get the table columns to have different widths on each row. I'm using an array to get the values which I am turning into width percentages and passing it into the column. The output seems to copy the row above even though it has different widths.
http://jsfiddle.net/0182rutf/2/
HTML
<table border='1' id="table">
JS
var Array = [
[10, 5, 10],
[50, 2, 10]
];
for (var k = 0; k < Array.length; k++)
{
var totalCol = 0;
$.each(Array[k], function (){totalCol += parseInt(this);});
$('#table').append('<tr id="' + k + '"></tr>')
for (var i = 0; i < Array[k][i]; i++)
{
var weight = Array[k][i];
var width = weight * 100 / totalCol;
$('#' + k).append('<td width="' + width + '%">column</td>');
}
}
Any idea how to fix this?
So as a followup for my comment above.
I would suggest going with flexbox here. But since you know the width of every column you want to draw you can also go without it and still keep IE9 support.
What I am doing here is simply having a div#grid acting as a package for your "table". Then with the JS I generate a div.row kind of like you generated the tr elements and in those I generate the div.cell elements like you would have done with the td elements and set the width directly on those "cells".
I changed your snippet to work:
http://jsfiddle.net/0182rutf/5/
CSS:
#grid {
border: 1px solid black;
}
#grid .row {
position: relative;
}
#grid .cell {
display: inline-block;
box-sizing: border-box;
border: 1px solid green;
}
JS:
var Array = [
[10, 5, 10],
[50, 2, 10]
];
for (var k = 0; k < Array.length; k++)
{
var totalCol = 0;
$.each(Array[k], function (){totalCol += parseInt(this);});
$('#grid').append('<div class="row" id="' + k + '"></div>')
for (var i = 0; i < Array[k][i]; i++)
{
var weight = Array[k][i];
var width = weight * 100 / totalCol;
$('#' + k).append('<div class="cell" style="width: ' + width + '%">column</div>');
console.log(weight);
}
}
HTML:
<div id="grid"></div>
Note that with your calculation 50 is a weight that is too much :)
Modify your JS to form a div based table and sample output should be as follows:
HTML
<div id="row1">
<div class="float-left div1">1st </div>
<div class="float-left div2">2st </div>
<div class="float-left div2">3st </div>
<div class="clear-fix"></div>
</div>
<div id="row2">
<div class="float-left div1">1st </div>
<div class="float-left div2">2st </div>
<div class="float-left div2">3st </div>
<div class="clear-fix"></div>
</div>
CSS
.float-left {
float:left;
border: 1px solid #ccc;
}
#row1 .div1 {
width:100px;
}
#row1 .div2 {
width:200px;
}
#row1 .div3 {
width:50px;
}
#row2 .div1 {
width:50px;
}
#row2 .div2 {
width:100px;
}
#row2 .div3 {
width:20px;
}
.clear-fix {
clear:both;
}
I think may be you can use this solution if you are comfortable. I created two tables and assigned a single row.
<table border='1' id="table0"></table>
<table border='1' id="table1"></table>
and script code is
var Array = [
[10, 5, 10],
[50, 2, 10]
];
for (var k = 0; k < Array.length; k++)
{
var totalCol = 0;
$.each(Array[k], function (){
totalCol += parseInt(this);
});
$('#table' + k).append('<tr id="' + k + '"></tr>')
for (var i = 0; i < Array[k].length; i++)
{
var weight = Array[k][i];
var width = weight * 100 / totalCol;
$('#' + k).append
('<td width="' + width + '%" >column</td>');
console.log(weight);
}
}
And fiddle link is here

jquery - showing box with if statement by click on button when field is completed - quiz creation

I'm desperately trying to create something very simple for you!
Here's my problem:
I'd like to create a small quiz in which when someone writes anything in a field (), and then click the button "ok" (not sure if I should use a or a ), then 3 possibilities arise (for each case a box appearing under the field input):
The answer is exact and correctly written: then the text will be "Great job!"
The answer is almost correct, meaning that the word is not correctly written (we can define if necessary "almost answers"): the text will be "Almost there..."
The answer is completely wrong, the text will be "Try again!"
Right now I have that:
<body>
<div>
<table>
<tbody>
<tr>
<td>To whom it belongs?</td>
</tr>
<tr>
<td>
<img src="#" alt="Tim's coat" width="100%"/>
</td>
</tr>
<tr>
<td class="answer-box">
<input type="text" class="field-answer" placeholder="Write it there!">
<button id="showresult" class="button-answer" value="Ok">OK</button>
</td>
</tr>
<tr>
<td>
<div class="res" id="switch">Great job!</div>
<div class="res" id="switch2">Almost there...</div>
<div class="res" id="switch3">Try again!</div>
</td>
</tr>
</tbody>
</table>
</div>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var artist = ["abba"];
var almostartist = ["abaa", "aaba", "aabaa"];
$(document).ready(function(){
$('.field-answer').bind('keyup', function(){
if("#showresult").click(function() {
if($.inArray($(this).val().toLowerCase().trim().replace(/[^\w\s\-\_!##\$%\^\&*\\")\(+=._-]/g, ''), artist) >= 0){
$('#switch').show('good');
}
else if($.inArray($(this).val().toLowerCase().trim().replace(/[^\w\s\-\_!##\$%\^\&*\\")\(+=._-]/g, ''), almostartist) >= 0){
$('#switch2').addClass('soso');
if{
$('#switch3').addClass('non');
}
else {
$('#switch3').removeClass('non');
}
});
});
}
</script>
But of course this is not working...
In case, my CSS is here:
.res {
display: none;
color: white;
font-weight: bold;
text-align: center;
background-color: #490058;
height: 75px;
max-width: 100%;
line-height: 70px;
font-size: 140%;
}
.res.good {
display: block;
}
.res.soso {
display: block;
}
.res.non {
display: block;
}
.answer-box {
text-align: center;
}
.button-answer {
border: none;
background-color: #490058;
color: white;
font-size: 120%;
font-weight: bold;
padding: 8px;
left: 260px;
}
.field-answer {
text-align: center;
border: none;
border-bottom: 2px solid black;
background-color: transparent;
max-width: 230px;
height: 40px;
font-size: 20px;
text-transform: uppercase;
outline: 0;
}
Someone could help me to figure that out, please?
I'm quite sure I'm not far, but cannot solve it...
If you need more precisions on stuffs, please don't hesitate! ;)
Thanks guys!
Baptiste
A slightly different approach - no better than any other suggestion - FIDDLE.
JS
var artist = ["abba"];
var almostartist = ["abaa", "aaba", "aabaa"];
$('.field-answer').focus(function(){
$('.res').css('display', 'none');
$(':input').val('');
});
$('#showresult').on('click', function(){
useranswer = $('.field-answer').val();
useranswer = useranswer.toLowerCase().trim().replace(/[^\w\s\-\_!##\$%\^\&*\\")\(+=._-]/g);
if( $.inArray( useranswer, artist ) === 0 )
{
$('#switch1').css('display', 'block');
}
else if ( $.inArray( useranswer, almostartist ) >= 0 )
{
$('#switch2').css('display', 'block');
}
else //if ( $.inArray( useranswer, almostartist ) < 0 )
{
$('#switch3').css('display', 'block');
}
});
your whole function is bound in to 'keyup' event.
keyup event only occurs once when key is released from pressed.
try deleting bind('keyup', function)
I've found a solution to your problems.
Check this Fiddle
In this script every time you click on the button the field text is compared with the values of the array
Depending on the value of the the corrisponding div is showed.
code
<script type="text/javascript">
$(document).ready(function(){
var artist = ["abba"];
var almostartist = ["abaa", "aaba", "aabaa"];
$("#showresult").click(function() {
var text=$('.field-answer').val();
if(artist.indexOf(text) > -1){
$('#switch').show();
}
else if(almostartist.indexOf(text) > -1){
$('#switch2').show();
}
else{$('#switch3').show();}
});
});
</script>
if you want the message appears on keyup you have to use this code
<script type="text/javascript">
$(document).ready(function(){
var artist = ["abba"];
var almostartist = ["abaa", "aaba", "aabaa"];
$(".field-answer").on('keyup',function() {
$('.res').hide()
var text=$('.field-answer').val().toLowerCase();
if(artist.indexOf(text) > -1){
$('#switch').show();
}
else if(almostartist.indexOf(text) > -1){
$('#switch2').show();
}
else{$('#switch3').show();}
});
});
</script>
If you like one of these solutions remember to falg in green my answer ;) thanks.

Synchronizing span and textarea scrollbars - scrollbar slightly off and pasting issue

I have a table set up in the following way, with each cell containing a span and a textarea:
<table>
<tr><td class="title">Original File</td></tr>
<tr><td><span id='ogline' onscroll="og.scrollTop=scrollTop"></span><span><textarea onscroll="ogline.scrollTop=scrollTop" onkeyup="linenumber()" id='og' onfocusout="linenumber()"></textarea></span></td></tr>
</table>
Along with that I have the following CSS:
<style>
span {
width:93%;
height: 100%;
}
textarea {
width:92%;
height: 100%;
border-style:solid;
border-color:black;
border-width:2px;
font-size:13px;
}
table {
width:100%;
height:100%;
}
.title {
height:5%;
text-align:center;
background-color:#009;
color:white;
}
#ogline {
padding-top:4px;
overflow:auto;
font-size:12px;
line-height:14.99px;
width:6%;
}
</style>
What I am trying to do is have the scroll bar of the span and the scroll bar of the textarea synch up. I've somewhat accomplished this using the onscroll event listener with the following code:
onscroll="og.scrollTop=scrollTop"
onscroll="ogline.scrollTop = scrollTop
This has somewhat accomplished what I want it to, with the span being about a line off of where it should be. The greatest problem I am having though is when I paste a large amount of text into the textarea. This almost completely doesn't work, with both scrollbars being completely off until I hold one of the scrollbars down for a significant amount of time before the other scrollbar will try to play catch up with the other.
Any suggestions? Is there maybe a better approach to this issue that I should try? Any help would be appreciated.
This could work:
var scrolling=false;
function og_scroll(el)
{
if (scrolling && el!=scrolling) {
return;
}
scrolling = el;
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) { // searching for id==og*
textareas[i].scrollTop=el.scrollTop;
}
}
scrolling = false;
}
function up(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop > 0) {
area.scrollTop -= 15;
}
}
function down(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop < area.scrollHeight) {
area.scrollTop += 15;
}
}
function fix_mouse_scroll() {
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) {
if ("onmousewheel" in document) {
textareas[i].onmousewheel = fixscroll;
} else {
textareas[i].addEventListener('DOMMouseScroll', fixscroll, false);
}
}
}
}
function fixscroll(event){
var delta=event.detail? event.detail : event.wheelDelta; // positive or negative number
delta = delta>0 ? 15 : -15;
event.target.scrollTop += delta;
//console.log(delta, ' with ',event.target.scrollTop);
}
Html part:
<tr><td> <span onmousedown='up(1)'>[UP]</span> <span onmousedown='down(1)'>[DOWN]</span> <textarea id='og1' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(2)'>[UP]</span> <span onmousedown='down(2)'>[DOWN]</span> <textarea id='og2' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(3)'>[UP]</span> <span onmousedown='down(3)'>[DOWN]</span> <textarea id='og3' onscroll="og_scroll(this);"></textarea></td></tr>
The full html code is here.

Categories