This is my first post.
I'm trying to do some basic meta-programming with javascript, and I was wondering if there is a way of get the id of a particular object and with that id, access to the variable name, or get simply the variable name of a particular object. I wanna recreate a situation in which you first create every single html in a web page, and append to some of the html tags events associated to a particular class -example class Person-. for example: Supposed the next code:
var someFunction = function(someText){alert(someText);}
function SomeClassFunction(){
this.aClassFunction = someFunction;
}
var aVariableName = new SomeClassFunction();
and in the HTML code suppose I have the next piece of code.
<html>
<head>
<title></title>
</head>
<body>
<div onclick="aVariableName.aClassFunction('Some text to show in alert');">
</div>
</body>
</html>
Then, as you may notice the onclick event uses the aVariableName I created before, but because I first create the name of the variable and then append the name in the code cause I knew aVariableName was the name of that object. What I wanna do or implement is to create the text above in html without know the variable name of an specific object. I have surfed on the net but, unfortunately I haven't found anything about it.
i dont know how to get the name of a variable from the code its self without doing a whole load of work parsing stuff, which will get messy, and i'd shoot someone for this.
var someValue;
var foo = function() { someValue; }
alert((foo + '')); // this is now a string, use substr to extract variable name
You know you can set events like this in javascript someElement.onclick = someFunction so you dont really need to know the name of the variable if all you're doing is setting an event handler.
In general, no — you can't get the name of a particular variable or its "id" either.
If you really want to, it may be possible to do Bad Things with exceptions and stack traces to get that information… But I don't know off the top of my head how to do that.
Edit: I assume that, by “variable ID”, you mean “a unique identifier for the object referenced by that variable”, like Python's id builtin:
>>> x = {}
>>> y = z = {}
>>> (id(x), id(y), id(z))
(123, 567, 567)
I'm not 100% sure that I understand your question correctly in regards to meta-programming, but typically you would attach an event handler to the click event of the DOM element, then you can examine properties of the element within the handler.
There are a couple things in JavaScript that facilitate meta-programming: eval will let you interpret arbitrary code, so you can build a string of code and eval it. The security concerns are numerous. You can also access properties of an object by index or by name, e.g.
aVariableName.aClassFunction
is the same as
aVariableName["aClassFunction"]
Hope that helps.
Related
I would like to use a query string parameter so that way I can specify the name of a DOM element.
I have some code that requires the height of the header and I would like that code to work for any theme. Only at times the header uses the <header> tag, at times it has a specific identifier, at times it is a specific class... to be able to reuse that code over and over again, I'd like to include it in a way such as:
<script src="https://www.example.com/js/my-script.js?c=header"></script>
What I want to be able to do is get the "?c=header" part from that JavaScript URL to send search a DOM object with jQuery(".header"). Do we have a way to know the URL of the JavaScript itself from the JavaScript being executed?
Obviously, I know of window.location.href and that's not the URL I'm looking for.
As mentioned by #Kaiido in a comment, there is the document.currentScript parameter that gives you access to the <script> tag which is currently running. Only there is a small trick to it, that parameter is defined on the first pass, not when executing functions within your script.
So what one can do is save that information, or at least what you need from that object, in the global scope or a static in your object.
In my case, I just did the following:
// Script to tweak things on many websites
var this_script_url = document.currentScript.src;
jQuery(document).ready(function()
{
// at this point: "document.currentScript === null"
var qs = this_script_url.split("?", 2);
if(qs && 2 == qs.length)
{
... // handle qs[1] which is the query string (a=1&b=3&...)
}
});
Please make sure you don't use a global name that's too generic. It should include the name of your script or abbreviation thereof. Otherwise you are likely to clash with another script's global.
Now if you have a prototype object, I would suggest you use a static member instead of a global.
var my_class = {};
my_class.script_url = document.currentScript.src;
// and later you can reference it directly as in:
url = my_class.script_url;
This way you are more likely to avoid clashing problems (the only thing that needs to be changing in case of a clash is the name my_class).
At this point, the ES5 or ES6 class keyword does not offer you to create variables.
At the top of my JavaScript document, which is linked to an HTML page, I declared:
var pizzaVar;
Then, I have a function later in the code that sets the variable's value and then calls another function:
function makePizza()
{
pizzaVar = document.getElementById("pizzaDiv").innerHTML;
givePizzaToppings();
}
But when I tried to use pizzaVar in the next function to set the innerHTML of pizzaDiv, nothing happened:
function givePizzaToppings()
{
var toppings = "<p>Onions and Bacon</p>";
pizzaVar = toppings;
}
However, if I changed the last line to
document.getElementById("pizzaDiv").innerHTML = toppings;
it worked. I don't want to have to put that in everytime I want to change pizzaDiv though, is there a way to fix this.
PS: I tried saying
var pizzaVar= document.getElementById("pizzaDiv").innerHTML;
outside of the functions but I got an error message saying:
TypeError: null is not an object(evaluating 'document.getElementById("pizzaDiv").innerHTML')
Your pizzaVar will point to a string value, which will be the HTML at the time of the assignment. It doesn't magically setup a link to change it.
If you wanted to use this global variable, you'd be better off pointing it to the div element and then using innerHTML every time you wanted to change its value.
Then you should research to understand why innerHTML is rarely the best tool to modify the DOM.
Unfortunately, whenever you want to change the .innerHtml of your pizza div, you're going to have to write document.getElementById("pizzaDiv").innerHTML on the left side of an equals sign. pizzaVar is not a pointer, and doesn't point to the .innerHtml of the div.
The error you got is telling you that document.getElementById("pizzaDiv") returned null and hence has no properties at all, much less an .innerHtml property. This is because it did not exist at the time of the .getElementById call.
Yo!
I have an arbitrary javascript file, let's call it localScript, and just say it looks something like this:
<script id="myScript" type="text/javascript">
function () {
var blue = 'blue';
var person = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"brown"
};
var bluePerson = function () {
person[color] = blue;
};
}
</script>
I want to be able to use another externalScript to dynamically change the contents of this localScript. For this simple example, let's just say I want to update some of the values in localScript, like—maybe change age of the person object to 75. (Obviously, there's very simple ways to do this, but for my use case it's imperative that I use another externalScript to generate the contents of this localScript).
It would be easy if there was something like .innerHtml which I could use in the externalScript which would allow me to select an element and then replace the 'innerHtml' contents. The localScript, though, obviously isn't composed of elements.
As far as I know, when using a script to modify another script, there aren't any 'easy' ways to reference variables/objects/items in the script.
Things I've considered are indexOf(), search(), and match(), which I could use in externalScript to find strings inside localScript and then replace the values. I feel though as these could be performance no-no's, especially if the script grows.
Are there any easy ways to do this—with an emphasis on performance? I feel like there must be some easy way to reference one of the items in the script, though, I suppose a script is all one large string.. and maybe there is no simple way.
BTW—I'm using AngularJS, if there are any built in methods—though I think this is mostly just a javascript thing.
Thanks a bunch!
It looks like a bad idea, but... well, if it is imperative...
It makes no sense to change a script in a <script> tag - if it is in DOM, it has already executed (and no longer matters). Thus, to change the script before it has a chance to execute, you need to load it using AJAX, change the text, then eval it.
You can easily change the variables. Refer following steps
Include external script just below the script you have written.
Access the variables in the external script as if they are locally declared.
The variables you have created in above script are available in global scope and hence should be accessible from everywhere.
Note: This answer was added before the function clause was added.
So I have a situation where I am trying out some DI based approached in JS, now lets not discuss the worth or validity of DI in JS etc let us just focus on the question.
So I get a targetConstructor, which would be something like:
function SomeClass(){};
doSomethingWithTargetConstructor(SomeClass);
So the above would pass the constructor of SomeClass into the method and that all works fine, however there is a test case which I cannot find a way to solve, as the targetConstructor will be a named function so you can extract the name from it. However the below situation does not work:
var someRootNamespace = {};
someRootNamespace.someSubNamespace = {};
someRootNamespace.someSubNamespace.someNamespacedClass = function(someArg){};
doSomethingWithTargetConstructor(someRootNamespace.someSubNamespace.someNamespacedClass);
So in the above example you cannot extract the name of the target constructor as it is a nameless function, HOWEVER in the debugger (as seen below) you can see that the targetConstructor prototype does contain the name information needed.
As basically I want the string representation of someRootNamespace.someSubNamespace.someNamespacedClass
However I cannot for the life of me find a way to get at the information shown in the debugger, so is it even possible to get at? and if so how do you go about it? as the information is there, I just need a way to get access to it.
I have an HTML document (here), which creates an iframe-based media player for a collection of songs within albums (I just used letters to define these albums and songs in the mymusic array, for simplicity).
Focusing on the top 3 iframes, the way I have set out the user interaction is to generate the HTML for forms of available albums and songs using Javascript, and write them to the iframes in the body. If you run it and make a selection in the Albums menu, you will see that the options in the Songs menu correspond with the mymusic array, so this works.
However, when I choose a song, the function nowplaying(trackindex,albumindex) should be called using an onchange event in the Songs form, the same way as in the form generated using showinitial() ... but the function does not get called.
I have ruled out the coding of nowplaying itself as a cause, because even when I change nowplaying to alert("hello"), it does not get called. So this leads me to think the problem is with the onchange attribute in "anything", but I can't see the problem. The way I coded it is no different to before, and that worked fine, so why won't this work?
Any help would be much appreciated!
Firebug is your friend....
i is not defined
function
onchange(event) {
parent.nowplaying(this.SelectedIndex,
i); }(change )
onchange is getting called, but i is not defined when calling nowplaying.
This is the result of this line:
p+="<html><head></head><body><form><select onchange='parent.nowplaying(this.SelectedIndex,i);' size='";
which is using "i" in the string, when it should append it as a variable:
p+="<html><head></head><body><form><select onchange='parent.nowplaying(this.SelectedIndex," + i + ");' size='";
To clarify, i is defined when anything(i) is called, but you aren't writing i into the code, just the letter "i". When nowplaying(this.SelectedIndex,i) is called, i is no longer defined, because you aren't inside of the anything() function anymore. You need to expand i when you append the html to p, so that the value is there and not the variable i.
function anything(i){
p+="...<select onchange='parent.nowplaying(this.SelectedIndex,i);'...";
Your onchange event handler is set from a string. When run, it will not have access to i, which is a local variable from the anything function that has long since gone away.
The simple fix would be:
p+="...<select onchange='parent.nowplaying(this.SelectedIndex,'+i+');'...";
which turns the current value of i at string-making time into an integer literal inside the string.
However, it's not generally a good idea to be creating code from strings. It's normally better to write the event handler as a normal function object:
// You will need the below workaround to get the iframe document in IE too
//
var iframe= document.getElementById('songs');
var idoc= 'contentDocument' in iframe? iframe.contentDocument : iframe.contentWindow.document;
idoc.open();
idoc.write(s);
idoc.close();
idoc.getElementsByTagName('select')[0].onchange= function() {
// This is a closure. The 'i' variable from the parent 'anything' function is
// still visible in here
//
parent.nowplaying(this.selectedIndex, i);
};
However you would generally want to avoid setting handlers from one frame on a different one. I'm not really sure what the iframes are gaining you here other than headaches. Why not just simply use positioned divs with overflow? You can still rewrite their content through innerHTML if you need to... though I would prefer to populate them using DOM methods, to avoid all the HTML-injection problems your current script has.