elementRef is null after building angular app

6.5k views Asked by At

In a component template, i'm selecting an svg element with ElementRef. It works fine but when i build the app and open it elementRef is null.

    @Component({
      selector: 'app-svg',
      template: `<div id="root">
        <object [data]='trustedUrl' type="image/svg+xml" height="450" width="650" #dataSvg></object>
      </div>`,
      styleUrls: ['./svg.component.css'] 

    })
constructor(private sanitizer: DomSanitizer, private elRef: ElementRef) {    
 }

elementRef targeted

@ViewChild('dataSvg') dataSvg: ElementRef;

pass it to elementRef variable

ngOnInit() {
    this.elementRef = this.elRef.nativeElement.querySelector('#dataSvg');  
     }

after content is loaded, i'm selecting the svg :

ngAfterContentInit() {
    const elementRef = this.elementRef;

    // when content is loaded...
    elementRef.addEventListener('load', function (event) {
      // ...retrieve svg element

elementRef.querySelector('svg') is null

when i run 'npm run build' and go to dist/index.html, the contentDocument > is null :

enter image description here

6

There are 6 answers

1
Qortex On

DOM is not completely built yet in ngOnInit. You need to wait for children (template here) to be created.

Instead of ngOnInit, put your code into ngAfterViewInit.

More info on hooks in component lifecycle can be found in the Angular documentation.

0
SeleM On

According to the official Doc, you cannot access to the @ViewChild element unless you do it in the AfterView hook (AfterViewInit or AfterViewChecked ) instead of the OnInit one.


  • You can find here a good article about differences between @ViewChild, @ViewChildren, @ContentChild and @ContentChildren.
2
dream88 On

You use @ViewChild('dataSvg') dataSvg: ElementRef; but in your template you haven't provided any anchor for dataSvg.

There are 2 ways to do this: 1) using @Directive as explained on Angular Docs 2) Using a template reference # :in your case: <object ... #dataSvg></object>

Not mentioned if you already use Directive, but in your template code, you only have an id=dataSvg

0
SaiKishore On

In the below place, explicitly give read: ElementRef,

@ViewChild('dataSvg') dataSvg: ElementRef;

It should be

@ViewChild('dataSvg', { read: ElementRef }) dataSvg: ElementRef;

0
user5329403 On

I found my solution of compatibility for append SVG element :

in my svg component i set the source of svg with binding innerHTML, when my input changes i'm loading the svg with a service which returns the svg data in a safe way:

binding the data source of SVG in the component :

 @Component({
  selector: 'app-svg',
  template: `<div id="root">
    <div [innerHTML]="svgSafe" type="image/svg+xml" height="450" width="650" #dataSvg></div>
  </div>`,
  styleUrls: ['./svg.component.css'] ,
  animations: [

  ]
})

load the source of svg with input :

 ngOninit() {

    var url = this.data.url;


    var id = 1; 

    if(url === 'assets/object_move.svg') {
       id = 1;
    }

    if(url === 'assets/object_wait.svg') {
      id = 2;
    }


    ..
    var dataSVG;
            this
              .loaderService
              .getSVGData(id)
              .subscribe((dataSvg) => {

      this.svgSafe = this.sanitizer.bypassSecurityTrustHtml(dataSvg.data);

            });
    }
0
Pejman Saberin On

There is a security risk associated with ElementRef:

Permitting direct access to the DOM can make your application more vulnerable to XSS attacks.

https://angular.io/api/core/ElementRef#description

Consider using Renderer2:

https://angular.io/api/core/Renderer2