Infinite loop clone node append twice - javascript

I've got a problem with a script that fires 2 times and it clone some columns and append twice.
My goal is to clone the element, which is not in the viewport, and append it at the end, then delete the element from front.
It seems like the element goes of the viewport and enter twice in the condition, where I check if left of the element is greater than its width.
That means I got two clone of the same element and appended twice at the end, which is not good.
Strange thing is that the delete of the element fire once.
here's some code:
var moving = false,
$holder = $('#carousel');
$holder.on('transitionend', function (){
moving = false; // era true
});
offset = 600;
function getPosition() {
wrapper = document.getElementById('carousel');
wrapper_length = wrapper.childElementCount;
width_of_elements = wrapper.children[0].getBoundingClientRect().width;
current_left = wrapper.children[0].getBoundingClientRect().left;
positive_current_left = current_left * -1;
if(Math.round(positive_current_left) > Math.round(width_of_elements)){
// clone + set left after the last one
clone = wrapper.children[0].cloneNode(true);
clone.style.left = wrapper.children[wrapper_length - 1].getBoundingClientRect().left + (offset * 2.6) + "px";
console.log(clone);
// append child cloned
wrapper.appendChild(clone);
// delete element cloned
wrapper.removeChild(wrapper.childNodes[0]);
}
if (!moving) {
window.requestAnimationFrame(getPosition);
}
}
window.requestAnimationFrame(getPosition);
Am I wrong somewhere?
here's a fiddle to see it in action:
fiddle

If all you want to do is to move an element to the end, you can "re"-appendChild. Looks a bit wonky when it starts to come around, but that you can fix. ;)
if (Math.round(positive_current_left) > Math.round(width_of_elements)) {
// clone + set left after the last one
moveMe = wrapper.children[0];
moveMe.style.left = wrapper.children[wrapper_length - 1].getBoundingClientRect().left + (offset * 2.6) + "px";
// append child cloned
wrapper.appendChild(moveMe);
}
fiddle

Related

How to make click event only trigger on text (not other whitespace within the same element) [duplicate]

I have a Div which is as big as half of my page using CSS:
<div id="bigdiv">
CLICK ON THIS TEXT
</div>
I am trying to write a javascript or jquery code which detects click on the text and not the rest of the element. Is there a way to do that?
Since we cannot listen for events directly on the textNodes themselves, we have to take a more creative path to solving the problem. One thing we can do is look at the coordinates of the click event, and see if it overlaps with a textNode.
First, we'll need a small helper method to help us track whether a set of coordinates exists within a set of constraints. This will make it easier for us to arbitrarily determine if a set of x/y values are within the a set of dimensions:
function isInside ( x, y, rect ) {
return x >= rect.left && y >= rect.top
&& x <= rect.right && y <= rect.bottom;
}
This is fairly basic. The x and y values will be numbers, and the rect reference will be an object with at least four properties holding the absolute pixel values representing four corners of a rectangle.
Next, we need a function for cycling through all childNodes that are textNodes, and determining whether a click event took place above one of them:
function textNodeFromPoint( element, x, y ) {
var node, nodes = element.childNodes, range = document.createRange();
for ( var i = 0; node = nodes[i], i < nodes.length; i++ ) {
if ( node.nodeType !== 3 ) continue;
range.selectNodeContents(node);
if ( isInside( x, y, range.getBoundingClientRect() ) ) {
return node;
}
}
return false;
}
With all of this in place, we can now quickly determine if a textNode was directly below the clicked region, and get the value of that node:
element.addEventListener( "click", function ( event ) {
if ( event.srcElement === this ) {
var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
if ( clickedNode ) {
alert( "You clicked: " + clickedNode.nodeValue );
}
}
});
Note that the initial condition if ( event.srcElement ) === this allows us to ignore click events originating from nested elements, such as an image or a span tag. Clicks that happen over textNodes will show the parent element as the srcElement, and as such those are the only ones we're concerned with.
You can see the results here: http://jsfiddle.net/jonathansampson/ug3w2xLc/
Quick win would be to have
<div id="bigdiv">
<span id="text">TEXT HERE</span>
</div>
Script:
$('#text').on('click', function() {
.....
});
Let's alter the content dinamically - I will make the clicking on lala available:
<div id="gig">
<div id="smthing">one</div>lala
<div id="else"></div>
</div>
Script:
var htmlText = $('#gig').text(); //the big divs text
var children = $('#gig').children(); //get dom elements so they can be ignored later
$.each(children, function (index, child) {
var txt = $(child).text().trim();
if (txt != '') { //if a child has text in him
htmlText = htmlText.replace(txt, 'xxx'); //replace it in the big text with xxx
}
});
htmlText = htmlText.split("xxx"); //split for xxx make it arrat
var counter = 0; //the part when the text is added
$.each(htmlText, function (i, el) {
htmlText[i] = el.trim();
if (htmlText[i] != "") { //if there is something here than it's my text
htmlText[i] = '<span id="text">' + htmlText[i] + '</span>'; //replace it with a HTML element personalized
counter++; //mark that you have replaced the text
} else { // if there is nothing at this point it means that I have a DOM element here
htmlText[i] = $(children[i - counter])[0].outerHTML; //add the DOM element
}
});
if (children.length >= htmlText.length) { //you might have the case when not all the HTML children were added back
for (var i = htmlText.length - 1; i < children.length; i++) {
htmlText[i + 1] = $(children[i])[0].outerHTML; //add them
}
}
htmlText = htmlText.join(""); //form a HTML markup from the altered stuff
$('#gig').html(htmlText); // replace the content of the big div
$('#text').on('click', function (data) { //add click support
alert('ok');
});
See a working example here: http://jsfiddle.net/atrifan/5qc27f9c/
P.S: sorry for the namings and stuff I am a little bit tired.
Are you able to do this, is this what you are looking for?
What the code does:
It's making only the text inside the div although the div could have other divs as well, makes only the text that has no HTML container like a div a span a p an a or something like that and alters it adding it in a span and making it available for clicking.
EDIT - Solution without adding wrapping element
Doing this without a wrapping element is quite a hassle. I managed to get it to work, however this will only work for one liners that are centered vertically AND horizontally.
To see the HTML and CSS that goes along with this, see the
jsFiddle: http://jsfiddle.net/v8jbsu3m/3/
jQuery('#bigDiv').click(function(e) {
// Get the x and y offest from the window
margin_top = jQuery(this).offset().top;
margin_left = jQuery(this).offset().left;
// Get the dimensions of the element.
height = jQuery(this).height();
width = jQuery(this).width();
// Retrieve the font_size and remove the px addition
font_size = parseInt(jQuery(this).css('font-size').replace('px', ''));
// Retrieve the position of the click
click_x = e.pageX;
click_y = e.pageY;
// These variables will be used to validate the end result
var in_text_y = false;
var in_text_x = false;
// Determine the click relative to the clicked element
relative_x = click_x - margin_left;
relative_y = click_y - margin_top;
// Determine whether the y-coordinate of the click was in the text
if (relative_y >= (parseFloat(height) / 2) - (parseFloat(font_size) / 2) &&
relative_y <= (parseFloat(height) / 2) + (parseFloat(font_size) / 2))
in_text_y = true;
// This piece of code copies the string and places it in a invisible div
// If this div has the same font styling and no paddings etc... it can
// be used to get the width of the text
text = jQuery(this).text();
text_width = jQuery('#widthTester').html(text).width();
// Determine whether the x-coordinate of the click was in the text
if (relative_x >= (parseFloat(width) / 2) - (parseFloat(text_width) / 2) &&
relative_x < (parseFloat(width) / 2) + (parseFloat(text_width) / 2))
in_text_x = true;
// If the x and y coordinates were both in the text then take action
if (in_text_x && in_text_y)
alert('You clicked the text!');
});
Also, this code can be optimized, since the same calculcation is done multiple times, but I thought that leaving the calculcations there better illustrated what was going on.
Solution by adding a wrapping element
If you put a span around the text, then you can add an onClick event handler to the span.
<div id="bigdiv">
<span>CLICK ON THIS TEXT</span>
</div>
jQuery code
jQuery('#bigdiv span').click(function() {
jquery(this).remove();
});
If you want to go straight through HTML, you can use
<div id="bigdiv" onclick="myFunction();">
and then simply apply the function afterwards in JS:
function myFunction(){
//...
}
EDIT: sorry, if you want the text to be affected, put in <p> around the text or <span> ie.
<div id="bigdiv">
<p onclick="myFuncion();"> TEXT </p>
</div>

Prevent overlapping while positioning element at height of another

Inside a long text document there are some "special words" to which I want to display notes/annotations on the left. Each note should be as close as possible to the level of the word it is refering to.
The HTML for this is organised in a table. Each paragraph is one table row, consisting on annotations in the left and main text in the right table column. the notes/annotations go to the left. However, unfortunately, there are also some other elements/text nodes in there.
<table>
<tr>
<td class"comments">
<span id="dog" class="note">Note for dog</span>
<span id="cat" class="note">Note for cat</span>
<span id="horse" class="note">Note for horse</span>
Somethin else than a note.
</td>
<td>[Text...]
<span id="dog_anchor" class="reference">Dog</span>
<span id="cat_anchor" class="reference">Cat</span>
<span id="horse_anchor" class="reference">Horse</span>
[Text...]
</td>
</tr>
</table>
It's easy to change the "note"-spans to absolute and positioned them on the level of their reference:
$('span[class*="note"]').each(function (index, value) {
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
$(this).css('top', pos_of_ref); // set own position to position of reference element
});
However, life is not so simple here. Since there could be a lot of reference words in one line (while on other there are none of them) I need a rather sophisticated way to distribute the notes so that they are as close as possible to their references without destroying anything in the layout (e.g. being placed outside of the table cell or overlapping with other elements).
Furthermore, the height of the table cells could not be changed. Elements which are not notes must not be moved. (Note elements are always in the order they appear in the main text. That's not the problem.)
So, I need an algorithm like this:
Take all notes in a table cell.
Analyse blank space in that table cell: Which areas are blank, which are blocked?
Distribute the notes in the table cell so that each note is as close as possible to its reference word without any element colliding with any other item in the table cell.
Is there any fast and elegant way to do this without having to write hundreds of lines of code?
Here is a JSfiddle: https://jsfiddle.net/5vLsrLa7/7/
[Update on suggested solutions]
Simply setting the position of the side notes to relative or just moving notes down won't work, because in this case, the side notes will just go downwards relative to their desired position which results in side notes way to far from their reference words. After all, for a neat solution I need to side notes spread in both directions: up and down.
[Update]
The expected result would be something like this:
As you see, it's never possible to place all the notes at the height of their reference. However, the free space is used to position them as close as possible, moving them up and down.
I changed move() function as follows:
function move(){
var prev_offset = 0;
$('span.note').each(function (index, value){
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
if (prev_offset >= pos_of_ref){
pos_of_ref = prev_offset + 30;
}
$(this).css('top', pos_of_ref); // set own position to position of reference element
prev_offset = pos_of_ref;
});
}
I'm assuming that your element's notes will be in the correct order always
I made some changes to your javascript:
function move()
{
var arrayTops = [];
$('span[class*="note"]').each(function (index, value)
{
var my_id = $(this).attr('id');
var element_ref = document.getElementById(my_id + "_anchor"); // get reference element
var pos_of_ref = element_ref.offsetTop; // get position of reference element
pos_of_ref = getCorrectTopPosition(arrayTops,pos_of_ref);
$(this).css('top', pos_of_ref); // set own position to position of reference element
arrayTops.push(pos_of_ref);
});
}
function getCorrectTopPosition(arrayTops, newOffsetTop)
{
var notesHeight = 18;
var marginBetweenNotes = 3;
var noteheightWithMargin = notesHeight + marginBetweenNotes;
var lastTop = arrayTops[arrayTops.length-1];
if((lastTop + noteheightWithMargin) >= newOffsetTop)
return lastTop + noteheightWithMargin;
return newOffsetTop;
}
Thanks for all the answers and comments. I was finally able to figure out at least a partical solution which works for me.
First of all, I was able to restructure my HTML, so that now the "non note" elements in the left td are all wrapped in one div which is now the very first element in the td. So, now there is nothing between notes, maybe something before them.
The idea of my solution is not to give the notes a new position but to set a new margin-top to each of them. The maximum amount of margin-top values to be added within a table cell is calculated before (called "roaming space"), being the space below the last note in a table cell. Thus, the table layout is not destroyed.
function move_notes() {
$('tr').each(function (index, value) {
var current_tr = $(this);
var last_app_element_in_tr = $(this).find('span[class*="note"]').last();
if ($(last_app_element_in_tr).length) /* Only preceed if there is at least one note in the table row */ {
var tr_height = $(this).height();
var tr_offset = $(this).offset().top;
var bottom_of_tr = tr_offset + tr_height;
var bottom_of_last_app_el = $(last_app_element_in_tr).offset().top + $(last_app_element_in_tr).height();
var roaming_space = bottom_of_tr - bottom_of_last_app_el; // Calculate the amount of pixels which are "free": The space below the very last note element
$(this).find('span[class*="note"]').each(function (index, value) {
var my_id = $(this).attr('id');
var element_ref = $(current_tr).find("#" + my_id + "_anchor");
var pos_of_ref = $(element_ref).offset().top;
var new_margin_top;
/* Calculate the new margin top: The note should be at the same level as the reference element.
When loading, in most cases the notes are placed too high. So, the margin top of the note should equal
the amount of pixels which the note is "too high". So we subtract the height and the offset of the element
before the current note from the offset of the reference. */
var previous_note = $(this).prev();
// not just notes, but every element in the td in general
if (! $(previous_note).length) // If there is no previous_note, than take the table cell
{
closest_td = $(this).closest("td");
new_margin_top = pos_of_ref - $(closest_td).offset().top;
} else {
new_margin_top = pos_of_ref - $(previous_note).offset().top - $(previous_note).height();
}
var difference_to_previous = $(this).css('marginTop').replace(/[^-\d\.]/g, '') - new_margin_top; // Calculate the difference between the old and the new margin top
if (new_margin_top > 0 && Math.abs(difference_to_previous) > 2) // Only move, if the new margin is greater than zero (no negative margins!) if the difference is greater than 2px (thus preventing ugly "micro moving".
{
var new_roaming_space = roaming_space - difference_to_previous;
if (new_roaming_space > 0) /* if there is still room to move */ {
var margin_top_ready = new_margin_top + "px";
$(this).css('margin-top', margin_top_ready);
roaming_space = new_roaming_space;
} else /* If there is no more space to move: */ {
var margin_top_ready = roaming_space + "px"; // take the rest of the "roaming space" left as margin top
$(this).css('margin-top', margin_top_ready);
return false; // Stop the execution because there is nothing left to do.
}
}
});
}
});
}
window.onload = function () {
move_notes();
};
$(window).resize(function () {
move_notes();
});
As you will notice, one of my main concerns is still not addressed: Notes are only moved down, never up. Because of various problems with my real world webpage I didn't implement that yet. However, an algorith could be something like: If the new margin top is greater than the height of the current note and the difference between the offet of the current note anchor and the following note anchor is less than the height of the current note, than subtract the height of the current note from the new margin.
Still, two problems remain:
If the window is maximized or quickly resized from a rather thin width to a greater width, the adjustment of the note positions won't work. I don't know why.
The performance could be better. As a user, you can see the notes jump down. (Because of strange and unpredictable behaviour in Firefox, I had to move the event handler from document.ready to window.onload)

Detect click on the inner text of the element without wrapping the text in a second element

I have a Div which is as big as half of my page using CSS:
<div id="bigdiv">
CLICK ON THIS TEXT
</div>
I am trying to write a javascript or jquery code which detects click on the text and not the rest of the element. Is there a way to do that?
Since we cannot listen for events directly on the textNodes themselves, we have to take a more creative path to solving the problem. One thing we can do is look at the coordinates of the click event, and see if it overlaps with a textNode.
First, we'll need a small helper method to help us track whether a set of coordinates exists within a set of constraints. This will make it easier for us to arbitrarily determine if a set of x/y values are within the a set of dimensions:
function isInside ( x, y, rect ) {
return x >= rect.left && y >= rect.top
&& x <= rect.right && y <= rect.bottom;
}
This is fairly basic. The x and y values will be numbers, and the rect reference will be an object with at least four properties holding the absolute pixel values representing four corners of a rectangle.
Next, we need a function for cycling through all childNodes that are textNodes, and determining whether a click event took place above one of them:
function textNodeFromPoint( element, x, y ) {
var node, nodes = element.childNodes, range = document.createRange();
for ( var i = 0; node = nodes[i], i < nodes.length; i++ ) {
if ( node.nodeType !== 3 ) continue;
range.selectNodeContents(node);
if ( isInside( x, y, range.getBoundingClientRect() ) ) {
return node;
}
}
return false;
}
With all of this in place, we can now quickly determine if a textNode was directly below the clicked region, and get the value of that node:
element.addEventListener( "click", function ( event ) {
if ( event.srcElement === this ) {
var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
if ( clickedNode ) {
alert( "You clicked: " + clickedNode.nodeValue );
}
}
});
Note that the initial condition if ( event.srcElement ) === this allows us to ignore click events originating from nested elements, such as an image or a span tag. Clicks that happen over textNodes will show the parent element as the srcElement, and as such those are the only ones we're concerned with.
You can see the results here: http://jsfiddle.net/jonathansampson/ug3w2xLc/
Quick win would be to have
<div id="bigdiv">
<span id="text">TEXT HERE</span>
</div>
Script:
$('#text').on('click', function() {
.....
});
Let's alter the content dinamically - I will make the clicking on lala available:
<div id="gig">
<div id="smthing">one</div>lala
<div id="else"></div>
</div>
Script:
var htmlText = $('#gig').text(); //the big divs text
var children = $('#gig').children(); //get dom elements so they can be ignored later
$.each(children, function (index, child) {
var txt = $(child).text().trim();
if (txt != '') { //if a child has text in him
htmlText = htmlText.replace(txt, 'xxx'); //replace it in the big text with xxx
}
});
htmlText = htmlText.split("xxx"); //split for xxx make it arrat
var counter = 0; //the part when the text is added
$.each(htmlText, function (i, el) {
htmlText[i] = el.trim();
if (htmlText[i] != "") { //if there is something here than it's my text
htmlText[i] = '<span id="text">' + htmlText[i] + '</span>'; //replace it with a HTML element personalized
counter++; //mark that you have replaced the text
} else { // if there is nothing at this point it means that I have a DOM element here
htmlText[i] = $(children[i - counter])[0].outerHTML; //add the DOM element
}
});
if (children.length >= htmlText.length) { //you might have the case when not all the HTML children were added back
for (var i = htmlText.length - 1; i < children.length; i++) {
htmlText[i + 1] = $(children[i])[0].outerHTML; //add them
}
}
htmlText = htmlText.join(""); //form a HTML markup from the altered stuff
$('#gig').html(htmlText); // replace the content of the big div
$('#text').on('click', function (data) { //add click support
alert('ok');
});
See a working example here: http://jsfiddle.net/atrifan/5qc27f9c/
P.S: sorry for the namings and stuff I am a little bit tired.
Are you able to do this, is this what you are looking for?
What the code does:
It's making only the text inside the div although the div could have other divs as well, makes only the text that has no HTML container like a div a span a p an a or something like that and alters it adding it in a span and making it available for clicking.
EDIT - Solution without adding wrapping element
Doing this without a wrapping element is quite a hassle. I managed to get it to work, however this will only work for one liners that are centered vertically AND horizontally.
To see the HTML and CSS that goes along with this, see the
jsFiddle: http://jsfiddle.net/v8jbsu3m/3/
jQuery('#bigDiv').click(function(e) {
// Get the x and y offest from the window
margin_top = jQuery(this).offset().top;
margin_left = jQuery(this).offset().left;
// Get the dimensions of the element.
height = jQuery(this).height();
width = jQuery(this).width();
// Retrieve the font_size and remove the px addition
font_size = parseInt(jQuery(this).css('font-size').replace('px', ''));
// Retrieve the position of the click
click_x = e.pageX;
click_y = e.pageY;
// These variables will be used to validate the end result
var in_text_y = false;
var in_text_x = false;
// Determine the click relative to the clicked element
relative_x = click_x - margin_left;
relative_y = click_y - margin_top;
// Determine whether the y-coordinate of the click was in the text
if (relative_y >= (parseFloat(height) / 2) - (parseFloat(font_size) / 2) &&
relative_y <= (parseFloat(height) / 2) + (parseFloat(font_size) / 2))
in_text_y = true;
// This piece of code copies the string and places it in a invisible div
// If this div has the same font styling and no paddings etc... it can
// be used to get the width of the text
text = jQuery(this).text();
text_width = jQuery('#widthTester').html(text).width();
// Determine whether the x-coordinate of the click was in the text
if (relative_x >= (parseFloat(width) / 2) - (parseFloat(text_width) / 2) &&
relative_x < (parseFloat(width) / 2) + (parseFloat(text_width) / 2))
in_text_x = true;
// If the x and y coordinates were both in the text then take action
if (in_text_x && in_text_y)
alert('You clicked the text!');
});
Also, this code can be optimized, since the same calculcation is done multiple times, but I thought that leaving the calculcations there better illustrated what was going on.
Solution by adding a wrapping element
If you put a span around the text, then you can add an onClick event handler to the span.
<div id="bigdiv">
<span>CLICK ON THIS TEXT</span>
</div>
jQuery code
jQuery('#bigdiv span').click(function() {
jquery(this).remove();
});
If you want to go straight through HTML, you can use
<div id="bigdiv" onclick="myFunction();">
and then simply apply the function afterwards in JS:
function myFunction(){
//...
}
EDIT: sorry, if you want the text to be affected, put in <p> around the text or <span> ie.
<div id="bigdiv">
<p onclick="myFuncion();"> TEXT </p>
</div>

when element is removed, then reposition/animate each next element jQuery

Actually I have dynamic notification ".noti", and all has
position:fixed;
bottom:0;
width:250px;
right://adjusted via jQuery bcz they are dynamically added
var s = $('body').find('.noti').size();
xxxxx.css({right:s*250});
Now what I want to do is that, when I removed a element, then each next element must reposition/adjust their "right:xxx" property.
for example I have 5 div :
|_ _ _ _ _|
and I removed the right most div
|_ _ _ _ |
then all other divs must reposition as
| _ _ _ _|
I tried ".next":
var next = $(this).closest('.noti').next('.noti');
if(next.length > 0){
var nextright = next.css('right');
nextright = nextright.split('px').join('');
next.animate({right:nextright-250},300);
}
but it'll only reposition the next div.
So can somebody tell me that how can I use ".each()" or ".nextAll()" or a "for loop" to reposition all next elements.
Thanks & regards
UPDATE:
Now I tried :
var parent = $(this).closest('.noti'),next = parent.next('.noti');
var df = parent.attr('data-for');
if(next.length > 0){
$('.noti').each(function(){
if(df != $(this).attr('data-for')){
var t=$(this),pos = t.css('right');
pos = pos.split('px').join('');
t.animate({right:pos-250});
}
});
}
Its works good only when I want to remove the right most element. but if I removed any element from the middle, than each ".noti" reposition their "right" property. But I want that only the "nextAll" elements must reposition.
UPDATE : SOLUTION
Finally this problem is solved {solution is based on Tandon's answer} http://jsfiddle.net/7f2aU/5/
Thanks
DEMO Click on div to remove it
var width = $('#container div').width();
$('#container div').each(function(index){
// set css property `right` to the width * index (zero-based) + 30 (random number)
$(this).css("right", ((width * index) + 30));
});
$("#container div").click(function(){
var thisIndex = $(this).index(); // current element's index
// console.log(thisIndex); a check
$(this).siblings("div").each(function(index){
// to make sure the element `$(this)` (the sibling) is to the left of the element clicked on
if((index + 1) > thisIndex){
var css = parseInt($(this).css("right"), 10); // parse the property
$(this).css("right", css - width); // set it shifted to right by an offset equal to width
// console.log($(this).css("right")); a check
}
});
$(this).remove(); // finally, remove it
});

JQuery .each() callback function doesn't run on each iteration/loop

Here's what should happen.
1. Get the rel attribute of the clicked link
2. For every div with class 'entry':
(i)Get its 'left' position
(ii) Calculate its outer height
(iii)Loop through all instances of 'a.tag_filter'. If it finds the same string in the 'rel' as the one oringinally clicked on then add 1 to 'V' and break out of the loop.
(iv)If 'V' is equal to 0 after the loop we know the same tag isn't present within that '.entry' so fade it out.
(v)Once the fadeout has finished loop through all the '.entry' after the faded out one and get their 'left' values.
(vi)If the left value of the faded entry = the left value of the current '.entry' then reposition it to the new 'top' value.
What is currently happening.
It runs through and fades out all the correct '.entry' elements and only after all of them have faded out does it reposition them remaining '.entry' elements.
After each element is faded out I would like the repositioning loop to run so it essentially positions the remaining elements one at a time rather than all at once.
Heres my code EDIT:
$('a.tag_filter').click(function(e){
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.spotlight_entry_container_grid').each(function(i){
var $entry = $(this);
var tagArray = [];
$('a.tag_filter', this).each(function(){
tagArray.push ($(this).attr('rel'));
});
if($.inArray(selectTag,tagArray) == -1){
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.spotlight_entry_container_grid:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
//we need to keep the entries in their columns.
//matching left values will do it. No need to animate left values.
if(leftPos == nextLeftPos){
$laterEntry.animate({ top: topPos});
}
});
});
}
});
});
Hopefully that makes sense
Any help would be appreciated!
I'm probably doing something crazy but I just can't spot it.
Thanks
in here
$('a.tag_filter', this).each(function(){
var curTag = $(this).attr('rel');
if(curTag == selectTag){
v++;
return false;
}
});
returning false inside of $().each() breaks the looping through each element in the wrapped set.
From the documentation
Returning 'false' from within the each
function completely stops the loop
through all of the elements (this is
like using a 'break' with a normal
loop). Returning 'true' from within
the loop skips to the next iteration
(this is like using a 'continue' with
a normal loop).
Also, I would recommend caching $(this) inside of each each() in a local variable for performance instead of referencing it several times.
EDIT:
After looking at the code further, I think the following should do it
$('a.tag_filter').click(function(e){
// prevent the default anchor behaviour
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.entry').each(function(i){
var $entry = $(this);
// get an array of the anchor tag rel attributes
var tagArray = [];
$('a.tag_filter', this).each(function() {
tagArray.push ($(this).attr('rel'));
});
// if we can't find the selected tag in the entries tags
if ($.inArray(selectTag,tagArray) == -1) {
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.entry:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
// for the first element, set top and left to the faded out element values
if (j == 0) {
$laterEntry.animate({ top: topPos, left: leftPos });
}
// for later elements in the loop, ste the values to the previous element values
else {
$laterEntry.animate({ top: nextTopPos, left: nextLeftPos });
}
});
});
}
});
});
You don't need to cache $(this), jQuery auto caches the this selector for function callbacks.

Categories

Resources