Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Issue with Angular 2 template when using d3 #496

Closed

Description

@Gimly

Hello,

Hopefully this question is not too off topic, but I'm getting a really weird issue with the yo aspnetcore-spa template when trying to use d3.js with it. The issue seems to be somehow linked to something in the template because the same code doesn't have the behaviour in an Angular CLI project.

I'm using d3.js to display a simple bar chart I found as an example online. It's a component that imports d3 and uses it to add an SVG and create the bar chart. When I access it through a link I added to the template's left menu, everything works fine, the chart is displayed just fine. But, if I try to access it directly through the URL I've configured as route for the component, I get this exception thrown:

Exception: Call to Node module failed with error: TypeError: Cannot read property 'createElementNS' of undefined
at Object.<anonymous> (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:9352:33)
at Object.<anonymous> (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:10129:39)
at Selection.selection_select [as select] (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:9561:53)
at Selection.selection_append [as append] (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:10128:18)
at BarchartComponent.createChart (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:474:39)
at BarchartComponent.ngOnInit (C:\sources\d3NetCoreAngular2\ClientApp\dist\main-server.js:460:15)
at AppView._View_BarchartComponent_Host0.detectChangesInternal (BarchartComponent_Host.ngfactory.js:28:86)
at AppView.detectChanges (C:\sources\d3NetCoreAngular2\ClientApp\dist\vendor.js:12652:19)
at AppView.detectContentChildrenChanges (C:\sources\d3NetCoreAngular2\ClientApp\dist\vendor.js:12670:24)
at AppView.detectChangesInternal (C:\sources\d3NetCoreAngular2\ClientApp\dist\vendor.js:12662:19)

I'm really lost as to why there would be a difference between accessing the component through a link or directly. Could it be because of a server-side pre-rendering? Is there something else in the template that would make a difference between the two ways of accessing? I've tried adding a breakpoint in the typescript, if I access through the link, the breakpoint is triggered and the code stopped, but if I access directly (or if I refresh the page), then the breakpoint is not triggered and I get the exception.

Here are the important parts of the component's typescript:

...
@Component({
    selector: 'barchart',
    template: require('./barchart.component.html'),
    styles: [require('./barchart.component.css')],
    encapsulation: ViewEncapsulation.None
})
export class BarchartComponent implements OnInit, OnChanges, AfterViewInit {

    @ViewChild('chart')
    private chartContainer: ElementRef

    ...

    ngOnInit() {
        this.htmlElement = this.chartContainer.nativeElement;
        this.host = d3.select(this.htmlElement);
        let svg = this.host.append('svg')
            .attr('width', this.width + this.margin.left + this.margin.right)
            .attr('height', this.height + this.margin.top + this.margin.bottom);
        ...
    }
    ...
}

The html is pretty simple:

<div class="d3-chart" #chart></div>

I've uploaded the whole project in this project: https://github.com/Gimly/d3NetCoreAngular2

Activity

  1. MarkPieszak commented on Dec 7, 2016

    @MarkPieszak
    Contributor

    Can you try wrapping the logic inside of the ngOnInit with the code below and see if it works? D3 doesn't readily get rendered on the server so you might have to make sure it's only rendered on the client.

    import { isBrowser } from 'angular2-universal'; // add this uptop
    
    if (isBrowser) {
       // your d3 code
    }
    
  2. Gimly commented on Dec 7, 2016

    @Gimly
    Author

    Thanks! It does work indeed!
    I fought that issue for nearly a week, and it's fixed in just a line... 👍 Oh well, that's how you learn.

    Does it mean that my guess was correct? When I access the URL directly, the code is pre-rendered server-side?

    Care to explain what in the template activates that server-side rendering?

  3. MarkPieszak commented on Dec 7, 2016

    @MarkPieszak
    Contributor

    Well when you refresh, or type an address and press enter you're hitting the server side, which in turn tries to render that specific section of the application with Angular Universal. Once that's rendered to a string and loaded on the page, the client-side bootstrap starts and then takes over, and the rest of the your time navigating is like a normal SPA. But because of that initial server side render, you get performance boosts, real SEO (since all crawlers can reach your site now), and deep-linking (think social media sharing), all at your finger tips.

    You just have to always keep in mind how your code / components will be handled on the server(Node) side, and you'll be good to go :)

  4. SteveSandersonMS commented on Dec 8, 2016

    @SteveSandersonMS
    Member

    Thanks for resolving this @MarkPieszak!

  5. Gimly commented on Dec 8, 2016

    @Gimly
    Author

    Thanks a lot for your help and explanation @MarkPieszak.

  6. flaneuse commented on Nov 29, 2018

    @flaneuse

    FYI isBrowser() has been switched to isPlatformBrowser. See Angular Universal Gotchas

    import { Component, Inject, PLATFORM_ID, OnInit } from '@angular/core';
    import { isPlatformBrowser, isPlatformServer } from '@angular/common';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent implements {
    
      constructor(
        @Inject(PLATFORM_ID) private platformId: Object
      ){
      }
    
      ngOnInit(){
        if (isPlatformBrowser(this.platformId)) {
         //Client only code.
        } else {
         //Server only code.
        }
      }
    }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions