0

Currently I have an Angular component that appends a list of script tags into the DOM with Renderer2 library, the code of these scripts is retrieved from an external source. In the following snippet, scripts array is the list of source links. Being this the case, I'm unable to modify the JS code from them:

  for(let i = 0; i<scripts.length; i++){
    let script = this.renderer2.createElement('script');
    script.type = `text/javascript`;
    script.src = scripts[i];
    this.appendedChildren.push(script);
    this.renderer2.appendChild(this._document.body, script);
}

I tried to remove them from the DOM, but the scripts keep executing:

ngOnDestroy(){
  for(let i = 0; i<this.appendedChildren.length; i++)
    this.renderer2.removeChild(this._document.body, this.appendedChildren[i]);
}

What I would like is to get the pid or some kind of identificator to be able to kill the JS scripts within the ngOnDestroy(), and also a method to do it so.

5
  • The pid is your browser's tab, since Javascript is single-threaded. There is not one new process spawned for each <script> tag in your DOM. Once it's loaded in memory, simply deleting the <script> tag won't do anything. What you are trying to do is hard, because the loaded script is just added to the rest in memory, and executed in the same thread. And it's also kind of "dirty", trying to kill a running script like that doesn't sound clean. What is your actual problem (problem X) instead of this "problem Y" ? Commented Dec 27, 2021 at 12:56
  • Currently I get the source links from an external API, these are scripts that render ads. I need to stop showing these ads when the user triggers some condition, such as pressing a button. It's hard for me to see a different approach than this, what I could do is to get the JS code from the src and modify it dynamically (adding some common method) to kill it when something is done from the component, but that looks tricky and hard indeed. Commented Dec 27, 2021 at 13:15
  • If you need to hide the ads, then simply use CSS display:none? Commented Dec 27, 2021 at 13:18
  • I've been reading the scripts I get, the thing is that there is no common ground between them, each one generates an img or an iframe tag without adding any class or id, and they append it into the body, which makes them impossible to detect and therefore to hide them. I'll ask the API dev to add a class inside the elements that the scripts generate, which I can parse afterwards and hide the ads, I don't see any other feasible solution. Thanks for your help, will update this thread as soon as I get news. Commented Dec 27, 2021 at 13:58
  • Ooof, sounds like some headache :/ Good luck with this, then Commented Dec 27, 2021 at 14:25

2 Answers 2

0
constructor(private renderer: Renderer2) {}

let script = this.renderer.createElement('script');
script.type = `text/javascript`;
script.src = 'testme.js';
script.id = "testScriptName";
this.renderer.appendChild(this._document.body, script);

ngOnDestroy() {
var elem = document.querySelector("#testScriptName");
document.querySelector("#testScriptName").parentNode.removeChild(elem)
}
Sign up to request clarification or add additional context in comments.

2 Comments

Please try it. @Across
If the script is already running, removing it from the DOM won't do anything.
0

Okay, I've been told a way to do it and it works flawlessly.

Instead of creating scripts, I can create an iframe and pass all the scripts using the attribute srcdoc from the iframe, this would be the structure I want to create from the Angular component and append to the DOM, I should be creating an iframe per script:

  <iframe class="iframe-container" srcdoc='
  <html>
    <head></head>
    <body>
      <script src="https://script-source.com"></script>
    </body>
  </html>'>
</iframe>

So to create and append the scripts from the Angular component, notice that I'm adding the component into an appended children array (I'm aware there are cleaner ways to do this, just to get the idea):

let iframe = this.renderer2.createElement('iframe');
iframe.setAttribute('class', 'iframe-ad');
iframe.setAttribute('srcdoc', `
  <html>
    <head></head>
    <body>
      <script src="https://src-example-url.com"></script>
    </body>
  </html>
`);

this.appendedChildren.push(iframe);
this.renderer2.appendChild(this._document.body.querySelector('div.iframe-holder'), iframe);

In order to delete the iframe, just adding these lines into the ngOnDestroy() makes it:

ngOnDestroy(){
  for(let i = 0; i<this.appendedChildren.length; i++){
    this.renderer2.removeChild(this._document.body, this.appendedChildren[i])
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.