Scripting Object (as iframe replacement) in IE does odd stuff - javascript

I'm using the strict xhtml on my website, so I don't have the "Iframe" element. Instead, I'm trying to use the object tag.
I want to dynamically open content, so I've got a javascript function like this:
<object id="oPageName">
<script>
function openPage(pageName) {
var ifContent = document.getElementById("oPageName");
ifContent.data = pageName;
}
</script>
If I pass in say "someFolder/somepage.aspx" to openPage function, it simply sets the content page to "http://mysite/" - like it's chopping off the remaining part of the URL.
It works great in FF and Chrome, but not IE 8.
Any tips on this odd behavior?

If I pass in say "someFolder/somepage.aspx" to openPage function, it simply sets the content page to "http://mysite/"
You're doing better than most, then. Changing object.data in IE8 does nothing at all for me, just like it always has in IE.
There is a non-standard 'object' property on <object>s in IE, that gives you the document object of the inner HTML page (as you would expect to get from the unsupported contentDocument property). However, navigating that page (through object.object.URL or object.object.parentWindow.location) does the same as writing to object.data: nothing. (IE seems to get confused; if you look at the object.object.location.href, it actually points to the parent URL even though it's the child document.)
Basically, it's bugged to hell and you're best off forgetting <object> for HTML embedding today. Swallow your pride and include the iframe, using the Transitional DTD if you want to validate.

In earlier versions of IE (don't know about IE8) certain attributes on certain element types are immutable after being set once (programmatically or otherwise). I believe object and all the form elements (input, textarea etc.) behave this way.
I'm sure there's a more elegant way of solving this problem, but you could try something like this (untested):
function openPage(pageName) {
var ifContent = document.getElementById("oPageName");
try {
ifContent.setAttribute('data', pageName);
catch (e) { // catch immutable attribute error
// create a new object and replace the old one
var o = document.createElement('object');
o.setAttribute('name', pageName);
ifContent.parentNode.replaceChild(o, ifContent);
}
}
Most JS framworks have their own versions of setAttribute() which work around IE's attribute handling bugs.

Related

javascript clonenode() method is not working with safari

My code is perfectly working with IE but its not working with safari.Clonenode() method is not working in safari .
I have a code like this
function ApplyNowWizard_addVehicleTypeList(vehicleDOM)
{
oParent = $(this.data).get(0);
oParent.documentElement.appendChild(vehicleDOM.cloneNode(true).documentElement);
}
In safari vehicleDOM.cloneNode(true).documentElement give null.
As documentElement is a Document field, I assume vehicleDOM must be a Document. Note the DOM specification comment about cloneNode:
And, cloning Document, DocumentType, Entity, and Notation nodes is implementation dependent.
Since what you really want is a clone of the document element anyway, it sounds like you may be better off cloning that rather than the Document:
oParent.documentElement.appendChild(vehicleDOM.documentElement.cloneNode(true));

setting innerHTML property breaks references to child elements

The issue is similar to the one described here, as far as I can tell. However, I am not using mootools and my question and results are different.
This is a test page to demonstrate the issue: http://jsfiddle.net/S7rtU/2/.
I add elements to a container using createElement and appendChild. As I add each, I also store a reference to it in a private array (elems).
Then, I decide to clear the container, and do so by setting container.innerHTML = ''.
(In my example, I set it first to a pending message, and then 3s later, using setTimeout, I clear it. This is to give time to observe the changes to the DOM.)
Then, I try to repopulate the container from the elems array, calling container.appendChild for each of the stored elements.
I have tested on the browsers I have at hand: Firefox 17.0.1, Chrome 23.0.1271.97, Safari 3.1.2, IE 6 and IE 7. All except IE 6 & 7 will actually restore those elements. So they are successfully stored in memory and references not destroyed. Furthermore, the event handlers registered to those elements still work.
In IE, the elements do not reappear.
What I have read about this issue, including the other SO question, seem to suggest that references are supposed to be broken when you modify innerHTML on the container. Event handlers are also supposed to be broken. However the 3 modern browsers I tested do not break the references, nor the event handlers.
Of course, to make this work in IE I can use something like this, but this is significant extra processing if there are lots of elements:
function explicitClearContainer() {
var e;
// Explicitly remove all elements
for (var i = 0; i < elems.length; ++i) {
e = elems[i];
// Update the reference to the removed Node
elems[i] = e.parentNode.removeChild(e);
}
}
My question is what is known about this behaviour, what can be expected in different environments, what are the pitfalls of using this sort of technique?
I would appreciate any comments.
The innerHTML property was only "standardised" in HTML5, which really just documents common browser behaviour for many features. Things such as innerHTML have been implemented differently in different browsers and will continue to be different for some time, so best to avoid using it if it's causing problems.
There are other approaches to clearing the child nodes of an element, e.g.:
function removeContent(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
Which should avoid your issues with innerHTML and is a bit less code than your version. You can also replace element with a shallow clone of itself, but that may cause other issues.

`clone()` not working in Internet Explorer 6

I was trying to clone an element and append it to another child with following statement of jQuery:
$(userListJId).clone().appendTo(tempOwnJString);
Where userListJId and tempOwnJString are the id's of elements.
The above line of code works fine in Internet Explorer 7 and higher versions of it but does not seem to be working in Internet Explorer 6.
What could be the possible reason?
I used clone() on IE6 and so that should not be the problem.
Maybe you are creatong invalid HTML and IE6 which is less permissive than IE7 complains about this.
Can you show us your code and also the version of jQuery?
It's funny you should ask this because I had a quite similar problem (though it affected IE7 and probably IE6).
Also, not sure if you have done something special (i.e. defining variables) but perhaps you should refer to the objects as $('#userListJId') instead of just the element name. Again, I can't see the rest of the code, so you may have already defined those variables outside the document.* scope.
Basically, in IE, certain attributes cannot be modified after the object is created, an example being the ID attribute.
The work around is to not clone the object, at least through .clone(), but to take the outer HTML of the object you wish to clone as a string and do a regex .replace() on the id attribute, and then append the modified HTML into tempOwnJString.
Another gotchya in IE, is that sometimes (usually?) when it parses the HTML, it doesn't wrap quotes around attribute values if they contain only alphanumeric characters, so be mindful of this in your regex pattern.
Here is an example of some code I used.
if ($.browser.msie === true)
{
//unfortunately jQuery doesn't have an outerHTML function, so this is a hacky work around
templateHTML = $("#activityTemplate").clone().wrap('<div>').parent().html();
newHTML = templateHTML.replace(/id\=\w+/ig, 'id='+jsonObj.ContactLogID);
$(newHTML).prependTo($("#activityContainer"));
// in case i need to refer to newly created object
clone = $("#"+jsonObj.ContactLogID);
}
Again I can't say for certain if this is the issue you're having but with the information you gave and without any debug info (which IE6 doesn't really provide anyway) this is the best guess.
Echoing what #Foxtrot said, you need to ensure you set the id on the cloned element or you'll freak IE6 out. Afterall, all browsers follow the standard that ids must be unique. Their behavior when you violate this varies. You are experiencing variation.
As a trivial example:
var clone = $(userListIJD).clone();
clone[0].id = 'somethingElse'; // use a formula here, as presumably this is run over and over
// proceed with appending the clone

Safari Native Code

Is anyone familiar with Native Code in OS X Safari (Version 3 and WebKit)? I'm using Javascript to parse some information in a form and one of my inputs is named "tags". When trying to get the value of that element using:
// button is being passed through a function as a DOM object
var tags = button.form.elements["tags"].value;
Safari returns some kind of function. I've gotten it to alert values like "function tags() { [native code] }" and Node Trees but I just can't understand why I would be having trouble. If anyone has a clue, please let me know. I've gotten it to work by changing the name of the input to something else and also by iterating through all elements and using if () statements to determine whether it's the element I want, but I'm awfully curious as to why Apple would restrict the use of any form element named "tags"...
P.S. - It's test and works fine in firefox.
[native code] just means that it's a function that is built in to the browser, rather than written in JavaScript. tags appears to be a WebKit extension to the DOM to allow you to get a list of elements in the form by tag name. For instance, if I run this on the StackOverflow page, I get the answer text area:
document.getElementById('submit-button').form.elements.tags("textarea")[0]
The issue is that an index into a collection in JavaScript also access any object properties (including methods), so when you try to access your named element tags, you get instead the method on the elements object that WebKit defines. Luckily, there is a workaround; you can call namedItem on the elements list to get an item by id or name:
var tags = button.form.elements.namedItem("tags").value;
edit: Note that its probably better to use namedItem in general even in other browsers, in case you need to retrieve an element named item or length or something like that; otherwise, if you use them as an index with the [] operator, you'll get the built in method item or length instead of your element.

Override members on a built-in JavaScript object

I would like to override the default behavior of the offsetParent member of all html elements. I would like to do something like this if it's possible:
// For <div id="foo"></div>
var oFooElem = document.getElementById("foo");
oFooElem._offsetParent = oFooElem.offsetParent;
oFooElem.prototype.offsetParent = function() {
window.status = 'offsetParent called.';
return this._offsetParent;
};
Is this even possible? If so, please post the corrected code sample. Thanks!
Update:
#some Thank you for your help. It sounds like this is not possible. I have expanded on the problem that provoked this question in a new question if you're interested.
As far as I know it is not possible.
In firefox I get exception "setting a property that only has a getter", IE gives error, Chrome gives error, but in Opera it works (if I assign it on the element, not the prototype)!
But you have another problem. offsetParent isn't a function so it will never be called like a function and your alert will never happen. In opera (the only browser I found where you could replace it in) you only get the function back.
You can however add a new function (will work in Firefox, Chrome and Opera but not in IE since IE don't have the constructor property):
var e = document.getElementById("mydiv"); //Get a div element
//Adds a _offsetParent function to all DIV elements.
e.constructor.prototype._offsetParent=function(){
alert("offset parent called"); return this.offsetParent;
};
e._offsetParent();
Update
By reading your description here I see your error:
you get a reference to the object
called myInnerContent
you remove that object from the DOM when you replace the content of the outer tag.
you try to get the parent from the old object who is orphan and
that no longer are in the DOM. IE gives you an Error and Firefox gives you null.
You already have the solution on your page: Save the name of the object. Optionally you can choose to update the global variable when you update the content, or only update the innerHTML of the inner div.

Categories