Search code examples
jqueryjquery-selectorstraversal

jQuery traversing elements get all previous elements that match selector


I have a collection of divs that contain either images or checkboxes. My end goal is to have the onclick event on the checkbox also check all previous checkboxes.

Here is my layout (dynamically created so id #'s can change based on page load data):

   <div id="Main1">
      <div id="Secondary1">
         <div id="div1">
            <img id="section1" src="image1" alt="" />
            <span>Div 1 text</span>
          </div>
         <div id="div2">
            <img id="section2" src="image2" alt="" />
            <span>Div 2 text</span>
          </div>
         <div id="div3">
            <input type="checkbox" id="section3">
             Div 3 text
             </input>
         </div>
         <div id="div4">
            <input type="checkbox" id="section4">
             Div 4 text
             </input>
         </div>
         <div id="div5">
            <input type="checkbox" id="section5">
             Div 5 text
             </input>
         </div>
         <div id="div6">
            <input type="checkbox" id="section6">
             Div 6 text
             </input>
         </div>
      </div>
   </div>

I want to be able to check the section5 and have it auto check the previous checkboxes.

The code I've been using, which is producing sporadic results is below:

$('input[id^=section]').click(function() {
   if($(this).attr('checked')) {
       var slide = $(this).attr('id').replace('section', '');
       $(this).replaceWith('<img src="images/ajax-loader.gif" id="loader" alt="" />'); //replace checkbox with loader animation
       $.ajax({
            type: 'POST',
            url: 'URL to AJAX page',
            data: '{ data for ajax call }',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function() {
               $('#loader').parents('div[id^=Secondary]').children('div[id^=section]').each(function() {
                    if($(this).children('input[id^=section]').attr('id') != undefined) {
                          if($(this).children('input[id^=section]').attr('id').replace('section', '') < slide) {
                             $(this).children('input[id^=section]').replaceWith('<img src="images/checkmark.gif" alt="" />');
                       }
                    }
              });
            },
            error: function() {
                   //handle errors
            }
        });
   }
});

Seems to me I'm going about this inefficiently, I had tried .prev() and .prevAll() but without success. However I could have been using them incorrectly as well. Any assistance is appreciated.


Solution

  • Try this: http://jsfiddle.net/kgc4M/

    if(this.checked) {
        $(this).closest('div').prevAll('div:has(:checkbox)')
                             .find(':checkbox').attr('checked','checked');
    
    }
    

    EDIT: From your comment, you want to use .replaceWith() to replace the checkbox with an image, yet reuse the ID of the checkbox.

    Try this:

    if(this.checked) {
        $(this).closest('div').prevAll('div:has(:checkbox)')
                    .find(':checkbox')
                    .replaceWith(function() {
                          return "<img src='/some/path.jpg' id='" + this.id + "' />";
                    }).remove();
    }
    

    Note that I'm also calling unbind() on the checkboxes being replaced, since I don't think replaceWith() will clean that up for you. I'll double check though.

    EDIT: Appears as though .replaceWith() removes the events and data, but keeps an entry in jQuery.cache for the removed elements. To be thorough, I got rid of unbind() but added .remove() at the end, which completely removes them from the cache.