80

I have successfully integrated Angular 2 (Alpha 44) with D3.js:

<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>
  System.config({packages: {'app': {defaultExtension: 'js'}}});
  System.import('app/app');
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>

app.js:

/// <reference path="./../../typings/tsd.d.ts" />

import {Component, bootstrap, ElementRef} from 'angular2/angular2';

@Component({
  selector: 'my-app',
  template: '<h1>D3.js Integrated if background is yellow</h1>',
  providers: [ElementRef]
})
class AppComponent { 
  elementRef: ElementRef;

  constructor(elementRef: ElementRef) {
   this.elementRef = elementRef;
  }

afterViewInit(){
    console.log("afterViewInit() called");
    d3.select(this.elementRef.nativeElement).select("h1").style("background-color", "yellow");
  }
}
bootstrap(AppComponent);

Everything is working fine. But Angular 2 documentation for ElementRef states the following:

Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. Alternatively you take a look at {@link Renderer} which provides API that can safely be used even when direct access to native elements is not supported. Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.

Now the question arises how to integrate D3.js with the Renderer API's?

6
  • Is this in any help? ng-newsletter.com/posts/d3-on-angular.html Commented Nov 4, 2015 at 7:33
  • I am also trying to get D3 to work with angular 2. In the example above, I can see that you reference the d3-script in you index.html, but I can´t see how you get a hold of the d3-variable in app.js? Commented Nov 16, 2015 at 6:08
  • 8
    @user2915962 - npm install d3 , ensure postinstall runs and d3.d.ts is created by tsd, then import * as d3 from 'd3/d3'; Commented Dec 1, 2015 at 8:33
  • There's a video mentioned in one of the comments here: stackoverflow.com/q/34704148/2050479 that is quite interesting Commented Feb 10, 2016 at 7:12
  • 1
    @urosjarc - That's Angular 1, which has a very different way of doing these sorts of things. Commented Aug 30, 2016 at 12:25

4 Answers 4

58
+75

To use Renderer, you need the raw HTML element (aka nativeElement). So basically you have to use whatever your library is, get the raw element and pass it to Renderer.

For example

// h3[0][0] contains the raw element
var h3 = d3.select(this.el.nativeElement).select('h3');
this.renderer.setElementStyle(h3[0][0], 'background-color', 'blue');

The warning about ElementRef is about using it directly. That means that this is discouraged

elementRef.nativeElement.style.backgroundColor = 'blue';

But this is fine

renderer.setElementStyle(elementRef.nativeElement, 'background-color', 'blue');

For showing purposes you can use it as well with jQuery

// h2[0] contains the raw element
var h2 = jQuery(this.el.nativeElement).find('h2');
this.renderer.setElementStyle(h2[0], 'background-color', 'blue');

My recommendation though is to stick to use what angular2 provides you to do this easily without depending on another libraries.

With pure angular2 you have two easy ways

  • Using directives
// This directive would style all the H3 elements inside MyComp
@Directive({
    selector : 'h3',
    host : {
        '[style.background-color]' : "'blue'"
    }
})
class H3 {}

@Component({
    selector : 'my-comp',
    template : '<h3>some text</h3>',
    directives : [H3]
})
class MyComp {}
  • Using ViewChild with local variables
@Component({
    selector : 'my-comp',
    template : '<h3 #myH3>some text</h3>',
})
class MyComp {
    @ViewChild('myH3') myH3;
    ngAfterViewInit() {
        this.renderer.setElementStyle(this.myH3.nativeElement, 'background-color', 'blue');
    }
}

Here's a plnkr with all the cases I mentioned in this answer. Your requirements may differ, of course, but try to use angular2 whenever you can.

Sign up to request clarification or add additional context in comments.

2 Comments

So, for the example of using bootstrap's collapse plugin, would I be right in saying that jQuery(this.el.nativeElement).collapse('show'); would be a perfectly acceptable way of instantiating the plugin?
I guess the directive approach wouldn't work for dynamically appended h3s right? Example: plnkr.co/edit/U2lvYqtGvdf7kWoRg10N?p=preview
6

Try this:

npm install [email protected] --save to set the version you need

npm install @types/[email protected] --save or a higher version if you want d3 4+

and then in your ts do

import * as d3 from 'd3';

Should work just fine

3 Comments

using the latest d3 (v4) and based on angular 2 quickstart example i had to also add 'd3':'npm:d3' to map and 'd3': {main:'build/d3.js', defaultExtension:'js'} to packages in systemjs.config.js file.
Hi @Entrodus, do you mind to give me the exact install sequence, based on Quickstart? I tried to follow this, including the system's mod you proposed, but I'm still stuck (no ./build/d2.js, no ./build folder either).
@StéphanedeLuca: 1.Set up angular quickstart > 2.install d3 and typings for d3 version 4.4.0 > 3.added map and packages directives for d3 in system.config.js > 4.add import of d3 in angular component that uses d3 > 5.Victory.
4
npm install --save d3

check d3 version in package.json and check it in node_modules too.

then, in the component.ts, import it as below

import * as d3 from 'd3';

Comments

3

I was having trouble using ElementRef, I'm not sure if that API has changed. So I ended up using ViewContainRef to get the nativeElement.

import {Component, ViewContainerRef, OnInit} from '@angular/core';
declare var d3:any;
@Component({
    selector: 'line-chart',
    directives: [],
    template: `<div class="sh-chart">chart</div>`
})
export class LineChart implements OnInit{
    elem ;
    constructor(private viewContainerRef:ViewContainerRef) {}
    ngOnInit(){
        this.elem = this.viewContainerRef.element.nativeElement;

        d3.select(this.elem).select("div").style("background-color", "yellow");
    };
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.