How can I find out which FORM an HTML element is contained within, using a simple/small bit of JavaScript? In the example below, if I have already got hold of the SPAN called 'message', how can I easily get to the FORM element?
<form name="whatever">
<div>
<span id="message"></span>
</div>
</form>
The SPAN might be nested within other tables or DIVs, but it seems too long-winded to iterate around .parentElement and work my way up the tree. Is there a simpler and shorter way?
If it wasn't a SPAN, but an INPUT element, would that be easier? Do they have a property which points back to the containing FORM? Google says no...
The form a form element belongs to can be accessed through element.form.
When the element you are using as reference is not a form element, you'd still have to iterate through the parentElement or use some other kind of selector.
Using prototype, you could simplify this by using Element.up():
$(element).up('form');
Other answers to this question have pointed out how to do the same in jQuery.
Why not just use:
var nodesForm = node.form;
?
It works on FF3, FF4, google chrome, Opera, IE9 (I tested myself)
Guess you have to iterate through all elements then.
You can try using jQuery:
$("input").parent("form")
http://docs.jquery.com/Traversing/parent#expr
Regarding Gumbo's Post:
As much as prototype and jQuery are useful, some people don't implement them into their projects.
Could someone please explain why Gumbo's solution was downgraded, other than the fact that he repeated what the OP was originally trying to avoid?
node = document.getElementById(this.id);
while (node.nodeName != "FORM" && node.parentNode) {
node = node.parentNode;
}
To answer the OP's question:
Traversing the DOM is the fastest way to achieve this effect - perceived speed is accomplished by 1) better written JS code, or 2) execution time (if you store the form on page load for that element, you'll still be traversing, but you'll have a quicker call to a stored variable when you need to retrieve that information).
There are no attributes nested in non-form elements that would associate it with the form (span.form does not exist).
If you are using a script (php/perl) to generate your page, and you're going to be making a lot of calls to the form, you could embed the form id in the HTML for that element. Still, a look up would need to occur.
I hope this helps,
vol7ron
You could backtrack in the DOM tree until you get to the right node:
node = document.getElementById("message");
while (node.nodeName != "FORM" && node.parentNode) {
node = node.parentNode;
}
Or a small jQuery (ignoring jQuery itself):
$("#message").parents("form:first")
Other than node.parentNode, I don't believe there is a way to find a specific ancestor of a given node. Most libraries usually do what you describe and iterate up through parentNode.
If you're not using a library like prototype, jquery or Ext, it would probably be a good idea. By now, they've resolved all the incompatibilities and quirks in the DOM to make most operations like this a trifle.
Related
I wish to implement the following Javascript function:
function AllToDom(partsArray)
{
// Magic!
}
// Called like:
var rowObject = AllToDom(['<tr>', tdElem1, tdElem2, '<td>XXX</td>', '<td>',
divContents,'</td></tr>']);
// Where tdElem1, tdElem2, divContents are DOM node objects.
The thing is I want it to work on any kinds of combinations of DOM nodes and HTML fragments. As long as it produces a valid HTML of course. Unclosed HTML tags and disallowed element combinations (like <table><div></div>) are allowed to have undefined behavior.
My first idea was to concatenate it all in a HTML string, except in place of DOM elements add a placeholder comment <!--SNOOPY-->. So the above would result in the following string:
<tr><!--SNOOPY--><!--SNOOPY--><td>XXX</td><td><!--SNOOPY--></td></tr>
This is already a valid piece of HTML, so next I create a <div>, assign this to innerHTML, gather the produced DOM nodes, and iterate through them and replace all <!--SNOOPY--> with the respective DOM element.
There are two flaws with this approach however:
Adding a <tr> as a child element to a <div> is invalid. I don't know if it might not break on some condition.
Internet Explorer 8 (the least version that I need to support) strips all comments when assigning to innerHTML.
Are there any workarounds? Is this possible at all?
Finally found an answer: jQuery has already done all the dirty work in their parseHTML() method. And I just happen to be using jQuery anyway, so good for me! :)
I checked what the magic was behind the scenes, and it's really pretty gruesome. First, they inspect the HTML (with regexs...) to see what parent tag they need to use, and then they have a workaround for IE8, which apparently it DOES preserve comment nodes - but only if they come after a text node. All comments before the first text node are lost. And some tags are affected this way too, which I had no idea about. And then there's half a dozen other workarounds for IE & Webkit problems that I've never even heard of.
So, I'm just going to leave it to them to do the right thing, because trying to reproduce that stuff would be madness.
I'm looking for a solution to a little problem I have, currently I'm looking to get the entire DOM tree from an element (e.g. all the parents), which I can do using .closest('body').first().
The problem is I'm looking for a way to go through each element and parent and remove all of the text/html from them except the original target, so basically have a blank tree but have html in the bottom element.
Although I haven't tried it yet, I was thinking just .each() might work, although something tells me it would have a problem with the nested structure?
Any advice would be great!
Thanks
Dom
UPDATE:
Accepted answer works great! I adapted the code and added to the fiddle below to allow it to work with deep nested structures like the ones I was working with...
Fiddle here: http://jsfiddle.net/RDNTc/2/
That script remove every text nodes of the parent of the target :
$('p').parentsUntil('body').each(function(){
$(this).contents().each(function(){
if(this.nodeType === 3) this.parentNode.removeChild(this);
});
});
http://jsfiddle.net/RDNTc/;
You can traverse up the parents in jQuery using .parents(). Then use .each() to iterate over them in a loop.
Whenever I want to find if an element exist in the DOM I use the following code.
if($('#target').length){
// do stuff.
}
This works well and I use it quite a lot on client sites.
Question:
How fast is this method? What are the speed implications when this is used a lot in a project?
You would be much better off using if(document.getElementById('target')) instead. JavaScript is always faster than jQuery (since jQuery is just a bunch of JavaScript hidden under the carpet)
EDIT: If you use it a lot, you can make a custom function:
function idExists(id) {return !!document.getElementById(id);}
Native JS is always faster than a query through jQuery. It just may not be as friendly.
After running a query through jsperf.com, native (querySelectorAll) is 57% faster than jQuery
However, if you use id, jQuery will be faster than querySelectorAll. In any case of id, use document.getElementById to test for an elements existence.
http://jsperf.com/jquery-obj-length
Try searching a DOM element with JQuery context say:
if an element u search say, an Input control, lies with in a table, pass table as your context:
A simple example:
$(function(){
var name= $('#Name','#mytab').val();
alert(name);
});
the jquery engine find the element 'Name' with in 'mytab' and not the entire form
follow this fiddle link : http://jsfiddle.net/NzbJr/10/
I've a jQuery object and I shall retrieve the next sibling node, which may be a text node.
For example:
<div id="test">some text<br/>other text</div>
var test = $("#test");
var br = $("br", test);
alert(br.next().length); // No next ELEMENTS
alert(br.get(0).nextSibling.nodeValue); // "other text"
alert(br.get(0).nextSibling.nextSibling); // null
The DOM level 2 allows to get the next NODE sibling, but jQuery next() works on elements (nodeType 1, I guess).
I am asking this because I'm already using jQuery and I prefer to don't touch the DOM nodes directly (also because jQuery itself may provide a layer of abstraction from DOM and may run where DOM level 2 is not supported, but this is only a thought).
If jQuery doesn't provide this, shall I use DOM like above, or there are better options?
EDIT: I forgot something: I don't want to get ONLY text elements, but any kind of node, just as nextSibling does.
I'm using .contents() to iterate over the content, but this is pretty annoying (and slow, and many other bad things) when you just need the next node and DOM provides a solution.
EDIT2: Looking jQuery source code, it seems it relies on nextSibling.
Use the DOM. Don't be scared of it; it's easy and you already seem to know what to use. jQuery is built on top of the DOM and for this kind of thing, using the DOM will in fact work in more browsers than the jQuery version.
To my knowledge, there is no method in jquery like nextSibling in javaScript which also returns text elements.But you can go to the parent element and use contents() as it will also consider text elements.
So i got this snippet of code:
$(document).ready(function () {
var replacementDoneIn = $("body").html();
var regExMatch = /premier(( {1,5}?)?co(mpany)?([ |\.])?)?/ig;
var replaceWith = "Nikon";
var resultSet = replacementDoneIn.replace(regExMatch, replaceWith);
$("body").html(resultSet);
});
which is some what working for me, but it does not cover more robust and complicated scenario.
I would like to expand find/replace capabilities with a help of jQuery. To properly utilize find/replace of the text inside of the body element excluding any html elements and any attributes and their values.
note: Not being completely certain on how jQuery text() function traverses children of the element it is applied on to.
note: as far as i understand i can loop through all elements in html via $("*"), but does that create any issues for such script
so if you could direct me to the right path, it would be greatly appreciated. Links to resources that address this already, your advices, all will work. Because for some reason my head produces only complicated solutions, so I am wondering may be there are simpler approach.
Thank you in advance.
Check my answer to this question:
How to replace text in html document without affecting the markup?
I posted a simple function that traverses text nodes, replacing its content, without affecting the markup or JavaScript connected event handlers.
If I understand your question correctly, using text() will be the way to go. It includes only the text nodes of of an element and any descendents of that element. So doing
(document.body).text();
will get you the text of all elements contained within the body of the document. Using your regular expression against this should achieve what you need.