3

I have a situation where I need to import external content into a dom element, then take that input and inject it into a different dom element. However, it must be done without any library.

The content can be a mix of script tags, a tags, iframes etc...

In the following example I'm saving the external content into the text area element, then use the append method of jQuery and saves it into the container, which results in the execution of the script and the addition of the anchor element to the container div.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
  <textarea style="display:none" id ="thirdParty">
    <a href="http://www.google.com">
      test 
    </a>
    <script>
      alert("3rd party content");

    </script>
  </textarea>

  <div id="container">

  </div>

  <button onclick="inject()">
    Test
  </button>

  <script>
    function inject() {
      $('#container').append(document.getElementById('thirdParty').value);
    }
  </script>

</body>

Is there anyway to recieve the same result without the usage of jQuery?

1
  • I've updated the answer. It's now fully functional and doesn't rely on eval(). This is the correct way to solve this issue. Commented Nov 17, 2016 at 16:41

3 Answers 3

3

Yes, using innerHTML :

document.getElementById('container').innerHTML += document.getElementById('thirdParty').value

Hope this helps.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
  <textarea style="display:none" id ="thirdParty">
    <a href="http://www.google.com">
      test 
    </a>
    <script>
      alert("3rd party content");
    </script>
  </textarea>

  <div id="container">

  </div>

  <button onclick="inject()">
    Test
  </button>

  <script>
    function inject() {
      document.getElementById('container').innerHTML += document.getElementById('thirdParty').value;

      var elements = document.getElementById('container').getElementsByTagName('script')
      for (var i = 0; i < elements.length; i++){
        eval(elements[i].innerHTML);
      }
    }
  </script>
</body>

Sign up to request clarification or add additional context in comments.

7 Comments

I've already tried that, but unfortunately the script (in this example the alert message) doesn't get executed as happens with jQuery, which is something I need.
Well, if you insert javascript code with innerHTML it will not be executed automatically unless you use jQuery or mootools. So you will have to eval it yourself manually, according to the linked answer.
@RobertoLinares Not true, see my answer.
@ScottMarcus I tried your response on the StackOverflow's default demo and on jsfiddle but the alert doesn't show.
eval should not be used in any production circumstance.
|
3

The JS runtime won't run the script by simply copying the script from the hidden placeholder because the runtime has already finished parsing the code. The script must be injected as a NEW <script> element for it to be processed.

Also, relying on eval() is widely known to be a dangerous practice and is to be avoided at all costs.

This code does exactly what you are seeking:

var btn = document.getElementById("btnGo");
btn.addEventListener("click", inject);
var output = document.getElementById("container");

function inject() {
  
      // It's important to extract the contents of a textarea without parsing
      // so use ".textContent", instead of ".innerHTML". Otherwise, you'll
      // get the "<" and ">" characters as "&lt;" and "&gt;"
      var newContent = document.getElementById("thirdParty").textContent;
  
      // We'll need to separate the <script> from the non-script content ***
      var start = newContent.indexOf("<script>") + 8;
      var end = newContent.indexOf("<\/script>");
      var scriptCode = newContent.substring(start, end);
      console.log("Script code is: " + scriptCode);
  
      var nonScriptCode = newContent.replace(scriptCode, "").replace("<script>","").replace("<\/script>","");
      console.log("Non-script code is: " + nonScriptCode);

      // *******************************************************************
  
      // In order for the script to execute properly, it must be injected into
      // the DOM as a NEW script, not simply moved from one location to the other.
      var scriptNode = document.createElement("script");

      // And here, we also don't want the content to be parsed as HTML 
      // (in case there are < symbols in the script) so we use ".textContent" again.
      scriptNode.textContent = scriptCode;
  
      // Then we can inject that script into the DOM
       output.appendChild(scriptNode);
  
      // Now, when injecting the content into another element, it's important
      // that the contents do get parsed, so here we use ".innerHTML"
      output.innerHTML= nonScriptCode;
}
<textarea style="display:none" id ="thirdParty">
    <a href="http://www.google.com">
        test 
    </a>
    <script>
        alert("3rd party content");

    </script>
</textarea>

<div id="container">

</div>

<button id="btnGo">
    Test
</button>

2 Comments

@Liam That's just because of the Stack Overflow snippet environment. You can see the link appear and clicking it will "attempt" to navigate you, but again the SO snippet environment is blocking the actual navigation.
@Liam I've updated the answer. It's now fully functional and doesn't rely on eval(). This is the correct way to solve this issue.
-1

Replace your inject to:

function inject() {
    document.getElementById('container').innerHTML += document.getElementById('thirdParty').value;
}

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.