Currently, I am using Ionic and Angular with Firebase to develop a daily readings application that dynamically displays an iframe for embedded YouTube videos based on the date. Everything works fine until I try to use data bindings in the source URL for the iframe instead of a static URL. This results in an error: Error: NG0904: unsafe value used in a resource URL context.
After researching, I discovered DomSanitizer and SafeResourceUrl as possible solutions. However, I am facing difficulties implementing this strategy due to fetching the URL data through observables. Most examples I found were either using static URLs or different approaches like vanilla JavaScript versus Angular/TypeScript methods. Coming from a PHP background, transitioning to the FAng stack has been challenging for me.
I attempted to integrate DomSanitizer script following Angular specifications and suggestions on forums, but because of the observable, nothing seems to work, and I encounter errors and IDE complaints.
Here is my attempt at implementing a dynamic URL:
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { Injectable } from '@angular/core';
// other imports
export interface Readings {
id?: string;
orderNo?: number;
parshah?: string;
date?: string;
videoTorah?: string;
torahPortion?: string;
url?: string;
safeUrl?: string;
}
@Injectable({
providedIn: 'root'
})
export class DataService {
url: string;
urlSafe: SafeResourceUrl;
constructor(
private firestore: Firestore,
private domSanitizer: DomSanitizer
) { }
getReadings(): Observable<Readings[]> {
const readingsRef = collection(this.firestore, 'readings');
const q = query(readingsRef, orderBy('orderNo'), limit(3));
return collectionData(q, { idField: 'id' }) as Observable<Readings[]>;
}
getUrl(readings: Readings): SafeResourceUrl {
this.getReadings();
this.url = 'https://www.youtube.com/embed/' + readings.videoTorah;
this.urlSafe = this.domSanitizer.bypassSecurityTrustResourceUrl(this.url);
return this.urlSafe;
}
}
In my home.page.ts, I added this line to my constructor:
this.dataService.getReadings().subscribe(res => {
this.readings = res;
this.cd.detectChanges();
});
this.dataService.getUrl();
Originally, my home.page.html called the URL like this:
<iframe width="560" height="315" [src]="reading.videoTorah" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
Now it looks like this:
<ion-list>
<ion-item *ngFor="let reading of readings">
<iframe width="560" height="315" src="getUrl()" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<ion-label>
{{ reading.orderNo }} {{ reading.parshah }} {{ reading.torahPortion }}
</ion-label>
</ion-item>
</ion-list>
Despite trying to call the function after src="getUrl()", it didn't work as expected. I may be completely off track now, but as a hobbyist developer seeking guidance, I feel there's a simple solution I'm overlooking due to my limited formal coding education. My online courses did not cover these advanced topics, so I'm actively studying TypeScript and RxJS to overcome such obstacles.