How to enable new added row clickable in html table? - javascript

I have a table with each row having a class ".clickablerow" and I defined onclick function when click on this row, a dialog will show up then I can insert above or below some text as new row. The question is, though I've added ".clickablerow" to these new added rows, they are actually not clickable and no such dialog showing up.
My code is like:
JS:
$(document).ready(function() {
$(".clickable-row").click(function(){
var i = $(this).rowIndex;
var html = "<tr class='clickable-row' > <td> a test </td></tr>";
$('#table_id > tbody > tr').eq(i).after(html);
});
HTML:
<head>
...
<link rel="stylesheet" href="../static/css/main.css">
<link rel="stylesheet" href="./static/css/bootstrap.min.css">
<script src="./static/js/jquery.min.js"></script>
<script src="./static/js/bootstrap.min.js"></script>
<script src="./static/js/jquery.expander.min.js" type="text/javascript"></script>
<script src="./static/js/main.js" type="text/javascript"></script>
....
<head>
<body>
....
<table>
<tbody>
<tr class='clickable-row' >
<td style="border: 0;"> Initial message ....</td>
</tr>
</tbody>
</table>
....
</body>
If I click on the row, a new row with class 'clickable-row' will be added, however, that new row is not clickable. Any idea are welcome!
Thanks

Just delegate the click event to the <table> or the <tbody>:
const tableBody = document.getElementById('tableBody');
tableBody.onclick = (e) => {
const target = e.target;
let row = target;
while (!row.classList.contains('clickable-row') && row !== tableBody) row = row.parentElement;
if (row === tableBody) {
return; // Ignore the click if we could not find a .clickable-row
}
const newRow = tableBody.insertRow(target.rowIndex);
newRow.className = Math.random() < 0.5 ? 'clickable-row' : 'disabled-row';
newRow.innerHTML = '<td>...</td>';
};
table {
font-family: monospace;
width: 100%;
border-collapse: collapse;
text-align: center;
user-select: none;
}
tr.disabled-row {
background: #EEE;;
}
tr.clickable-row {
cursor: pointer;
}
tr.clickable-row:hover {
background: yellow;
}
td {
border: 2px solid black;
padding: 8px 4px;
}
<table>
<tbody id="tableBody">
<tr class="clickable-row"><td>...</td></tr>
</tbody>
</table>
With jQuery, you can use .on():
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
In addition to their ability to handle events on descendant elements not yet created, another advantage of delegated events is their potential for much lower overhead when many elements must be monitored. On a data table with 1,000 rows in its tbody, this example attaches a handler to 1,000 elements:
$( "#dataTable tbody tr" ).on( "click", function() {
console.log( $( this ).text() );
});
An event-delegation approach attaches an event handler to only one element, the tbody, and the event only needs to bubble up one level (from the clicked tr to tbody):
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});
The previous example would then look like this:
$('#tableBody').on('click', '.clickable-row', (e) => {
$(e.currentTarget).after(`<tr class=${ Math.random() < 0.5 ? 'clickable-row' : 'disabled-row' }><td>...</td></tr>`);
});
table {
font-family: monospace;
width: 100%;
border-collapse: collapse;
text-align: center;
user-select: none;
}
tr.disabled-row {
background: #EEE;;
}
tr.clickable-row {
cursor: pointer;
}
tr.clickable-row:hover {
background: yellow;
}
td {
border: 2px solid black;
padding: 8px 4px;
}
<table>
<tbody id="tableBody">
<tr class="clickable-row"><td>...</td></tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Create a "delegated" binding by using on().
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time.
$('#table_id').on('click', '.clickable-row', function() {
debugger;
var i = this.rowIndex;
var html = "<tr class='clickable-row' > <td> a test " + i + "</td></tr>";
$('#table_id > tbody > tr').eq(i).after(html);
});
table#table_id {
border-collapse: collapse;
}
#table_id tr {
background-color: #eee;
border-top: 1px solid #fff;
}
#table_id tr:hover {
background-color: #ccc;
}
#table_id th {
background-color: #fff;
}
#table_id th,
#example td {
padding: 3px 5px;
}
#table_id td:hover {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table_id">
<tbody>
<tr class='clickable-row' data-href='url://'>
<td style="border: 0;"> Initial message ....</td>
</tr>
</tbody>
</table>

Related

How to create a lot of custom JavaScript "alert" boxes in the same file?

I tried to google this question, and the answer to custom alert boxes in javascript is usually jquery dialog. And this works great with one query, but I have a huge table where 90% of the cells is supposed to be clickable to open up a small alert window with information.
I tried one Stack question (link under). But the same answer made a fault in the code.
So here is my sample code that "works" right now:
<table>
<tr>
<td>Manufacturer</td>
<td>Product</td>
<td>Price range 1</td>
<td>Price range 1</td>
<td>Price range 1</td>
</tr>
<tr>
<td>Umbrella Company</td>
<td>Vaccine</td>
<td><div onclick="alert('1399')">1399</div></td>
<td><div onclick="alert('4299')">4299</div></td>
<td><div onclick="alert('5999')">5999</div></td>
</tr>
</table>
This option works, and but is not working as custom.
This other option, with custom code with jQuery works with one cell, and all the other cells just cries out the same statement.
Test the jsfiddle source under with both tables, one with alert() and one with jquery box.
Is it not possible to do it this way?
Source one: How to change the style of alert box?
Source two: https://jsfiddle.net/olelasse/e6hk9340/
You could avoid more duplication by using child functions or passing the element reference but this is the general idea. I'm not a huge fan of DOM refs because it's fragile. Move one element and everything goes to Hades in a handbasket.
function functionAlert(msg) {
var confirmBox = $("#confirm");
confirmBox.find(".message").text(msg);
var myYes = confirmBox.find(".yes");
myYes.on('click', function() {
confirmBox.hide();
});
//myYes.click(myYes);
confirmBox.show();
}
#confirm {
display: none;
background-color: #F3F5F6;
color: #000000;
border: 1px solid #aaa;
position: fixed;
width: 300px;
height: 400px;
left: 40%;
top: 40%;
box-sizing: border-box;
text-align: center;
}
#confirm button {
background-color: #FFFFFF;
display: inline-block;
border-radius: 12px;
border: 4px solid #aaa;
padding: 5px;
text-align: center;
width: 60px;
cursor: pointer;
bottom: 5px;
}
#confirm .message {
padding: 5px;
text-align: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<title>JS Alert Box</title>
</head>
<body>
<h2>
Table 1
</h2>
<h3>
Alert()
</h3>
<table border="1">
<tr>
<td>Manufacturer</td>
<td>Product</td>
<td>Price range 1</td>
<td>Price range 2</td>
<td>Price range 3</td>
</tr>
<tr>
<td>Umbrella Company</td>
<td>Vaccine</td>
<td><div onclick="functionAlert('1399')">1399</div></td>
<td><div onclick="functionAlert('4299')">4299</div></td>
<td><div onclick="functionAlert('5999')">5999</div></td>
</tr>
<tr>
<td>Umbrella Company</td>
<td>Vaccine 2</td>
<td><div onclick="functionAlert('1299')">1299</div></td>
<td><div onclick="functionAlert('4199')">4199</div></td>
<td><div onclick="functionAlert('5899')">5899</div></td>
</tr>
<tr>
<td>Microhard</td>
<td>PDA</td>
<td><div onclick="functionAlert('999')">999</div></td>
<td><div onclick="functionAlert('3599')">3599</div></td>
<td><div onclick="functionAlert('6299')">6299</div></td>
</tr>
</table>
<div id="confirm">
<div class="message">
</div>
<button class="yes">Close</button>
</div>
</body>
</html>
Don't write the HTML by hand. Generate it dynamically based on your data. You could use a library like React, or just use the DOM as I've demonstrated below.
This way, no matter how large your table is, you need only write the event handler logic once. There are additional ways you could simplify this code, but which you choose will depend on your experience and goals.
// All your data are belong to this array
const data = [
["Umbrella Company", "Vaccine", 1399, 4299, 5999],
["Soylent Corporation", "Soylent Green", 299, 399, 599],
["Omni Consumer Products", "ED-209", 19990, 39990, 78990],
["Tyrell Corporation", "Nexus-6", 27990, 31990, 59990],
];
const table = document.getElementById("products");
for (const row of data) {
const tr = document.createElement("tr");
const manTD = document.createElement("td");
manTD.innerText = row[0];
tr.appendChild(manTD);
const prodTD = document.createElement("td");
prodTD.innerText = row[1];
tr.appendChild(prodTD);
const range1TD = document.createElement("td");
range1TD.innerText = row[2];
range1TD.addEventListener("click", function() {
alert(row[2]);
});
tr.appendChild(range1TD);
const range2TD = document.createElement("td");
range2TD.innerText = row[3];
range2TD.addEventListener("click", function() {
alert(row[3]);
});
tr.appendChild(range2TD);
const range3TD = document.createElement("td");
range3TD.innerText = row[4];
range3TD.addEventListener("click", function() {
alert(row[4]);
});
tr.appendChild(range3TD);
table.appendChild(tr)
}
<table id="products">
<tr>
<th>Manufacturer</th>
<th>Product</th>
<th>Price range 1</th>
<th>Price range 1</th>
<th>Price range 1</th>
</tr>
</table>
Whenever possible try and keep your code DRY, below I've modified your code to do the following->
Used a delegated event handler on the table. This means you only need one event to handle all the TD's, and better still if a TD was added dynamically later it would work with the added lines.
Used an array to store the data, we can then use this to render the table lines.
Used the .dataset property to store the type of data stored in the TD, I'm only using this to prevent the dialog showing if you don't click a TD with numbers in, but I could have used a class, or even parsed the .innerText
const data = [
["Umbrella Company", "Vaccine", 1399, 4299, 5999],
["Umbrella Company", "Vaccine2", 1299, 4199, 5899],
["Microhard", "PDA", 999, 3599, 6299]
];
const table =
document.querySelector('table');
const confirmBox =
document.querySelector('#confirm');
const confirmBoxMsg =
confirmBox.querySelector('.message');
const confirmBoxYes =
confirmBox.querySelector('.yes');
function fillTable() {
for (const d of data) {
const tr = document.createElement('tr');
for (const v of d) {
const td = document.createElement('td');
td.dataset.type = typeof v;
td.innerText = v;
tr.appendChild(td);
}
table.appendChild(tr);
}
}
table.addEventListener('click', ev => {
const td = ev.target.closest('td');
if (!td) return; //did with click a TD?
if (td.dataset.type !== 'number') return;
confirmBoxMsg.innerText = td.innerText;
confirmBox.style.display = 'block';
});
confirmBoxYes.addEventListener('click', ev => {
confirmBox.style.display = 'none';
});
fillTable();
#confirm {
display: none;
background-color: #F3F5F6;
color: #000000;
border: 1px solid #aaa;
position: fixed;
width: 300px;
height: 400px;
left: 40%;
top: 40%;
box-sizing: border-box;
text-align: center;
}
#confirm button {
background-color: #FFFFFF;
display: inline-block;
border-radius: 12px;
border: 4px solid #aaa;
padding: 5px;
text-align: center;
width: 60px;
cursor: pointer;
bottom: 5px;
}
#confirm .message {
padding: 5px;
text-align: left;
}
<html>
<head>
<title>JS Alert Box</title>
</head>
<body>
<h2>
Table 1
</h2>
<h3>
Alert()
</h3>
<table border="1">
<tr>
<td>Manufacturer</td>
<td>Product</td>
<td>Price range 1</td>
<td>Price range 2</td>
<td>Price range 3</td>
</tr>
</table>
<div id="confirm">
<div class="message">
</div>
<button class="yes">Close</button>
</div>
</body>
</html>

How do I delete only one row of appended information in a table using jQuery?

I am trying to make a "My Favorite Movies" list page where users can add and rate movies. This program should include:
1) a form where you can add to the list and rate it
2) a table of all the things you've added
3) delete button for each row of the table that lets you remove elements from the list (what i'm having trouble on)
Instead of deleting only one row, it deletes every appended movie/rating in the table. Also if you click anywhere else, it deletes everything as well.
4) bonus: sort feature, so i can sort entries in the table by the their title or their rating.
example here: rithm school example
$(function() {
$('#addMovieButton').click(function() {
var addToTitle = $('#title').val();
$('#tableTitle').append('<tr><td>' + addToTitle + '</td></tr>');
var addToRating = $("#rating").val();
$('#tableRating').append('<tr><td>' + addToRating + '</td></tr>');
$('#tableDelete').append('<tr><td><input type="button" value="Delete All"</tr></td>');
$('#tableRow').on('click', function() {
$('#tableTitle').last().children().remove();
$('#tableRating').last().children().remove();
$('#tableDelete').last().children().remove();
});
});
});
h1 {
text-align: center;
}
table {
width: 100%;
border-radius: 10px;
}
table,
td {
border: 1px solid black;
padding: 15px;
}
th {
height: 50px;
text-align: center;
}
td {
text-align: center;
}
body {
font-family: helvetica;
}
form {
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<label><b>Title</b></label>
<input id="title" type="text" value="Movie Title">
<label><b>Rating</b></label>
<input id="rating" type="text" value="Rate The Movie from 0 to 10">
<button type='button' id="addMovieButton">Add Movie</button>
</form>
<table>
<tr id="tableRow">
<th id="tableTitle">Title</th>
<th id="tableRating">Rating</th>
<th id="tableDelete">Delete</th>
</tr>
</table>
<table> Structure
The structure of the appended "row" are not valid HTML. A <table> will have at least one <tbody>. If the user doesn't add it the browser will. Although most methods, function, and properties will treat the <table> as the direct parent of <tr>, there are some advantages to targeting <tbody> instead. If there's a <thead> then targeting the <tbody> can free you from extra steps trying to avoid the <th>.
Keep these rules in mind when structuring a <table>
<tbody> can only have <tr> as children (direct descendants)
<tr> can only have <td> and <th> as children
<td> and <th> can have anything as descendants.
Make sure rows are structured like so:
<tr><td</td>...<td></td></tr>
Add row to <table> or <tbody>
Demo
The following demo has detailed comments within the HTML, and CSS, as well as step by step details commented in the JavaScript
$(function() {
/*
Bind the <form> to the 'submit', 'click', and 'change' events.
Pass the Event Object thru
*/
$('form').on('submit click change', function(event) {
// Reference the type of event
let eType = event.type;
// if the 'submit' event was triggered...
if (eType === 'submit') {
// Stop the <form> from sending data to a server and resetting
event.preventDefault();
// Get the values of the <input>
let name = $('.title').val();
let rate = $('.rating').val();
// Declare a htmlString using a Template Literal
const row = `
<tr><td>${name}</td>
<td>${rate}</td>
<td><input class='sel' type='checkbox'>
</td></tr>`;
// Render the htmlString as the last child of the <tbody>
$('.data').append(row);
// Reset <form>
$(this).trigger('reset');
// ...otherwise if the 'click' event triggered...
} else if (eType === 'click') {
// ...and the clicked tag has class 'del'...
if ($(event.target).hasClass('del')) {
/*
Collect all checked <input class='sel'>
then on .each() one...
*/
$('.sel:checked').each(function(i) {
/*
Get the ancestor <tr> of the current .sel
and remove it
*/
$(this).closest('tr').remove();
});
// Reset the <form>
$('form').trigger('reset');
}
// ...otherwise if the 'change' event was triggered...
} else if (eType === 'change') {
// ...and the changed tag id is 'all'...
if (event.target.id === 'all') {
// Check if #all is checked or not
let allChk = $('#all').is(':checked');
// Loop thru each() <input class='sel'>...
$('.sel').each(function(i) {
/*
and check current .sel if #all is checked
or uncheck current .sel if #all is NOT checked
*/
$(this).prop('checked', allChk);
});
}
}
// Stop any events from bubbling any further up the event chain
event.stopPropagation();
});
});
:root {
font: 400 3vw/1.2 Arial;
}
form {
text-align: center;
}
table {
width: 100%;
border-radius: 10px;
table-layout: fixed;
margin: 12px auto
}
table,
td {
border: 1px solid black;
padding: 15px;
}
th {
height: 30px;
width: 20%;
}
th:first-of-type {
width: 60%;
}
td {
text-align: center;
}
button,
input,
label {
display: inline-block;
font-size: initial;
}
.all {
font-weight: 400;
padding: 3px 6px;
border: 1.5px inset rgba(0, 28, 255, 0.3);
margin-top: 3px;
}
.all::after {
content: 'Selected'
}
/*
When input#all is :checked the label.all that follows
#all will change
the content of its pseudo-element from 'Selected' to 'All'
*/
#all:checked+.all::after {
content: 'All'
}
button:hover {
cursor: pointer;
outline: 3px outset rgba(0, 28, 255, 0.4);
color: rgba(0, 28, 255, 0.6);
}
.all:hover {
cursor: pointer;
color: rgba(0, 28, 255, 0.8);
background: rgba(0, 28, 255, 0.2);
}
.rating {
text-align: right;
width: 4ch;
}
.title {
padding-left: 5px;
width: 27ch;
}
/*
The checkbox #all is not visible to user but is accessible through the label.all
which it is synced with (see comments in HTML
*/
#all {
display: none
}
<form>
<label>Title</label>
<!--
The [required] attribute enables built-in form validation
If the submit event is triggered
and either <input> is blank, the submit event is interrupted and
a tooltip will notify
user that the <input> cannot be empty
-->
<input class="title" type="text" placeholder="Pulp Fiction" required>
<label>Rating</label>
<!-- See previous comment -->
<input class="rating" type="number" min='0' max='10' placeholder="10" required>
<!--
<button type='submit'> or <input type='submit'>
or <button> within a <form> will trigger a submit event by default
-->
<button>Add Movie</button>
<table>
<thead>
<tr>
<th>Title</th>
<th>Rating</th>
<th>
<button class='del' type='button'>Remove</button>
<!--
A <label> and a form control (ie <input>, <textarea>, <select>, etc) can be synced by
matching the [for] attribute value to the form controls #id:
1. <label for='XXX'>
2. <input id='XXX'>
When synced, clicking one will remotely click the other
-->
<input id='all' type='checkbox'>
<label class='all' for='all'></label></th>
</tr>
</thead>
<!--
See post on <table> structure
-->
<tbody class='data'></tbody>
</table>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
you've put all titles in a parent, and all rating in another parent ,and all delete buttons in another one . you should place the information about each row in a parent and then you can delete by row easily.
(also you can add td,tbody it's just sample to showing the way)
$('#addMovieButton').click(function () {
var addToTitle = $('#title').val();
var addToRating = $("#rating").val();
$('#table').append('<tr><th>' + addToTitle + '</th><th>' + addToRating + '</th><th><input type="button" value="Delete All" class="tableDelete"></th></tr>');
$('.tableDelete').click(function () {
$(this).parents('tr').remove();
});
});
h1 {
text-align: center;
}
table {
width: 100%;
border-radius: 10px;
}
table,
td {
border: 1px solid black;
padding: 15px;
}
th {
height: 50px;
text-align: center;
}
td {
text-align: center;
}
body {
font-family: helvetica;
}
form {
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<label><b>Title</b></label>
<input id="title" type="text" value="Movie Title">
<label><b>Rating</b></label>
<input id="rating" type="text" value="Rate The Movie from 0 to 10">
<button type='button' id="addMovieButton">Add Movie</button>
</form>
<table id="table">
</table>

How do I only select the "tr" element that was clicked?

I have an HTML table with different rows (TR) and when I click on one row the background color changes (if it blank it becomes blu and if it blue it becomes white).
How can I exclude from this onclick event the TR that have the TD with the class EXPANDREDUCE?
My code is the following but it doesn't work because in this way it works on each TR i click but I need to check if in the TR that I clicked there is one or more TD with the CLASS EXPANDREDUCE and if yes i don't need to do anything:
function rowHighlight() {
$("TR").click(function() {
try {
$(this).parent().prev()[0].tagName;
HighLightTR(this);
} catch (err) {}
});
}
By using the event.target property, like this:
$("tr").on("click", function(event) {
var tr = $(event.target);
});
NOTE: To check to see if it has the class EXPANDREDUCE, change your selector to "tr.EXPANDREDUCE".
Good luck.
Here's an example:
$(function() {
$("thead tr").addClass("background");
$("tbody tr:even").addClass("even");
$("tbody tr:odd").addClass("odd");
$("tbody input:checkbox:checked").parent().parent().addClass("sel");
$("tbody tr").click(function(e) {
var flag = $(this).hasClass("sel");
if (flag) {
$(this).removeClass("sel");
} else {
$(this).addClass("sel");
}
});
});
table {
width: 400px;
border: 2px solid #999;
text-align: center;
border-collapse: collapse;
}
table td, table th {
border: 2px solid #999;
height: 25px;
}
.background {
background-color: #CCC;
}
.even {
background-color: #FFE7BA;
}
.odd {
background-color: #FFF0F5;
}
.sel {
background-color: #FFFF00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<table>
<thead>
<tr>
<th>title</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
</tbody>
</table>
</div>

How to handle new fields with jquery that have array

I have for example 3 fields that user can input a number a,b,c
So field C will check if number entered in field C is < a and > b.
In the form i have a button that create an additional line with
another a,b,c; so i don't know how to control same operation like before...
FIDDLE
$(".c").change(function() {
if ($('.c').val() > $('.a').val() || $('.c').val() < $('.b').val()) {
$('.c').css("backgroundColor", "#ff0000");
} else {
$('.c').css("backgroundColor", "#00FF00");
}
});
$('.add').click(function() {
var tr = '<tr>' + '<td>Cota1</td>' +
'<td><input type="text" name="tol_cota1[]" class="form-control a"></td>' +
'<td><input type="text" name="tolb_cota1[]" class="form-control b"></td>' +
'<td><input type="text" name="medido_cota1[]" class="form-control c"></td>' +
'<td><input type="button" class="btn btn-danger remove" value="Remove Line"></td>' + '</tr>';
$('.details').append(tr);
});
// delete row
$('.details').delegate('.remove', 'click', function() {
var con = confirm("Are you sure you want to remove the line?");
if (con) {
$(this).parent().parent().remove();
}
});
The change event doesn't bubble, which means you will need an event listener for every input in your form.
jQuery will take care of that automatically when using using the .on() method with a selector (its second parameter), which is equivalent to the old deprecated .delegate() method. From its description in the official docs, it will:
Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
So, if you do something like this:
$('.details').on('change', 'input', (event) => { ... });
This will listen for change events on any <input> element inside all elements matching the .details selector, regardless if they already existed when the method was called or if they were created afterwards as it is your case.
Now, once a change event occurs, you should use the .parent(), .eq and .find() methods to select the row in which the <input> that triggered the event is located, from there you get all 3 inputs based on their position or selector, their value, and do your logic to update that specific row.
Anyway, if instead of listening for change events you use input, which does bubble, you can benefit from event delegation. This means that a single event listener will be created for the whole <tbody> in this case, instead of one per <input>. Using event.target you will be able to distinguish which one triggered the event, which you need to use anyway to get the other inputs in the same row.
All together, it will look something like this:
// Better to keep the reference instead of getting it each time:
const details = $('#details');
details.on('input', 'input', (event) => {
const children = $(event.target).parents().eq(1).children();
const avgInput = children.eq(3).find('input');
const max = parseInt(children.eq(1).find('input').val());
const min = parseInt(children.eq(2).find('input').val());
const avg = parseInt(avgInput.val());
if (isNaN(max) ||isNaN(min)|| isNaN(avg)) {
// Don't do anything if any of them is blank.
return;
}
avgInput.css('backgroundColor', avg > max || avg < min ? '#ff0000' : '#00FF00');
});
details.on('click', '.remove', (event) => {
if (confirm('Are you sure you want to remove the line?')) {
$(event.target).parents().eq(1).remove();
}
});
$('#add').click(() => {
details.append(`
<tr>
<td>Cota1</td>
<td><input type="text"></td>
<td><input type="text"></td>
<td><input type="text"></td>
<td><button class="remove">DELETE</button></td>
</tr>
`);
});
body {
font-family: sans-serif;
font-size: .75rem;
}
table {
border-collapse: collapse;
table-layout: fixed;
position: relative;
}
table th,
table td {
width: 20%;
padding: 0;
border-bottom: 1px solid #EEE;
height: 1.75rem;
}
input {
width: 100%;
box-sizing: border-box;
padding: .5rem;
border: none;
outline: none;
text-align: center;
}
input:hover {
background: #FAFAFA;
}
input:focus {
background: #FFA;
}
.remove {
width: 100%;
box-sizing: border-box;
padding: .5rem;
border: none;
outline: none;
background: #FFF;
cursor: pointer;
}
.remove:hover {
background: #F44;
}
#add {
width: 100%;
border: none;
background: #FFF;
padding: .5rem;
border-radius: 2px;
color: #000;
text-transform: uppercase;
font-size: .75rem;
margin: 1rem 0 0;
box-shadow: 0 0 1rem rgba(0, 0, 0, .25);
transition: box-shadow ease-in .125s;
}
#add:hover {
box-shadow: 0 0 .5rem rgba(0, 0, 0, .25);
}
<table>
<thead>
<tr>
<th> </th>
<th>TOL +</th>
<th>TOL -</th>
<th>AVG</th>
<th></th>
</tr>
</thead>
<tbody id="details">
<tr>
<td>Cota1</td>
<td><input type="text"></td>
<td><input type="text"></td>
<td><input type="text"></td>
<td> </td>
</tr>
</tbody>
</table>
<button id="add">ADD</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
the best way would be using the closest function
$(".c").change(function(){
if($(this).val() > $(this).closest('.a').val() || $(this).closest('.c').val() < $('.b').val())
{
$(this).closest('.c').css( "backgroundColor", "#ff0000" );
}else{
$(this).closest('.c').css( "backgroundColor", "#00FF00" );
}
});

Odd border around html table cell with colspan?

My question is similar to THIS question, but I'm unable to use divs instead of colspans with a table.
It appears to be an issue that only appears in chrome, but I need to find a workaround.
My use case is very similar to the one below. Notice how the top border for 3.3 spans two columns, which is clearly not right. In my use case, the user is able to change which cells are merged so I can't set the border for a specific cell.
How do you set a cell's border to be confined to its own cell instead of sharing with a common cell whose colspan is greater than 1?
HTML
<div style="padding: 10px">
<table>
<tr>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
<td>1.4</td>
<td>1.5</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td colspan="2">2.3</td>
<td>2.5</td>
</tr>
<tr>
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
<td>3.4</td>
<td>3.5</td>
</tr>
<tr>
<td>4.1</td>
<td>4.2</td>
<td>4.3</td>
<td>4.4</td>
<td>4.5</td>
</tr>
<tr>
<td>5.1</td>
<td>5.2</td>
<td>5.3</td>
<td>5.4</td>
<td>5.5</td>
</tr>
</table>
</div>
CSS
table {
table-layout: fixed;
border-spacing: 0;
border-collapse: collapse;
}
td {
border: 1px solid lightgrey;
height: 60px;
width: 60px;
text-align: center;
vertical-align: middle;
}
td.active {
border: 1px solid blue;
}
td.brdr-b-hide {
border-bottom: none;
}
td.brdr-r-hide {
border-right: none;
}
JavaScript
var fnActivate = function(target) {
target.addClass('active');
if(!target.is(':first-child')) {
target.prev().addClass('brdr-r-hide')
}
var tr = target.closest('tr');
if(!tr.is(':first-child')) {
var prevTr = tr.prev();
$('td', prevTr).eq($('td', tr).index(target)).addClass('brdr-b-hide');
}
};
var fnDeactivate = function(target) {
target.removeClass('active');
if(!target.is(':first-child')) {
target.prev().removeClass('brdr-r-hide')
}
var tr = target.closest('tr');
if(!tr.is(':first-child')) {
var prevTr = tr.prev();
$('td', prevTr).eq($('td', tr).index(target)).removeClass('brdr-b-hide');
}
}
$('table').on('click', 'td', function(e){
var target = $(e.currentTarget);
if(e.ctrlKey && target.hasClass('active')){
fnDeactivate(target);
} else if(e.ctrlKey) {
fnActivate(target);
} else {
fnDeactivate($('table td.active'));
fnActivate(target);
}
});
CODE: Plunkr
Issue was fixed by using:
table {
border-collapse: separate;
}
Code: Plunkr
It's a little different on the front end as each cell now has its own border of 1px, but it's a good workaround for the time being.
I think this usecase is best adressed with the outline css property.
See: http://jsfiddle.net/4zxv4o59/
td.active {
outline: 1px solid blue;
}
Outlines do not take up space, they are drawn above the content.
from https://developer.mozilla.org/en/docs/Web/CSS/outline

Categories

Resources