Referring to a div inside a div with the same ID as another inside another - javascript

How can I refer to a nested div by id when it has the same id as a div nested in a similarly named div
eg
<div id="obj1">
<div id="Meta">
<meta></meta>
</div>
</div>
<div id="obj2">
<div id="Meta">
<meta></meta>
</div>
</div>
I want to get the innerHTML of meta
document.getElementById('obj1').getElementById('Meta').getElementsByTagName('meta')
doesn't work

IDs should only be used when there is one of that item on the page, be it a SPAN, DIV or whatever. CLASS is what you should use for when you may have a repeating element.
Code there doesn't work because you're referring to an element by unique ID, but have more than one on the page.

Id is supposed to be unique.

Hate to point out the obvious, but in your example, obj1_Meta and obj2_Meta are unique id's, so if it's the case in your working code:
document.getElementById('obj1_Meta').getElementsByTagName('meta')[0].innerHTML;
would work as described. As a double check, did you over think this?
If not, bummer...
As "bad" or "wrong" as your code is, an option that will work is to use a JavaScript framework like jQuery. Once you've included it, you can get elements by passing it a CSS selector (even a semantically incorrect one) like so:
$('#obj1 #obj1_Meta meta').html()
$() is jQuery's way of saying document.getElementById() ...on steroids.
.html() is its equivalent of .innerHTML
Other frameworks, like PrototypeJS and MooTools also provide similar functionality.
Prototype for example:
$$('#obj1 #obj1_Meta meta').innerHTML;//note the double $'s
Frameworks save lots of time and trouble with regard to browser compatibility, "missing" JavaScript methods (like getElementsByClassName) and coding AJAX quickly. These things make them a good idea to use to anyway.

IDs are meant to be unique, use classes intelligently.
<div id="obj1" class="obj">
<div id="obj1_Meta" class="obj_Meta">
<meta></meta>
</div>
</div>
<div id="obj2" class="obj">
<div id="obj2_Meta" class="obj_Meta">
<meta></meta>
</div>
</div>
.obj = targets both elements
#obj1.obj = targets only the first
#obj1.obj_Meta = targets obj1 inner DIV
#obj2.obj = targets only the second
#obj2.obj_Meta = targets obj2 inner DIV

You may also run into problems with this markup because the "meta" tag is only legal inside the head tag, not the body tag. As far as I can tell from looking at Firebug, Firefox will even go so far as to pull those meta tags out of the body and toss them into the head (and, in this case, put any text content inside the parent div), so you won't see them in the DOM at all.

For the HTML you've given, this should work:
document.getElementById('obj1').getElementsByTagName('div')[0].getElementsByTagName('meta');
Just ignore the bogus id on the inner div and get it by tag name. You should also be able to ignore the inner div completely, since getElementsByTagName searches the entire subtree:
document.getElementById('obj1').getElementsByTagName('meta');

As the id attribute is a unique document-wide identifier, you should probably namespace your ids.
<div id="obj1">
<div id="obj1_Meta">
<meta></meta>
</div>
</div>
<div id="obj2">
<div id="obj2_Meta">
<meta></meta>
</div>
</div>
document.getElementById('obj1_Meta').getElementsByTagName('meta')

Related

How can I store "data" attributes in a Node inside a contentEditable container?

I'm making a mention system for comments, similar to facebook's, but I can't figure out how to store mention's ID.
So I have this:
<div contenteditable>
<span data-id="123">Peter</span> is a good person
</div>
However, when looking at the actual HTML generated by the browser, it completely removes the data-id attribute:
<div contenteditable>
<span>Peter</span> is a good person
</div>
What is the right approach here?
data- attributes are visible in the DOM under normal circumstances, and to access them, you need to target the dataset of that element in JS.
E.g.
let div = document.getElementById('span');
console.log(div.dataset);
<div contenteditable>
<span id="span" data-id="123">Peter</span> is a good person
</div>

Need a more elegant way of finding an element in the dom tree with jQuery

I have a few elements flying around in an element that need to be altered when the window finishes loading ($(window).load...)
When the script loads, I've been struggling to find a more elegant way of finding a string.
Noticeably below, you can also see the rampant re-use of parent and next operators...
I've tried closest but it only goes up the dom tree once (from what I understand) and parents has never really worked for me, but I could be using it wrong.
Ex.
$(window).load( function(){
if($(".postmetadata:contains('Vancity Buzz')").length){
$(this).parent().parent().next().next().next().next('.articleImageThumb img').hide();
}
});
HTML output this runs through looks like this:
<div class="boxy">
<div class="read">
<div class="postmetadata">Vancity Buzz</div>
<div class="articleTitle"></div>
</div>
<div class="rightCtrls"></div>
<div class="initialPostLoad"></div>
<div class="ajaxBoxLoadSource"></div>
<div class="articleImageThumb">
<a href="#">
<img src="image.png" class="attachment-large wp-post-image" alt=""/>
</a>
</div>
</div>
I think you want to do this:
$(".postmetadata:contains('Vancity Buzz')")
.closest('.read') //Closest will get you to the parent with class .read
.siblings('.articleImageThumb').hide(); //this will get you all the siblings with class articleImageThumb
this refers to window there not the element you are checking in the if condition.
Fiddle
I don't know if your intention is to have the empty anchor tag just by hiding the image. if so just add a find to it.
You can just do this
$('.articleImageThumb img').toggle($(".postmetadata:contains('Vancity Buzz')").length)
If there are multiple divs and you do need to traverse then there are multiple ways
$(".boxy:has(.postmetadata:contains('Vancity Buzz'))").find('.articleImageThumb img').hide()
or
$('.postmetadata:contains("Vancity Buzz")').closest('.boxy').find('.articleImageThumb img').hide()
or
$(".boxy:has(.postmetadata:contains('Vancity Buzz')) .articleImageThumb img").hide()
Have you looked into parents http://api.jquery.com/parents/ you can pass a selector like so:
$(this).parents('.boxy').find(".articleImageThumb")
Careful though, If there is a parent boxy to that boxy, parents() will return it and thus you find multiple .articleImageThumb.

Clear text inside DIV

I'm using the following HTML structure:
<div id="clock">5:30 AM
<div id="day">Wednesday
</div>
<div id="date">14 December
</div>
</div>
I update the contents of these elements using Javascript. For "day" and "date" I use $("#day").text(day) and $("#date").text(date). Because "clock" is a parent element I had to use $("#clock").prepend(clock) to succesfully add the text.
The problem with the latter function, is that new text is prepended every time the clock is refreshed, i.e. it builds up a list of clock times. For the first two functions the text is just replaced, like it should. Is there a way to make this happen for the "clock" function as well?
EDIT: Sorry, should have been a bit more clear about the clock. Have edited the code, so you understand. BTW, the reason the clock is parent element is that could make the other two elements depend on the clock's position and styling.
I also created a jsFiddle: https://jsfiddle.net/daanodinot/NZtFA/
I left the list building thing (annoyingly) in!
BTW, I'm not too sure if function(); setInterval('function()', 1000) is the best way to refresh, so if you something better I'd be happy to know :)
What you need to do is change the structure of your html to this.
<div id="wrapper">
<div id="clock"></div>
<div id="day"></div>
<div id="date"></div>
</div>
Then for the javascript
$('#clock').text('12:45');
$('#day').text('Wednesday');
$('#date').text('12/14/2011');
This way you can just change/refresh the text of clock instead of prepending values to it.
Another approach, with your current html, which i do not recommend.
<div id="clock">
<div id="day">
</div>
<div id="date">
</div>
</div>
The js
$('#clock').contents().get(0).nodeValue = '12:45';
$('#day').text('Wednesday');
$('#date').text('12/14/2011');
If you have HTML
<div id="clock">
<div id="day"></div>
<div id="date"></div>
</div>
Then you don't have to modify #clock at all. By doing $("#day").text(day) and $("#date").text(date) content of those divs is changed and you don't have to touch #clock.
But in case you want to replace a content of a element then use .html(newContent). See documentation.
You should first add a new element with prepend and then replace it's content, now you just constantly keep prepending new elements instead of working on the same element again.
What do you mean by
Because "clock" is a parent element I had to use
$("#clock").prepend(clock) to succesfully add the text.
?
It seems redundant. Since $('#day') and $('#date') uniquely address your targeted elements.
My tip:
Do not use clock. $("#day").text(day) and $("#date").text(date) already update the numbers inside your #clock element.
Hy,
my consideration for your problem is, IF you choose to manipulate the Content of the #clock div you could simply do this:
var newContent="";//in here comes whatever you want to add to your clock div
$('#clock').html($('#clock').html()+newContent);
That's the way I use it most of the time but you could also do this:
var curContent=$('#clock').html();
curContent+="<>put in your code to add</>";
$('#clock').html(curContent);
This is I guess a bit slower than the first one, but it works.

Jquery .after() not inserting as expected

EDIT: Solution found How to wrap every 3 child divs with html using jquery?
I'm printing a list with a lot of <div>'s and want to insert a </div><div class="clearfix"> after every 6th <div> with jQuery.
Naturally that would be something like
$('#staffscroll .person:nth-child(5n)').after('</div><div class="clearfix">');
But the output becomes <div class="clearfix"></div> which just doesn't make sense.
Any thoughts?
Ok, maybe should provide some more code..
I'm working with a slideshowscript. The whole take is basicly to put stuff in a <div>.
For example..
<div id="slideshow">
<div class="clearfix"> First slide wrapper
<img>
<img>
<img>
<img>
</div>
<div class="clearfix"> Second slide wrapper
<img>
<img>
<img>
<img>
</div>
<div class="clearfix"> Third slide wrapper
<img>
<img>
</div>
</div>
The problem is that I'm working with a CMS aswell, which havn't got that much control over dynamic output. So my thought was that I just could output all the content, and then provide the slide-wrappers afterwards.
Therefore the </div><div class="clearfix">
Havn't got a clue if it makes any more or less sense now, but I hope you get what I'm trying to do.
The statement you try to insert isn't correct XML. You are thinking about your HTML document as a big string, but this is the wrong way to do if you want to use tools like jQuery.
I suggest you to learn more about DOM and how to use it. Your whole approach is wrong, so your sample of code isn't correctable.
IIRC, jQuery parses the string to a DOM fragment and then inserts it. When your </div><div class="clearfix"> is parsed it's assumed the </div> is an error, and it also closes the <div class="clearfix">. Therefore the effect you observed.
That's because after isn't modifying the HTML -- it's creating new DOM elements and adding them to the document. You should use wrapAll to wrap a group of elements. My guess is that your code will look something like this:
var start = 0,
$list = $('#staffscroll .person').slice(0, 6);
while ($list.length) {
$list.wrapAll('<div class="clearFix"></div>');
start += 6;
$list = $list.end().slice(start, start + 6);
}
jsFiddle working example
As I replace the .wrapAll for .append or a similiar?

jquery-how to detect child id?

<div id="first">
<div id="here">...</div>
</div>
<div id="second">
<div id="here">...</div>
</div>
jquery:
$("#second #here").click(function(){});
how to write jquery to detect when I click the second ?
This is the wrong question to be asking, because you are not supposed to have duplicate IDs in a document. An ID is like the social security number of an element. You can't give multiple elements the same one, because then when you tell Javascript to find an element by ID it will be terribly confused by the fact there's more than one and give you unexpected results. The reason ID lookups are as fast as they are is because the browser can have a hash table of ID->element - violating that understanding is a bad practice, to say the least.
When you have several elements that are all of the same "type", the proper practice is to class them:
<div id="first">
<div class="here">...</div>
</div>
<div id="second">
<div class="here">...</div>
</div>
So then you can do:
$('#first').find('div.here');
Or:
$('div.here', '#second');
Or:
$('#first div.here');
Which would all return what you expect them to return.
This is what you are looking for, but like Paolo said, you cannot have duplicate ID's. If you're styling things, use a class.

Categories