Laden...

[Gelöst] JavaScript: Spaltenbreiten zweier Tabellen synchronisieren (Ansatz vorhanden)

Erstellt von tikra vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.209 Views
tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren
[Gelöst] JavaScript: Spaltenbreiten zweier Tabellen synchronisieren (Ansatz vorhanden)

Hallo,

ich habe 2 Tabellen, die zunächst via Auge miteinander verglichen werden sollen.
Hierzu ist es wichtig, dass die Spalten direkt untereinander stehen.

Hinter diesen 2 Tabellen stehen 2 GridViews, welche mittels DataTable/DataBind gefüttert werden. Ich bin nicht in der Lage jeder Spalten 100 oder 200px zuzuweisen, da es sehr viele Spalten sind und der Platz wichtig ist.

Ich habe mich schon mit serverseitigen und clientseitigen Lösungen auseinander gesetzt.

Wobei ich nicht weiß, wie ich den "Finished"-Status eines PostBacks abfangen könnte, um dann den entsprechenden JavaScript-Spaltenalgorithmus zu feuern.

Anyway: Beide Ansätze laufen auf das selbe Problem: Ist die width/Breite "aufgebraucht" die zur Verfügung steht, lässt sich die Tabelle nicht mehr weiter durch .width-Argumente vergrößern.

Kleines html-Beispiel (solange auf + clicken, bis Ende des Screens erreicht):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
        
        <title>An XHTML 1.0 Strict Template</title>
        
        <style type="text/css">
            td {
                border: 1px solid black;
            }
        </style>
        
        <script type="text/javascript">
        function test3() {
            var table = document.getElementById("mytable");
            
            table.rows[0].cells[0].width = table.rows[0].cells[0].clientWidth + 15;
        }
        </script>
    </head>

    <body>
    
        <table id="mytable">
            <tr><td>eidfdfdfdfdfdfdffdns</td><td>fdfdfdfdfdfdfdfdfdfdzwei ssssdrei</td></tr>
            <tr><td>eidfdfdfdfdfdfdffdns</td><td>fdfdfdfdfdfdfdfdfdfdzwei ssssdrei</td></tr>
            <tr><td>eisns</td><td>zwei drei</td></tr>
        </table>
        
        <table id="mytable2">
            <tr><td>einsdsdss</td><td>zweidsdsd drei</td></tr>
            <tr><td>esssins</td><td>zwei ddsdsdsrei</td></tr>
        </table>
        
        <input type="button" Value="+" onclick="test3()" />
    
    </body>

</html>

Der Vorteil der clientseitigen Lösung liegt darin, dass man die tatsächliche Spaltenbreite mittels clientWidth auslesen kann, auch ohne das eine Breite gesetzt wurde.
Dies ist mit der serverseitigen Lösung mittels

gridView.Rows[0].Cells[0].Width

natürlich nicht möglich. Dort müsste man es unschön über die Anzahl von Buchstaben * fixe Pixel Anzahl ausrechnen, dies wäre allerdings nicht genau, unschön und deckt AUCH NICHT das Problem der Headerzeile ab, welchen zum größten Teil Titel beinhalten, welche einen wrap beinhalten...

Hoffe ich konnte vermitteln, was mein Problem ist.

Mal schauen ob dort jemand eine Idee zu hat.

Schönes Wochenende schon einmal euch allen!

16.842 Beiträge seit 2008
vor 13 Jahren

Wenn Du nur nen js-Event feuern willst, wenn die Seite geladen ist, wieso nutzt Du nicht den js-Event "window.onload = function...", um dein Algorithmus zu starten?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

du könntest es mal mit table-layout:fixed oder mit einer colgroup versuchen.
Siehe table-layout (fixe/variable Breiten) und Spalten vordefinieren

Die dynamische Breitenänderung würde ich auf jeden Fall clientseitig per Javascript angehen, da Du auf dem Server - wie Du schon richtig bemerkt hast - nicht an die echten Zahlenwerte des Clients kommst.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren

Okay, mal angenommen ich wüßte wie es geht - und wir blenden die oben beschrieben Problematik, dass ich .width nicht setzen kann, da der Fensterplatz bereits ausgefüllt ist (er ignoriert das Statement dann, wie das html-Beispiel zeigt) - WIE löse ich dieses Script nach dem erfolgreichen PostBack aus?

Muss ich da so eine JavaScript-Injection im Codebehind machen?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

Muss ich da so eine JavaScript-Injection im Codebehind machen?

Exakt. mit Page.ClientScript.RegisterStartupScript(...) geht das relativ einfach.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren

Vielen Dank, hilft schon einmal sehr weiter. 😃

Hast du mal obiges Script ausprobiert? Die Tabelle wird ab dem Punkt, wo der rechte Border rechts "andockt" nicht mehr größer, genau das Problem hätte ich auch in dem Script um die Spalten anzugleichen.

Wenn ich .DataBind() ausführe und das GridView angezeigt wird, DANN kann er die Seite nach rechts "verlängern" und es wird ein horizontaler Scrollbalken sichtbar.
Wenn ich die Spalten dieser Tabelle nun via JavaScript vergrößern will, ist keine Änderung zu sehen.

Danke & Gruß

timmi

tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren

Niemand eine Idee zu dieser Problematik?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

vrsuch mal so (ausser der Width für die Zelle wird auch die der Tabelle neu berechnet und analog gesetzt):

        function test3() {
          var table = document.getElementById("mytable");
          var newCellWidth = table.rows[0].cells[0].offsetWidth + 25;
          var newTableWidth = table.offsetWidth + 25;
          table.rows[0].cells[0].style.width = newCellWidth + "px";
          table.style.width = newTableWidth + "px";
        }

Gruß, MarsStein

Edit: ausserdem hatte ich den <td> noch den style white-space:nowrap gegeben, sonst hat er noch umgebrochen - nach rechts scrollen klappte aber trotzdem.

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren

Au weia, du bist der Knaller. Ich danke dir! 😃

Edit: Falls du das noch liest, wieso verwendest du nun offsetWidth und nicht clientWidth? Unterschied?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo,

offsetWidth: Breite des gesamten Elements
clientWidth: Breite des Elements ohne Scrollbar, falls das Element eine eigene Scrollbar besitzt.

In Deinem Beispiel ist es egal, da weder die TDs noch die TABLE eine eigene Scrollbar besitzen. Wenn man aber die width über den Style setzt, muss die Scrollbar normalerweise mitgerechnet werden, daher in diesem Fall die Verwendung von offsetWidth.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

tikra Themenstarter:in
185 Beiträge seit 2007
vor 13 Jahren

Ich muss leider nochmal stören. Fakt ist, dass es mit deinem Ansatz auf jeden Fall funktionieren muss. Jetzt geht es nur noch um die Umsetzung, eigentlich mag ich diese "Pixelzählerei" nicht, hier ist sie allerdings leider nötig:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta http-equiv="Content-Style-Type" content="text/css" />

        <title>An XHTML 1.0 Strict Template</title>

        <style type="text/css">
        
            table
            {
                border: 1px solid red;
            }
            
            td
            {
                border: 1px dashed black;
            }
        </style>

        <script type="text/javascript">
        
            // function test3()
            // {
                // var tblTop = document.getElementById("top");

                // tblTop.rows[0].cells[0].width = tblTop.rows[0].cells[0].offsetWidth + 15;
            // }
            
            // function test4()
            // {
                // var tblTop = document.getElementById("top");
                
                // var newCellWidth = tblTop.rows[0].cells[0].offsetWidth + 25;
                // var newtblTopWidth = tblTop.offsetWidth + 25;
                
                // tblTop.rows[0].cells[0].style.width = newCellWidth + "px";
                // tblTop.style.width = newtblTopWidth + "px";
            // }
            
            // function test5()
            // {
                // var tblTop = document.getElementById("top");
                
                // var newCellWidth = tblTop.rows[0].cells[0].offsetWidth + 25;
                // var newtblTopWidth = tblTop.offsetWidth + 25;
                
                
                // tblTop.width = tblTop.offsetWidth + 25;
                // tblTop.rows[0].cells[0].width = tblTop.rows[0].cells[0].offsetWidth + 25;
            // }
            
            function test6()
            {
                var tblTop = document.getElementById("top");
                var tblBottom = document.getElementById("bottom");
                
                var colTop, colBottom;
                
                for (var i = 0; i < tblTop.rows[0].cells.length; i++)
                {
                    colTop = tblTop.rows[0].cells[i];
                    colBottom = tblBottom.rows[0].cells[i];
                    
                    // Obere Spalte ist kleiner.
                    if (colTop.offsetWidth < colBottom.offsetWidth)
                    {
                        tblTop.width = tblTop.offsetWidth + (colBottom.offsetWidth - colTop.offsetWidth);
                        
                        colTop.width = colBottom.offsetWidth;
                        colBottom.width = colBottom.offsetWidth;
                    }

                    // Untere Spalte ist kleiner.
                    else
                    {
                        colBottom.width = colTop.offsetWidth;
                        //colTop.width = colTop.offsetWidth;
                    }
                    
                    tblBottom.width = tblTop.offsetWidth;
                    tblTop.width = tblTop.offsetWidth;
                    
                    // if (tblTop.offsetWidth < tblBottom.offsetWidth)
                    // {
                        // alert('Tabelle oben kleiner -> oben width von unten setzen');
                        // tblTop.width = tblBottom.offsetWidth+15;
                        // tblBottom.width = tblBottom.offsetWidth+15;
                    // }
                    
                    // else
                    // {
                        // alert('Tabelle unten kleiner -> unten width von oben setzen');
                        // tblBottom.width = tblTop.offsetWidth+15;
                        // tblTop.width = tblTop.offsetWidth+15;
                    // }
                }
            }
            
        </script>
        
    </head>

    <body>

        <table id="top">
        
            <tr>
            
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                
            </tr>
            
            <tr>
            
                <td>1ssssssssss</td>
                <td>22sssssssss</td>
                <td>33ssssssssssssss3</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1ssssssssss</td>
                <td>22sssssssss</td>
                <td>33ssssssssssssss3</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1ssssssssss</td>
                <td>22sssssssss</td>
                <td>33ssssssssssssss3</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                
            </tr>

        </table>

        <br />
        
        <table id="bottom">

            <tr>
            
                <td>666666</td>
                <td>55555</td>
                <td>4444</td>
                <td>333</td>
                <td>22</td>
                <td>1</td>
                <td>666666</td>
                <td>55555</td>
                <td>4444</td>
                <td>333</td>
                <td>22</td>
                <td>1</td>
                <td>666666</td>
                <td>55555</td>
                <td>4444</td>
                <td>333</td>
                <td>22</td>
                <td>1</td>
                
            </tr>
            
            <tr>
            
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                <td>1</td>
                <td>22</td>
                <td>333</td>
                <td>4444</td>
                <td>55555</td>
                <td>666666</td>
                
            </tr>
        
        </table>

        <br />
        
        <input type="button" Value="Synchronisieren" onclick="test6()" />

    </body>

</html>

Wird der untere Teil, welcher auskommentiert ist genutzt und nicht der obere, dann funktioniert es, ist aber viel zu viel ungenutzter Platz der generiert wird.

Wo liegt mein Fehler?

3.170 Beiträge seit 2006
vor 13 Jahren

Hallo tikra,

das ist ein relativ kompliziertes Problem, allerdings nicht von der Sache her sondern eher wegen des unterschiedlichen Browserverhaltens.
Folgender Code löst das Problem (zumindest in FF und IE), dabei werden die Spalten allerdings etwas breiter als benötigt, Begründung weiter unten:

function test6()
{
    var tblTop = document.getElementById("top");
    var tblBottom = document.getElementById("bottom");

    var colTop, colBottom, max;
    var diffTop = 0;
    var diffBottom = 0;

    for (var i = 0; i < tblTop.rows[0].cells.length; i++)
    {
      colTop = tblTop.rows[0].cells[i];
      colBottom = tblBottom.rows[0].cells[i];
      
      // breitere Spalte bestimmen
      max = Math.max(colTop.offsetWidth, colBottom.offsetWidth);
      // Sammeln der Änderungen getrennt für oben/unten
      diffTop += max - colTop.offsetWidth;
      diffBottom += max - colBottom.offsetWidth;
      // beide Spalten auf breiteren Wert setzen
      colTop.style.width = max + "px";
      colBottom.style.width = max + "px";
    }
    // breitere Tabelle bestimmen
    max = Math.max(tblTop.offsetWidth + diffTop, tblBottom.offsetWidth + diffBottom); // *BEMERKUNG LESEN
    // beide Tabellen auf breiteren Wert setzen
    tblTop.style.width = max + "px";
    tblBottom.style.width = max + "px";
}

*Bemerkung: An der im Code markierten Stelle wäre eigentlich diffTop und diffBottom nicht nötig, wenn sich die Browser einheitlich verhalten würden, da durch setzen der Spaltenbreiten die offsetWidth für beiden Tabellen sich schon entsprechend ändert.
Im Firefox funktioniert es ohne, wenn man table-layout: fixed angibt. Dann spielt der IE aber nicht mit. Damit beide Browser zurechtkommen, muss die gesamte Verbreiterung je Tabelle mitgerechnet werden. Dadurch werden die Spalten etwas breiter als eigentlich nötig wäre. Warum man das so machen muss, kann ich allerdings auch nicht sagen.

Zusätzlich gilt: Die Funktion verbreitert die Tabelle (aufgrund des o.g. Effekts) noch weiter, wenn die Funktion mehrfach aufgerufen wird.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca