can we pass DOM elements using postMessage? - javascript

I have 2 iframes on a page and I am trying to pass DOM element from one iframe to another using postMessage. But chrome keep giving me error:
"DataCloneError: An object could not be cloned. "
Is there a way around this issue ?

According to the spec, you can't send DOM nodes and it will throw an error.
Messages can be structured objects, e.g. nested objects and arrays, can contain JavaScript values (strings, numbers, Date objects, etc), and can contain certain data objects such as File Blob, FileList, and ArrayBuffer objects.

You might try with innerHTML, which "gets or sets the HTML or XML markup contained within the element." (https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)
With innerHTML you can pass element's content as a string, and then, in the other iframe, insert that content, again with innerHTML.
In this answer there is a simple way to get the innerHTML content of a node:
https://stackoverflow.com/a/1750860/1401341
You won't get events attached to the element, but in some cases this method could be enough.

Related

convert HTML DOM element to JavaScript Object?

I have a web page with the element:
<div id='myid'></div>
In chrome dev tools, when I type in the console
document.getElementById('myid')
returns a html element,
<div id='myid'></div>
is there an alternative method I can use to view it and it's properties as a JavaScript object instead rather than a html element?
convert html to javascript
I have seen this post, but all I want to do is get the element, not do any parsing and build something new and ideally in dev tools.
is there an alternative method I can use to view it and it's properties as a JavaScript object instead rather than a html element?
all I want to do is get the element, not do any parsing and build something new and ideally in dev tools
Yes if you are only interested in the dev tools (console), you can always use console.dir() method, it's made for this:
console.dir(document.getElementById('myid'));
console.dir() method:
Displays an interactive list of the properties of the specified JavaScript object. The output is presented as a hierarchical listing with disclosure triangles that let you see the contents of child objects.
Would do something like using the Document Element interface to access the array of attributes / properties.

How jQuery data() breaks circular reference

I have read an why it's better and how it's implemented. But what i don't really understand is how does it break the circular reference?.
how does it break the reference circle?
$(div1).data('item', div2);
$(div2).data('item', div1);
like example, the divs above point to each other, how is it prevented? I have a hunch, but i just want to make sure if my hunch is right.
The circular reference problem happens in some browsers when you put a reference to a DOM object on a DOM object as a property on that DOM object. Then, you have two DOM objects pointing at each other. Removing a DOM object with a custom property on it doesn't clear that custom property. A garbage collector that isn't that smart doesn't realize that this DOM reference doesn't count so it gets stuck and there are several ways that this can lead to leaks.
.data() solves this problem because the .data() data is NOT on the DOM object. It's just a javascript data structure that can be associated with the DOM object via a unique string ID.
The one confusing part of this is that when you read with .data("key") and the key isn't found in the javascript .data() data structure, then and only then, jQuery will look for an attribute on the DOM object called "data-key". But whenever you write with .data("key", "myData"), it never writes to the DOM object, only to the javascript data structure.
Thus, since .data() never writes the data to the DOM object, there can't be any of these types of circular references that some browsers have trouble with.
There are some other useful things to know about the .data() data structure. When you use jQuery's .remove() to remove elements from the DOM or when you call $(elem).html("new html"), jQuery clears the .data() data on any removed items. This is one case where it's good not to mix jQuery with plain javascript. If you're using .data(), then you should always remove items from the DOM using jQuery functions so .data() is cleaned up appropriately. Otherwise, you can get memory leaks this way (both the .data() data can leak and any removed DOM objects that are referenced in the .data() can leak. But, if you only use jQuery methods for removing items from the DOM (including the replacing of innerHTML), then jQuery will clean things up appropriately and there will be no leaks.
So, for example, this will create a memory leak:
// suppose elem is a DOM element reference
// store some data in jQuery's data storage on behalf of a DOM element
$(elem).data("someKey", "someValue");
// remove DOM element with plain Javascript
elem.parentNode.removeChild(elem);
Because you removed the DOM element with plain Javascript, jQuery did not have a chance to clean up the data you previously stored. The DOM element itself will be garbage collected, but the .data() value you previously stored is now orphaned in jQuery's storage and is essentially a "leak" as it will likely never be cleared. On the other hand, if you do this:
$(elem).data("someKey", "someValue");
$(elem).remove();
Then, jQuery will see that you're removing the DOM element and will also clear the data you stored with .data().
A fairly simple way to see how it works is to create a couple line script with a non-minimized version of jQuery and then just step through a call to $(elem).data("key", "whatever") in the debugger and watch how it works.

How do you move html from one div to another with Jquery without breaking javascript

I have two divs for different sections of my webpage, a working and a reference section. One is fixed size, the other is variable sized and they are vertically stacked. I am trying to design it so that if you want to work on something in the reference pane, you click a link and it swaps all the data between the two panes. My idea was to do the following:
var working = $("#working_pane").html();
var ref = $("#reference_pane").html();
$("#working_pane").html(ref);
$("#reference_pane").html(working);
The problem with this, is it seems that any javascript referenced inside of these panes (for example, in place editors) get broken upon switching. No javascript errors occur, it's just that nothing happens, like the javascript ties are broken.
Is there any to move the html without breaking the javascript contained?
When you are working with bits of an HTML document, you should aim to work with the Node objects that are the content as the browser sees it, not HTML strings.
To get HTML the browser has to look at the Nodes and serialise them to a string. Then when you assign that HTML to another part of the document (with innerHTML or jQuery html(...)), you are telling the browser to destroy all the content that was previously in the element, laboriously parse the HTML string back into a new set of Node objects, and insert these new Nodes into the element.
This is slow, wasteful, and loses any aspect of the original Node objects that can't be expressed in serialised HTML, such as:
event handler functions/listeners (which is why your editors are breaking)
variable references other JavaScript code has to the Nodes (also breaks scripts)
form field values (except, partially, in IE due to a bug)
custom properties
So — and this applies whether you're using jQuery or the plain DOM — don't throw HTML around! Take the original node objects and insert them into the place you want them (they'll leave the place they originally were automatically). The references stay intact so scripts will keep working.
// contents() gives you a list of element and text node children
var working = $("#working_pane").contents();
var ref = $("#reference_pane").contents();
// append can be given a list of nodes to append instead of HTML text
$("#working_pane").append(ref);
$("#reference_pane").append(working);
This could be happening maybe as a result of duplicate ids. basically you may have element a in a div which has the id=id1 now this gets stored in a var and gets injected into a new div. now currently seems you have no mechanism for making sure you do not have duplicate ids at the same time. this can break js
So look into this and if you do make sure elements are first stored in a var then the originals are removed and then appended into a new location.

What's the best way to get a list of the contents of a specific group of DOM elements in javascript?

The basic scenario: I've got a series of elements on an HTML page, generated dynamically. (Currently, they're all divs, but they don't need to be.)
What I want is a javascript function that will loop though all of those divs (or whatever) looking for the presence of a specific value.
What's the best, most cross-browser way to do this? Does getElementsByName() work on divs in all browsers? Can I give them all the same ID and get an array back out of getElementById somehow?
If I change those divs to spans or inputs, does that make things easier?
Thanks!
(edit: it would be best, for this project, if there was a solution without using any external js libraries. I assume jQuery has a function that does just this in one line, but for the moment I'd like to avoid opening that can of worms with the client.)
getElementsByTagName is defined in DOM Core, so any browser which implements that works. That's about every browser in current use.
Take a gander over here for the specifics: http://www.quirksmode.org/dom/w3c_core.html
One gotcha to be ware of, is that getElementsByTagName returns a NodeList - not an array. It works the same, but it is evaluated very late, so if you add/remove nodes to the DOM while traversing a NodeList, you will get weird results. In these cases, write two loops; First loop through the NodeList and store all entries in an array - Then loop through the array.
It doesn't matter what the elements are, but what does matter is where they are in the page. If they are all child elements of a single parent element, your problem is simple. Give the parent element an ID and you can use getElementById() to grab it and iterate its children.
getElementById() behavior is undefined when more than one instance of an ID is found in the document. Most will return the first Element they can find, but you certainly can't cound on getting an array.
getElementsByTagName() will work only if you can use some obscure tag that you are sure won't appear elsewhere in your page. You could augment this by specifying that the elements you are interested in will have an attribute present that you can check for (such as #class or #title). You can then loop through the result of getElementsByTagName() checking for this and only look at Elements where the attribute is present.
You can use this site to see what getElementBy most suites your needs.
There are some using libraries and some like troelskn wrote that apply for standard javascript in all supporting browsers.

How efficient is element.cloneNode(true) (deep clone)?

I'm building the HTML code within an XML DOM object to be used as the contents of the innerHTML of a div element using an XSL template. Traditionally we create a new XML DOM document and add the input parameters as XML Elements for the transform via javascript. This is all very time-consuming as we are basically hand picking the data from another XML document that represents our current account and copying the data into a transient XML DOM document.
What I'd like to do is clone the relevant node of the account document (i.e. customer info) and use it as the basis for the transform. I don't want to use the account document directly as I'd like to be able to add transform specific input, without making changes to the account object.
How efficient is using .cloneNode(true) for a desired node of about typically less than 200 elements from a document of typically 2000+ elements? The target platform is IE6 with no external tools (i.e. ActiveX).
CloneNode is pretty efficient but it will be consuming more memory doing it that way.
Another approach to consider is to use a Template object and a processor, pass your additional/changed data as parameters to the processor and the element that you would have otherwise cloned as the input element. This approach would require fairly significant mods the XSL though.
IE will fail on certain things.
e.g. checked radio/checkboxes will not be checked when you add your copy to the DOM.
Example:
http://webbugtrack.blogspot.com/2008/03/bug-199-cant-clone-form-element-in-ie.html
http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html
To see what IE will actually return, try replacing the url with this in the Address Bar of one of your pages, and press enter.
javascript:'<xmp>'+window.document.body.outerHTML+'</xmp>';
If you are happy with the results, great!, but I think you'll end up less than satisfied at what IE returns (both in the DOM, and this "string" value equivelant.
If you don't need form-elements, cloneNode is a real reliable tool ...
-- and in inserting ajax-data it is incredible in efficiency ...
However, as especially IE has a history of having problems with name-attributes, it is inconvenient to address any of these if you insert data ...
-- I don't really understand your XSL(T)-using, to me it sounds like using a gas-station as a (not !-) convenient place to change a 1960 WV to a 2008 Skoda ...
Userely they have some common technology, though it is not used in the same way, computerization in some way is just a minor problem, the major problems is in nearly any other way !o]
Have you got any need for form-elements ?-)

Categories

Resources