Dynamically adding script element to a div does not execute the script - javascript

I am trying to add a script block dynamically to the document. When I do this, the script block is not getting executed.
<body>
<div id="dynamicDiv">
</div>
<script type="text/javascript">
var elem = document.getElementById("dynamicDiv");
var tmpStr = "<script type=\"text\/javascript\"> ";
tmpStr += "function hello (val)";
tmpStr += "{";
tmpStr += "alert('hello ' + val);";
tmpStr += "}";
tmpStr += "<\/script>";
elem.innerHTML = tmpStr;
hello("World");
</script>
</body>
The above code does not work. From another post (How do you execute a dynamically loaded JavaScript block?), I saw a reply that if script is added to innerHTML, it will not be executed. Instead of directly using innerHTML, create a div with this innerHTML and use appendChild to add the script.
<body>
<div id="dynamicDiv">
</div>
<script type="text/javascript">
var elem = document.getElementById("dynamicDiv");
var tmpStr = "<script type=\"text\/javascript\"> ";
tmpStr += "function hello (val)";
tmpStr += "{";
tmpStr += "alert('hello ' + val);";
tmpStr += "}";
tmpStr += "<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = tmpStr;
elem.appendChild(newdiv);
hello("World");
</script>
</body>
How ever, this solution also did not work for me.
In another reply, I again saw that we should get the script elements and execute them using eval.
<body>
<div id="dynamicDiv">
</div>
<script type="text/javascript">
var elem = document.getElementById("dynamicDiv");
var tmpStr = "<script type=\"text\/javascript\"> ";
tmpStr += "function hello (val)";
tmpStr += "{";
tmpStr += "alert('hello ' + val);";
tmpStr += "}";
tmpStr += "<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = tmpStr;
elem.appendChild(newdiv);
var scripts = newdiv.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
hello("World");
</script>
</body>
This solution works for me.
But if do this in a function then it does not work.
<body>
<div id="dynamicDiv">
</div>
<script type="text/javascript">
function createFunction(){
var elem = document.getElementById("dynamicDiv");
var tmpStr = "<script type=\"text\/javascript\"> ";
tmpStr += "function hello (val)";
tmpStr += "{";
tmpStr += "alert('hello ' + val);";
tmpStr += "}";
tmpStr += "<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = tmpStr;
elem.appendChild(newdiv);
var scripts = newdiv.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
hello("World 1");
}
createFunction();
hello("World 2");
</script>
</body>
I can see that the function is available after the script is evaled. and is available in the function createFunction. Outside createFunction() scope, hello() is not available.
What am I doing wrong? Am I missing something very basic? Please check and help.
Thanks,
Paul
P.S. I don't use jQuery.
I am using chrome to test this.

Would like to point out that the reason the 3rd snippet you provided works inside the for loop, but not outside is because you are using eval. eval takes a string and executes it as js, which is why it is working inside the loop, but using eval isn't parsing it for future use, which is causing it to be unusable elsewhere. Therefore, when you go to call it outside the loop, you get a reference error.
UPDATE:
If you are getting the string back with the <script> tags in it, you can just parse out the script tags.
var string = "<script type=\"text\/javascript\"> ";
string += "function hello (val)";
string += "{";
string += "alert('hello ' + val);";
string += "}";
string += "<\/script>";
string = string.replace(/<(script|\/script).*?>/g,'');
function createFunction() {
var elem = document.getElementById("dynamicDiv");
var script = document.createElement('script');
script.innerHTML = string;
elem.appendChild(script);
hello("World 1");
}
createFunction()
hello('world 2');
JSFiddle: http://jsfiddle.net/3wYD6/
I don't really see the point of this, but if you really want to do this you can create a new script element and then set it's innerHTML to the function, then append the new script to a div.
var elem = document.getElementById("dynamicDiv"),
script = document.createElement('script');
script.innerHTML =
'function hello (val) {' +
'alert("hello " + val);' +
'}';
elem.appendChild(script);
hello('world');

In your first try you are creating a string and js interpreter handle it as a string, not an html tag, so js doesn't really care about your script tags presented in that string.
Then of course it's working when you start using eval() because eval - is evil:))
After all you can create script tags dynamically and then fill it with code:
var elem = document.getElementById("dynamicDiv"),
scriptTag = document.createElement('script'),
scriptTagCode = 'function hello (val){alert("hello " + val);}';
scriptTag.innerHTML = scriptTagCode;
elem.appendChild(scriptTag);
hello('foo');

Related

Print text on HTML from JavaScript

I have this for loop
<script>
...
for(i = 0;i < json.length;i++){
document.getElementById("pText").innerHTML = json[i].name;
document.getElementById("pLink").setAttribute("href",json[i].html_url);
}
</script>
I want to print a paragraph with a href on each loop, so i did this:
</script>
<a id="pLink">
<p id="pText">
</p>
</a>
It works but the thing is this only prints the last loop.
So i tried this inside the script
document.write("<a href=\"" + json[i].html_url + "\">");
document.write("<p>" + json[i].name + "</p>");
document.write("</a>");
instead of this:
document.getElementById("pText").innerHTML = json[i].name;
document.getElementById("pLink").setAttribute("href",json[i].html_url);
And it prints everything i want but it replaces the whole page.
How can i do this? Do i need to create an id for every loop? Like "pText1, pText2, etc.
Create a container element for that loop, and add the html as you had in mind
<div id="container"></div>
Then in javascript
var container = document.getElementById('container');
var my_html = '';
for(var i = 0;i < json.length;i++){
my_html += '<a href="' + json[i].html_url + '\">';
my_html += '<p>'+ json[i].name + '</p>'
my_html += '</a>'
}
container.innerHTML = my_html;
What we are doing here is adding the content to a string as many times as needed and then add it to the container so it already has all the loops
document.getElementById("pText").innerHTML = json[i].name;
document.getElementById("pLink").setAttribute("href",json[i].html_url);
If you want to use your this code, you have to write "+=" instead of the "=".
var json = [
{"name":"Name 1", "html_url": "http://www.example.com"},
{"name":"Name 2", "html_url": "http://www.example.com"},
{"name":"Name 3", "html_url": "http://www.example.com"}
];
for(var i = 0; i < json.length; i++){
document.getElementById("pText").innerHTML += json[i].name + "<br>";
document.getElementById("pLink").setAttribute("href",json[i].html_url);
}
<a id="pLink">
<p id="pText">
</p>
</a>
I will do it in the following way:
let json = [{'name':'Google','html_url':'https://www.google.com/'}, {'name':'Facebook','html_url':'https://www.facebook.com/'}, {'name':'Twitter','html_url':'https://twitter.com/?lang=en'}];
let item = document.querySelector(".pLink")
for(let j = 1; j<json.length; j++){
let cln = item.cloneNode(true);
document.body.appendChild(cln);
}
let aTag = document.querySelectorAll('a.pLink');
aTag.forEach(function(item, i){
let a = item.setAttribute("href",json[i].html_url);
let p = item.querySelector('.pText');
p.innerHTML = json[i].name;
})
<a class="pLink">
<p class="pText">
</p>
</a>

Looping inside a string in JavaScript

How does a loop work in a string like this?
var w = window.open('','','width=792,height=612');
$(w.document.body).html('<div>'+
'<ul>' +
for(var i=o; i<=10; i++){
'<li>'+ i +'</li>'+
}
'</ul>'+
'</div>');
I highly suggest you create your string before inserting it into your table.
$(document).ready(function(){
var w = window.open('','','width=792,height=612');
var myString = "";
for(var i=0; i<=10; i++){
myString += "<tr><td>hello</td></tr>";
}
$('body').html('<table>' + myString + '</table>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
</body>
I also corrected a lot of your code since there was a few error, ex: var i = o instead of i = 0.

Why doesn't my for loop execute?

When i use document.write it works, but it doesn't work with getElementById.
The same for while.
`
<div id="mydiv"></div>
<script>
var i = 0;
for (i=0; i<=10; i++){
//while (i<=10){
document.getElementById("mydiv").innerHTML = i + "<br>";
//i++;
}
</script>
Output is just 10, but I want to list 0-10 line by line. How to fix?
Each time your loop ran, it overwrite innerHTML for the div.
This implementation starts with an empty string for html, then uses += to concatenate the counter and <br> on each iteration.
var i = 0;
var html = '';
for (i=0; i<=10; i++){
html += i + '<br>';
}
document.getElementById("mydiv").innerHTML = html;
You are over-writing or replacing the contents. You need to append, so you can use += operator instead of =.
<div id="mydiv"></div>
<script>
var i = 0;
for (i=0; i<=10; i++){
document.getElementById("mydiv").innerHTML += i + "<br>";
}
</script>
You're overwriting. Append instead.
for (var i = 0; i <= 10; i++) {
var div = document.getElementById("mydiv");
div.innerHTML = div.innerHTML + "<br/>" + i;
}
<div id="mydiv"></div>
While other answers are true, I think it's a risky practice because your browser might try to execute the code before having loaded all html elements. (For example if your div is after the code..)
So I propose this:
<div id="mydiv">
<script>
for (var i=0; i<=10; i++){
document.write ( i + "<br />");
}
</script>
</div>
N.B: However, keep in mind you cannot use "document.write" after the page finished loading.
You can also do that to be safe:
<div id="mydiv"></div>
<script>
document.onload = function(){
temp=""
for (var i=0; i<=10; i++){
temp += i + "<br />";
}
document.getElementById("mydiv").innerHTML = temp;
}
</script>

document.getElementById.innerHTML does not write anything ..?

My Problem:
document.getElementById("values").innerHTML does not write anything. If I try to do document.getElementById("values").innerHTML = "stuff"; (just with a String) - nothing happens.
What am I doing wrong here?
HTML:
<form onsubmit="save_entry();return false;">
<label for="i_km">Kilometer: <input type="text" name="km" id="i_km"></label><br>
<label for="i_fuel">Sprit: <input type="text" name="fuel" id="i_fuel"></label><br>
<input type="submit" value="Save" />
</form>
<div id="values"></div>
JavaScript:
function save_entry() {
var anzahl = localStorage.length/2;
var nameKeyKm = "k" + anzahl;
localStorage.setItem(nameKeyKm,document.forms[0]["km"].value);
var nameKeyF = "F" + anzahl;
localStorage.setItem(nameKeyF,document.forms[0]["fuel"].value);
document.write("Entry saved!")
}
function show_entry() {
document.getElementById("values").innerHTML = "<table><th>Kilometers</th><th>Tanked</th>";
for (var i = 0; i < localStorage.length/2; i++) {
alert("d");
var temp_km = "k"+i;
var temp_f = "F"+i;
document.getElementById("values").innerHTML = "<tr>";
document.getElementById("values").innerHTML = "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML = "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML = "</tr>";
}
document.getElementById("values").innerHTML = "</table>";
}
show_entry();
This does work!
function show_entry(){
var content = '';
content = content + '<table><th>Kilometer</th><th>Getankt</th>';
for(var i = 0; i < localStorage.length/2; i++)
{
var temp_km = "k"+i;
var temp_f = "F"+i;
content = content + "<tr>";
content = content + "<td>"+localStorage.getItem(temp_km)+"</td>";
content = content + "<td>"+localStorage.getItem(temp_f)+"</td>";
content = content + "</tr>";
}
content = content + "</table>";
document.getElementById("values").innerHTML = content;
}
innherHTML is an attribute, so everytime you write document.getElementById('id').innerHTML = '...' you are actually changing the value of innerHTML to that thing, not concatenating it.
So writing document.getElementById("values").innerHTML = "<table><th>Kilometers</th><th>Tanked</th>"' changes the value of innerHTML to "<table><th>Kilometers</th><th>Tanked</th>"', and, afterwards, you replaced this value for <tr>, then for <td>...</td> and so on...
You clearly want to create a table. Therefore, you should be concatenating the strings, using +=, like this:
function show_entry() {
document
.getElementById("values")
.innerHTML = "<table><th>Kilometers</th><th>Tanked</th>";
for(var i = 0; i < localStorage.length/2; i++)
{
var temp_km = "k"+i;
var temp_f = "F"+i;
document.getElementById("values").innerHTML += "<tr>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML += "</tr>";
}
document.getElementById("values").innerHTML += "</table>";
}
show_entry();
Each time you do
document.getElementById("values").innerHTML = "...";
you will replace the html inside the div with ID 'values'
So calling it multiple times with different values doesn't make sense.
You would either call it once and setting the whole innerHTML at once, like this
document.getElementById("values").innerHTML = "<tr><td>....etc...</td></tr>";
If you would call innerHTML sequentially you would do it as follows (which is just how to append any string in javascript), but in the comments below I just learned this should not be done like this:
document.getElementById("values").innerHTML += "<tr>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML += "</tr>";

Drawing cycle by using js oop and svg

I am getting out of focus when I am practicing the oop and I don't know how to continue.
I have two code and I need to unite the both code.
I need to initialize the variable of svg by using the method of oop.
Need help.
Thanks.
link svg:
function ArrayMaker(svgcx, svgcy ,svgr ,svgstroke ,svgstroke_width ,svgfill ) {
this.svgcx = 100;
this.svgcy = 50;
this.svgr = 40;
this.svgstroke = "red";
this.svgstroke_width = 3;
this.svgfill = "yellow";
this.theArray = [ this, svgcx ,svgcy ,svgr ,svgstroke ,svgstroke_width ,svgfill ];
}
ArrayMaker.prototype = {
someMethod: function () {
alert( 'someMethod called');
},
getArray: function () {
return this.theArray;
}
};
var am = new ArrayMaker( 'one', 'two' );
var other = new ArrayMaker( 'first', 'second' );
alert(am.getArray());
this code is work:
var cx=100;
var cy=50;
var r=40;
var stroke="red";
var stroke_width=3;
var fill="yellow";
var htm = "<html>";
htm += "<head>";
htm += "<title>test3</title>";
htm += "</head>";
htm += "<body>";
htm += "<svg ";
htm += " version=";
htm += "\"1.1\"";
htm += ">";
htm += "<circle ";
htm += "cx="+cx+" ";
htm += "cy="+cy+" ";
htm += "r="+r+" ";
htm += "stroke="+stroke+" ";
htm += "stroke-width="+stroke_width+" ";
htm += "fill="+fill+" ";
htm += "/>";
htm += "</body>";
htm += "</html>";
document.write(htm);
To create SVG elements with JS you need to use createElementNS() and create elements with the SVG namespace (http://www.w3.org/1999/xhtml). For example, see this demo on my site: http://phrogz.net/SVG/svg_in_xhtml5.xhtml
var svgNS = "http://www.w3.org/1999/xhtml";
function createOn( root, name, attrs ){
var el = document.createElementNS(svgNS,name);
for (var attr in attrs){
if (attrs.hasOwnProperty(attr)) el.setAttribute(attr,attrs[attr]);
}
return root.appendChild(el);
}
var svg = createOn( document.body, 'svg', {viewBox:'-100 -100 200 200'} );
createOn( svg, 'circle', { cx:-60, cy:-50, r:20, fill:'#000' });
Note that SVG attributes are not in any namespace, so you can use setAttribute() (as I did above) or setAttributeNS(null,...). However, this is not true for attributes specified outside of SVG, like XLink's href. For such you need to create the attributes with the correct namespace.
You should move away from w3schools and document.write. They both represent old ways of doing things.
Phrogz answered before me, but I'll post a link to a jsFiddle you can play with anyway.
http://jsfiddle.net/ctrlfrk/nnjsw/
The code in that link will show you how to properly create a 'circle' object, and how to add a method to the prototype (in this case to move the circles)

Categories

Resources