score:9

Accepted answer

Please refer to the cool explanation of the data joins.

When you call

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

You actually get 3 selections: 'enter' (whith the new elements not present in the DOM yet), 'exit' (those present in DOM but not longer present in the data) and 'update' which contains nodes that are already in DOM and still have the data assigned to them via the .data call above.

In general, for 'enter' selection you create new nodes, for 'exit' you need to remove the old ones, and for 'update' you just change attributes - may be with some nice transition effect. See the updated 'tick' function code.

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

See the Demo (backgroundJobs is switched on timer between the two hard-coded datasets).

score:0

In order to be able to add and delete rows dynamically, this strategy works for 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; });

score:1

The rows variable will be a selection that will only contains nodes if enter() is not empty. The second time around, if you haven't added any new rows into backgroundJobs, the data bind will update the existing nodes and enter() won't contain any nodes (meaning rows won't contain any nodes).

You can get around this by holding a reference to the update selection taking advantage of the fact that nodes appended to the enter selection get added to the update selection behind the scenes:

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

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

Now rows will refer to a selection that contains all previously existing and newly added nodes.


Related Query