I've often used the word "parent" as a JavaScript variable name, and have never had any problems.
I've recently learned that "parent" can refer to something else such as when used to access an element in an IFrame's parent such as parent.document.getElementById("someID").
Should I stop using the word "parent" as a JavaScript variable name, and go through all my existing script to change it? Note that http://msdn.microsoft.com/en-us/library/ie/0779sbks%28v=vs.94%29.aspx and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words do not indicate that I shouldn't.
'parent' is not a reserved word but a global object in the browser's execution environment. Whether or not you want to have a variable name that conflicts with that is your decision.
For reference, here is a list of actual reserved words in JS:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
If it makes sense for your variable to be called parent then go ahead and name it that, you just need to be aware that it will shadow the parent property of the window object (the global scope), but that's not an issue since you can explicitly reference that using window.parent rather than just parent wherever you need to work with it.
The only time it should become an issue is if there is code that shares scope with your parent variable which is attempting to access window.parent without explicitly specifying that they want the property, and that's probably an indication that the code needs to be tweaked.
"JavaScript" isn't the same as "ecosystem within which JavaScript is executed".
Browsers have the window and document references, which have properties... like parent. You can still reference the global parent. If your parent is called on a different object there's no collision anyway.
Related
I have a directive and inside it's template is a <img> element and I want to execute a custom method that is within my directives scope:
<my-directive>
<!-- my directives template -->
<p>...</p>
<img onload="myScopeMethod()">
<p>...</p>
<!-- my directives template -->
</my-directive>
I found this Get width height of remote image from url but this works only if im applying it to a directive that works on the <img> element.
The directives purpose is to show a widget that allows me to manipulate the image (scale it by dragging a slider) but I somehow need to get it's original size.
How can I get it to execute the method from my controllers scope?
You would generally want to take your load handler function out of the template itself and stick it in the link function. From there it kind of depends on your directive and whether you are using an isolate scope, inherited scope, or the same scope as the parent.
If you have a scope key in your directive definition object and it's set to an object literal, then you are using the isolate scope. In that case, you'll need to pass it in somehow, and the most straightforward way is to use the '&' option.
If you don't have a scope key or have a scope key and it's set to a boolean value you're using the same scope or an inherited scope. In this case, all you need to do is call $scope.originalScopeMethod() and it will either call it on the scope or find it in the prototype chain.
Here's an example with the three different scenarios. The table at the bottom is being fed from the 'main' controller scope while the small numbers are fed from the directive scope.
If it were me I'd probably go with either isolate or inherited scope so you can keep track of multiple images separately a little easier. The shared scope version in my example would only work for a single image, but you could make it work with an array or hash if you really wanted.
Let me know if I misunderstood your question in any way.
I'm trying to build a context menu directive with some specific characteristics (that are not directly relevant to this question). I've attempted to implement this as an "attachment" directive that attaches the scope of the element it's set on, to a pre-made "menu" element. Since I was unable to find any canonical documentation on this topic, I've based my implementation on some digging around with the Chrome Developer Tools.
I have made a simplified testcase that shows my implementation (and the problem) here: http://plnkr.co/edit/URafJe0OcRsMsmaEdmDi?p=preview
It effectively uses $new on the element's scope to create a new inheriting child scope, and then attempts to attach that scope to the 'menu' element (referenced by ID), by setting its $scope data property, and setting the ng-scope class.
The problem I am encountering, is that the menu element still does not seem to be able to access the attached scope. Any expression relating to that scope, comes up empty (again, see the Plunker above). The $scope data property is correctly set to the newly created inheriting child scope, and that scope is correctly inheriting so that the parent scope values should be accessible. I have also verified that it is interpreting any bindings at all by adding a simple "1 + 1" expression - this works fine.
Why can I not access the scope that is supposedly attached to the element, and/or what is the correct way to manually attach a scope to an element in a directive?
Here is a fork of your plunkr: http://plnkr.co/edit/V0dbM4NFcxdT8YEXWs4l?p=preview
I dont know how to do what you want without using $compile. I did something like this in the plunkr:
menu_element = $compile(menu_element)(child_scope);
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.
In a webapplication I came across, there is a javascript line in logout.jsp as:
parent.parent.renderProcessingTextOff();
On debugging the page with IE script debugger, it is breaking on above line with error as:
Object doesn't support this property or method
What is the meaning of this error?
How to solve it?
I am new to javascript, so please explain in simple terms.
Flow of logout is:
on click of logout button, a command is passed and intercepted in interceptor, which directs it to appropriate processor, which forwards the request to logout.jsp.
Its a spring application, if that information is of any help.
Thanks for reading!!
Are there frames or iframes on your page? Or object elements?
parent is a property of the window object (and the window. part of window.parent is assumed if you leave it out).
From MDN:
When a window is loaded in an <iframe>, <object>, or <frame>, its parent is the window with the element embedding the window.
So if from an iframe that is at least two levels down, the line parent.parent.renderProcessingTextOff(); says to call the renderProcessingTextOff() function defined by its grandparent.
Obviously if that line of code appeared where there wasn't a grandparent with that function defined then you'll get the error you quoted.
In this case, it looks like the first word, parent is an object instance. That object has a property called parent, and to access it you use the syntax parent.parent. The property is in turn another object, which is supposed to have a property called renderProcessingTextOff which is called as a function.
If I would venture to guess about your problem, it seems that parent.parent is of the top level Object class, and Object does not have that method.
If you already is using the IE script debugger, put a breakpoint at that line and examine the parent and parent.parent objects.
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.