I am trying to integrate d3 and angular2 alpha.37 (started from here). The problem I am currently having is that the generated DOM elements don't get the attributes used in the emulated styling view encapsulation, and so I can't style them without setting the view encapsulation for the element to None (or Native, but I would rather use emulated).
I managed to programmatically extract the required attribute from an element inside the component [1], and then add it to the generated elements[2], which does work, but this is clearly incredibly hacky:
import {Component, View, Attribute, ElementRef, LifecycleEvent} from 'angular2/angular2';
import d3 from 'd3';
@Component({
selector: 'bar-graph',
properties: [ 'data' ]
})
@View({
template: '<div class="chart"></div>',
styles: [`.chart {
background: #eee;
padding: 3px;
}
div.bar {
width: 0;
transition: all 1s ease-out;
-moz-transition: all 1s ease-out;
-webkit-transition: all 1s ease-out;
}
div.bar {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 5px;
color: white;
box-shadow: 2px 2px 2px #666;
}`]
})
export class BarGraph implements LifecycleEvent.OnChanges {
data: Array<number>;
divs: any;
constructor(elementRef: ElementRef, @Attribute('width') width: string, @Attribute('height') height: string) {
var el:any = elementRef.nativeElement;
var graph:any = d3.select(el);
this.hostAttr = graph[0][0].children[0].attributes[1].name; //hack here [1]
this.divs = graph.
select('div.chart').
style({
'width': width + 'px',
'height': height + 'px',
}).
selectAll('div.bar');
}
render(newValue) {
if (!newValue) return;
this.divs.data(newValue)
.enter().append('div')
.classed('bar', true)
.attr(this.hostAttr, true) //add the attribute here [2]
.style('width', d => d + '%')
.text(d => d + '%');
}
onChanges() {
this.render(this.data);
}
}
Is there a recommended way to deal with this sort of thing (or should I stop tinkering with the DOM outside of Angular2)?
We can add an attribute to a DOM element using two methods. First, is the setAttribute(name, value) and second is the setAttributeNode(attribute_node) .
If you want to define your own custom attributes in HTML, you can implement them through data-* format. * can be replaced by any of your names to specify specific data to an element and target it in CSS, JavaScript, or jQuery.
To change the attribute value of an HTML element HTML DOM provides two methods which are getAttribute() and setAttribute(). The getAttribute() is used to extract the current value of the attribute while setAttribute() is used to alter the value of the attribute.
Not a complete answer (yet), but maybe some useful information that can help in finding a solution:
None
and using global styles was the only solution that I could get to work. Using Native
seemed to result in no elements being added to the DOM at all, but I'd have to do some more tests to figure out the cause. d3.js
, things get even more tricky when introducing elements that are created internally by the library, e.g. through the methods in the d3.svg
namespace. Undoubtedly a workaround for that could be found as well.d3
however. There are plenty of libraries out there that have their own DOM generation/manipulation mechanisms, and it is not unrealistic to think that a portion of those will at some point be integrated in some or other angular2
application. In that sense, it's surprising that the issue does not seem to have come up yet (or maybe my Google-fu is particularly weak this week).In terms of solutions, these are the two approaches that I'm currently considering in case no one comes up with something nicer:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With