2013-08-02 16 views
5

Używam D3, aby narysować tabelę HTML, a wszystko działa wspaniale przy wejściu. Kiedy dodaję nowy element do mojego zbioru danych, dodaje on poprawnie nowy element do tabeli.Rysowanie tabeli HTML przez D3 nie aktualizuje istniejących danych

Problem występuje, gdy aktualizuję istniejący obiekt (obiekt w kolekcji backgroundJobs poniżej) w kolekcji. Kiedy ponownie uruchomię kod D3, aby zsynchronizować tabelę, nie działa. Nic się nie dzieje.

Oto kod:

var visibleColumns = ['Name', 'Start', 'End', 'Status', 'Metadata', 'Errors']; 

var table = d3.select('#jobs').append('table'); 
var thead = table.append('thead'); 
var tbody = table.append('tbody'); 

thead.append("tr") 
    .selectAll("th") 
    .data(visibleColumns) 
    .enter() 
    .append("th") 
    .text(function (column) { return column; }); 

function tick() { 
    var rows = tbody.selectAll("tr") 
     .data(backgroundJobs, function(d) { 
      return d.name; 
     }) 
     .enter() 
     .append("tr"); 

    var cells = rows.selectAll("td") 
     .data(function(row) { 
      return [{column: 'Name', value: row.name}, 
        {column: 'Start', value: row.startedTimestamp}, 
        {column: 'End', value: row.endedTimestamp}, 
        {column: 'Status', value: row.isRunning}, 
        {column: 'Metadata', value: ''}, 
        {column: 'Errors', value: row.errorMsg}]; 
     }) 
     .enter() 
     .append("td") 
     .text(function(d) { return d.value; }); 
} 

setInterval(tick, 500); 

Odpowiedz

7

Proszę odnieść się do chłodnego wyjaśnienia data joins.

Po wywołaniu

tbody.selectAll("tr").data(some-new-data); 

rzeczywiście dostać 3 opcje: „enter” (pokojowe nowych elementów nie występujących w DOM jeszcze), „exit” (obecnych w DOM, ale nie dłużej obecny w dane) i "aktualizacja", która zawiera węzły, które są już w DOM i nadal mają dane przypisane do nich za pośrednictwem połączenia .data powyżej.

Ogólnie rzecz biorąc, w przypadku wyboru "wprowadź" tworzysz nowe węzły, w celu "wyjścia" musisz usunąć stare, a w przypadku "aktualizacji" wystarczy zmienić atrybuty - może to przynieść miły efekt przejścia. Zobacz zaktualizowany kod funkcji "tick".

function tick() { 
    var rows = tbody.selectAll("tr") 
    .data(backgroundJobs, function(d) { 
     return d.name; 
    }); 

    rows.enter() 
     .append("tr"); 

    rows.order(); 

    var cells = rows.selectAll("td") 
     .data(function(row) { 
      return [{column: 'Name', value: row.name}, 
       {column: 'Start', value: row.startedTimestamp}, 
       {column: 'End', value: row.endedTimestamp}, 
       {column: 'Status', value: row.isRunning}, 
       {column: 'Metadata', value: ''}, 
       {column: 'Errors', value: row.errorMsg}]; 
     }); 

    cells.enter() 
     .append("td"); 

    cells.text(function(d) { return d.value;}); 

    cells.exit().remove(); 

    rows.exit().remove(); 
} 

Patrz Demo (backgroundJobs jest włączony czasowy pomiędzy dwoma zestawami danych zakodowane).

+1

dlaczego to wywołanie 'rows.order();'? – manu08

+0

Aby kolejność wierszy w tabeli była zgodna z kolejnością zadań w tablicy backgroundJobs. Bez wyraźnego sortowania wszystkich nowych zadań ("nowe" pod względem łączenia danych - te, które stanowią "wejście" wyboru) są dołączane na końcu tabeli. – amakhrov

1

Zmienna rows będzie wybór, który będzie zawiera tylko węzły jeśli enter() nie jest pusta. Za drugim razem, jeśli nie dodano żadnych nowych wierszy do backgroundJobs, powiązanie danych zaktualizuje istniejące węzły, a enter() nie będzie zawierać żadnych węzłów (co oznacza, że ​​rows nie będzie zawierać żadnych węzłów).

Można obejść ten problem poprzez przytrzymanie odniesienie do wyboru aktualizacji, korzystając z faktu, że węzły załączonym do wyboru wejść dodane do wyboru aktualizacji za kulisami:

var rows = tbody.selectAll("tr") 
    .data(backgroundJobs, function(d) { 
     return d.name; 
    }); 

rows.enter() 
    .append("tr"); 

Teraz wiersze będą odnosić do selekcji, która zawiera wszystkie poprzednio istniejące i nowo dodane węzły.

0

Aby móc dodawać i usuwać wiersze dynamicznie, strategia ta działa na mnie:

// ROW MANAGEMENT 

// select all tr elements 
var tr = this.table.select("tbody").selectAll("tr").data(cur_data); 

// exit rows 
tr.exit().remove(); 

// enter rows 
var trEnter = tr.enter().append("tr"); 

// CELL MANAGEMENT 

trEnter.selectAll("td").data(function(d) { return d3.values(d); }).enter().append("td").text(function(d) { return d; }); 

// select all td elements 
var td = tr.selectAll("td").data(function(d) { return d3.values(d); }); 

// exit cells 
td.exit().remove(); 

// enter and update/add data to cells 
td.enter().append("td"); 
td.text(function(d) { return d; }); 
Powiązane problemy