Object.defineProperty for all browsers? - javascript

Asking about Object.defineProperty as demonstrated below:
function testComponent(){
var testProperty;
Object.defineProperty(this, "testProperty",
{
get : function()
{
return testProperty;
},
set : function(val)
{
testProperty = val;
}
});
}
Where it would be used like so:
testObject = new testComponent();
testObject.testProperty = "testValue";
Based on what I've seen so far, it looks like there is no cross browser solution, as I've tried using es5-shim with no luck, but I would like to confirm. I also found a reference to this post and my tests still fail in IE 7 & 8, can anyone shed any light on this?
I remember looking through a related question a few months ago somewhere on S/O and I think I saw someone had written a solution for this in an answer. Any general workarounds for getter / setters would also be appreciated. The idea is that I need some equivalent of a getter setter on an object without passing the parameter change through a method. I don't need IE6, but I would like to support browsers in the range of IE7+ ff 3.6+ , etc
QUnit tests below: (jsFiddles)
(these pass in all browsers on my machine except IE 7 & 8
direct use of defineProperty, no shims: http://jsfiddle.net/uSYFE/
fiddle using the ES5 shim, I'm assuming all I need to do is include it? : http://jsfiddle.net/hyperthalamus/ntwDy/
fiddle using the IE recommended solution : http://jsfiddle.net/hyperthalamus/xfvz3/

According to ES5-shim:
/!\ Object.defineProperty
This method will silently fail to set "writable", "enumerable", and "configurable" properties.
Providing a getter or setter with "get" or "set" on a descriptor will silently fail on engines that lack "defineGetter" and "defineSetter", which include all versions of IE up to version 8 so far.
IE 8 provides a version of this method but it only works on DOM objects. Thus, the shim will not get installed and attempts to set "value" properties will fail silently on non-DOM objects.
https://github.com/kriskowal/es5-shim/issues#issue/5
So you know your answer. It can be done on DOM elements, that's it (and on IE8 only).
I'd suggest you just use get/set methods if you want IE7 to work.

For older IEs you'd have to make sure your property is a dom object (even a fake tag) and use onPropertyChange to get notified. See this post by John Dyer for more details.

I've had this same question myself. (See here.) It doesn't look like it's fully possible in IE8 or lower. Otherwise the ES5 Shim is your best bet.

Related

Is there a mozilla equivalent to webkitGetAsEntry?

Now that webkitGetAsEntry() has been activated on Chrome 21 to allow folder drag&drop, is there an equivalent in mozilla - mozGetAsEntry(), getAsEntry(), or something else? I've only been able to find very minimal info on webkit's method and the whatwg proposal; I can find nothing for Firefox (or any other browsers).
References:
http://wiki.whatwg.org/wiki/DragAndDropEntries#DataTransferItem.getAsEntry.28.29
http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available
http://blog.protonet.info/post/26894439416/html5-drag-drop-files-and-folders
What you're looking for is the mozGetDataAt() method, which returns an nsIFile object:
https://developer.mozilla.org/En/DragDrop/Recommended_Drag_Types#file
So to answer your question, the equivalent would be:
mozEntry = event.dataTransfer.mozGetDataAt(0);
or..
event.dataTransfer.mozGetDataAt(0).isFile() etc.
Documentation for nsIFile(contains the fields that are in the webkit entries):
https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIFile

Firefox Javascript: Why does .all not work?

In IE, I can go like:
var x = document.getElementById("header");
alert(x.all[0].tagName);
If I try that in Firefox, I get the error "all is undefined".
What is the Firefox equivalent of IE's .all property?
.all is a Microsoft-specific extension to the DOM, and is not supported by any other browsers (except Opera, I believe, who simulate it in order to improve compatibility with sites written for IE).
You can use things like x.children and x.childNodes, or x.getElementById() and x.getElementsByTagName() to reference elements below the current one in the tree, depending on your usage. I suspect in this case x.children is what you're after.
all would be the name of an array. It is not a native javascript keyword.
You may want to look at childNodes instead.

Is Math.ceil() & Math.round() supported on IE8?

I have a Javascript function that calculates a value and re-inserts the value into a <td> while also injecting the value into a hidden <input>.
This is my function:
$("input[name^='policies']:checkbox").change(function() {
var el = $(this);
if (el.is(":checked")) {
no_policies++;
}
if (el.is(":not(:checked)")) {
no_policies--;
}
subscription = no_policies*policy_cost;
first_payment = Math.ceil(subscription+no_policies*(policy_cost/days_month)*days_left).toFixed(2);
alert(first_payment);
$("td#first_payment").text("R "+first_payment);
$("input#first_payment_txt").val(first_payment);
$("td#subscription").text("R "+subscription.toFixed(2));
});
Everything works on IE8 up until this statement:
first_payment = Math.ceil(subscription+no_policies*(policy_cost/days_month)*days_left).toFixed(2);
I suspect IE8 is having trouble with Math.ceil, is that true? Also, is there any other function/method I can use to circumvent this?
Thanks in advance.
Answer is yes to both your questions:
Math.ceil()
Math.round()
Supported in the following document
modes: Quirks, Internet Explorer 6
standards, Internet Explorer 7
standards, Internet Explorer 8
standards, Internet Explorer 9
standards.
See also general table of Javascript compatibility for different IE versions:
Seems like microsoft supports Math.ceil on all versions beginning from ie6 (msdn), maybe one of the variables use is undefined or you devide by 0 or one of the variables is not a number so the result cannot be ceiled/rounded.
IE8 actually has a fairly good debugger. I recommend hitting F12 to open it, then going to the Script tab and selecting the Start Debugging button. This will let you set breakpoints along the script, letting it stop and wait for you to analyze variables as it executes at your own pace. As Adriano mentions in his comment, it's most likely an issue with one of your variables.

setAttribute doesn't work in IE6

how to set element attribute with javascript in IE6..? It seems setAttribute doesn't work. I really need to do it on the fly. Thanks.
Code
<script type="text/javascript" language="javascript">
menuItems = document.getElementById("menu").childNodes;
for (i = 0; i < menuItems.length; i++)
{
if (menuItems[i].className != "blue")
menuItems[i].setAttribute('onmouseover', 'HoverMenu(this)');
}
</script>
(Most of the below was before the OP clarified they were setting an event handler; left the list of other issues in case others find them useful)
IE6 makes a mess of several aspects of setAttribute. Without knowing the exact problem you were dealing with (this was before the edit inidicating it was an event handler), it's hard to be sure whether that's really the problem, but here are a couple of known issues:
You can't use setAttribute to set event handlers
It's best to set event handlers using the reflected property or with addEventListener [standard] / attachEvent [IE], not setAttribute (and you can't use setAttribute on IE).
So, any of these will work:
// Using reflected property
theElement.onclick = yourFunction;
// Using DOM2 standard addEventListener; note it's "click", not "onclick"
theElement.addEventListener("click", yourFunction, false);
// IE's non-standard alternative to addEventListener
theElement.attachEvent("onclick", yourFunction);
...not
// This doesn't work on IE (at least)
theElement.setAttribute("onclick", "yourFunction();");
The addEventListener / attachEvent way of doing this is cool for other reasons: You can have multiple event listeners on the same event of an element. You can't do that using the reflected property.
So for your specific situation:
menuItems = document.getElementById("menu").childNodes;
for (i = 0; i < menuItems.length; i++)
{
if (menuItems[i].className != "blue") {
menuItems[i].onmouseover = function() {
HoverMenu(this);
}
}
}
Certain attributes need their modified names
class
The correct way to set the class attribute is to use the reflected property className:
// Correct, cross-browser way. Works on IE6+, all versions of
// Chrome, etc. Completely reliable.
theElement.className = "new set of classes";
or on modern browsers (so, not IE6!) you can use classList.
One of IE6's many setAttribute bugs is that this doesn't work:
// Should also work, but fails on IE6 (and probably some other old versions)
theElement.setAttribute("class", "new set of classes");
Instead, IE6 (and probably a couple of other versions) make you use "className" instead of "class", even though that makes no sense whatsoever. The reflected property has the name className because it used to be that in JavaScript, you couldn't use reserved words (like class or for or if) as property literals (obj.class was invalid). That's not been true for a while now (ECMAScript 5 fixed it), but that's why the reflected property is className, not class.
But since setAttribute takes a string, it should accept the proper name of the attribute. The fact it doesn't is just an IE bug (and one they've fixed in modern versions of IE if they're not in [in]compatibility mode).
for
Similarly, to set the for attribute (for instance, on labels), one uses the htmlFor reflected property:
// Correct, cross-browser way. Works on IE6+, all versions of
// Chrome, etc. Completely reliable.
theLabel.htmlFor = "id-of-field";
On any non-broken browser, you can also use setAttribute:
// Should also work, but fails on IE6 (and probably some other old versions)
theLabel.setAttribute("for", "id-of-field");
...but not on IE6, it wants "htmlFor" instead of "for" for the same reason it wants "className" rather than "class" (e.g, because it's broken).
This page has quite a list of attributes that are problematic with IE.
setAttribute can't be used to set the style attribute
...you have to use the style property instead; but to be fair, that's usually a more convenient way. Example: This won't work on IE:
theElement.setAttribute("style", "color: blue"); // Doesn't work on IE
...but this will:
myElement.style.color = "blue";
Slightly OT: Look at libraries
JavaScript libraries like Prototype, jQuery, Closure, or any of several others will make most of the above a lot easier and smooth out differences amongst browsers if you go through their APIs.
I would really look at jquery. It has all the functionality that works with IE6 and this would be so much easier than the code you have here. It would look like this:
menuItems = $("#menu")[0].childNodes;
$.each(menuItems, function()
{
var item = $(this);
if (item.attr("className") != "blue")
item.mouseover(HoverMenu);
}
This code might need to be tweaked a little as I am just writing from memory.
I say easier because what you are trying to do in setting events like this varies based on browser and can be a headache to setup. But with jquery it is all done for you.

Does Low Pro Prototype DOM Builder work in IE?

Dan Webb's Low Pro UJS extension to Prototype offers the following elegant DOM Builder:
var listItem = $li({ id : 'item-1' },
$strong("Some text")
);
// returns a node equivalent to: <li id="item-1"><strong>Some text</strong></li>
$('a_list').appendChild(listItem);
While this works like a dream for us in Firefox and Safari, it explodes with delight in IE 6 and IE7 with the error "Object doesn't support this property or method"
Any insight into what Dan Webb's DOM Builder might be doing to wrap Element.new that isn't compatible with IE?
I would imagine the "Object doesn't support this property or method" error is coming from a call to one of Prototype's extended element methods (which are not applied automatically in IE). However, all the elements you're dealing with are coming from LowPro or the $() function, which should extend the elements for you.
You could try this and see if it resolves the problem:
var listItem = Element.extend($li({id: 'item-1'},
Element.extend($strong("Some text"))
));
$('a_list').appendChild(listItem);
If that fixes it then LowPro isn't extending the elements, which is very odd. If it doesn't then there must be something else wrong, can you post a demo page somewhere?
Since v1.6, Prototype has a had a built-in element constructor. The syntax is just a little different than Low Pro.
$('a_list').insert(new Element("li", {id: 'item-1'})).update('some text').wrap('strong')

Categories

Resources