Get the position(index) of an element in the parent - javascript

I want to get the position of a an element in its parent. For example
<div>
<h2 class="one">A</h2>
<span>Something</span>
<h2 class="two">B</h2>
<h2 class="three">C</h2>
</div>
Now suppose I get a reference of h2.two $('h2.two'); in an event. I want the position of this element relative to other h2's in the div. In this case it is 2. and please don't tell me I can get it through the classname, because there won't be these classnames. Its just for explanation.
NB: I want its position in the list of h2, basically in $('h2.two').parent().children('h2') not all elements
function buildPath(element)
{
var Xpath,position=-1;
element=$(element);//Just in case;
Xpath=getTagName(element);
parent=element.parent();
console.log(parent.children(Xpath));
var position = element.siblings(Xpath).element.index(element);//I want the position here
Xpath="/"+Xpath+"["+position+"]";
console.log(Xpath);
console.log(getTagName(parent));
if (getTagName(element)=='body')
return Xpath;
}

var $theH2 = $('h2.two');
var index = $theH2.siblings("h2").andSelf().index($theH2);
Here is a working example:
http://jsfiddle.net/Bm6Wd/
Click on an h2 and it will alert the index.

Related

Individually change element inside of a class through their ID [duplicate]

I am wanting something similar to this person, except the element I want to match might not be a direct sibling.
If I had this HTML, for example,
<h3>
<span>
<b>Whaddup?</b>
</span>
</h3>
<h3>
<span>
<b>Hello</b>
</span>
</h3>
<div>
<div>
<img />
</div>
<span id="me"></span>
</div>
<h3>
<span>
<b>Goodbye</b>
</span>
</h3>
I would want to be able to do something like this:
var link = $("#me").closestPreviousElement("h3 span b");
console.log(link.text()); //"Hello"
Is there an easy way to do this in jQuery?
EDIT: I should have made my specification a little bit clearer. $("#me") may or may not have a parent div. The code should not assume that it does. I don't necessarily know anything about the surrounding elements.
var link = $("#me").closest(":has(h3 span b)").find('h3 span b');
Example: http://jsfiddle.net/e27r8/
This uses the closest()[docs] method to get the first ancestor that has a nested h3 span b, then does a .find().
Of course you could have multiple matches.
Otherwise, you're looking at doing a more direct traversal.
var link = $("#me").closest("h3 + div").prev().find('span b');
edit: This one works with your updated HTML.
Example: http://jsfiddle.net/e27r8/2/
EDIT: Updated to deal with updated question.
var link = $("#me").closest("h3 + *").prev().find('span b');
This makes the targeted element for .closest() generic, so that even if there is no parent, it will still work.
Example: http://jsfiddle.net/e27r8/4/
see http://api.jquery.com/prev/
var link = $("#me").parent("div").prev("h3").find("b");
alert(link.text());
see http://jsfiddle.net/gBwLq/
I know this is old, but was hunting for the same thing and ended up coming up with another solution which is fairly concise andsimple. Here's my way of finding the next or previous element, taking into account traversal over elements that aren't of the type we're looking for:
var ClosestPrev = $( StartObject ).prevAll( '.selectorClass' ).first();
var ClosestNext = $( StartObject ).nextAll( '.selectorClass' ).first();
I'm not 100% sure of the order that the collection from the nextAll/prevAll functions return, but in my test case, it appears that the array is in the direction expected. Might be helpful if someone could clarify the internals of jquery for that for a strong guarantee of reliability.
No, there is no "easy" way. Your best bet would be to do a loop where you first check each previous sibling, then move to the parent node and all of its previous siblings.
You'll need to break the selector into two, 1 to check if the current node could be the top level node in your selector, and 1 to check if it's descendants match.
Edit: This might as well be a plugin. You can use this with any selector in any HTML:
(function($) {
$.fn.closestPrior = function(selector) {
selector = selector.replace(/^\s+|\s+$/g, "");
var combinator = selector.search(/[ +~>]|$/);
var parent = selector.substr(0, combinator);
var children = selector.substr(combinator);
var el = this;
var match = $();
while (el.length && !match.length) {
el = el.prev();
if (!el.length) {
var par = el.parent();
// Don't use the parent - you've already checked all of the previous
// elements in this parent, move to its previous sibling, if any.
while (par.length && !par.prev().length) {
par = par.parent();
}
el = par.prev();
if (!el.length) {
break;
}
}
if (el.is(parent) && el.find(children).length) {
match = el.find(children).last();
}
else if (el.find(selector).length) {
match = el.find(selector).last();
}
}
return match;
}
})(jQuery);
var link = $("#me").closest(":has(h3 span b)").find('span b').text();

How to delete current element if previous element is empty in jquery?

I want to delete element with class "tehnicneinfo" but only if the element I'm checking ( with class "h2size") has no child. I have a bunch of those elements, generated by a plugin and I want to delete only the ones that have the next element without child. I wrote jquery code, but it delets all of my elements, not only the ones that have the next element without child. Here is my jquery code:
$('.news .h2size > div').each(function() {
var ul = $(this).find('ul');
if(!ul.length) $(this).remove();
var h1 = $('.news').find('.tehnicneinfo');
var h2size = $('.news').find('.h2size');
if(h2size.prev().is(':empty'))
{
h1.remove();
}
});
this code is inside $(document).ready(function(). Can you tell me what I'm doing wrong? The code is for something else also, so I'm having truble only from var h1 = $('.news').find('.tehnicneinfo'); this line on. Thanks in advance!
Html:
<div class="news">
<h1 class="tehnicneinfo">xxx</h1>
<div class="h2size">
<div id="xyxyxy">
.......
</div>
</div>
<h1 class="tehnicneinfo">yyy</h1>
<div class="h2size"></div>
....
</div>
That's the html, only that there is like 20 more lines that are the same, but with different values (not yyy and xxx). I would need to delete all 'yyy' (they are not all with same value).
You can use filter to filter the ones you want to remove then remove them
"I want to delete only the ones that have the next element without child"
$('.tehnicneinfo').filter(function(){
return !$(this).next().children().length;
// only ones with next sibling with no children
}).remove();
JSFIDDLE

How to wrap the content of DOM Element into another Element with minimal performance overhead?

I would like to wrap the live content of a DOM element into another, keeping all the structure and all attached event listeners unchanged.
For example, I want this
<div id="original">
Some text <i class="icon></i>
</div>
to become
<div id="original">
<div id="wrapper">
Some text <i class="icon></i>
</div>
</div>
Preferably without jQuery.
If there is nothing else other than ID to distinguish your nodes, and given that #original has multiple child nodes, it would probably be simpler to create a new parent node and insert that:
var original = document.getElementById('original');
var parent = original.parentNode;
var wrapper = document.createElement('DIV');
parent.replaceChild(wrapper, original);
wrapper.appendChild(original);
and then move the IDs to the right place:
wrapper.id = original.id;
original.id = 'wrapper';
noting of course, that the variables original and wrapper now point at the 'wrong' elements.
EDIT oh, you wanted to leave the listeners attached... Technically, they still are, but they're now attached to the inner element, not the outer one.
EDIT 2 revised answer, leaving the event listeners attached to the original element (that's now the outer div):
var original = document.getElementById('original');
var wrapper = document.createElement('DIV');
wrapper.id = 'wrapper';
while (original.firstChild) {
wrapper.appendChild(original.firstChild);
}
original.appendChild(wrapper);
This works simply by successively moving each child node out of the original div into the new parent, and then moving that new parent back where the children were originally.
The disadvantage over the previous version of this answer is that you have to iterate over all of the children individually.
See https://jsfiddle.net/alnitak/d0jss2yu/ for demo
Alternatively, do it this way. It also displays result in the adjacent result div.
<div id="original">
Some text <i class="icon"></i>
</div>
<button onclick="myFunction()">do it</button>
<p type="text" id="result"></p>
<script>
function myFunction() {
var org = document.getElementById("original");
var i = org.innerHTML; //get i tag content
var wrap = document.createElement("div"); //create div
wrap.id="wrapper"; //set wrapper's id
wrap.innerHTML= i //set it to i tag's content
org.innerHTML=""; // clear #orignal first
org.appendChild(wrap); //append #wrapper and it's content
var result = org.outerHTML;
document.getElementById("result").innerText = result;
}
</script>
Updated answer:
This should work better and with less code than my previous answer.
var content = document.getElementById("myList").innerHTML;
document.getElementById("myList").innerHTML = "<div id='wrapper'></div>"
document.getElementById("wrapper").innerHTML = content;
EDIT: This will destroy any event listener attached to the child nodes.
Previous answer:
I don't tried it, but something like this should work:
var wrapper = document.createElement("DIV");
wrapper.id = "wrapper";
var content = document.getElementById("myList").childNodes;
document.getElementById("myList").appendChild(wrapper);
document.getElementById("wrapper").appendChild(content);
Create the wrapper element.
Get myList contents.
Add the wrapper element to myList.
Add myList contents to be child of the wrapper element.

javascript - how to get img tags from any element?

I want to get img tags attribute values from any element, img tags could be more than 1, and also can be randomized.
like,
<div> hellow <img src='icons/smile.png' title=':)'> how are u <img src='icons/smile2.png' title=':D'></div>
I want to grab their title attribute values and then want to store in some var currentHTML; with all existing div data.
and then insert into any element just like $('#div').html(currentHTML);
and output should be like this,
hellow :) how are u :D
How can I do this?
Thanks in advance.
Try this:
$("img").each(function()
{
$(this).replaceWith($(this).prop("title"));
});
Fiddle. Its just looping through each image and replacing it (with replaceWith()) with its own title attribute.
UPDATE:
Things got more complex. Check this snippet:
// The text result you want
var currentHTML = "";
// Instead of search for each image, we can search of elements that
// contains images and you want to get their text
$(".images").each(function()
{
// Check note #1
var cloned = $(this).clone().css("display", "none").appendTo($("body"));
// Here we select all images from the cloned element to what
// we did before: replace them with their own titles
cloned.find("img").each(function()
{
$(this).replaceWith($(this).prop("title"));
});
// Add the result to the global result text
currentHTML+= cloned.html();
});
// After all, just set the result to the desired element's html
$("#div").html(currentHTML);
Note #1: Here is what is happening in that line:
var cloned = here we create a var which will receive a cloned element;
the cloned element will the current element $(this).clone();
this element must be hidden .css("display", "none");
and then appended to the document's body .appendTo($("body"));.
Note that in your initial html, the div containing the images received the class images:
<div class="images"> hellow <img src='icons/smile.png' title=':)' /> how are u <img src='icons/smile2.png' title=':D' /></div>
So you can do that on more than one element. I hope this helps.
Here's a neat little function you can reuse.
$(function(){
function getImageReplace($el) {
var $copy = $el.clone();
$copy.find('img').each(function(){
$(this).replaceWith($(this).attr('title'));
});
return $copy.text();
}
//now you can use this on any div element you like
$('#go').click(function() {
alert(getImageReplace($('div')));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div> hellow <img src='icons/smile.png' title=':)'> how are u <img src='icons/smile2.png' title=':D'></div>
<button id='go'>Convert images</button>

Javascript get class text inside element

I have a bunch of span4 class elements in my html. they look something like this:
<div class="span4">
<div class="widget">
<div class="header">blablabla</div>
</div>
</div>
I want to sort the span4 by that text iside header class.
I do this to sort them
$(".span4").sort(sortAlpha)
but how do I select the text inside the header class?
I'm doing this but I guess there is a better way
function sortAlphaAsc(a,b){
var nomeA = $(a.childNodes[1].childNodes[1]).text();
var nomeB = $(b.childNodes[1].childNodes[1]).text();
return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;
};
there must be a better way than
$(a.childNodes[1].childNodes[1]).text()
var elems = $(".span4");
elems.sort(function(a, b) {
return $(a).find('.header').text().toUpperCase().localeCompare(
$(b).find('.header').text().toUpperCase()
);
});
$(".span4").parent().html(elems);​
FIDDLE
Try this:
function sortAlphaAsc(a,b){
var nomeA = $(a).find('div.header').text();
var nomeB = $(b).find('div.header').text();
return nomeA.toLowerCase() > nomeB.toLowerCase();
};
You could detach the spans, sort and append them.
That will be very fast too as changing elements in memory and only updating the DOM once in the end is very efficient.
var $spans = $(".span4").detach();
var sortedSpans = $spans.sort(function(spanA, spanB) {
var spanTextA = $("div.header", spanA).text();
var spanTextB = $("div.header", spanB).text();
return spanTextA > spanTextB;
});
$("body").append(sortedSpans);
Obviously instead of body you append it back to it's actual container element.
Or if the spans are in a common container store the parent in cache var $parent = $spans.parent() and in the end simply do $parent.html(sortedSpans).
I don't know your whole mark-up but that should get you started.
DEMO - Detach spans, sort them and append again
Do you mean something like this:
$('.span4').find('.header').text();
This will return the text inside the header div.

Categories