Dynamically create and embed data URL in Angular -- [Question Asked]

Query asked by user

In my Angular application, I have the following invariable basic conditions:

  1. The application dynamically loads a ZIP file from an external URL.
  2. Within this ZIP file, there’s a HTML file which is to be extracted. This HTML file may contain images with data:image/jpeg;base64,...-like sources (but no external links).
  3. The HTML file has to be displayed “as is” by the Angular application in a separate browser tab

I managed to implement 1. and 2. seamlessly with JSZip etc. Thus, we can assume, there’s a String variable htmlFileContent now. Displaying the iFrame on specific conditions in an otherwise empty Angular tab is also not the problem, I managed to do this. To achieve the rest of point 3, I see two different approaches:

Using a div:

Use htmlFileContent as the innerHTML of a div element, like so:

<div [innerHtml]="{{ htmlFileContent }}"></div>

This works indeed, but has some umcomely side effects, e. g. the title of the “inner” HTML header is rendered as well in the browser. Hence, I could try and parse htmlFileContent into a DOM and remove the unwanted tree elements. This might be a working solution, but somehow I don’t feel good about it.

Additionally, the HTML contains some in-file anchor links (<a href="#topOfPage"> style) which would also not work any more and need to be corrected.

Using an iFrame:

I know well about the uglyness and deprecation of iFrame usage, nevertheless, in my eyes this seems to be an adequate approach to my problem. So I would use:

<iframe [src]="fileUrl" class="fullscreenIFrame"></iframe>

And here the problem arises: One could set fileUrl="data:text/html;charset=utf-8,"+ htmlFileContent. But then, Angular will (rightly) complain: ERROR Error: NG0904: unsafe value used in a resource URL context (see https://g.co/ng/security#xss) and nothing will be displayed. So, currently I am trying something like this using the DomSanitizer from @angular/platform-browser:

this.filedata = this.sanitizer.bypassSecurityTrustHtml(htmlFileContent);
this.fileUrl = this.sanitizer.bypassSecurityTrustResourceUrl("data:text/html;charset=utf-8,"+ this.filedata) ;

Which will indeed work partly: I get a warning SafeValue must use [property]=binding: rendered in the output and the “inner” HTML is cut where the first src="data:..." image appears.

And here I’m stuck. My iFrame can, of course, have only one src and I can’t concatenate fileUrl (which then would be shortened to the data:text/html;charset=utf-8, content) and fileData there as one is a SafeResourceUrl and one a SafeHtml object.


Here’s a MWE of my problem:

https://stackblitz.com/edit/angular-ivy-uzpcsy?file=src/app/app.component.ts

(Interestingly, the image is rendered here… Anyway, the SafeValue warning persists.)

Do you have any suggestions on how to handle this particular requirement? Might the div-approach still be the better one? Any help is greatly appreciated – many thanks!

Answer we found from sources

As I didn’t receive or find another possibility, this is the way I implemented it ‚Äì just for future reference:

import { ActivatedRoute, Router, UrlSegment } from '@angular/router';
import { DomSanitizer, SafeHtml, SafeResourceUrl } from '@angular/platform-browser';

export class MyComponent implements OnInit {
  
  filedata: SafeHtml = 'Loading...';
  currentUrl: string = '';  

  constructor(
    private activatedRoute: ActivatedRoute,
    private sanitizer: DomSanitizer,
  ) {}

  ngOnInit(): void {
    // Use the Angular possibilities to retrieve to complete current URL
    this.activatedRoute.url.subscribe(url => {
      this.currentUrl = '';
      url.forEach(urlElement => {
        this.currentUrl += urlElement + '/';
      });
      this.currentUrl = this.currentUrl.substring(0, this.currentUrl.length - 1);
    });
    this.loadFileData();
  }

  loadFileData(): void {
    // This is the function where the ZIP file is downloaded and the file
    // content is extracted. As it is not part of the question or the
    // answer, I will not post it here.
    // Let's just assume, the file content is now stored in "response".
    this.filedata = 
    this.sanitizer.bypassSecurityTrustHtml(this.correctFileData(response));
  }

  // Receives the file content response as first parameter,
  // removes the unwanted tags and corrects the anchor links.
  private correctFileData(response: string): string {
    let el = document.createElement('html');
    el.innerHTML = response;

    // Remove all "head" tags including their inner elements
    // (Of course, the should be only one head tag, but you never know...)
    let headElements = el.getElementsByTagName('head');

    for (let i = 0; i < headElements.length; i++) {
      el.removeChild(headElements[i]);
    }

    // Correct all anchor links: Prepend the current URL
    // So http://my.address.com/#anchor would become
    // http://my.address.com/myApp/myRoute/mySubRoute#anchor
    // for example
    let links = el.getElementsByTagName('a');
    for (let i = 0; i < links.length; i++) {
      let link = links[i];
      if (link.href.indexOf('#') != -1) {
        console.log(link.href + ' --> ' + this.currentUrl + 
          link.href.substring(link.href.indexOf('#')));
        link.href = this.currentUrl + link.href.substring(link.href.indexOf('#'));
      }
    }

    return el.outerHTML;
  }

And in the component’s HTML, I just use:

<div [innerHTML]="filedata"></div>

Possibly, there are other, better solution, but this one works very well for my use case.

Answered By – ahuemmer

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0


What is Angular?

Angular is an open-source, JavaScript outline written in TypeScript. Google keeps up with it, and its basic role is to foster single-page activities. As an edge, Angular enjoys clear benefits while likewise outfitting a standard design for formulators to work with. It empowers stoners to deliver huge tasks in a viable way. textures overall lift web improvement viability and execution by outfitting an agreeable construction so that formulators do n't need to continue to modify regulation from scratch. textures are efficient devices that offer formulators a large group of extra elements that can be added to programming easily.

However, is JavaScript ideal for creating single-sprinter activities that bear particularity, testability, and trend-setter efficiency? maybe not.

JavaScript is the most by and large utilized client-side prearranging language. It's composed into HTML reports to empower relations with web sprinters in endless extraordinary ways. As a genuinely simple to-learn language with inescapable help, creating current operations is appropriate.

Nowadays, we have various textures and libraries intended to give essential outcomes. As for front end web advancement, Angular addresses incalculable, while possibly not all, of the issues formulators face while utilizing JavaScript all alone.
Who we are?

We are team of software engineers in multiple domains like Programming and coding, Fundamentals of computer science, Design and architecture, Algorithms and data structures, Information analysis, Debugging software and Testing software. We are working on Systems developer and application developer. We are curious, methodical, rational, analytical, and logical. Some of us are also conventional, meaning we're conscientious and conservative.

Answer collected from stackoverflow and other sources, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0