D3 добавление атрибута данных условно
Я создаю таблицу с d3, которая будет использоваться плагином FooTable jquery, и для этого требуется наличие некоторых атрибутов данных в строке заголовка. Но не все столбцы имеют все атрибуты данных и задаются вопросом, есть ли способ сделать это.
Этот подход похож на работу, добавляя все возможные атрибуты данных и оставляя некоторые пробелы, но я уверен, что это не хорошая практика.
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.
Пример colspec:
[{"data-name": "username"}, {"data-name": "Date Joined", "data-hide": "true"}]
В настоящее время получается:
<th data-class="" data-hide="true" data-ignore="" data-type="">Joined</th>
Want
<th data-hide="true" >Joined</th>
Любые предложения?
Ответы
Ответ 1
Кажется хорошим кандидатом для .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]);
});
});
Я часто использую .each
, когда область видимости для каждого элемента имеет больше смысла, чем попытка определить множество атрибутов для каждого элемента.
Для краткого списка атрибутов, особенно если вы беспокоитесь о дополнительных данных в объектах, возможно, проще всего перебрать нужные ключи, а не все:
.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]);
});
});
Ответ 2
Вам не нужно вызывать each() или filter()... Функция attr() сделает это для вас внутренне. Просто вызовите его с помощью функции вместо значения, и эта функция вернет желаемое значение для каждой точки привязки или null, если атрибут не нужен для конкретной привязки, например:
...
.attr('data-class', function(d) {
return 'data-class' in d ? d['data-class'] : null;
});
Если ваша функция возвращает значение null, атрибут не добавляется. Вы даже можете объединить несколько атрибутов в один вызов, предоставив карту имен attr для таких функций:
...
.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;
}
});
или если вы похожи на меня и не хотите вводить так много, вы можете уменьшить список имен атрибутов в соответствующей карте:
...
.attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) {
result[attr] = function(d) {
return attr in d ? d[attr] : null;
}
return result;
}, {}));
Ответ 3
Вы можете использовать функцию .filter()
только для работы с подмножеством выделения, которое вам нужно установить для атрибутов, например
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"];
});
Ответ 4
Очиститель должен использовать фильтр
.filter(d => !!d["data-class"]) // filter only data with the "data-class" property
.attr("data-class", d => d["data-class"])