Hi Shawn, and CC @mbostock,
As you may know, @tmcw and I are using d3-bootstrap components in iD. Right now we have a home-grown typeahead component, and I was looking into generalizing it for inclusion in d3-bootstrap. However, it's not clear to me how to translate some of the bootstrap idioms to d3, and I wanted to see if you had any thoughts.
bootstrap-typeahead uses $.fn.data to store a per-element Typeahead
instance which implements the necessary state and behavior. For typeahead, this includes most importantly a reference (this.$menu
) to the ul
element that displays the typeahead results. Imagine implementing for d3-bootstrap-typeahead a typeahead.close(selection)
function -- it needs to hide the menu element corresponding to each element in the selection.
In d3, per-element state is normally either part of the datum or manifested in the local variables of a element-specific closure. Neither of those are suitable in this case: for reusable components like typeahead, the data need to be reserved for user purposes. And closures provide no way of obtaining the state given only a selection or element.
Alternatives:
- Store data in DOM element properties. This appears to be what existing boostrap-d3 components do. Simple, but introduces risks of name collision, and leads one towards an un-d3-ish classical
Typeahead
prototype.
- Materialize all state in the DOM such that it can be recalculated later. For instance, finding the typeahead menu based on DOM traversal or sub-selection. Awkward and error-prone in some cases.
- Create a per-element data side-channel akin to $.fn.data. This also boils down to DOM element properties, but perhaps in a more maintainable way.
That's a very brief summary of the issues so let me know if it is unclear. Otherwise, any thoughts?