Insert and execute javascript - javascript

I have a javascript variable:
var foo='<script type="text/javascript">alert("Hello World");<\/script>'
The variable is inserted with element.innerHTML=foo; after an event occurs on the page, about 10 seconds after the page is loaded.
Is there a way to execute the 'alert' function right after the insertion?

If you absolutely, positively have to take JavaScript code that's in a string and execute it, you basically have to use eval or an eval-like mechanism. In some years of JavaScript programming, I've never had to resort to it, and I do suggest that you look at whether there's another way to achieve your actual overall goal.
So here, you'd strip off the script tag stuff and just eval the code, e.g.:
var script = foo.replace(/^<script[^>]*>/, "").replace(/<\/script>$/, "");
eval(script);
// Or window.evalInGlobalScope(script); // -- See below
Obviously you have to be sure you trust the source of the string, since you're executing the code therein.
eval is a slippery beast and plays very odd games with context and scope. If you need something that looks more like what you'd get if you did add a script tag to the page, here's a function that does that cross-browser (from my answer to this other question here on Stack Overflow):
window.evalInGlobalScope = (function() {
var fname, scr;
// Get a unique function name
do {
fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
}
while (typeof window[fname] !== 'undefined');
// Create test script
scr = "function " + fname + "() { }";
// Return the first function that works:
return test(evalInGlobalScope_execScript) ||
test(evalInGlobalScope_windowEval) ||
test(evalInGlobalScope_theHardWay) ||
evalInGlobalScope_fail;
function test(f) {
try {
f(scr);
if (typeof window[fname] === 'function') {
return f;
}
}
catch (e) {
return false;
}
finally {
try { delete window[fname]; } catch (e) { window[fname] = undefined; }
}
}
function evalInGlobalScope_execScript(str) {
window.execScript(str);
}
function evalInGlobalScope_windowEval(str) {
window.eval(str);
}
function evalInGlobalScope_theHardWay(str) {
var parent, script, d = document;
parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
if (parent) {
script = d.createElement('script');
script.appendChild(d.createTextNode(str));
parent.appendChild(script);
}
}
function evalInGlobalScope_fail() {
throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
}
})();
Live example using the above

You don't need to make lots of changes, just one small change.
Right now you have such line of code:
oDiv.innerHTML = foo;
Just change it to those three lines instead:
var oScript = document.createElement("script");
oScript.innerHTML = foo;
oDiv.appendChild(oScript);
And have foo contain only the raw JS, without the <script> and </script> tags.
Live text case.

Related

Can I magically make the selectors non-functional if the selection value is empty?

Background:
I have a function that I call like this:
hide_modules('string1','string2');
The function is something like:
function hide_modules(param1,param2) {
MM.getModules()
.withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
}
Most of the time I call the function with values as shown above.
Sometimes I do not want 'string1' to have a value and I'd like the my function to not use that first selector, effectively like this:
MM.getModules()
// .withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
I've tried just calling it with an empty string, 0, false as param1 but the end result class selection is not what I want.
Sometimes I also call it with param2 empty and not wanting to have the param2 related selector used either.
So the question is:
Without writing a big if-then-else statement, is there some fancy way I can make those selectors non-functional (the equivalent of commenting it out like above) when the param1 and/or param2 values are not specified?
The supporting code that my function calls is provided for me in a 3rd party library that I can't change. I include some of the relevant parts here as it may help with the answer:
var withClass = function (className) {
return modulesByClass(className, true);
};
var modulesByClass = function (className, include) {
var searchClasses = className;
if (typeof className === "string") {
searchClasses = className.split(" ");
}
var newModules = modules.filter(function (module) {
var classes = module.data.classes.toLowerCase().split(" ");
for (var c in searchClasses) {
var searchClass = searchClasses[c];
if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
return include;
}
}
return !include;
});
Since js doesn't supports function overloading, the only way is to validate your parameters inside your method. Check for truthy and ternary operator will do the trick
var modules = MM.getModules();
modules = param1 ? modules.withClass(param1) : modules;
modules = param2 ? modules.exceptWithClass(param2) : modules;
modules.enumerate(function(module) {
module.hide(
// some other code
);
});
to skip first parameter
hide_modules(null,'string2');
to skip second parameter
hide_modules('string1');

Javascript concatenate a function similar to how text can be added

In javscript we can do this
var text = "the original text";
text+=";Add this on";
If a library has a function already defined (e.g)
//In the js library
library.somefunction = function() {...};
Is there a way to add something on so that I can have two functions run?
var myfunction = function() {...};
Something like:
library.somefunction += myfunction
So that both myfunction() and the original library.somefunction() are both run?
You can use this kind of code (leave scope empty to use default scope):
var createSequence = function(originalFn, newFn, scope) {
if (!newFn) {
return originalFn;
}
else {
return function() {
var result = originalFn.apply(scope || this, arguments);
newFn.apply(scope || this, arguments);
return result;
};
}
}
Then:
var sequence = createSequence(library.somefunction, myFunction);
I think what you want to create is a Hook (function) - you want to call library.somefunction but add a bit of your own code to run before. If that's the case, you can make your myfunction either call or return the library function after it's done with your bit of code.
var myfunction = function() {
// your code
// ...
return library.somefunction();
}

How to use prototype for custom methods and object manipulation

Honestly, I am trying to understand JavaScript prototypes and I'm not making much progress. I am not exactly sure how to explain what I am trying to do, except to say that in part my end goal is to learn how to traverse the DOM similar to jQuery and to add custom methods to manipulate particular elements being accessed.
EDIT : The code below has been updated to reflect concepts I have learned from the answers received so far, and to show where those fall short of what I am looking to accomplish.
function A(id) {
"use strict";
this.elem = document.getElementById(id);
}
A.prototype.insert = function (text) {
"use strict";
this.elem.innerHTML = text;
};
var $A = function (id) {
"use strict";
return new A(id);
};
var $B = function (id) {
"use strict";
return document.getElementById(id);
};
function init() {
"use strict";
$A('para1').insert('text goes here'); //this works
$A('para1').innerHTML = 'text goes here'; //this does not work
console.log($A('para1')); //returns the object A from which $A was constructed
console.log($B('para1')); //returns the dom element... this is what I want
/*I want to have $A('para1').insert(''); work and $A('para1').innerHTML = '';
work the same way that $B('para1').innerHTML = ''; works and still be able
to add additional properties and methods down the road that will be able
act directly on the DOM element that is contained as $A(id) while also
being able to use the properties and methods already available within
JavaScript*/
}
window.onload = init;
Where possible please add an explanation of why your code works and why you believe it is the best possible method for accomplishing this.
Note: The whole purpose of my inquiry is to learn this on my own... please do not suggest using jQuery, it defeats the purpose.
var $ = function(id) {
return new My_jquery(id);
}
function My_jquery(id) {
this.elem = document.getElementById(id);
}
My_jquery.prototype = {
insert : function(text) { this.elem.innerHtml = text; return this;}
}
$('para1').insert('hello world').insert('chaining works too');
add any method u want to operate on elem in My_jquery.prototype
You can use a scheme like the following:
function $(id) {
return new DOMNode(id);
}
function DOMNode(id) {
this.element = document.getElementById(id);
}
DOMNode.prototype.insert = function(value) {
if (value) {
// If value is a string, assume its markup
if (typeof value == 'string') {
this.element.innerHTML = value;
// Otherwise assume it's an object
} else {
// If it's a DOM object
if (typeof value.nodeName == 'string') {
this.element.appendChild(value);
// If it's a DOMNode object
} else if (this.constructor == DOMNode) {
this.element.appendChild(value.element);
}
}
} // If all fails, do nothing
}
$('id').insert('foo bar');
Some play stuff:
<div id="d0">d0</div>
<div id="d1">d1</div>
<div id="d2">d2</div>
<script>
// insert (replace content with) string, may or may not be HTML
$('d0').insert('<b>foo bar</b>');
// insert DOMNode object
$('d0').insert($('d1'));
// Insert DOM element
$('d0').insert(document.getElementById('d2'));
</script>
You may find it useful to study how MyLibrary works, it has some very good practices and patterns.
Try this.
var getDOM= function(id) {
this.element= document.getElementById(id);
}
getDOM.prototype.insert= function(content) {
this.element.innerHTML= content;
}
var $= function(id) {
return new getDOM(id);
};
$('id').insert('Hello World!'); // can now insert 'Hello World!' into document.getElementById('id')

Set JavaScript variable to check definition later

How can you set a var to something you want to later check if it's defined or not?
Example: To check if jQuery is not defined, you'd do this:
if (typeof(jQuery) === 'undefined') {
}
But what if I want to do something like this (this obviously doesn't work):
var toCheckLater = jQuery; // This fails.
// Some time later..
if (typeof(toCheckLater) === 'undefined') {
}
What I'm trying to do is dynamically load scripts from an array, but I want to set ahead of time the variable whose definition I'll check for later. And I'd like to avoid a big block of ifs or switch statement. Meaning I'm hoping to find a solution a bit more elegant than:
switch (scriptName) {
case 'jQuery':
if (typeof(jQuery) === 'undefined') {
}
break;
case 'someOtherScriptName':
.
.
.
}
Any ideas?
Thanks in advance.
A function would do:
var toCheckLater = function() { return typeof jQuery == "undefined"; }
// later:
toCheckLater()
You might also use a fabric for such functions:
function getChecker(name) {
return function() {
return typeof window[name] == "undefined";
// alternative:
return name in window; // can be undefined, but the variable exists
};
}
var toCheckLater = getChecker("jQuery");
Use
if (typeof jQuery === "undefined")
to check for undefined.
I don't quite get what you're trying to achieve, but I think you could do something like this
var toCheckLater = typeof jQuery; //if, for example, jQuery is defined you'll get "function"
// Some time later..
if (toCheckLater === 'undefined') {
}
Simply do this:
var scriptName = 'jQuery';
if( !window.hasOwnProperty(scriptName) ){
//jQuery is undefined
}
var checker = function(scriptArray) {
for(var i in scriptArray)
this[i] = i?i:loadScript(i); // make your own loadScript function
}
checker({'jquery','anothercode'});
//access checker.jquery / checker.anothercode
You could use something like this. Create a 'class' that load all the scripts.
You have use the typeof Method
typeof(variable_name) will give you "string", "object", "undefined" or "number" depending on the variable
typeof(jQuery) == "undefined"
is the way to go.
Your array of scripts:
var scripts = ['script1', 'jQuery'];
After loading the scripts you can use the same array and loop through it.
for (var i = 0, n = scripts.length; i !== n; i++) {
if (!window.scripts[i]) {
// falsy
}
}
This assumes that the scripts array references a global variable that the script will expose when loaded.
However, if I understand what you're going for, a better method would be to register a callback for when the appropriate script element is loaded. See these questions for some examples: (1), (2)
Code like this is pretty standard:
function loadScriptAsync(src, callback) {
var script = document.createElement('script'),
place = document.getElementsByTagName('script')[0];
script.type = "text/javascript";
script.async = true;
script.src = src;
script.onload = script.onreadystatechange = function() {
callback();
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
place.parentNode.insertBefore(script, place);
}

XSLT+JavaScript: using classes

I'm trying to use classes in XSL (the 'msxsl:script' tag). But I get the 'Syntax error' message when debugging the file. Here's a simple code that I'm using:
function Test1(str)
{
this.str = str;
}
Test1.prototype.getStr = function()
{
return this.str;
}
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}
If I insert the code to a aspx file and call the test function, everything works fine, without any error messages.
Is it possible to use classes in XSL?
It seems that there are some odd restrictions on what you can use at the top level of the script blocks, and that they won't allow the use of this in top-level functions. However, if you go one level deeper, some of these restrictions go away:
function MakeTest1()
{
function inner(s)
{
this.str = s;
}
inner.prototype.getStr = function()
{
return this.str;
}
return inner;
}
var Test1 = MakeTest1();
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}

Categories

Resources