Question:
I'm having a little trouble with jQuery:
Consider this HTML, where I want to left-click on "https", change it's value and then click ok. On OK, it should remove the textbox, and re-attach the onclick handler.
This is does, but onclick is already issued by the current click...
Why ? And how to do this correctly ?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Tabelle editieren</title>
<!--
<script src="jquery-1.4.4.min.js" type="text/javascript"></script>
-->
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.js"></script>
<style type="text/css" media="all">
html {margin: 0px; padding: 0px; height: 100%;}
body {margin: 0px; padding: 0px; height: 100%;}
input{margin: 0px; padding: 0px; }
tr:nth-child(2n+1) {background-color: #F0F0F0;}
tr:nth-child(2n) {background-color: #FEFEFE;}
td
{
margin: 0px; padding: 0.5cm; padding: 0px; text-align: left;
}
</style>
<script type="text/javascript" language="javascript">
function hello(me) {
//alert("hello");
var str = $(me).text();
//alert(str);
$(me).html("<input id=\"my1\" type=\"text\" style=\"width: 198px; height: 100%;\" value=\"" + str + "\" /><input id=\"my1confirm\" type=\"button\" onclick=\"bye(this);\"style=\"width: 35px;\" value=\"" + "OK" + "\" />");
$(me).attr('onclick', '').unbind('click');
return false;
}
function bye(me) {
var objTR = $(me).parent();
//var tb = $(me).closest('table');
var tb = objTR.find('input');
var str = tb.val();
tb.remove();
objTR.text(str);
alert("TODO: sending change event with { id : \"" + objTR.attr('id') + "\", str : \"" + str + "\" } to server");
/*
objTR.click(function () {
alert("hi");
return false;
});
*/
objTR.attr('onclick', '').bind("click", function (e) {
e.preventDefault();
alert("it shouldn't execute this in this click, but it does... ");
//hello(this);
//event.stopImmediatePropagation();
});
return false;
}
$(document).ready(function () {
//$('#myDataTable').dataTable().makeEditable();
});
</script>
</head>
<body style="margin: 0.5cm;">
<h1>Application configuration</h1>
<!--
-->
<table border="1" style="border-collapse: collapse;" >
<thead>
<tr style="background-color: Black; color:White; font-weight: bold; text-transform: capitalize;">
<th style="width: 235px; text-align: left;">key</th>
<th style="width: 235px; text-align: left;">value</th>
</tr>
</thead>
<tfoot>
<tr style="background-color: Black; color:White; font-weight: bold; text-transform: capitalize;">
<th style="text-align: left;">key</th>
<th style="text-align: left;">value</th>
</tr>
</tfoot>
<tbody>
<tr>
<td>Environment</td>
<td id="server">testing</td>
</tr>
<tr>
<td>Protocol</td>
<td id="Protocol" onclick="hello(this);">https</td>
</tr>
<tr>
<td>UserHashMode</td>
<td id="UserHashMode">true</td>
</tr>
<tr>
<td>Logo</td>
<td id="Logo">LogoFileCustomerN.png</td>
</tr>
</tbody>
</table>
</body>
</html>
It seems that inline event handlers cannot be unbound by jQuery: Unbinding inline onClick not working in jQuery?
So I'm not sure if it'll work, but instead of using:
.attr("onclick", "")
try:
.removeAttr("onclick")
Let us know if that changes anything.
UPDATE:
I made a jsFiddle to show you how it could function "easier": http://jsfiddle.net/S2ARR/3/
A lot of it depends on certain things, such as using my structure - putting a span inside of the column instead of using the column for everything. I didn't use the id of elements for jQuery selecting because I wasn't sure why you weren't - if you set the id of elements and you need to access them, you might as well use the id selector in jQuery. So you wouldn't need to use .parent() or .find() in my example if you just used the id. Hopefully this is what you were looking for. I think the important thing was the .stopPropagation() call, otherwise it didn't seem to work.
i changed your event to delegate, removed onclick from the table and called it using jquery. However i'm not sure if what i get is your desire behavior.
jsfiddle
Update
Hi, i updated with the desired behavior.
Solution
Instead of binding the event via the onclick attribute, you can bind it to the table cell with jquery.
$(function(){
$("#Protocol").click(function(){
// your content
});
});
Then, you can guarantee that you can unbind the event with unbind later on.
Related
I'm using JavaScript to create some HTML that renders a Bootstrap table. Here's the code for that:
function displayTableData(d){
let html = '';
html += '<table id="my-table" class="table">'
html += '<body>'
html += '<h5 id="team-name">' + d.TEAM_NAME + '</h5>'
html += '<tr>'
html += '<td class="table-labels">Wins</td>'
html += '<td class="table-data" id="wins">' + d.WINS + '</td>'
html += '</tr>'
html += '<tr>'
html += '<td class="table-labels">Losses</td>'
html += '<td class="table-data" id="Losses">' + d.LOSSES + '</td>'
html += '</tr>'
html += '<tr>'
html += '<td class="table-labels">Points</td>'
html += '<td class="table-data" id="points">' + d.POINTS + '</td>'
html += '</tr>'
html += '</body>'
html += '</table>'
document.getElementById('my-data').innerHTML = html
}
CSS:
#my-table {
/* display: none; */
background-color: #EAEAEA;
padding: 20px;
border-radius: 5px;
}
Currently, only the wins, losses, and points rows have the background color #EAEAEA applied.
How do I also get the top row (team-name) to have the background color #EAEAEA?
(I want to apply the background color to the entire table.)
Thank you!
You should remove <body> and <h5> tags from the table. It is incorrect.
Inside the <table> tag You can only put <thead>, <tbody> or <tfoot>.
HTML
The anatomy of a <table> is not flexible. The only content that can be within a <table> in descending order is depicted in Figure I.
Figure I
Element
Content
<table>
<caption>
<colgroup>
<thead>
<tbody>
<tfoot>
<caption>
Flow content
<colgroup>
<col>
<thead> <tbody> <tfoot>
<tr>
<tr>
<th> <td>
<th>
Flow content, no sectioning or heading content
<td>
Flow content
<body> is always after the <head> element and never the child of another element. <tbody> should be placed within <table> and if not explicitly placed within a <table>, the browser will add it by default. <h5> should be a <caption> placed within the <table> and before <tbody>.
CSS
CSS in a Bootstrap environment is tricky. Usually the Bootstrap styles set by BS classes cannot be overridden by adding CSS after the BS stylesheet CSS. Typically, novices will use !important but using it can become a messy problem later on. It is safer to override BS CSS by specificity. Simply double up the class selector (see Figure II).
It's also important to familiarize yourself with the BS classes associated with <table> otherwise you'll be struggling trying to do simple styling.
Figure II
table.table.table {/*...*/}
th.label.label {/*...*/}
td.data.data {/*...*/}
It appears that you wanted rounded corners on the <table> which cannot simply be done with border-radius: 5px. In the example, the CSS has all of the required rulesets to make rounded corners marked with a ✳️. The JavaScript has also been improved.
Details are commented in example
/**
* Render a table with the given object as content to a given element
* within the DOM.
* #param {object} data - Object that provides the content
* #param {string|object} element - As a string it is a selector. As an
* object it is a DOM object. If undefined it defaults to <body>
* #param {boolean} clear - If true, it will remove everyting within the
* element to which the <table> will be inserted into. #default
* is false.
*/
function displayTableData(data, element, clear = false) {
let root = typeof element === "string" ? document.querySelector(element) : element === undefined ? document.body : element;
if (clear) root.replaceChildren();
let html = `<table id="${data.id}" class="table table-sm table-bordered border-dark">
<caption class="caption-top">${data.team}</caption>
<tbody>
<tr>
<th class="label" scope="row">Wins</th>
<td class="data wins">${data.wins}</td>
</tr>
<tr>
<th class="label" scope="row">Losses</th>
<td class="data lossess">${data.losses}</td>
</tr>
<tr>
<th class="label" scope="row">Points</th>
<td class="data points">${data.points}</td>
</tr>
</tbody>
</table>`;
root.insertAdjacentHTML("beforeend", html);
}
const stats = {
id: "table-data1",
team: "San Fransisco Giants",
wins: 81,
losses: 81,
points: 716
};
displayTableData(stats, ".row");
table.table.table {
width: 50vw;
margin: 20px auto;
padding: 0;/*✳️*/
border-spacing: 0;/*✳️*/
border-collapse: separate;/*✳️*/
border-bottom-left-radius: 5px;/*✳️*/
border-bottom-right-radius: 5px;/*✳️*/
}
caption.caption-top {
padding: 0;
font-size: 1.2rem;
border-top-left-radius: 5px;/*✳️*/
border-top-right-radius: 5px;/*✳️*/
text-align: center;
}
table.table.table,
caption.caption-top,
th.label.label,
td.data.data {
border: 0.5px solid #000;/*✳️*/
background: #eaeaea;
}
table.table.table {
border-bottom: 0;/*✳️*/
border-top: 0;/*✳️*/
background: transparent;/*✳️*/
}
th.label.label {
font-weight: 500;
}
tr:last-of-type th.label.label {
border-bottom-left-radius: 5px;/*✳️*/
}
tr:last-of-type td.data.data {
border-bottom-right-radius: 5px;/*✳️*/
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style></style>
</head>
<body>
<main class="container">
<section class="row"></section>
</main>
</body>
</html>
I wrote a simple database page using JavaScript (jQuery).
In the main view there is a table with data (in one div), and in the other div there is editing view(in the same index.html file).
This second div is initially hidden. After clicking on the record, it opens and you can close it after clicking "Save" or "Cancel". And it basically works.
The problem is, I didn't really think what to do, if I clicked the back button in my browser. Right now, when I click from an edit record item, it takes me back from the entire page at all. I wish it would just take me back to table view, so that the editing div would close/clear.
What is a good approach in this functionality? Below is a very simplified page to illustrate what I mean.
<html>
<head>
<meta name="viewport" content="width=device-width"/>
<title>Index</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.min.js"></script>
</head>
<style>
#EditDiv
{
background-color: blanchedalmond;
}
#DetailsDiv
{
background-color:burlywood;
font-size: 30px;
width: 50%;
}
#SaveButton
{
background-color:indianred;
font-size: 30px;
width: 100%;
}
.box{
width: 100%;
height: 100%;
position: absolute;
top: -80px;
left: 0;
background-color: rgb(243, 229, 229);
overflow:auto;
border-style: solid;
border-width: thin;
border-color: lightsteelblue;
}
</style>
<body>
<div id="TableDiv">
<table id="testtable" style="width:50%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>Anna</td>
<td>Thompson</td>
<td>20</td>
</tr>
</table>
</div>
<div id="DetailsDiv" class="box stack-top" >
<p style="font-size: 30px; font-weight: bold;">
Edit row
</p>
<button id="SaveButton" onclick="Save()" >SAVE</button>
<div id="EditDiv"></div>
</div>
</body>
<script>
$('#DetailsDiv').hide();
$("#testtable tr").click(function() {
$( "#EditDiv" ).empty();
$( "#EditDiv" ).append( $(this).children("td").html());
$('#DetailsDiv').show();
const state = { 'page_id': 1}
const title = ''
const url = 'index5.html#' + $(this).children("td")[0].textContent;
history.pushState(state, title, url)
});
function Save()
{
$( "#EditDiv" ).empty();
$('#DetailsDiv').hide();
}
</script>
</html>
This isn't the expected functionality of the browser back button. The back button should be reserved for allowing the user to go to a previous webpage URL before yours. Preventing this functionality would be a bad experience for your user and should be avoided.
You could implement "routing" in your application. When the user clicks "Edit", you could use the History pushState API to change your URL to /page/edit, and when the user saves change it back to /page/. This would then justify changing state when the user clicks the back button.
Implementing this properly is outside the scope of this single question, however.
I'm writing a Vanilla JS program in codesandbox environment as shown below:
function Game() {
alert("hi");
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
}
td:first-child {
border-left-width: 0px;
}
td:last-child {
border-right-width: 0px;
}
table tr:nth-child(1) td {
border-top-width: 0px;
}
table tr:nth-child(3) td {
border-bottom-width: 0px;
}
<!DOCTYPE html>
<html>
<head>
<title>Tic-Tac-Toe</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app">
<table width="300" height="300" onclick="Game();">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</body>
</html>
When I execute the above code snippet in codesandbox.io then it gives below error:
ReferenceError Game is not defined
Not sure why the execution environment of codesandbox is unable to detect the Game function. If I write the alert statement outside the function then it gets called successfully on page load:
alert("hi");
function Game() {
}
I've linked the external JS and CSS files correctly in the head tag of the HTML page.
You need to define the function as a variable attached to the global window object. Try defining the function like this:
window.Game = function() {
alert("hi");
}
Alternatively, instead of an inline onclick event handler try giving the table element an id such as game-table and then add an event listener:
document.querySelector('#game-table').addEventListener('click', Game);
I need to create a shim for the entire page to capture click events, but the shim must not stop other events like mouseover etc on the other html elements on the page.
I have solution that sort of works, but I am having a couple of problems with it:
Whenever I click on the page, if I click directly on some text, the click event of the shim does not fire (there is no event-cancelling on the page).
The onclick problem only occurs in IE.
In FF and Chrome there is a problem with the mouseover events not being fired in the background, so I would of course appreciate any tips on solving that as well...
Here is a very basic example demonstrating the problem.
Any ideas? :-)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<style type="text/css">
body
{
font-size:20px;
height:100%;
}
#shim
{
position: absolute;
padding: 0;
margin: 0;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
zindex: 1;
}
#trace
{
border: 1px solid #ccc;
height: 100px;
}
</style>
<script type="text/javascript">
function trace(e) {
e = e || event;
document.getElementById('trace').innerHTML = "Hovered innerHTML: " + (e.target || e.srcElement).innerHTML;
}
</script>
</head>
<body>
<div id="shim" onclick="alert('shim clicked')">
</div>
<table border="1" onmouseover="trace(event)">
<tr>
<td>
AAAAAA AAAAAA
</td>
<td>
BBBBBB BBBBB
</td>
<td>
CCCCCCCC CCCCC
</td>
<td>
DDDDDD DDDDDDDDDD
</td>
<td>
EEEEEE EEEE
</td>
<td>
FFFFFF FFFFF
</td>
<td>
GGGG GGGGGGGG
</td>
<td>
EEEE EEEE
</td>
<td>
FFFF FFFFFF
</td>
</tr>
</table>
<div id="trace">
</div>
</body>
</html>
I do not know if it is possible to fix your problem, but I have done something like a few weeks ago that works for me.
Basically, I create a global event handler, registering all events I need in the document element and then, using event.srcElement or event.element, I was able to get the element that fires the event in the first place. Based on the event and the element, I can decide what to do.
Copy/paste this html code snippet and try it out in IE7. When you toggle the hidden columns it leaves a gap between the columns. In Firefox it works fine, the columns touch when minimized. Haven't tried IE8 yet, would be curious to hear how it works there. Any ideas? I've tried a bunch of things in the CSS like table-layout:fixed but no luck.
Note: Not looking for a different toggling method because the table I'm really dealing with is 50+ columns wide and 4000+ rows so looping/jquery techniques are too slow.
Here's the code - if someone can re-post a working version of it I'll instantly give them the check and be forever in your debt!
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script>
function toggle() {
var tableobj = document.getElementById("mytable");
if (tableobj.className == "") {
tableobj.className = "hide1 hide2";
}
else {
tableobj.className = "";
}
}
</script>
<style>
table { border-collapse: collapse; }
td, th { border: 1px solid silver; }
.hide1 .col1 { display: none; }
.hide2 .col2 { display: none; }
</style>
</head>
<body>
<input type="button" value="toggle" onclick="toggle();" />
<table id="mytable">
<tr>
<th>A</th>
<th colspan="2">B</th>
<th colspan="2" class="col1">B1</th>
<th colspan="2">C</th>
<th colspan="2" class="col2">C1</th>
</tr>
<tr>
<td>123</td>
<td>456</td>
<td>789</td>
<td class="col1">123</td>
<td class="col1">456</td>
<td>789</td>
<td>123</td>
<td class="col2">456</td>
<td class="col2">789</td>
</tr>
</table>
</body>
</html>
Here's a solution that uses JQuery to toggle the column headers (see my other answer for the rationale). Apart from the JQuery stuff, the rest of the html page is the same.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>
<script>
function toggle() {
var tableobj = document.getElementById("mytable");
if (tableobj.className == "") {
tableobj.className = "hide1 hide2";
$('th[class^=col]').hide();
}
else {
tableobj.className = "";
$('th[class^=col]').show();
}
}
</script>
<style>
table { border-collapse: collapse; }
td, th { border: 1px solid silver; }
.hide1 .col1 { display: none; }
.hide2 .col2 { display: none; }
</style>
</head>
<body>
<input type="button" value="toggle" onclick="toggle();" />
<table id="mytable">
<tr>
<th>A</th>
<th colspan="2">B</th>
<th colspan="2" class="col1">B1</th>
<th colspan="2">C</th>
<th colspan="2" class="col2">C1</th>
</tr>
<tr>
<td>123</td>
<td>456</td>
<td>789</td>
<td class="col1">123</td>
<td class="col1">456</td>
<td>789</td>
<td>123</td>
<td class="col2">456</td>
<td class="col2">789</td>
</tr>
</table>
</body>
</html>
Don't yet have an explanation of why IE is doing this, but here's what's happening and here's how to work around it.
1) If you set the table class to 'hide1 hide2' in the html, then the table will render properly (no gap). Therefore, the problem seems to be related to the way that IE handles changes to a table via styles.
2) The gap between the columns is the width of the spanned column header.
3) If you eliminate column spanning (and the extra columns), then everything works fine.
I've found two workarounds. The first is to use code to toggle the display, but you've rejected that option.
The alternative is to eliminate the colspans. There are a variety of ways to do that. One is to convert the group of cells to be spanned into an embedded table (that is, instead of two TD elements, you'll have one TD which contains a TABLE with one TR and two TDs). Or you can use SPANs for cleaner code (with, say, a BORDER-RIGHT for all cells but the last).
Try this doctype declaration:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">