Get elements that have not been added to the DOM - javascript

If I create a new HTML element using document.createElement, but I do not add it to the DOM, is there a way to find it? As this is a method of document, it seems somewhat logical that it might become property of document.
Example:
(function(){
document.createElement("a");
})();
console.log(document.getElementsByTagName("a").length); // -> 0
I understand why the above example doesn't work. Is there an alternative?

You're just creating some elements, without insterting them in the DOM.
You need to store them if you want to know how many they are.
var myElements = []:
var elem = document.createElement("a");
myElements.push(elem);
myElements.length; // use their length for your needs

If you are creating elements in several different functions then you need to update the global array:
var linkElements = []; //declared in global
function addLinkElements()
{
var link = document.createElement("a");
// add link element to global array
linkElements.push(link);
// total link elements
alert( "Total anchors: " + linkElements.length + document.getElementsByTagName("a") );
}
Note: Remember to remove update the array in all functions adding these link elements.
hope that helps.

Related

How to write a var to apply script on multiple pages?

I want to apply the same script on multiple pages, but I need to store some var inside, which may not be present on particular pages.
window.onorientationchange = function () {
var $t1 = $(".test1")[0];
var $t2 = $(".test2")[0];
var $t3 = $(".test3")[0];
var $t4 = $(".test4")[0];
var $t5 = $(".test5")[0];
// do some stuff
}
I want to store this code in .js file and then apply it across several pages, the problem is that some of this var's are not present on particular pages, how do I make it universal?
Also
If I add lines like:
if (window.matchMedia("(orientation: portrait)").matches) {
if ($t1.is(":empty") && $t2.is(":visible")) {}}
inside mentioned event listener, how do I deal with an "empty" var's, which is not defined on the previous step?
Several things.
Based on your variable naming, it looks like you are expecting $t1 to be a jQuery object.
However, when you try to access an element by index [0], you are returning the first element that matched the selector, no longer wrapped as a jQuery object.
What you want is to use the .eq(0) function to access the element by index, so a jQuery object is returned
https://api.jquery.com/eq/
var $t1 = $(".test1").eq(0);
At that point, you can use the .length test to check if your $t1 contains any elements
window.onorientationchange = function () {
var $t1 = $(".test1").eq(0);
// ...
if($t1.length){
// do stuff with $t1
}
}

html + js: dataset variable being ovewriten after assigning it a value based on src attribute

So I have a for loop that iterates over a list of iframes:
var iFr;
for (var i = 0; i < iFrames.length; i++) {
iFr = iFrames[i];
if (isFooBar()) {
iFr.dataset['sourceBackup'] = iFr.src; //assign src value to data-source-backup
iFr.removeAttribute('src'); // remove src attribute
}
}
The weird part is that it seems to remove the src value also from dataset['sourceBackup'] or data-source-backup which I don't understand why. As I'm doing it AFTER assigning it to dataset['sourceBackup'].
UPDATE:
I even tried using object.assign() :
iFr.dataset['sourceBackup'] = Object.assign({}, {'src': iFr.src}).src;
Yet still the iFr.dataset['sourceBackup'] dataset gets erased for some iframes elements but not for others which is confusing.
Update 2
The problem was with outer code not with the code here. I was having multiple references to the same iframe in different contexts. So this was causing the weird behavior.
This is happening because both iFr.dataset['sourceBackup'] and iFr.src are pointing to the same object. The assignment does NOT make a copy of the object. Therefore, when you remove the object, it is not available regardless of which reference you use.
To actually clone the object, see this answer: How do I correctly clone a JavaScript object?

Javascript class initialization and jQuery DOM in memory

Which is the best way between:
var myClass = function() {
this.myContainer = function(){ return $(".container");}
this.mySubContainer = function(){ return this.myContainer().find(".sub"); }
}
AND
var myClass = function() {
this.myContainer = $(".container");
this.mySubContainer = this.myContainer.find(".sub");
}
Is there any concrete differences?
The memory problem arose when I have seen that my web page, that has enough javascript ( about 150KB of mine + libs ) takes more then 300-400MB of RAM. I'm trying to find out the problem and I don't know if this could be one of them.
function myClass{
this.myContainer = function(){ return $(".container");}
this.mySubContainer = function(){ return this.myContainer().find(".sub"); }
}
Here you will need to call it something like myClassInstance.myContainer() and that means jquery will search for .container element(s) any time you are using that function. Plus, it will create 2 additional closures any time you will create new instance of your class. And that will take some additional memory.
function myClass{
this.myContainer = $(".container");
this.mySubContainer = this.myContainer.find(".sub");
}
Here you will have myContainer pointing to an object which already contains all links to DOM nodes. jQuery will not search DOM any time you use myClassInstance.myContainer
So, second approach is better if you do not want to slow down your app. But first approach could be usefull if your DOM is frequently modified. But I do not beleave you have it modified so frequently that you may need to use second approach.
If there is a single variable you are trying to assign , then the second approach looks cleaner..
Yes they are different.
MODEL 1:
In the first model, myContainer is a function variable.It does not contain the jQuery object.You cannot call any of jQuery's methods on the objet. To actually get the jQuery object you will have to say
var obj = this.myContainer() or this.myContainer.call()
MODEL 2:
The second model stores the actual jQuery object.
try alerting this.myContainer in both models, u will seee the difference.
Yes this is different. after you fix your syntax error :
function myClass(){... // the parentheses
1st
When you create a new object var obj = new myClass(), you are creating two functions, and the jquery object is not returned until you call it
var container = obj.myContainer();
2nd
As soon as the object is initialized the dom is accessed and you have your objects cached for later use;
var container = obj.myContainer;

JavaScript - Manipulation HTMLElements inside JS object

In my current project, I've encountered a somewhat strange behavior (from my point of view) when I'm trying to alter the properties af a html element.
In my code, a have defined a javascript object - This object has a 'this.element' property, containing a html element, that gets passed through the constructor. Within this object, I have a couple of functions. In one of theese functions I'm trying to alter some styling of that object, by doing:
this.element.style.visibility = "hidden";
I get no errors when trying to do this, but the style remains unchanged. After some time, I discovered a workaround:
document.getElementById(this.element.id).style.visibility = "hidden";
Which is basically the same. This works, and I can set the style of my element. Though this workaround works, it requires my elements to have ID. While this is not a problem, my coding could get a whole lot easier, if I could get around this.
I'm testing this with Chrome, which is the same browser we'll use once the project is ready for deployment, so using a different browser is not really an option for me.
I would greatly appreciate if anybody can help me understand/solve this situation :)
- Thanks in advance
EDIT: Some more code.
This example I threw together illustrates what I'm doing. However when I run this on it's own, I can't achieve the behavior I was describing.
I don't know if this is of importance, but in my case the function representing "changeAllStyles" works fine when getting called just after the constructor. All subsequence calls of this function, is due to an invocation of the "onMessage" event, coming from websockets.
var myObjArray = [];
function init(){
//Using jQuery to select all elements containing the "data-whatever" attribute:
var elements = $('*[data-whatever]');
//Create a myObj object for each of theese elements:
for (var i = 0; i < elements.length; i++) {
var params = elements[i].getAttribute("data-whatever");
myObjArray.push(new myObj(elements[i], params));
myObjArray[i].changeStyle();
}
}
function myObj(element, params){
this.element = element;
this.params = params;
this.changeStyle = function(){
this.element.style.visibility = "hidden";
};
}
function changeAllStyles(){
for (var i = 0; i < myObjArray.length; i++) {
myObjArray[i].changeStyle();
}
}
It sounds as though elsewhere in the code you're removing the DOM element after having initialized this.element and then recreating it, like this:
HTML:
<div id='bar'><span id='foo'>This is foo</span> inside 'bar'</div>
JavaScript:
var foo = document.getElementById('foo');
var bar = document.getElementById('bar');
bar.innerHTML = "<span id='foo'>This is a new foo</span> inside 'bar'";
foo.style.visibility = "hidden"; // <== No effect, wrong element
As you can see, we're getting the "foo" element, and getting the "bar" element, and then replacing the contents of "bar" with brand-new stuff. That means all of the elements inside "bar" are removed, and then new elements are created. It happens that one of the new elements has the ID "foo" and so
document.getElementById(foo.id).style.visibility = "hidden";
...would work even though foo.style.visibility = "hidden"; doesn't work, because it's a completely different element that happens to have the same ID.
There is nothing wrong with the code you show, except its complexity maybe.
My gut feeling is that unholy things are occuring behind the scene. I cannot debug the code I can't see, but I can propose a cheap workaround.
You could as well collect the elements with document.querySelectorAll('[data-whatever]'), get back your individual parameters with getAttribute() and fiddle with style directly, like so :
function changeAllStyles()
{
var elements = document.querySelectorAll ('[data-whatever]');
for (var i = 0; i < elements.length; i++)
{
var elt = elements[i];
my_parameters = elt.getAttribute ('data-whatever');
play_with (my_parameters);
elt.style.color = a_nice_shade_of_pinkish_brown;
}
}
I concur with T.J. Crowder.
My bet is, someone is destroying and recreating the DOM elements behind your back. If they are recreated by copy, you can still access their clones by Id or class or attributes, but the references to the original DOM elements are dead.
To track this down, you could try something like:
this.changeStyle = function()
{
this.element.__check = "booh!";
var possible_clone = document.getElementById (this.element.id);
if (possible_clone.__check != "booh!")
{
report_to_boss ("something fishy there");
}
};

Use getElementById on newly created DOM object before it is inserted into the document -- HOW?

The getElementById method cannot be used unless the DOM element is attached to the document. By what method or mechanism can I access and modify a DOM element before it is attached to the document?
I have a large DOM element and I want to access a piece of it. I would classically use getElementById, but the DOM element is not attached to the document.
var element = document.createElement("div");
element.id = 'testqq';
var el = document.getElementById('testqq'); // el will be null!
source: https://developer.mozilla.org/en/dom/document.getelementbyid
I am looking for an answer that does not use jQuery. I love jQuery, but it is not an option for my current problem.
Well, you already have a reference to it with your element variable.
But I'll bet you mean you want something nested inside. If that's right, you could use getElementsByTagName('*'), then iterate over the collection that's returned, testing the ID property until yours is found.
var div = document.createElement('div');
div.innerHTML = '<p>yo</p><div><span id="tester">hi</span></div>';
var all = div.getElementsByTagName('*');
// search for element where ID is "tester"
for (var i = 0, len = all.length; i < len; i++) {
if (all[i].id === 'tester') {
var result = all[i];
break;
}
}
alert( result.id );
Before you try the loop, you can test to see if querySelectorAll is supported in the browser, and use that if so.
if( div.querySelectorAll ) {
var result = div.querySelectorAll('#tester');
} else {
// Do the loop with getElementsByTagName()
}
The document.createElement function returns a new element object, but that element doesn't exist in the DOM until you insert it.
The document object has no recollection of elements you asked it to create, so when you call document.getElementById('testqq'), it has absolutely no idea what you're looking for.
In your example, you have a reference to the element already. Why do you need to ask the document for it?

Categories