removing iframe will cause memory leaks? - javascript

I have a single page application which create and remove a number of iframe based on user input. each iframe could contain a jqgrid, a form for input submission with jquery.validate plugin etc...
the main page could access all the iframes to retrieve current operation status and some data to rebuild the main menu.
is safe to just remove the iframes or i need to .empty() the body before removing them?
EDIT:
when i say "retrieve current operation status and some data" i actually access the iframe properties using something like this
jqueryFrameObject[0].contextWindow.myCoolProperty
but never cache the object in the main page

No : jQuery takes care of removing the elements which could lead to memory leaks :
In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed.
If you don't keep other pointers (including hidden ones based for example on closures), you'll be safe. Be careful not to use the native addEventListener if you don't want to keep hidden links to your removed elements.

Related

Pushing dynamic content using GTM element visibility trigger and data layer

Google Tag Manager's Element Visibility Trigger appears to be a rather excellent way of tracking whether an element has appeared within the viewport, using a class or ID.
The standard reporting appears to pull back data something like this
However what I would like to do is to be able to use the trigger to detect and report items in a dynamically created list. For instance the element would be triggered based on its class which is shared by all the other elements in the list, each element may be populated with specific data to be pulled from a database eg: name, product ID, price etc.
Currently this has been done using the Custom Event Trigger, but this reports all elements on the page whether they are loaded or not.
What I would like to know is whether the element visibility trigger is the right thing for this and if so, how can I manipulate it to do what I need?
Probably yes.
You'd use the CSS Selector and select via the class name for your dynamically created items.
In the "When to fire this trigger" option you would select "Every time an element appears".
Finally you would set the "listen to DOM changes" option. This checks every time the DOM is manipulated (e.g. by inserting your list element) if the other criteria in the trigger are now matched.
Note that GTM warn that there may be a performance penalty for using that option (since this runs on every DOM manipulation). So you probably don't want to do this a lot.

How to handle dynamically-added DOM elements for progressive enhancement without knowing the method of adding?

I have a simple script that that "progressively enhances" specific <input> elements with a draggable slider (demo of the jQuery plugin).
Additional <input> elements may be added, and the whole thing will be placed in many different scenarios (it's a pluggable frontend widget). In other words, I cannot hook onto some "Add Another Slider" button's click event, because I have no idea where those additional elements may come from (it may be a button, several buttons, some AJAX call, etc).
To handle those additional elements, currently I'm using:
// for any dynamically added elements:
setInterval(find_and_init_all_sliders_that_are_not_yet_inited, 200);
Is there a better way?
TL;DR:
I wanna run a function each time new DOM elements are added. But I have no info or control on how or where those new elements will be added.

Saving and reloading a DIV structure with values on page load/unload

I have a <div id="populated"> element on the page which receives dynamically created content, including populated DIVs, text areas, input texts and check boxes. Moreover, there are some elements with addEventListener.
My question is: how to save this "populated" DIV and reload it when a user returns to the page?
What I've tried, by using localStorage:
Save the entire DIV as a serialised object (got tips from here). Problem: "Uncaught TypeError: Accessing selectionDirection on an input element that cannot have a selection."
Save the entire DIV as innerHTML. Problems: 1) bind events are lost 2) already entered data in textareas/inputs is lost.
I can rebind the events, but parsing the DIV structure and storing/restoring .value for each element seemed too complicated.
I'm using "pure" JavaScript (no frameworks) and without AJAX. Any ideas, keywords?
There are basically three ways to persist data on the web:
Server-Side
Local Storage
Cookies
Now cookies have a finite limit to how much they can store (and IIRC that limit varies by browser), so if your DIV has a decent amount of stuff in it, cookies won't cut it. Local storage works for newer browsers ... if it works at all that is (you should really post your storage error as a separate SO post of its own).
As for what to store, you can basically give up on storing bound events ... unless you want to convert every one to an in-line attribute (eg. "onclick='...") and save all the HTML ... but that would be a terrible idea because inline events quickly become a nightmare. (If you only have one or two this might be an option ... but I wince at suggesting it.)
What is commonly done instead is that you serialize your data in to an structure that just contains the data (no DOM, no events, etc.). You store that (however you choose), and then when you want to "load" it you deserialize it, building any DOM elements you need and hooking up any events you want at that point. JSON.stringify (present in newer browser's, or available via Crockford's JSON library if you want to support older ones) is one option for doing this serialization, as is jQuery's serialize and serializeArray methods. Or you can roll your own solution.
So in short:
Serialize just the data you want to save (via JSON.stringify, $.serialize or $.serializeArray, or your own function)
Choose from server-side (the common approach), cookies (limited space) or local storage (only on newer browsers and you'll have to solve your error) to store it
When you get it out of storage, deserialize it, building DOM elements and binding events to those elements as needed.
Hope that helps.
It took some redesign, but I managed to solve the problem:
The structure of the DIV is stored as innerHTML on onpageonload in localStorage.
The values of the fields inside the DIV are serialised and stored in localStorage.
The binding function is independent and can be called so it parses the whole DIV.
On onbeforeunload the scrips goes through the DIV as saves the "inner HTML" and the values. While loading, the scripts checks if localStorage is empty: if not, populates the DIV, loads the values and rebind the events.

Is it more efficient to keep DOM elements on the page or to re-render them as needed?

I have a dialog box that has settings associated with it. When the user clicks the "settings" button, a form is displayed so they can modify them.
What is more efficient:
to have the settings div exist hidden on the page and display when needed
OR
to create the settings div and populate it with data when needed?
In the first scenario you don't need to create the DOM elements and populate them every time, but if there are many dialog boxes open at once (a common situation) then the amount of elements on the page is pretty large and many of them are not going to be used often. But in the second situation, elements are created and appended to the DOM which gets expensive.
I'd suggest you to "cache" your html on the page, but enforce browser to do not render it until necessary (until user request the data, or simply scroll to it). The main idea is to add your html (with data) to the page, but comment it out. For example,
<div id="cached-html">
<!--
<div>
...some custom html here
</div>
-->
</div>
Then once user requested the html, you can do the following:
var html = document.getElementById('cached-html'),
inner = html.innerHTML;
html.innerHTML = inner.substring(4, inner.length - 4);
Pros. is that you don't bother your browser with initial rendering (later you can simply user display:none to hide it again), so your page renders faster.
And another note - if your data (and as a consequence inner html) changes frequently, then it will be better to re-render it each time user request it, but if it is almost static, then hide/show should be more effective.
There can be problems either way, it depends on your page. If you already have a lot of elements on the page, it may be better load add them when you need them. If your page is already very "scripty" you may want to load the elements and show them when needed.
The real question is what would be better for your page, more script, or more dom elements.
When you have to display same setting div at multiple places.
Keeping that hidden is a better solution.
Remember that creating a new dom element or cloning a existing dom element gives almost same performance, but for code clarity/maintainence cloning or template is better.
Implementation using template: Make a template of div setting and keep that hidden:
<div class="template_setting">
Your settings(children of template_setting)
</div>
Javascript/Jquery code:
-Whenever someone opens a dialogue box, make a clone of childrens of template_setting and append to div_dialogue.
-As you may have multiple templates on the same page( which is not always true).
Apply a custom event on the id of newly created setting div.( keep id of each setting div different, you can increment each one by some character/number).
$('#dialogue_opener').click(function(event){
$('.template_setting').children().clone().appendTo(div_dialogue)
.trigger('adjustSettingID');
Consider a hybrid solution. Load the "settings" div after the page is ready. This way, the user won't feel the extra "expense", and you'll have the div ready for when you need it.
I've typically seen that rendering from JavaScript is pretty darn fast. I've built lots of "just in time" menus, grids, and forms and the users can't tell the difference. The nice thing about it is that you don't have to keep a form current, just blow it away and default everything to the data in you settings object. Makes for cleaner code in my opinion.

Using jQuery to disable everything on a page. Break my code

For my current project, I require the facility to be able to remove all functionality from a page, so that it is complete and literal static page. Removing the ability to follow any links, and disabling and javascript listeners allowing content to be changed on the page. Here is my attempt so far:
$("*").unbind().attr("href", "#");
But in the pursuit of a perfect script, and to allow it to work in every eventuality for any possible page (and with the uncertainty of a on liner being effective enough), I thought i'd consult the experts here at stackOverflow.
In summary, my question is, 'Can this be (and has it been) done in a one liner, is there anything this could miss?'. Please break this as best you can.
No. Nothing in this stops meta redirects, or timeouts or intervals already in flight, and it does nothing about same origin iframes (or ones that can become same origin via document.domain) that can reach back into the parent page to redynamize content.
EDIT:
The sheer number of ways scripts can stay submerged to pop up later is large, so unless you control all the code that can run before you want to do this, I would be inclined to say that it's impossible in practice to lock this down unless you have a team including some browser implementors working on this for some time.
Other possible sources of submarine scripts : XMLHttpRequests (and their onreadystatechange handlers), flash objects that canscript, web workers, and embedding code to run in things like Object.prototype.toString.
I did not want to write a lengthy comment so I'm posting this instead.
As #Felix Kling said, I don't think your code will remove the href attributes on every element but rather remove every element and then select their href attributes.
You probably need to write:
$("*").attr("href", "#").detach() ;
to remove the attributes instead of the elements.
Other than that, I doubt that you could remove the event handlers in one line. For one thing you would need to account for DOM level 2 Event registration (only settable with scripting) and DOM level 1 Event registration (via attributes or scripting).
As far as I'm concerned, your best bet is to make a shallow document copy using an XML parser and replace the old document (which you could backup-save to the window).
First: Your code will remove everything from the page, leaving a blank page. I cannot see how it would make the page "static".
$('*').detach();
will remove every element form the DOM. Nothing left. So yes, you remove every functionality in a way, but you also remove all the content.
Update: Even with the change from detach to unbind, the below points are still valid.
Event listeners added in the markup via oneventname="foo()" won't be affected.
javascript: URLs e.g. in images might still be triggered.
Event listeners added to window and document will persist.
See a DEMO.

Categories

Resources