I have an object with a variable number of processes and their properties. These processes are to be visually displayed on the website. Since the user can edit/delete/add processes and their properties on the website, the object is constantly changing or being expanded. So it must always be possible to dynamically adjust/update the web page.
My approach would have been to have an initial function and an update function, which is called again and again, as soon as there are changes to the object. This update function with a foreach loop then calls other functions needed to build the page for each element of the object.
In this case, almost the entire HTML content is created with Javascript using createElement(). Is this the common way to go, or are there other, more efficient ways to do this?
I'm trying to build a Tampermonkey user script that modifies the functionality of an event applied to an element.
Let's say the source website have this:
<div id="item_1">…</div>
And within the source website's Javascript:
document.getElementById("item_1").addeventlistener("click", function(){
// Source website's lines of code for the function to be applied on click event occurrence.
}
I know that I can easily overwrite the event functionality by using:
document.getElementById("item_1").addeventlistener("click", function(){
// My lines of code here
}
But what I'm looking for is to first copy the anonymous function that was previously passed-in to the addEventListener method. I want to copy it to a temporary variable so that I can retrieve the original Event Listener attached function back.
There's another question having an answer telling that copying functions of Event Listeners is impossible. I believe this may be possible somehow as I think that the passed-in anonymous function is stored within the heap with some reference. If I'm able to get that reference, I will be able to get a copy for the code to another variable.
I don't have access to edit the source's script. I know that I could have refactored the code to handle event population. Also, I know I can do some manipulation on the source's JavaScript, but I don't want to go this way as my user script code will get too complicated and if the source code was changed a little, my code will be broken easily. I want to easily copy the Event Listener function to a variable I have.
Since I've tried and not succeeded many times I figure it's time to ask. I would like have several elements on the screen on which the user can click. Once the user decides to double click somewhere on the body I would like to console.log the text elements of the array.
This isn't nearly as intuitive as I thought it was going to be. The following example isn't all that practical, just curious why I can't get it to work.
EDIT: I would like to NOT use a global variable.
Fiddle can be found here
You just need to alter the scope of the array textArray so that your function ferryArray() can access it and loop over.
Here is the working fiddle.
I'm not running into a memory leak in my application yet, but I'm worried about possible problems in the future. I would like to know if doing something like this:
SomeClass.prototype.someMethod= function() {
var that= this
this.$div2.click(function() {
that.someMethod2();
});
}
And lets say that this.$div2 is appended to another div this.$div1. If I call
this.$div1.remove();
and later loses the reference of my SomeClass instance does the SomeClass instance gets garbage collected? And what about the HTML element this.$div2? this.$div2 would not be inside the DOM because it is appended to this.$div1.
I ask this because the event handler in this.$div2 might keep a reference to the HTML element this.$div2 and also keeps a reference to the instance of SomeClass through the closure because of the variable "that".
So should I care about properly removing all events and HTML elements like this? Or simply removing the "root" element (this.$div1) solves the problem?
this.$div2 is appended to this.$div1. If I call this.$div1.remove(); and later lose the reference of my SomeClass instance does the SomeClass instance gets garbage collected?
Yes, when all references to it are lost - also those through event handlers , - the instance can get garbage-collected.
And what about the HTML element this.$div2? this.$div2 would not be inside the DOM because it is appended to this.$div1.
It does not matter whether it is currently attached to the DOM. If some non-collectible object references $div1, it also could access its child node $div2 and that one's event handlers, so the instance referenced from the handler would not be collectible.
I ask this because the event handler in this.$div2 might keep a reference to the HTML element this.$div2 and also keeps a reference to the instance of SomeClass through the closure because of the variable "that".
That's a circular reference and should get handled well by the engines (when none of the objects inside the circle is referenced from outside it can get collected). However, (old?) Internet Explorers fail to do this when a DOM object is involved in the circle.
For that reason the .remove jQuery method (code) internally calls the (internal) cleanData method which detaches all event listeners.
So should I care about properly removing all events and HTML elements like this? Or simply removing the "root" element (this.$div1) solves the problem?
Yes, calling remove on a jQuery wrapper automatically removes all events (from all child elements) and DOM nodes.
Should I care about properly removing all events and HTML elements
like this?
The short answer is No! at least in 99% of the cases, it will not matter in any way because the memory used by one DOM element is trivial compared to the overall memory used by a web page.
However it is always a good practice to release the memory used by disposing unneeded objects, but you cannot say that GC would definitely releases the memory utilized by the elements because garbage collection is entirely up to the browser! In theory GC should only kick in when there are no references to the DOM element, at least that's how Chrome works, but in languages like JavaScript, you don't explicitly tell the run-time you're done with the object, things get messy in JavaScript so quickly: a function might pass the object on to some more functions, the object might get saved away as a member within yet another object, an object might get referenced through the closure etc, so it's completely up to the browser how and what to collect!
In your case removing div1 frees the html document and the element would not render in the view, in fact jQuery's remove method takes care of removing all the events, expando properties, and child elements attached to the element together with the element itself, however you keep a reference of div1 and div2 in yet another object making both DOM elements Orphan elements! removing SomeClass instance variable releases all references to the DOM elements making them candidate for garbage collection but here comes the tricky that variable that causes the DOM element make a reference to the instance of SomeClass through clusure! This issue is known as Circular Reference in IE:
JavaScript Objects and DOM elements that store references to one
another cause Internet Explorer’s garbage collector to not reclaim
memory, resulting in memory leaks
You can read more about it here
This particular leak is mostly of historical interest IE<8, but a good example of breaking circular links is to avoid using the variable that, instead use proxy or delegate to change the event handler's context to some particular context.
ECMA 5th bind method is quit useful changing contexts when in comes to DOM event handlers, here's a simple handler based on your code without using variable closure:
this.$div2.click((function() {
this.someMethod2();
}).bind(this));
If you will create element dynamically, then assign to them events. i think that your code is not a good way to do that. you should follow this manner:
for fixed elements if you need an event, use these two functions; the first called in the constructor, the second in the destructor.
on_Events: function() {
$('your_form').on('event_name', {element_Selector}, callback_function)
},
off_Events: function() {
$('your_form').off('event_name', {element_Selector}, callback_function)
}
for dynamically objects. add events when creating an element and remove these events just before destroying the element.
I have a plugin i created which works great when there is only one instance of it on the page.
However it uses a global variable to store the current item index.
When I place multiple instances of this on the page, it all goes wrong, as each block of script gets confused because there are multiple instances of the same global variable on the page.
Is there any way i can 'instantiate' each plugin i add to the page to avoid this, so each block of javascript only accesses its own global fields / properties?
You can attach the variable to the element using .data():
$(this).data('my-plugin', someValue);
// Note: if the above line is in a regular jQuery plugin ($.fn.myPlugin = ...)
// then 'this' does not need to be wrapped.
Retrieve it again with:
$(this).data('my-plugin');
This way the variable is associated directly with the element your plugin is initialised on.