user5329403
user5329403

Reputation: 157

elementRef is null after building angular app

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

Upvotes: 4

Views: 7032

Answers (6)

Pejman Saberin
Pejman Saberin

Reputation: 69

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

Upvotes: 0

SaiKishore
SaiKishore

Reputation: 11

In the below place, explicitly give read: ElementRef,

@ViewChild('dataSvg') dataSvg: ElementRef;

It should be

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

Upvotes: 1

user5329403
user5329403

Reputation: 157

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);

            });
    }

Upvotes: 0

SeleM
SeleM

Reputation: 9678

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.

Upvotes: 3

dream88
dream88

Reputation: 511

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

Upvotes: 3

Qortex
Qortex

Reputation: 7466

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.

Upvotes: 2

Related Questions