HTML in string with JavaScript code, JS not working - javascript

Here is my test javascript function
<script type="text/javascript">
function test() {
var sHTML = "<script type='text/javascript'> " +
"function showmsg() { " +
"alert('message'); " +
"} " +
"<\/script>" +
"<div>" +
"<a href='#' onclick='javascript:showmsg(); return false;'>click</a>" +
"</div>";
var divTemp = document.createElement("div");
divTemp.innerHTML = sHTML;
var d = document.getElementById("div1");
d.appendChild(divTemp);
}
</script>
When I run this function, the div along with a tag is added in the div1, but when I click on anchor tag, it says showmsg is not defined, which is indicating that browser is NOT parsing the script tag.
How to achieve this without any 3rd party library?
Update:
The possible usage is, I want to allow user to create HTML templates along with JavaScript code, then my JS library will use those HTML templates to render user defined markup, plus allowing user to implement his/her custom logics through JS.

You need to run eval on the script contents when using innerHTML. Try something like:
var scripts = divTemp.getElementsByTagName('script');
for(var i=0; i<scripts.length; i++) {
eval(scripts[i].textContent);
}
Obviously, you need to do this in end, after injecting the innerHTML into the DOM.

Browsers do not run JavaScript code when a <script> tag is dynamically inserted like that.
Instead of that, you can just define the function directly!
function test() {
window.showmsg = function() {
alert("message");
};
var sHTML = "<div>" +
"<a href='#' onclick='javascript:showmsg(); return false;'>click</a>" +
"</div>";
var divTemp = document.createElement("div");
divTemp.innerHTML = sHTML;
var d = document.getElementById("div1");
d.appendChild(divTemp);
}
Libraries like jQuery have code to strip <script> blocks out of text that's being stuffed into some element's innerHTML, and then evaluate it with eval(), so that's one thing to do if the code is somehow "stuck" in a block of content.

Using jquery, is this can help you :
$('<script>function test(){alert("message");};</' + 'script><div>click</div>').appendTo(document.body)
http://jsfiddle.net/TSWsF/

Related

Eval multiple javascript variables not working

I am trying to grab some text content (HTML comments) on the page and convert it into variables. The text content will be of the format:
I have constructed some Javascript that works up to a point, but will not go past the final variable declaration "var shorturl = ..."
Javascript code below:
$(document).ready(function() {
if (document.getElementById("ajax-gallery")) {
var shortcode = '<!-- [var module="gallery"; var id="1"; var type="single"; var data="only";] -->';
shortcode = shortcode.replace("<!-- [", "");
shortcode = shortcode.replace("] -->", "");
eval('shortcode');
var shorturl = "shorturl = " + module + "/shortcode_" + type + ".php?id=" + id + "&data=" + data;
eval('shorturl')
updateGallery(shorturl, "ajax-gallery");
}
});
I would have thought this would work, but apparently not. I know that eval is frowned upon but at present I cannot find a "nicer" method.

Dynamically adding jquery into div

Apologies, I know there are a number of questions along the same lines and they've helped me a lot but I'm still falling at the final hurdle.
I'm trying to dynamically add some jQuery into a div using this:
function displayPage(position,page){
// position arrives looking something like '#pageW20' - ignore quotes
// page arrives looking something like 'pages/benefits.html' - ignore quotes
var pos = position.substring(1); // New variable without the '#' that appears in the first character of position
var myDiv = document.getElementById(pos); // Find the div, typically equates to a div id similar to 'pageW20'
var str = "<script type='text/javascript'>";
/* Build the script which typically looks like this:-
<script type='text/javascript'> $( "#pageB15" ).load( "pages/benefits.html", function(){openLetter()}); </script>
*/
str += '$( ' + '"' + position + '"' +' ).load(' + page + ', function(){openLetter()})';
str += '<';
str += '/script>';
alert(str); // Works to here, alert churns out expected output.
//$('"' + position + '"').append(str); // Tried this, end up with syntax error
myDiv.appendChild(str); // This gives Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
}
The last two lines show the errors I'm getting trying 2 different methods. Any clues.
Thanks appreciate your interest.
Update: Here's what I get in my console at the alert() stage which is what I was hoping for -
<script type='text/javascript'>$( "#pageW20" ).load("pages/work.html", function(){openLetter()})</script>
Update: Now solved, thanks #gaetano. My code now looks like:
function displayPage(position,page){
var pos = position.substring(1);
var myDiv = document.getElementById(pos);
myDiv.innerHTML=""; // Remove existing div content
/* Build the script which typically looks like this:-
<script type='text/javascript'> $( "#pageB15" ).load( "pages/benefits.html", function(){openLetter()}); </script>
*/
var str = '$( ' + '"' + position + '"' +' ).load(' + page + ', function(){openLetter()});';
console.log(str);
var s = document.createElement('script');
s.type = 'text/javascript';
s.text = str;
myDiv.appendChild(s);
}
I cannot understand why you are trying to create and append a script on the fly like described in the comments.
The error you get is:
myDiv.appendChild(str);
But appendChild requires as first parameter a node.
So if you need to continue in this direction you have to create a script node element and after you can append it to the html like in my example:
function displayPage(position, page) {
var pos = position.substring(1); // New variable without the '#' that appears in the first character of position
var myDiv = document.getElementById(pos); // Find the div, typically equates to a div id similar to 'pageW20'
var str = '$( ' + '"' + position + '"' + ' ).load("' + page + '", function(){openLetter()})';
var s = document.createElement('script');
s.type = 'text/javascript';
s.text = str;
myDiv.appendChild(s);
}
displayPage('_XXX', 'page');
console.log(document.getElementById('XXX').outerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="XXX"></div>
The str variable you're passing isn't a Node, it's a String. Try first using:
var line = document.createElement("p");
line.innerHTML = str;
myDiv.appendChild(line);

Getting values outside a HTML form

Inside my content.js I am writting a new HTML page with a pre polulated form, which contains var a and var b. Those 2 variables are created before, inside content.js, so I can easily use them inside my HTML page. Now I want to override those variables a and b as the user finishes editing the form and presses the button Accept. Is there anyway I can achieve this?
This is a part of the code
var a="FName";
var b="LName";
var myWindow = window.open("Accept", "myWindow", "width=450, height=300");
myWindow.document.write(
"<html>"+
"<head>"+
'<script> function closeWindow(){ var x = document.getElementById("firstname").value alert(x); window.close();}'+
"</script>"+
"</head>"+
"<body>"+
"<form>"+
"<div id=leadinformation>"+
"<p id=titleParagraph>You are about to create a new Lead:</p>"+
"First Name....."+ "<input type=text id=firstname value="+a+">" +"<br>"+
"Last Name....."+ "<input type=text id=lastname value="+b+">" +
"</div>"+
"<div>"+
"<button id=Accept onClick=closeWindow() >Accept</button>"+
"<button id=Close onClick=closeWindow() >Close</button>"+
"</div>"+
"</form>"+
"</body>"+
"<html>"
);
myWindow.document.getElementById('Accept').onclick=Accept;
myWindow.document.getElementById('Close').onclick=Close;
function Accept(){
alert(myWindow.document.getElementById('firstname').innerText);
}
function Close() {//do smthing
}
Sorry for bad formating.
Currently the output of the Accept(); is empty at the moment. How can I get first name input result?
What I want to achieve:
1) I am creating a button on a page
2) When I click on the button a new html page pops out (the one that I am hardcode writing it)
3) I pre populate the form with some variables that I created before
4) When Clicking The Accept button on the form the Accept() function is triggered where I would want to use those input values the user has written.
This should help you: Sharing global javascript variable of a page (...).
The question is about "How to share a variable to another page in an iframe", but this works for a new windows as well.
i.e.:
myWindow.document.write(
"<html>" +
"<head>" +
'<script>' +
'function closeWindow(){' +
'var x = document.getElementById("firstname").value;' +
'alert(x);' +
'// do something to parent.a and parent.b here, just because you can:' +
'parent.a = "Oh, would you look at it, it works!";' +
'parent.b = "And it is so pretty too!";' +
'window.close();' +
'}' +
"</script>" +
"</head>" +
" Your body code here, etc " +
"</html>"
);
Also, please note that your code lacks a semicolon (;) after inserting value to var x in your new window's JavaScript code. That will most probably make your code malfunction. The closing </html> tag lacks the slash, but I don't know if that's gonna break anything; you'd better fix that as well, just in case.

How to properly generate HTML in a JavaScript widget?

I've been following this tutorial on how to make JS widget. However I noticed that manually building html with plain JavaScript is not DRY. I am planning to build a form, tables etc. in a JS widget. Whats the best way to do this?
$.getJSON(jsonp_url, function(data) {
var fruits = ["Apples", "Mangoes", "Banana"];
var myHtml = "<ul>";
$(fruits).each(function(i){
myHtml += "<li>" + fruits[i] + "</li>";
});
myHtml += "</ul>";
$('#example-widget-container').html(myHtml);
});
if you want one of your divs or containers to continuously grow while you build dynamic content, without losing older content, use jQuery.append
$('#example-widget-container').append(myHtml);
this is probably the cleanest way. Or you can do other things like
var html = $('#example-widget-container').html();
newHtml = yourContent;
$('#example-widget-container').html(html + newHtml);
In JavaScript you can generate html content in different ways :
Create HTML with a string directly :
$("#sampleArea").append('<div class="' + newClass + '">' + newText + '</div>');
Create HTML with jQuery Api wrapping :
$("#sampleArea").append($('<div/>',{class : newClass}).text(newText));
Use a template engine in Javascript (like mustache.js) :
<script id="exampleTpl" type="x-tmpl-mustache">
<div class="{{class}}">{{text}}</div>
</script>
<script>
var data = {
class: newClass,
text: newText
}
var template = $('#exampleTpl').html();
var html = Mustache.render(template, data);
$('#sampleArea').append(html);
</script>
The best solution will depends of your use.

Generating a string of jQuery for Ajax uploading

My page generates a jQuery string (the jqueryBlock below) that gets ajaxed up to a php file that writes it into a new html file, where it will execute. The code "A" below is what I have now to generate the final jQuery, "B" below in the new html file.
"A"
var targetName = "redbox";
target = $('div[filename=' + targetName + ']').hide()[0];
var jqueryBlock= '<script>$(function() {\n';
jqueryBlock += "$('#" + this.id + "').click(function() {\n";
jqueryBlock += "$('#" + target.id + "').show();\n";
jqueryBlock += "}).css('cursor', 'pointer');\n";
jqueryBlock += "$('#" + target.id + "').dblclick(function(){\n$(this).hide();\n});\n";
jqueryBlock += "})<\/script>";
"B"
<script>$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
})
.css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
})</script>
This all works, but it's a nightmare to write block A, trying to keep track of the multiple levels of quotes and all the parens and braces and not being able to break lines to make them more readable. I'm thinking that there must be a way to do this where I can write something that looks more like the finished jQuery for "A". Can anyone suggest a better method?
Thanks.
Ok, well... I came up with some ideas... you may like some, all, or none of it. But I figured I'd paste it here. Just a couple of techniques. You can view the JsFiddle as well.
The first, make a function for creating the jQuery selector. This way you can just pass the id, and get your selector, no quotes to worry about.
function makeJqIdSelector(id) {
return "$('#" + id + "')";
}
The same way of thinking, you could write functions to wrap something in <script> tags (or even a function.
function wrapScriptTags(scr) {
return "<script>\n" + scr + "\n<\/script>";
}
Finally, you can use an array to join the elements so you don't have to keep typing out \ns. ie:
var arr = [];
arr.push("a",
"b",
"c"
);
var str = arr.join("\n");
//output:
//a
//b
//c
This has the added effect of being more efficient as well. (probably not an issue for modern browsers, and especially not for this few strings)
Here it is all together:
var thisSelect = makeJqIdSelector(this.id);
var targetSelect = makeJqIdSelector(target.attr('id'));
var jblock = [];
jblock.push(
"$(function() {",
thisSelect + ".click(function() {",
targetSelect + ".show();",
"}).css('cursor', 'pointer');",
targetSelect + ".dblclick(function(){\n$(this).hide();",
"});",
"});"
);
var jqueryBlock = wrapScriptTags(jblock.join("\n"));
output
<script>
$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
}).css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
});
</script>
Note: Obviously, I did not spend a lot of time making sure the output was perfect. It was just for the technique - I have no real way of testing it.
If I understanded everything, you could ajax up only the dynamic variables to the PHP file, and change it to something like this:
<script>$(function() {
$('#<?php echo $_GET['id']; ?>').click(function() {
$('#<?php echo $_GET['id']; ?>').show();
})
.css('cursor', 'pointer');
$('#<?php echo $_GET['id']; ?>').dblclick(function(){
$(this).hide();
});
})</script>
In coffeescript you can use a text block that keeps track of the indention level for you. Maybe you can change to coffeescript just for this script.
http://coffeescript.org/#strings

Categories