Reputation: 157
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 :
Upvotes: 4
Views: 7032
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
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
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
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.
@ViewChild
, @ViewChildren
, @ContentChild
and @ContentChildren
.Upvotes: 3
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
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