Assigned property appears as undefined - javascript

I am doing ajax. At a certain point, I assign someproperty to a DOM object selected by id (suppose it is 12345), and I confirm that the value has been assigned by using alert():
window.document.getElementById('12345').someproperty = true;
alert(window.document.getElementById('12345').someproperty);
At this point, the alert correctly shows true. Then, at some point later, I invoke a javascript command that looks up the value of someproperty for the object:
alert(window.document.getElementById('12345').someproperty);
and this time, it shows undefined. Why is the value not defined?

I have a feeling that you're doing some nasty .innerHTML somewhere between your to lookups of .someproperty.
Assigning to .innerHTML destroys the current DOM, and replaces it with a new DOM that is obtained by parsing the HTML string you provided. So I'm guessing you're destroying an entire section, and replacing it with a nearly identical new section. This naturally wipes out the stateful information in the original DOM.
You should modify the individual DOM elements that need updating instead of wiping them out entirely using .innerHTML.

Related

Why can't I use element.remove() on an element created with createElement() if I do something in between in the DOM? [duplicate]

When creating elements via code, I have encountered an issue where modifying the innerHTML property of an element breaks any references to other elements that are injected into the modified element prior to the modification.
I have a test case here: http://jsfiddle.net/mJ7bF/1/ in which I would expect the link1 reference to behave exactly as link2 does.
This second test case is the same code, but instead of using the innerHTML property to add the <br> tag, I create the line break with an object. This test behaves as expected: http://jsfiddle.net/K4c9a/2/
My question is not regarding this specific code, but the concept behind it: what happens to the link1 reference in that first test case? If it doesn't refer to the HTML/DOM node that is visible when the cont node is injected into the document, what DOES it refer to, and how does this fit in with the ByReference nature of javascript objects?
few things here.
first of all. strings are immutable hence doing element.innerHTML += "<br>" acts as a complete read and rewrite.
second, why that is bad:
aside from performance, mootools (and jquery, for that matter) assigns special unique sequential uids to all referenced elements. you reference an element by calling a selector on it or creating it etc.
then consider that SPECIFIC element with uid say 5. the uid is linked to a special object called Storage that sits behind a closure (so its private). it has the uid as key.
element storage then works on a element.store("key", value") and element.retrieve("key")
and finally, why that matters: events are stored into element storage (eg, Storage[5]['events']) - do element.retrieve("events") and explore that in fireBug if you're curious.
when you rewrite the innerHTML the old element stops existing. it is then recreated but the event handler AND the reference to the function that you bound earlier will no longer work as it will now get a NEW uid.
that's about it, hope it makes sense.
to add a br just do new Element("br").inject(element) instead or create a templated fragment for the lot (fastest) and add in 1 big chunk, adding events after.
HTML is represented internally by a DOM object structure. Kind of like a Tree class in traditional programming languages. If you set innerHTML, the previous nodes in the parent node are destroyed, the new innerHTML is parsed, and new objects are created. The references are no longer the same.
div
|-- a..
The div object above contains an Anchor object as a child. Now set a variable link1 as a reference to the address of this Anchor object. Then the .innerHTML is += "<br />", which means all of the nodes of div are removed, and recreated dynamically based on the parsed result of the new value of .innerHTML. Now the old reference is no longer valid because the Anchor tag was re-created as a new object instance.

The reasoning behind direct link between DOM Element and the variable it is assigned?

I am kinda newbie and I really want to understand why the variables we create don't just get the values inside the DOM element, but becomes the DOM element?
Here is some basic code;
var elementValues = document.getElementById("p1");
elementValues.style.color = "red";
// I don't understand why we don't need this step in order to manipulate the DOM.
// document.getElementById.getElementById("p1") = elementValues;
Aren't we basically saying to copy the values from DOM element with an id of p1 and paste them into elementValues?
But why the color of DOM element changes when I change the color of elementValues? From what I understand it acts like a pointer.
In Javascript, Object variables store a reference to the objects. Hence, document.getElementById returns a reference. So when you modify the values of elementsValues, your are editing the referenced object.
Have a look on Working with Objects - Comparing Object. You could read the whole page also to have an overview.
Yes, it is like a pointer.
By using var elementValues = document.getElementById("p1"); you are assigning a reference to the DOM element to the variable. Nothing about the element gets saved to the variable, but "where to find it".

How does storing JQuery Fields in an array compare to just storing the selection string?

I am having to store a large array of JavaScriptobjects, these objects need to contain a message, and a way of selecting an associated HTML element.
Currently, I've been using the the following code to add to this array:
if (field[0].id != ""){
this.selectorString = "#" + field[0].id;
}
else if (field.attr("name") != ""){
this.selectorString = "[name='" + field.attr("name") + "']";
}
I didn't want to store the entire field, as I wasn't confident on JavaScripts/JQuery memory management or how it worked. Selection strings seemed the safer option, as opposed to a large array of fields. I could then just use the stored string to perform a JQuery selection statement and manipulate the field.
The Big Question
If I store the fields, will this take up a large amount of memory, or is it purely reference to an object that is already stored somewhere in the big black hole of JavaScript of which I know little?
Is there an alternative that anyone can think of that would enable me to achieve what I'm going for. The 'fields' can be divs/spans/input fields/anything, that might not necessarily have an ID/Name - which will cause problems if I'm not storing the field.
Many thanks.
If I store the fields, will this take up a large amount of memory, or is it purely reference to an object that is already stored somewhere in the big black hole of JavaScript of which I know little?
Just a reference (the "big black hole" is called the "DOM" or "DOM tree" or sometimes "page"). But note that if you remove the element you're referring to from the DOM at some point, but still have a reference to it from a JavaScript variable, the element is kept in memory (just not in the DOM tree) until/unless you assign a new value to that variable or that variable goes out of scope.
Concrete example: Say we have this on our page:
<div id="foo">....</div>
And we have this code:
var f = $("#foo");
Now we have a jQuery object wrapped around a reference to that element. It's not a copy of the element, just a reference to it.
Now suppose we did this:
f.remove();
That div is no longer in the DOM (on the page), but it still exists because we still have a reference to it from the f variable (indirectly; f refers to a jQuery object which, in turn, refers to the element). But if that variable goes out of scope, or we assign some other value to it (for instance, f = null;), then the element is not referenced from anywhere and can be reclaimed.
If you're not removing elements from the DOM (directly, or indirectly by replacing the contents of an an ancestor of theirs), then very little memory is used to simply refer to the existing element.

Element reference breaks on modification of innerHTML property of container

When creating elements via code, I have encountered an issue where modifying the innerHTML property of an element breaks any references to other elements that are injected into the modified element prior to the modification.
I have a test case here: http://jsfiddle.net/mJ7bF/1/ in which I would expect the link1 reference to behave exactly as link2 does.
This second test case is the same code, but instead of using the innerHTML property to add the <br> tag, I create the line break with an object. This test behaves as expected: http://jsfiddle.net/K4c9a/2/
My question is not regarding this specific code, but the concept behind it: what happens to the link1 reference in that first test case? If it doesn't refer to the HTML/DOM node that is visible when the cont node is injected into the document, what DOES it refer to, and how does this fit in with the ByReference nature of javascript objects?
few things here.
first of all. strings are immutable hence doing element.innerHTML += "<br>" acts as a complete read and rewrite.
second, why that is bad:
aside from performance, mootools (and jquery, for that matter) assigns special unique sequential uids to all referenced elements. you reference an element by calling a selector on it or creating it etc.
then consider that SPECIFIC element with uid say 5. the uid is linked to a special object called Storage that sits behind a closure (so its private). it has the uid as key.
element storage then works on a element.store("key", value") and element.retrieve("key")
and finally, why that matters: events are stored into element storage (eg, Storage[5]['events']) - do element.retrieve("events") and explore that in fireBug if you're curious.
when you rewrite the innerHTML the old element stops existing. it is then recreated but the event handler AND the reference to the function that you bound earlier will no longer work as it will now get a NEW uid.
that's about it, hope it makes sense.
to add a br just do new Element("br").inject(element) instead or create a templated fragment for the lot (fastest) and add in 1 big chunk, adding events after.
HTML is represented internally by a DOM object structure. Kind of like a Tree class in traditional programming languages. If you set innerHTML, the previous nodes in the parent node are destroyed, the new innerHTML is parsed, and new objects are created. The references are no longer the same.
div
|-- a..
The div object above contains an Anchor object as a child. Now set a variable link1 as a reference to the address of this Anchor object. Then the .innerHTML is += "<br />", which means all of the nodes of div are removed, and recreated dynamically based on the parsed result of the new value of .innerHTML. Now the old reference is no longer valid because the Anchor tag was re-created as a new object instance.

What is a reverse reference to the DOM object?

In this link: http://css-tricks.com/snippets/jquery/jquery-plugin-template/ it has a line of code that says
// Add a reverse reference to the DOM object
base.$el.data("yourPluginName", base);
what does the "reverse reference to the DOM object" mean?
Assuming that you know the jQuery data function:
It's storing a reference to the instance of the class in the data cache of jQuery, meaning that the stored instance can be used to access the initial base object if it in the current context is not available.
This way, the class instance can be used later. However, the use of the prototype keyword upon the initial class that the instance were created from will modify the instance.
EDIT:
Ooops, it seems that Anurag is right, and I was giving wrong information.
Sorry, the information I gave in initial answer was not completely correct. I've updated the answer, so it now tells the truth.
In the comments you're asking:
so you mean its storing the current state of "base" in the data cache but if we make changes to "base" later on then the one in the data wont be affected? so if for some reason we needed to get the original one again we can do data('yourPluginName') to retrieve it? can you give me an example of when this would be helpful?
It seems that none of the statements are correct.
As I did obviously not remember adequately, the thing stored in data is only a reference to the object:
var obj = {};
obj.hello = "Hello";
$("#someElement").data("object", obj);
obj.world = " world.";
alert(
obj.hello +
$("#someElement").data("object").world
); // alerts "Hello world."
BTW, JavaScript variables with names like this base-thing (but, more often seen as that or similar) are typically used to represent the current context, accessed through the this keyword, which on many occasions is more easy to store in another variable due to scoping/context changes, that will make the current context and therefore this, change.
Also due to issues with context, the stored value in data could be used to access the specific object instance from another context (that is, when this represents something else), instead of the version of the base object that was continually used after a copy of it was stored.
I hope this answered you questions :D
The technique and the problem it solves is general and not specific to jQuery plugins. There may be cases where a Javascript object corresponds to a DOM element, and wraps logic specific to that DOM element. This object might be interested in listening to events such as clicks that happen within that DOM element. The information we get in those callbacks is the element that triggered it, and not the associated object. You could use jQuery's data API or any type of map in general to retrieve the corresponding object, and do something with it.

Categories