d3 adding data attribute conditionally

后端 未结 5 1385
悲&欢浪女
悲&欢浪女 2021-02-01 14:01

I\'m creating a table with d3 to be used by the FooTable jquery plugin and this requires having some data- attributes in the header row. But not all columns have all the data a

相关标签:
5条回答
  • 2021-02-01 14:34

    The most voted solution is perfect because .attr(a,b) works as conditional when b is null,

     d3chain.attr('data-class', d=>'data-class' in d ? d['data-class'] : null );
    

    but this solution is not geral, is not valid for other chaining methods, except using .each(), .filter or .call(). In general the most simple is call().

    .call(condFunc,param)

    Suppose that param is an global variable used as parameter in the condition, and that g is a global object used to return a value.

      // inconditional
      d3chain.attr(param, g[param])
    
      // conditional case using globals
      d3chain.call( s => { if (g[param]) s.attr(param,g[param]) })
    
      // conditional case passing the parameter
      d3chain.call( (s,p) => {
         if (g[p]) s.attr(p, g[p])
      }, param)
    

    .each(d => condFunc)

    Typical use:

     d3chain.each( d=> {
         if (param && d) d3.select(this).attr(d, g[param])
     })
    

    See @nrabinowitz answer for detailed example.

    .filter(d=>condFunc).etc

    Typical use:

     d3chain.filter( d=> param in d ).attr(param, d=> g[param])
    

    See @LarsKotthoff answer for detailed example.

    0 讨论(0)
  • 2021-02-01 14:37

    You don't need to call each() or filter()... The attr() function will do this for you internally. Just call it with a function instead of a value, and have that function return the desired value for each datum, or null if the attribute is not desired for a particular datum, like so:

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

    If your function returns null, the attribute is not added. You can even combine several attributes into one call by providing a map of attr names to functions like so:

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

    or if you're like me and would rather not type so much, you can reduce the list of attribute names into the appropriate map:

    ...
    .attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) {
        result[attr] = function(d) {
            return attr in d ? d[attr] : null;
        }
        return result;
    }, {}));
    
    0 讨论(0)
  • 2021-02-01 14:46

    Seems like a good candidate for .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]);
                });
            });
    

    I often use .each when having a per-item scope makes more sense than trying to figure out a bunch of attributes for each item.

    For a short list of attributes, especially if you're worried about extra data in the objects, it's probably easier to loop through the desired keys instead of everything:

            .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]);
                });
            });
    
    0 讨论(0)
  • 2021-02-01 14:51

    You can use the .filter() function to only operate on the subset of the selection that you need to set attributes for, e.g.

    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 讨论(0)
  • 2021-02-01 14:51

    A cleaner is to use filter

    .filter(d => !!d["data-class"]) // filter only data with the "data-class" property
    .attr("data-class", d => d["data-class"])
    
    0 讨论(0)
提交回复
热议问题