Wählen Sie die Zeile basierend auf einem anderen Tabellenzeilenindex aus

84489
Misiu

Ich habe 2 Tische. Man hält nur die erste Spalte meiner "Datentabelle" übrig, die in einer anderen Tabelle gespeichert ist, die rechts vor der ersten steht. Was ich tun muss, ist, alle Daten aus einer bestimmten Zeile an jqplot zu übergeben.

Meine Tische sehen so aus . Mein Code funktioniert grundsätzlich, aber ich denke, er kann verbessert werden.

$('table#baseTable  > tbody > tr > td').click(function() {
    var rowIndex = $(this).parent().index();
    $('div#log').html(rowIndex);

    var myData = [];

    $('#dataTable tbody tr:eq(' + rowIndex + ')').map(function() {
            return $(this.cells).get();
        }).each(function() {
    var headerVal = $(this).closest("table").find("thead > tr > th").eq($(this).index()).html();
    myData.push([headerVal, $(this).html()]);
})

    alert(myData);
    console.log(myData);
});​

Ich verwende diesen Code in der ASP-Seite, so dass ich jedes Mal, wenn ich UpdatePanel verwende, meine Funktionen erneut aufrufen muss.

Dies ist meine Plotfunktion:

function plot() {
    var $plot;
    var dataTableRows = $('#Grid3_br tbody tr');

    $('td.akcje').on('click', function() {
        var $newTitle = $(this).next().text();
        var myData = [],
            element = $(this),
            rowIndex = element.parent().index();

        $(dataTableRows[rowIndex]).map(function() {
            return $(this.cells).get();
        }).each(function(index, value) {
            myData.push(['M' + index, parseFloat($(this).html())]);
        })
        $('#wykres1').empty();//clears old plot. Don't know why re-plotting don't work for me
        $plot = $.jqplot('wykres1', [myData], {
            title: $newTitle,
            axes: {
                xaxis: {
                    renderer: $.jqplot.CategoryAxisRenderer,
                    tickOptions: {
                        formatString: '%s'
                    }
                },
                yaxis: {
                    tickOptions: {
                        formatString: '%.2f zł'
                    }
                }
            },
            highlighter: {
                show: true,
                sizeAdjust: 7.5,
                tooltipAxes: 'y'
            },
            cursor: {
                show: false
            }
        });

        $(window).resize(function() {
            $plot.replot({
                resetAxes: true
            });
        });
    });
}
Antworten
8

1 Antwort auf die Frage

9
Arne

Ich fange mit deinen Selektoren an:

Zunächst einmal sollten Sie nie einen Selektor mit einer ID haben - die Suche nach IDs ist ungefähr so ​​schnell, wie Sie das DOM nicht bekommen können.

Zweitens: Wenn Sie nicht möchten, dass andere Tabellen in Ihren Tabellen eingeschlossen werden (ich nehme an, dass Sie dies nicht tun), entfernen Sie die unmittelbaren untergeordneten Elemente (P> C). Die Suche nach Tag ist ebenfalls ziemlich schnell, daher verwenden wir das id-Element als Basis dafür.

$('#baseTable tbody td').click(function() {
    var rowIndex = $(this).parent().index();
    $('#log').html(rowIndex);

    var myData= [];

    $($('#dataTable tbody tr')[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​

Als Nächstes sollten Sie Elemente, die Sie gefunden haben, zwischenspeichern, mehr als einmal verwenden und die sich nicht ändern. Normalerweise ist es eine schlechte Wahl, Ereignisse direkt an die Elemente zu binden. Ich gehe davon aus, dass jQuery 1.7 in Ordnung ist und Sie nicht wirklich jQuery 1.4 verwenden möchten. Wir können also on für die Ereignisbindung verwenden .

var logDiv = $('#log'),
    dataTableRows = $('#dataTable tbody tr');

$('#baseTable tbody').on('click', 'td', function() {
    var myData = [],
        element = $(this),
        rowIndex = element.parent().index();

    logDiv.html(rowIndex);

    $(dataTableRows[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​

Als Nächstes ist der Zugriff auf das DOM ziemlich langsam. Wenn Sie die Daten für jqplot benötigen, benötigen Sie die Tabellenköpfe und können sich die Daten ändern?

Ich würde aber vorher alle Daten in einem Array speichern. Nun sieht es so aus:

var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

// cache data table headers
dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

// cache full row (including headers) for data table
dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

// the onClick - but on tr instead of td and with a fast lookup
$('#baseTable tbody').on('click', 'tr', function() {
    var rowIndex = $(this).index(),
        myData = dataTableData[rowIndex];
    logDiv.html(rowIndex);
    alert(myData);
    console.dir(myData);
});​

Ich mag es immer noch nicht index(). Ich mag es sogar weniger, als bei Ereignissen, die an Elemente gebunden sind, also werde ich Kompromisse eingehen:

var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

$('#baseTable tbody tr').each(function(row) {
    $(this).on('click', function() {
        var data = dataTableData[row];
        logDiv.html(row);
        alert(data);
        console.dir(data);
    });
});

Hier ist mein letzter Schritt (das ist zwar nicht wirklich nötig, aber ich mag es): Wir isolieren diesen Code von der Außenwelt und machen versehentliche Nachrichten um einiges schwieriger. Und wir ermöglichen eine Neuberechnung und Neubindung des Klickereignisses, wenn sich etwas ändert (Anzahl der Zeilen / Spalten oder des Inhalts).

var tableData = (function(){
    var logDiv = $('#log'),
        cacheRows = function() {
            var dataTable = $('#dataTable'),
                dataTableHeaders = [],
                dataTableData = [];
            // fetch headers
            dataTable.find('thead th').each(function(col) {
                dataTableHeaders[col] = $(this).html();
            });
            // fetch column data, prepare row arrays
            dataTable.find('tbody tr').each(function(row) {
                var rowData = (dataTableData[row] = []);
                $(this).children().each(function(col) {
                    rowData[2 * col] = dataTableHeaders[col];
                    rowData[2 * col + 1] = parseFloat($(this).html());
                });
            });
            // return row arrays
            return dataTableData;
        },
        bindOnClick = function() {
            var dataTableData = cacheRows();
            $('#baseTable tbody tr').each(function(row) {
                $(this).on('click', function() {
                    var data = dataTableData[row];
                    logDiv.html(row);
                    alert(data);
                    console.dir(data);
                });
            });
        };
    bindOnClick();
    return {
        refresh: bindOnClick
    };
})();

Wenn sich jetzt die Tabellen ändern, können Sie das beabsichtigte Verhalten durch Aufrufen beibehalten tableData.refresh(). Dies ist immer noch etwas unordentlich, da wir nie anrufen. Da wir offjedoch nur jQuery zum Ändern des DOM verwenden, müssen wir die Ereignisbehandlungsroutinen auflösen, wenn wir Elemente ändern. Es ist wahrscheinlich besser, das zurückgegebene Objekt so zu ändern, dass es zwei Funktionen hat: eine zum Aktualisieren des Caches und eine zum erneuten Binden. Ein erneutes Binden ist erforderlich, wenn die gesamte Tabelle neu erstellt wurde und kein DOM-Knoten erneut verwendet wird. Andernfalls treten Event-Handler aus. Wenn Sie die Tabelle nur selten aktualisieren, sollte es Ihnen gut gehen. Bei häufigen Aktualisierungen würde ich die indexFunktion erneut verwenden.

Bearbeiten: Hier ist ein Beispiel für das, was ich in meinem Kommentar unten beschrieben habe.

var prepareForPlotting = function(baseSelector, dataSelector, clickhandler) {
    var cacheRows = function() {
            var dataTable = $(dataSelector),
                dataTableHeaders = [],
                dataTableData = [];
            // fetch headers
            dataTable.find('thead th').each(function(col) {
                dataTableHeaders[col] = $(this).html();
            });
            // fetch column data, prepare row arrays
            dataTable.find('tbody tr').each(function(row) {
                var rowData = (dataTableData[row] = []);
                $(this).children().each(function(col) {
                    rowData[2 * col] = dataTableHeaders[col];
                    rowData[2 * col + 1] = parseFloat($(this).html());
                });
            });
            // return row arrays
            return dataTableData;
        },
        bindOnClick = function() {
            var dataTableData = cacheRows();
            $(baseSelector + ' tbody tr').each(function(row) {
                $(this).on('click', function() {
                    clickhandler(row, dataTableData[row]);
                });
            });
        };
    bindOnClick();
    return {
        recache: cacheRows,
        rebind: bindOnClick
    };
}

var logDiv = $('#log'),
    baseHandler = prepareForPlotting('#baseTable', '#dataTable',
        function(row, data) {
            logDiv.html(row);
            alert(data);
            console.dir(data);
        }
    );
wow :) Danke dafür. Ich versuche immer noch, jQuery zu lernen, und ich möchte die besten Vorgehensweisen zu Beginn lernen. Alle Ratschläge wie Sie sind sehr hilfreich. Alle zukünftigen Updates dazu sind willkommen :) Misiu vor 8 Jahren 0
Ihre Antwort ist großartig! Ich bin auf der Suche nach einer Möglichkeit, dies in einem Plugin zu ändern, so dass ich es in der Lage bin, es mehr als die auf der Seite zu verwenden. In meiner Lösung verwende ich 4 Tabellen wie hier gezeigt http://jsfiddle.net/Misiu/9j5Xy/12/ dies ist einfach. Diese 2 Lösungen werden in ASP 2.0-Webseiten verwendet. Jedes Mal, wenn ich Daten vom Server anfordere (Updates des Aktualisierungsbereichs), muss ich alle Javascript erneut initiieren. Kann Ihr genialer Code in plogin geändert werden? Damit ich es wie $ ('wrapper'). PlotData () aufrufen kann? Oder soll ich deine Lösung verlassen? Welches ist besser? Misiu vor 8 Jahren 1
In diesem Fall würde ich es mit den Selektoren als Parameter zu einer Funktion machen. Sie rufen es einmal pro Tabellenkombination auf und verwenden den Rückgabewert für die Aktualisierung neuer Daten (damit Sie es als Eventhandler für ein Änderungsereignis registrieren können, das Sie auslösen, wenn sich Daten in einer Tabelle ändern.) Aber ich würde zuerst die Warnung und den Aufruf von logDiv fallen lassen :-) Arne vor 8 Jahren 1
Warnung und Protokoll waren nur zu Testzwecken. Ich bearbeite meine Frage und füge Code hinzu, den ich gerade verwende :) So sagen Sie, dass es besser wäre, sie mit 2 Parametern zu verwenden: one-div, der alle Tabellen umschließt, und second-div-Anzeigeplot. Misiu vor 8 Jahren 0
nicht das div, ich würde die Selektoren für baseTable und dataTable und eine Rückruffunktion übergeben. Der Rückruf aktualisiert die Darstellung (damit Sie verschiedene Darstellungsbereiche auswählen können). Arne vor 8 Jahren 1
Ich habe alle Tabellen in einem div (wie in diesem jsfiddle-Link aus dem Kommentar oben) eingeschlossen. Kann ich stattdessen nur einen Parameter übergeben - den Wrapper-Div-Selektor? Aber ich verstehe diesen Ansatz der Callback-Funktion nicht. Könnten Sie es etwas erklären? Ich bin ein Anfänger :) Misiu vor 8 Jahren 0
Ich würde die Selektoren anstelle des div übergeben, damit Sie die dom-Knoten löschen und die Tabelle neu erstellen können, damit sie noch funktioniert. Die Rückruffunktion ... Ich füge in meiner Antwort ein Beispiel hinzu, es wäre zu lang für einen Kommentar. Arne vor 8 Jahren 1
Nochmals vielen Dank für Ihre Antwort und Kommentare. Ich möchte dafür 100 Mal auf den Upvote-Button klicken, aber ich kann es nur einmal. Wirklich danke Ruhe des Codes und brillante Erklärung. Misiu vor 8 Jahren 0
@Arne Ich mag Funktionskennungen, sie machen Code meiner Meinung nach lesbarer und einfacher zu debuggen (Stack-Trace sieht besser aus mit `name () -> otherName ()` anstelle von `function () -> function ()`). Ich würde also schreiben: `$ (this) .on ('click', Funktion rowClicked () {` Aber was wichtiger ist, ich würde es vermeiden, Funktionen in Schleifen (oder in `each`) zu erstellen. Warum sollten wir das erklären? _n_ (was in unserem Fall sehr umfangreich sein könnte), wenn wir eine Funktion nutzen können (http://jsfiddle.net/tomalec/cvPWv/2/). Gibt es einen Grund, habe ich es versäumt, http: // jsfiddle zu verwenden. net / tomalec / cvPWv / 3 / tomalec vor 7 Jahren 0
@Tomalec Ja, Funktionskennungen sind für Traces geeignet und könnten / sollten hier verwendet werden. Ich würde wahrscheinlich einiges von dem Zeug jetzt anders machen (Verwenden Sie Winkel oder Rückgrat!) ... Über Ihre zweite Geige: Wird das funktionieren? Die Funktion wird von jQuery aufgerufen. Wenn ich mich richtig erinnere, wird es mit dem DOM-Element aufgerufen, auf das Sie als "this" geklickt haben, und das Ereignis als einziges Argument für die Funktion. Sie können das nicht ändern, also woher würde Ihre Funktion ihre Argumente bekommen? Arne vor 7 Jahren 0
@Arne Personaly Ich habe angefangen, Funktionskenner-Fetischist zu sein, ich sehe keinen Sinn darin, unbenannte anonyme Funktionen überall zu verwenden. In Bezug auf Fidle sollte es. Wenn Sie Ihren Code mit einer Geige versorgen, kann ich das noch einmal überprüfen. Sie haben Recht, Ereignis ist das einzige Argument. Gemäß http://api.jquery.com/on/ `.on (events [, Selektor] [, Daten], Handler (eventObject))` können Sie jedoch Daten hinzufügen: `{rowIndex: rowIndex}` `event.data`. Einfach, sauber und einfach. tomalec vor 7 Jahren 0
Das war in Bezug auf die Geige [/2/] (http: // jsfiddle.net/tomalec/cvPWv/2/). Sie haben Recht [/3/(((tsp://jsfiddle.net/tomalec/cvPWv/3/)) funktionieren nicht. tomalec vor 7 Jahren 0