views:

1897

answers:

2

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

+2  A: 

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  });
                            }
                        });
                    });                                                                  
                }
         });  



 });
Russ Cam
The reason it's there is because once a 'rel' attribute matches the string stored in selectTag then theres no need to continue through the loop. If i remove return false nothing changes on the front end
I'm not sure how that would work. Surely that would run the if(v==0) block at every single instance of a.tag_filter..... http://www.redeemercentral.com/index.php/test/grid the development page so you can see whats happening. Click on a tag within the white polaroid style boxes.
If you click on "Life" you'll see that all the entries without the tag "life" attached fade out then the remaining slide up. However the middle column doesn't slide to the top with indicates to me that the "repositioning" .each() function isn't being called everytime an entry fades out so it only moves up once.
It _is_ being called, or the element wouldn't get repositioned at all. What we have here must be some sort of mistake on the top position calculation.
Thiago Arrais
Russ with your code above, we can't put the block in if(curTag != selectTag) because this will be true many times. We only need to remove the entry if the string in SelectTag doesn't equal ANY of the a.tag_filter rel attributes.
if it's easier, put a stripped down version of the html, css and javascript on http://jsbin.com and post to a URL (then add a comment with the URL) so that we can test any code against the page
Russ Cam
Thanks for sticking through this with me.I've ammended my code as shown in yours above.Check the page now www.redeemercentral.com/index.php/test/grid It correctly fades out all entries without the appropriate tag. It then fires off the .each() that repositions the columns but doesn't get it quite right. The middle column should end up in line with the left and right columns.
No problem. How about capturing the left and top values for the element that will be faded out, capture the values for the next laterEntry, apply the faded out values to the next laterEntry, then apply the laterEntry values to the next entry, so on and so forth? Would some code explain it better?
Russ Cam
Yea some code would be amazing. Thanks. I was under the impression this is sort of where I was at, except I have been calculating the distance to move from the height of the faded entry. Lets try just setting the top value. That actually makes a lot more sense.
Take a look at the code now, have amended to demonstrate copying left and top values
Russ Cam
Sorry maybe I should have pointed out earlier, the entries can stay in their columns so we only need to calculate top values and animate those. I've edited my original questions code to show what I have now.If you go to the webpage and click on "life" you'll notice the animating top values. The middle entry is still acting funny though. animates to the top = great, but then animates back down... huh!?
stepping through and debugging the script using firebug- http://getfirebug.com/ the middle entry gets animated twice because it appears that the outer each() iteration causes the fade out to occur on each non relevant entry before the callback function is executed for the first faded out div entry. Instead of $('div.entry:gt('+i+')').each ... try this selector $('div.entry:gt('+i+'):not(:hidden)').each ... so that hidden entries are ignored when evaluating left position. The second animation that puts the middle entry out of position is an evaluation against a hidden entry
Russ Cam
Doesn't seem to work either. I tried your code and then also $('div.entry:gt('+i+'):visible').each but neither had any effect.
I suggest stepping through the loop with firebug. Open firebug, then under "Script" select Enabled. In the window next to all, select the name of the script (test_functions.js). Set a breakpoint in the left margin next to if(leftPos == nextLeftPos) (line 62). Now reload the screen and then click the "Life" tag. in the watch window on the right will be the properties such as scope chain, what "this" references, etc. If you hover over the value for "this" it will be highlighted in the DOM. hit the play button in the script window until this references the entry with the balloons...
Russ Cam
at this point, use the step into (F11) which will execute a function at a time in the scope chain - there will be a lot of functions! Go through one at a time, and one will cause the balloon entry to be moved in the DOM. now keep playing until "this" references the balloon entry again and step into again. The balloon entry gets moved in the DOM again. You'll need to look into what $entry references at this point by setting up a watch expression in the watch window. Let me know if you need any further pointers and how you get on
Russ Cam
How would I go about setting up a watch expression? I see where it says "new watch expression" but what do I put in there? I did notice whilst stepping through that all the entries (missing the selected tag) fadeout at exactly the same time. Would it be possible to have 1 fadeout, then run the reposition loop, then the second fadeout and run the reposition loop again and so on? Or would that not make any difference?
You can set up watch expressions on variable values, DOM elements, propery values, etc. For example, you could have a watch expression set up on $entry.In theory, the fadeout of an entry should only happen in the callback function within each() for the entry in question i.e. entry 1 should fade out in the callback function in each() for entry 1 if it doesn't have the relevant tag, but that doesn't seem to be the case. You can achieve what you're asking but I can't look into it at the moment.
Russ Cam
If you could strip down the page and put the relevant code for a working demo on http://jsbin.com then I can have a look at getting it working.
Russ Cam
Have added it here - http://jsbin.com/igego you can edit it here http://jsbin.com/igego/edit
Russ Cam
I was just about to send you a link to the one I had done haha. Ok so that's where we're at.
A: 

You don't need to cache $(this), jQuery auto caches the this selector for function callbacks.

bryan.taylor