Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [HTML] How do I make a <table> with scrollbars?

This thread is locked; no one can reply to it. rss feed Print
 1   2   3 
[HTML] How do I make a <table> with scrollbars?
CGamesPlay
Member #2,559
July 2002
avatar

Quote:

It's a little better, but I still hate seamonkey. I tried it out and went back to FF.

Stop derailing the thread.

Quote:

Off to learn Javascript.

Great! While you're at it, look at HTML, too. You have a <p> element in your <head> element, you don't provide a type attribute on your <style> element, you're using a <meta> keywords (which everyone knows search engines don't use), and you don't have a <body> element.

Instead of <nobr>, you can use CSS, as well.

As far as the actual table is concerned: I'd add an extra table header cell the size of the scroll bar, to keep the table a box.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

- CGamesPlay -
Like I said earlier , I only started learning html a few days ago.
The <p> element in the html header section was a leftover from a test page I was using. If a <p> element is illegal in the header then why would the browser render it any way? That's like my compiler letting me use a function I haven't defined. It shouldn't be rendered in quirks mode due to the !DOCTYPE declaration , so I blame it on the browser. :P I won't use it that way anymore. As far as not providing a type attribute on the <style> element , what do you mean? Please provide an example.

So are there really no search engines that use meta keywords anymore , or is it just Google that doesn't use them now?

As for not using a <body> element , that's due to cut-paste coding and poor oversight. If I had started a new page over , I would have put it in.

Quote:

Instead of <nobr>, you can use CSS, as well.

What CSS would I use though?
I haven't tried this yet :

<style>
table {
  whitespace:no-wrap;
}
</style>

What I'm really interested in now is figuring out how to set different element widths using javascript. Should I use an onload attribute to call a javascript function? How do I get different objects properties and use them in a function?

Remember , I'm just a beginner at all this , so be patient and specific please.

Matthew Leverton
Supreme Loser
January 1999
avatar

<style type="text/css>
</style>

Quote:

What I'm really interested in now is figuring out how to set different element widths using javascript. Should I use an onload attribute to call a javascript function? How do I get different objects properties and use them in a function?

You could use an onload to call a function that scans the HTML for all tables with a certain class (say splitTable) and then does its magic.

foo.getElementsByTagName("TD") and foo.childNodes are your friends.

foo can be something like 'document' or any element.

foo.offsetWidth will give you the width of an element. Note that CSS is a bit unfriendly and you'll have to subtract the padding and border from it.

tdHeader.width = tdBody.offsetWidth - (border + padding)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

This javascript resizing is not going nicely.

So far I've been trying to use something like this :

<script type="text/javascript">
function AlterWidth() {
  var tableheaderdiv = document.getElementById("tableheaderdiv_id");
  alert(tableheaderdiv.width);
  tableheaderdiv.width = 400px;
  var tableheaderdiv_a = document.getElementById("tableheaderdiv_id");
  alert(tableheaderdiv_a.width);
}
</script>

// table stuff

<button onclick=AlterWidth();>Alter Table Header Div Width</button>

I've also tried that to adjust the table <head> width which does nothing in SeaMonkey , but works in IE7.

In both cases , the first alert shows up blank or says "undefined".
The second alert shows whatever width I set it to though , whether it rendered on the page or not.

The best javascript reference guide I've found so far is w3schools Javascript Reference but it doesn't have a listing of properties for the <div> tag on its HTML DOM reference. I looked at the properties for a table and it doesn't even have a height property! Sometimes I wonder just who was in charge of defining a table in HTML anyway. I'll have to do some specialized javascript testing tomorrow for <div> , <table> , <head> , and <body> to see what I can really adjust or not.

Any suggestions?

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

Like I said earlier , I only started learning html a few days ago.

No, I didn't mean that with any degree of sarcasm. I was just letting you know what you needed to work on :)

Quote:

If a <p> element is illegal in the header then why would the browser render it any way? That's like my compiler letting me use a function I haven't defined. It shouldn't be rendered in quirks mode due to the !DOCTYPE declaration , so I blame it on the browser. :P

If you want, you can rename the file to .xml, and make it well-formed XHTML. The browser (Firefox has this feature, at least), will error if you have any semantic problems.

Quote:

tableheaderdiv.width = 400px;

That's not valid Javascript any more than it's valid C++ :) You need to put it in a string. For example, these work:

width = "400px";
width = 400 + "px";

Quote:

<button onclick=AlterWidth();>Alter Table Header Div Width</button>

That's not valid XML. You need attribute quotes.
<button onclick="AlterWidth();">Alter Table Header Div Width</button>

Quote:

Any suggestions?

Get Firebug. Using the HTML tab, select an element. In the right pane, select DOM. It lists all the methods and properties for the given node.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

/derail

CGamesPlay said:

That's not valid Javascript any more than it's valid C++ :) You need to put it in a string. For example, these work:

width = "400px";
width = 400 + "px";

IMO, they should just use a single unit of measure and give you conversion functions. I know I would prefer it. I still think of strings as messy.

width = 400; // 400px
width = percentToPixels(50); // 50%.
width = emToPixels(16, fontFamily); // 16em

I think it might make positioning things easier as well if everything had a defined width, height, and position in pixels... Stupid Web languages... ::)

CGamesPlay
Member #2,559
July 2002
avatar

Then use prototype, or Ext…

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay said:

Then use prototype, or Ext…

If I ever get around to doing some Web development at home I probably will, but since I know little or nothing about those right now it's not an option to just start using them at work where I do most of my Web development...

CGamesPlay
Member #2,559
July 2002
avatar

I thought so too. Then I tried out Ext, and when I converted my application to it, I had half the code size :)

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

CGamesPlay said:

I thought so too. Then I tried out Ext, and when I converted my application to it, I had half the code size :)

The problem is integrating it into the existing system. I'm also not sure about the licensing issues... :-/ It's another LGPL project (the same as that drag 'n drop library I found a while ago), though there are commercial and OEM licensing options... I would definitely like to use it though.

CGamesPlay
Member #2,559
July 2002
avatar

[TINLA] As far as licensing goes, Ext is LGPL, meaning you can use Ext in an application and doing so does not make it LGPL itself. Additionally, if you modify Ext itself, you only have to distribute the sources to the changes you make if you distribute the application. In the web world, source and application are often equivalent anyways, so LGPL is even less binding.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

- CGamesPlay -
Thanks for the continuing grammar and usage corrections. Let's see if I've got style usage down now.

1<!--Using an external style sheet-->
2<head>
3 <link rel="stylesheet" type="text/css" href="externalstyle.css" />
4</head>
5<!--externalstyle.css-->
6tagname {attribute:value; attribute:value;}
7 
8<!--Using an inline style sheet-->
9<head>
10<style type="text/css">
11 tagname {
12 attribute:value;
13 attribute:value;
14 }
15</style>
16</head>
17 
18<!--Using inline styles in tags-->
19<tagname style="attribute:value; attribute:value;"></tagname>

And for plain html attributes :

<tagname attribute="value" attribute="value"></tagname>

I did all but the first from memory. I think those are right.

Okay , now I have a question about defining classes. How do I properly define a subclass using <style> tags?
I tried it like this :

<style type="text/css">
.baseclass1 {
  attribute:name;
  .b1subclass1 {
    attribute:name;
  }
}
</style>

but b1subclass1 doesn't get recognized. I'd like to use some form of inheritance so that I can just use

<tagname class="b1subclass1"></tagname>

Can an element have more than one class? If they can , the second one should override the first right?

Another question , what's the best way for mousedrag resizing? Add an extra element for a grab bar and recalculate the inner element's width based on the grab bar's position?

ImLeftFooted
Member #3,935
October 2003
avatar

<tagname class="class1 class2 class3"></tagname>

Now tagname above has 3 classes associated with it. I have no clue on what order or precedence it gets.

Matthew Leverton
Supreme Loser
January 1999
avatar

Quote:

I have no clue on what order or precedence it gets.

If I remember correctly, it goes based on the order the class is defined in the CSS. The order inside the attribute is irrelevant.

So if you do this:

.classname1
{
}
.classname2
{
}

Then <div class="classname1 classname2"> and <div class="classname2 classname1"> are identical with classname2 always overriding the classname1 since it comes after in the CSS file.

You can also do this:

.classname1.classname2
{
}

And that would only apply if both are present at the same time.

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

I think those are right.

Yes, they all are :)

Quote:

If I remember correctly, it goes based on the order the class is defined in the CSS.

The rules for cascading are complex. First and foremost, a rule with !important always overrides other rules. Then, the rule that is more specific wins, and finally the rule that appears last in the file wins, if all else is a tie. To find out how specific a rule is, it's mostly intuitive. However, a technical explanation is available here.

Quote:

<div class="classname1 classname2"> and <div class="classname2 classname1"> are identical with classname2 always overriding the classname1 since it comes after in the CSS file.

These two are always identical, regardless of the above rules. If you want the second one to override the first, you have to either be more specific in the rule, or put it after the first.

Quote:

Another question , what's the best way for mousedrag resizing? Add an extra element for a grab bar and recalculate the inner element's width based on the grab bar's position?

Yeah, mainly. You may want to look into Ext, as it will greatly simplify your work load.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

bamccaig
Member #7,536
July 2006
avatar

Edgar Reynaldo said:

Okay , now I have a question about defining classes. How do I properly define a subclass using <style> tags?
I tried it like this :

<style type="text/css">
.baseclass1 {
attribute:name;
.b1subclass1 {
attribute:name;
}
}
</style>

but b1subclass1 doesn't get recognized. I'd like to use some form of inheritance so that I can just use

<tagname class="b1subclass1"></tagname>

AFAIK, there is no such thing as sub-classes in css. Unfortunately, you're forced to define a whole new class. AFAIK.

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

AFAIK, there is no such thing as sub-classes in css. Unfortunately, you're forced to define a whole new class. AFAIK.

You know correctly. However, as has been stated:

1<style type="text/css">
2.message {
3 background: #eee;
4 border: solid 1px #666;
5}
6 
7/* This rule will only affect elements with both classes. Note that
8there is no space between the class names. Adding a space has a
9different meaning. */
10.message.error {
11 background: #fee;
12 color: red;
13 font-weight: bold;
14}
15</style>
16 
17<div class="message">This is a message.</div>
18 
19<div class="message error">This is an error.</div>

The first message will appear in a gray box with a dark gray border. The second message will appear in a pink (#fee) box with a dark gray border, and with red text. Notice how the second one had all the properties of the first, but some were overridden, and new ones were added.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>



</table>
</div>

<br />
<button style="align:center;" onclick="SplitTable()">Press this button to split the table above into two tables below</button>
<br />

<div id="splitscrolltable">

</div>

</body>

</html>

</code>

I had already used a string var in that manner before with success though , and I don't see what is different that would cause it to fail.

var mystring = "";
mystring = mystring + "Javascript is weird , man";
alert(mystring);

There's nothing wrong with javascript like that is there?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Here's my work in progress javascript and html for converting a normal table contained inside a div into two <div><table>'s with the second being scrollable and containing the <tbody> data from the original table.

I'm having trouble with it though , perhaps the way I'm working with strings is incorrect , however , I used the same method earlier in the script and it works fine.

For some reason , there is an exception thrown at the line where I first try to assign the var newtablehtml a value using string addition. It's near the bottom of the SplitTable() function.
<code>
<!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">

<head>

<title>Java Script Table Adjustment</title>

<script type="text/javascript">
function SplitTable () {
var table1div=document.getElementById("table1");
var starttable=table1div.getElementsByTagName("table");
var tabletheadstring = "cellspacing=\"0\" class=\"theadtable\"";
var tabletbodystring = "cellspacing=\"0\" class=\"tbodytable\"";
var max_cell_width = 0;
for (var i = 0 ; i < 1 ; i++ ) {
//alert("Table #" + i);
var tablethtags = starttable<i>.getElementsByTagName("th");
for (var k = 0 ; k < tablethtags.length ; k++) {
if (max_cell_width < tablethtags[k].offsetWidth) {max_cell_width = tablethtags[k].offsetWidth;}
}
var tabletdtags = starttable<i>.getElementsByTagName("td");
for (var k = 0 ; k < tabletdtags.length ; k++) {
if (max_cell_width < tabletdtags[k].offsetWidth) {max_cell_width = tabletdtags[k].offsetWidth;}
}
var status_string = "";
for (var k = 0 ; k < tablethtags.length ; k++) {
status_string = status_string + "Setting the width of table th tag #" + k + " , Max Cell Width = " + max_cell_width + "\n\r";
tablethtags[k].width = max_cell_width;
}
//alert(status_string);
status_string = "";
for (var k = 0 ; k < tabletdtags.length ; k++) {
tabletdtags[k].width = max_cell_width;
status_string = status_string + "Setting the width of table th tag #" + k + " , Max Cell Width = " + max_cell_width + "\n\r";
}
//alert(status_string);
status_string = "";
var headers = starttable<i>.getElementsByTagName("thead");
alert("var headers ok");
var tablebodys = starttable<i>.getElementsByTagName("tbody");
alert("var tablebodys ok");
var newtablehtml = "";
alert("newtablehtml clear ok");
newtablehtml = newtablehtml + "<div class=\"headertablediv\">\n\r<table " + tableheadstring + ">\n\r";
alert("1");
newtablehtml = newtablehtml + " <thead>\n\r" + headers[0].innerHTML + "\n\r </thead>\n\r</table>\n\r</div>\n\r";
alert("2");
newtablehtml = newtablehtml + "<div class=\"bodytablediv\">\n\r<table " + tabletbodystring + ">\n\r";
alert("3");
newtablehtml = newtablehtml + " <tbody>\n\r" + tablebodys[0].innerHTML + "</tbody>\n\r</table>\n\r</div>\n\r";
alert(newtablehtml);
table1div.innerHTML = newtablehtml;
// table1div.innerHTML = "<table " + tabletheadstring + ">\n\r <head>\n\r" + headers<i>.innerHTML + "</head>\n\r</table>\n\r" + "<table " + tabletbodystring + ">\n\r <head>\n\r" + tablebodys<i>.innerHTML + "</head>\n\r</table>\n\r";
}

}
</script>

<style type="text/css">
.widthadjuster {
}
.heightadjuster {

}
.theadtable {
position:fixed;
border:3px #ff9900 solid;
margin:2em 2em 0em 2em;
}
.tbodytable {
top:4em;
border:3px #ff9900 solid;
margin:0em 2em 0em 2em;
}
.tablebase {
width:90%;
border:3px #ff9900 solid;
margin:2em 2em 2em 2em;
}
th , tr , td {
border:1px black solid;
}
#table1 {
}
div {
background-color:#993399;
}
.outerdiv {

}
.headertablediv {

}
.bodytablediv {
overflow:auto;
height:5em;
}
</style>
</head>

<body style="background-color:#FFCCFF;">

Working with javascript to change the layout and properties of an html table

<hr style="width:100%; height:5px; color:#006600; background-color:#006600;" />

<div id="table1">
<table cellpadding="2" cellspacing="0" class="tablebase">

Header CellHeader CellHeader CellHeader Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
Row HeaderData CellData CellData Cell
bamccaig
Member #7,536
July 2006
avatar

JavaScript has the += operator, which also works for string concatenation. ;) Probably not the problem though. I'm not sure why you're concatenating \n\r to your strings. A \n should suffice... Probably still isn't the problem though.

** EDIT **

The error that I get is: "tableheadstring is not defined."

Edgar Reynaldo said:

// ...

newtablehtml = newtablehtml + "<div class=\"headertablediv\">\n\r<table " + tableheadstring + ">\n\r";

// ...

Perhaps you meant tabletheadstring? How are you debugging this? Firefox's Firebug extension told me exactly where and what the error was so if you're not using it you should be. ;)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Stupid typos.
I tried using SeaMonkey's javascript debugger Venkman , but I don't know how to use it very well and when I closed Venkman , SeaMonkey locked up. Every time I tried to click on the page or open or close it , it just beeped at me. Beep. Beep. Argh!
I've got FireFox and Firebug installed now , I'll use them next time. Thanks for spotting my mistake.

- Update -
Firefox's error console (menu->tools->error console) is quite handy for catching typographical errors. SeaMonkey has one too (menu->tools->web development->error console).

The most effective method I've found so far for making a table's body scroll is by splitting the table up into two tables contained in their own <div> tags , using one table for the <thead> section and one for the <tbody> section.

Right now I'm having trouble figuring out the best way to implement the javascript that does this though. I can use document.getElementsByTagName("table") to get a collection of all the tables in the document. Once I have this I can extract the table header and table body for use in modifying the table into the form mentioned earlier. I'd like to be able to make this javascript capable of scanning any html document for tables of a certain class so they can be made into scrolling tables. My question is how do I make an array that contains only the tables that are meant to be transformed? I suppose my actual question is how do I declare an array of the appropriate object type so I can assign table elements to it based on their class?

Another question is once I have the tables and I know what I want to replace them with how would I cut out just the table and paste in the new html? Should I try to find out the parent node of the table and then delete the table node? How would I know which table node to delete if there was more than one in its parent node?

Matthew Leverton
Supreme Loser
January 1999
avatar

To answer one question:

var tables = []; // create an empty array

var e = document.getElementsByTagName("table"); // find all tables
for (var i = 0; i < e.length; ++i)              // loop through them
  if (e.className.indexOf("splitTable") != -1)  // check its class name
    tables.push(e);                             // add it to the array

// now loop through the array and work on the tables
for (var i = 0; i < tables.length; ++i)
  splitTable(tables<i>);

You don't declare types of arrays or any other variable. An array can hold any mix of values.

Note that calls like getElementsByTagName() may return an active list, which can be confusing. For instance:

var e = document.getElementsByTagName("table"); // find all tables
alert(e.length); 
document.body.appendChild(document.createElement("table")); // add another table
alert(e.length); // should be one more than the previous call

That's why it's best to add them to an array if you plan on doing any modifications (which you are).

Note that if you were using some 3rd party JavaScript library it may be as simple as:

document.getElementsByClassName("splitTable").each(function(t)
{
  splitTable(t);
});

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Okay , I'm making some sort of progress I think.

I've got an array of just the tables that have the appropriate class attribute and I'm working on preserving the rest of the attributes for the table to be passed on to the transformed tables. However , I can't seem to figure out how to use the javascript string object replace method very well. I'd like to preserve the other classes that the table has if there are any so I've been trying this on the class node :

var classnodevalue = classnode.nodeValue;
if (classnodevalue == "makescroll") {
  table_attributes.removeNamedItem("class");
  alert("Removed class attribute from table");
} else {
  // this doesn't work
  classnodevalue.replace(/makescroll/ , "");
  // this doesn't work either
  classnodevalue.replace("makescroll" , "");

  classnode.nodeValue = classnodevalue;
}

I've been going by what's here : w3schools javascript string replace reference
I've tried their editable examples but I can't get it to actually modify the string. It looks like the replace method returns a string that has had part of it replaced , but it doesn't modify the string itself. Anyone know what I'm doing wrong?

- Update -
I ditched the replace method and I'm using substr() instead now and it works fine to build a new string minus the 'makescroll'. Note that I won't actually be removing the class attribute of the table but replacing the table node entirely.

This is a valid regular expression right?

/makescroll/

I've never used them before and they look pretty bizarre. Anyway , on to building the new tables.

Matthew Leverton
Supreme Loser
January 1999
avatar

replace() doesn't modify the string.

I wouldn't necessarily remove the class name. It could be useful for styling the table via CSS. But in general, it's handy to create some functions called removeClassName(), hasClassName(), and addClassName().

e.g.,

function removeClassName(e, className)
{
  e.className = e.className
   .replace(new RegExp("(^|\\s+)" + className + "($|\\s+)"), " ")
   .replace(/^\s+|\s+$/g,"");
}

That would remove the class name and trim the white space.

bamccaig
Member #7,536
July 2006
avatar

ImLeftFooted
Member #3,935
October 2003
avatar

Matthew's code:

if (e.className.indexOf("splitTable") != -1)  // check its class name

I started out thinking a regex would be simpler, but its actually a bit uglier... Anyway, this is slightly more accurate:

if (/(^|\.| )splitTable($|\.| )/.test(e.className))  // check its class name

Here is a way to do it with less typing:

if(/splitTable/.test(e.className))  // check its class name

 1   2   3 


Go to: