2013-08-13 12 views
25

Sto creando una tabella con d3 per essere utilizzata dallo FooTable jquery plugin e ciò richiede di avere alcuni attributi di dati nella riga di intestazione. Ma non tutte le colonne hanno tutti gli attributi dei dati e si chiedono se c'è un modo per farlo.d3 aggiunta attributo di dati in modo condizionale

Questo tipo di approccio funziona, aggiungendo tutti gli attributi possibili dei dati e lasciando alcuni vuoti, ma sono sicuro che non è una buona pratica.

var th = d3.select(selection).select("thead").selectAll("th") 
      .data(colspec) 
      .enter().append("th") 
      .text(function(d) { return d["data-name"]; }) 
      .attr("data-class", function(d) { 
       if ("data-class" in d) { 
        return d["data-class"]; 
       } else { 
        return ""; 
       } 
      }) 
      .attr("data-hide", function(d) { 
       if ("data-hide" in d) { 
        return d["data-hide"]; 
       } else { 
        return ""; 
       } 
      }) 
      .attr("data-ignore", function(d) { 
       if ("data-ignore" in d) { 
        return d["data-ignore"]; 
       } else { 
        return ""; 
       } 
      }) 

     etc. 

esempio colspec:

[{"data-name": "username"}, {"data-name": "Date Joined", "data-hide": "true"}] 

Attualmente ottenere:

<th data-class="" data-hide="true" data-ignore="" data-type="">Joined</th> 

Vuoi

<th data-hide="true" >Joined</th> 

Qualche suggerimento?

+0

+ 1'd solo per l'introduzione di me footable – Joum

+0

Quindi, se ho avuto la domanda diretta, quando una determinata cella non contiene dati, si vorrebbe la versione _minified_ della tabella per * * non ** mostra il campo, giusto? – Joum

+0

Non cercare di essere così intelligente (ancora!) Aggiunto commento sopra. – PhoebeB

risposta

26

sembra un buon candidato per .each():

var th = d3.select(selection).select("thead").selectAll("th") 
     .data(colspec) 
    .enter().append("th") 
     .text(function(d) { return d["data-name"]; }) 
     // now address each item individually 
     .each(function(d) { 
      var header = d3.select(this); 
      // loop through the keys - this assumes no extra data 
      d3.keys(d).forEach(function(key) { 
       if (key != "data-name") 
        header.attr(key, d[key]); 
      }); 
     }); 

Io uso spesso .each quando avere un per-oggetto ambito ha più senso che cercare di capire un po 'di attributi per ogni elemento.

Per un breve elenco di attributi, soprattutto se siete preoccupati per i dati aggiuntivi negli oggetti, è probabilmente più facile per scorrere i tasti desiderati invece di tutto ciò:

 .each(function(d) { 
      var header = d3.select(this); 
      ['data-class', 'data-hide', 'data-ignore'].forEach(function(key) { 
       if (key in d) 
        header.attr(key, d[key]); 
      }); 
     }); 
+1

Oh, è così intelligente! Grazie. – PhoebeB

+0

perché hai bisogno di un forEach all'interno di un .each? – Kraken

+0

.each esegue il loop degli oggetti dati (righe), mentre in questo esempio forEach esegue il looping degli attributi da applicare a ciascun elemento (cols). – nrabinowitz

6

È possibile utilizzare la funzione .filter() per operare solo sul sottoinsieme della selezione per cui è necessario impostare gli attributi, ad es.

var th = d3.select(selection).select("thead").selectAll("th") 
     .data(colspec) 
     .enter().append("th") 
     .text(function(d) { return d["data-name"]; }); 
th.filter(function(d) { return ("data-class" in d); }) 
     .attr("data-class", function(d) { 
      return d["data-class"]; 
     }); 
+0

Speravo di non dover scorrere tra gli elementi sei volte (numero di attributi dei dati), sebbene l'idea del filtro lo renderà meno oneroso. Non c'è modo di farlo in linea in un solo passaggio? – PhoebeB

+0

Un altro approccio sarebbe semplicemente chiamare una funzione su ciascun elemento che esegue l'impostazione di commutazione e attributo. In questo modo, avresti toccato ogni elemento solo una volta. –

44

Non è necessario chiama each() o filter() ... La funzione attr() lo farà internamente. Basta chiamare con una funzione invece di un valore, e che hanno la funzione restituisce il valore desiderato per ogni dato, o null se l'attributo non è desiderato per un particolare dato, in questo modo:

... 
.attr('data-class', function(d) { 
    return 'data-class' in d ? d['data-class'] : null; 
}); 

Se le vostre dichiarazioni di funzione null, l'attributo non è stato aggiunto. È anche possibile combinare diversi attributi in una sola chiamata, fornendo una mappa di nomi attr alle funzioni in questo modo:

... 
.attr({ 
    'data-class': function(d) { 
     return 'data-class' in d ? d['data-class'] : null; 
    }, 
    'data-hide': function(d) { 
     return 'data-hide' in d ? d['data-hide'] : null; 
    }, 
    'data-ignore': function(d) { 
     return 'data-ignore' in d ? d['data-ignore'] : null; 
    } 
}); 

o se siete come me e preferisce non scrivere così tanto, è possibile ridurre l'elenco dei attributi nomi nella mappa appropriata:

... 
.attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) { 
    result[attr] = function(d) { 
     return attr in d ? d[attr] : null; 
    } 
    return result; 
}, {})); 
+8

+1 per specificare che un attributo nullo non viene aggiunto – Breiz

+0

questo funziona bene se ci sono lievi variazioni per il rendering in base ai dati. Se si desidera eseguire il rendering di un oggetto completamente diverso basato su una chiave dati, penso che .each() sia più sintetico. – bryanph

Problemi correlati