2013-08-02 12 views
5

Sto usando D3 per disegnare una tabella HTML e le cose funzionano benissimo su invio. Quando aggiungo un nuovo elemento alla mia raccolta di dati, aggiunge correttamente il nuovo elemento alla tabella.Disegnare una tabella HTML tramite D3 non aggiorna i dati esistenti

Il problema si verifica quando aggiorno un oggetto esistente (un oggetto nella raccolta backgroundJobs sottostante) all'interno della raccolta. Quando rieseguo il codice D3 per sincronizzare la tabella, non funziona. Non accade nulla.

Ecco il codice:

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); 

risposta

7

Fare riferimento alla nuova spiegazione dello data joins.

Quando si chiama

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

È effettivamente ottenere 3 selezioni: 'enter' (whith i nuovi elementi non presenti nel DOM ancora), 'uscita' (quelli presenti nel DOM, ma non più presenti nel dati) e 'aggiornamento' che contiene nodi che sono già in DOM e hanno ancora i dati loro assegnati tramite la chiamata .data sopra.

In generale, per la selezione 'enter' si creano nuovi nodi, per 'exit' è necessario rimuovere quelli vecchi, e per 'update' basta cambiare gli attributi - potrebbe essere con un buon effetto di transizione. Vedere il codice funzione "tick" aggiornato.

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(); 
} 

Vedi le Demo (backgroundJobs viene acceso timer tra le due serie di dati hard-coded).

+1

perché comprendono la chiamata 'rows.order();'? – manu08

+0

In modo che l'ordine delle righe della tabella corrisponda all'ordine dei lavori nell'array backgroundJobs. Senza l'ordinamento esplicito tutti i nuovi lavori ("nuovi" in termini di unione dati - quelli che formano la selezione "invio") vengono aggiunti alla fine della tabella. – amakhrov

1

La variabile rows sarà una selezione che contiene solo nodi se enter() non è vuoto. La seconda volta, se non sono state aggiunte nuove righe in backgroundJobs, il binding dei dati aggiornerà i nodi esistenti e enter() non conterrà alcun nodo (ovvero rows non conterrà alcun nodo).

È possibile aggirare il problema in possesso di un riferimento alla selezione aggiornamento approfittando del fatto che i nodi aggiunto alla selezione immettere vengono aggiunti alla selezione aggiornamento dietro le quinte:

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

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

Ora righe farà riferimento a una selezione che contiene tutti i nodi precedentemente esistenti e appena aggiunti.

0

Al fine di essere in grado di aggiungere ed eliminare righe in modo dinamico, questa strategia funziona per me:

// 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; }); 
Problemi correlati