UNPKG

2.8 kBJavaScriptView Raw
1import { isArray } from "d3-let";
2import { select } from "d3-selection";
3import { createComponent, protoView } from "../core/component";
4
5//
6// d3-for directive
7// ======================
8//
9// Repeat a element over an array of items and establish
10// a one way binding between the array and the Dom
11export default {
12 create(expression) {
13 var bits = [];
14 expression
15 .trim()
16 .split(" ")
17 .forEach(v => {
18 v ? bits.push(v) : null;
19 });
20 if (bits.length !== 3 || bits[1] != "in")
21 return this.logWarn(
22 `directive requires "item in expression" template, got "${expression}"`
23 );
24 this.itemName = bits[0];
25 this.itemClass = `for${this.uid}`;
26 return bits[2];
27 },
28
29 preMount() {
30 return true;
31 },
32
33 mount(model) {
34 this.creator = this.el;
35 this.el = this.creator.parentNode;
36 // remove the creator from the DOM
37 select(this.creator).remove();
38 if (this.el) return model;
39 },
40
41 refresh(model, items) {
42 if (!isArray(items)) return;
43 let d;
44
45 var creator = this.creator,
46 itemClass = this.itemClass,
47 selector = `.${itemClass}`,
48 itemName = this.itemName,
49 sel = this.sel,
50 allItems = sel.selectAll(selector),
51 entries = allItems
52 .filter(function() {
53 d = this.__d3_view__.model[itemName];
54 return items.indexOf(d) > -1;
55 })
56 .data(items),
57 exits = allItems
58 .filter(function() {
59 d = this.__d3_view__.model[itemName];
60 return items.indexOf(d) === -1;
61 })
62 .classed(itemClass, false),
63 vm = sel.view();
64
65 let forComponent = vm.components.get(creator.tagName.toLowerCase());
66 if (!forComponent) forComponent = createComponent("forView", protoView);
67
68 let x, el, fel, tr;
69
70 (this.transition(exits) || exits).style("opacity", 0).remove();
71
72 // Add all missing entries
73 entries
74 .enter()
75 .append(() => {
76 el = creator.cloneNode(true);
77 fel = vm.select(el);
78 if (vm.transitionDuration(fel) > 0) fel.style("opacity", 0);
79 return el;
80 })
81 .each(function(d, index) {
82 x = { index: index };
83 x[itemName] = d;
84 forComponent({
85 model: x,
86 parent: vm
87 })
88 .mount(this, { model: vm.model })
89 .then(fv => {
90 fv.sel.classed(itemClass, true);
91 // replace the item with a property from the model
92 // This allow for reactivity when d is an object
93 items[index] = fv.model[itemName];
94 tr = fv.transition();
95 if (tr) tr.style("opacity", 1);
96 });
97 });
98
99 sel.selectAll(selector).each(function(d) {
100 // update model itemName property
101 this.__d3_view__.model[itemName] = d;
102 });
103 }
104};