Jquery .after() not inserting as expected - javascript

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?

Related

Remove style attribute from all descendants in jquery

I'm brand new to javascript/jquery, but have been going okay so far (though you'd hate to see my code), but I've hit a wall with trying to strip out style tags from some HTML I'm trying to clone.
The reason for cloning is that the CMS I'm forced to use (which I don't have access to code behind, only able to add code over the top) automatically builds a top nav, and I want to add a duplicate sticky nav once the user scrolls, but also add a couple of elements to the scrolled version.
The original HTML of the top nav looks a bit like like:
<nav id="mainNavigation" style="white-space: normal; display: block;">
<div class="index">
Participate
</div>
<div class="index" style="margin-right: 80px;">
News
</div>
<div class="index active" style="margin-left: 80px;">
<a class="active" href="/about/">About</a>
</div>
<div class="external">
Collection
</div>
<div class="index">
Contact
</div>
</nav>
I had mild success (other than those style tags I want to remove) with the following, even though it doesn't seem to make sense to me, as I expected some of the elements would be repeated (the whole < nav >…< /nav > tag should have been within the #mainNavigation clone, no?):
var originalNavItems = $('#mainNavigation').clone().html();
$("#site").prepend('
<div id="ScrollNavWrapper">
<div class="nav-wrapper show-on-scroll" id="mainNavWrapper">
<nav id="newScrolledNav" style="white-space: normal; display: block;">
<div class="index home">
Home
</div>
' + originalNavItems + '
<div class="newItem">
<a href="http://www.externalsite.com">
View on External Site
</a>
</div>
</nav>
</div>
</div>');
I've tried to use a few answers from related questions on here, but I keep getting incorrect results. Can you help me?
You can strip the style elements like so:
var el = $('#mainNavigation'); // or whatever
el.find('[style]').removeAttr('style');
You can use
var originalNavItems = $('#mainNavigation').clone().find("*").removeAttr("style");
Then you can use .append() to add that html elements
Fiddle
You can clone into an imaginary div and then fetch the mainNavigation also. You can also remove the style attributes along with that. Hope this works for you...
var temp = $('<div />').html($('#mainNavigation').clone());
temp.find('*').removeAttr('style');
originalNavItems = temp.html();
The nav is cloned but the html() function only returns the HTML for the contents and that's why it disappears. You can avoid some string manipulation by adding the cloned element directly before a target element.
$("#site").prepend('
<div id="ScrollNavWrapper">
<div class="nav-wrapper show-on-scroll" id="mainNavWrapper">
<nav id="newScrolledNav" style="white-space: normal; display: block;">
<div class="index home">
Home
</div>
<div class="newItem">
<a href="http://www.externalsite.com">
View on External Site
</a>
</div>
</nav>
</div>
</div>');
$('#mainNavigation').clone()
.find('[style]').removeAttr('style').end()
.insertBefore('#newScrolledNav .newItem');
In the previous case find('[style]') matches elements that have a style attribute.
I'm new to Stack Overflow (and js in general), so this might be really bad ettiquette, but I seem to have accidentally fixed it myself trying to debug my implementation of the first upvoted answer that #Anoop Joshi gave above. Please comment and let me know if it would have been better to just edit my question!
I decided to break the process down into separate steps – similar to #Kiran Reddy's response actually, but I hadn't got to trying his yet.
I tried:
var styledHTML = $('#mainNavigation').clone();
styledHTML.find("div[style]").removeAttr('style');
var originalNavItems = styledHTML.html();
$("#site").prepend('<div… etc.
with a console.log(styledHTML) etc under each line to check what I had at each stage – and it worked! (The code did, console.log didn't?)
I was just doing this to try and log the value of the variables at each stage, but whatever I did fixed it…
Now I need to figure out why I can't even make console.log(variable); work :-/
Try this code
$('#mainNavigation').children().removeAttr('style');
Hope this will help you.

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: get a reference to a specific element without using id

I'm tinkering a bit with jquery to show a hidden div when a link is clicked. This should be fairly simple, but there's a flaw to it in this case. I have the following markup:
<div class="first-row">
<div class="week">
<p>Uge 2</p>
<p>(08-01-11)</p>
</div>
<div class="destination">
<p>Les Menuires</p>
<p>(Frankrig)</p>
</div>
<div class="days">4</div>
<div class="transport">Bil</div>
<div class="lift-card">3 dage</div>
<div class="accommodation">
<p><a class="show-info" href="#">Hotel Christelles (halvpension)</a></p>
<p>4-pers. værelse m. bad/toilet</p>
</div>
<div class="order">
<p>2149,-</p>
<p class="old-price">2249,-</p>
</div>
<div class="hotel-info">
<!-- The div I want to display on click -->
</div>
</div>
When I click the "show-info" link I want the "hotel-info" div to display.
My backend devs don't want me to use ids (don't ask me why..) and the above markup is used over and over again to display data. Therefore I need to be able to access the "hotel-info" div in the "first-row" div where the link is clicked.
I've tried to do something like:
$(document).ready(function() {
$('.show-info').click(function() {
var parentElement = $(this).parent().parent();
var lastElementOfParent = parentElement.find(".show-hotel");
lastElementOfParent.show();
});
});
But without a result :-/ Is this possible at all?
Any help is greatly appreciated!
Thanks a lot in advance!
Try this:
$('.show-info').click(function() {
$(this).closest('.accommodation').siblings('.hotel-info').show();
});
Even better imo, as it would be independent from where the link is in a row, if every "row div" has the same class (I assume only the first one has class first-row), you can do:
$(this).closest('.row-class').find('.hotel-info').show();
Reference: .closest, .siblings
Explanation why your code does not work:
$(this).parent().parent();
gives you the div with class .accommodation and this one has no descendant with class .hotel-info.
It is not a good idea to use this kind of traversal for more than one level anyway. If the structure is changed a bit, your code will break. Always try to use methods that won't break on structure changes.
You're right in not using an ID element to find the DIV you want :)
Use closest and nextAll
Live demo here : http://jsfiddle.net/jomanlk/xTWzn/
$('.show-info').click(function(){
$(this).closest('.accommodation').nextAll('.hotel-info').toggle();
});

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

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')

Categories