Thread: .closest() use

    #1
  1. No Profile Picture
    Super Moderator
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Jun 2009
    Location
    Hartford, WI
    Posts
    1,535
    Rep Power
    111

    .closest() use


    This is just a quick question omw out the door....

    I never wanted to switch my table structure from an HTML table to a CSS build, and after a handful of my alterations, it appears I may be able to switch it back...

    The main issue was each row needed to be an independent FORM and able to be submitted/updated on its own. The only thing that contains a FORM tags is the initial wrapper of the row with a TR class. Since the form itself has no direct Submit, nor any 'action' definition, I think the entire CSS structure can be ruled out.

    Below is the JavaScript function that truly makes the action/submit happen. I just want to ask if my thought would be a valid change for when I sit down n make my major re-write an easy 1-day project... ^_^

    Just to reference:
    Code:
    actionCall: function(page, action, values) {
      $.ajax({
        url     : './inc/ajax.php?page=' + page + '&action=' + action,
        context : this,
        type    : 'post',
        dataType: 'json',
        data    : values,
        success : function(data) {
        },
        error   : function(xhr, err) {
          alert('Request Status: ' + xhr.status + ' Status Text: ' + xhr.statusText + ' ' + xhr.responseText);     
        }
      });    
    },
    Currently:
    Code:
    $(this).actionCall(page, 'add', $(this).closest('form').serialize());
    Intended:
    Code:
    $(this).actionCall(page, 'add', $(this).closest('tr').serialize());
    I think the main question is if it would serialize in the same manner or not when referencing the closest TR vs FORM...
    When the below is switched to 'Edit' mode, the content of each <SPAN class="td"> or <TD> will be altered into a FORM input of one type or another, and that is what is to be serialized/submitted.

    Current HTML:
    Code:
    <FORM class="tr">
      <SPAN class="td">X</SPAN>
      <SPAN class="td">01</SPAN>
      <SPAN class="td">$85.63</SPAN>
      <SPAN class="td">American Family</SPAN>
      <SPAN class="td"></SPAN>
      <SPAN class="td">Scheduled via 'Automated' (THRU March) (Renew in January)</SPAN>
      <SPAN class="action td">
        <SPAN class="row-info">
          <INPUT name="year" type="hidden" value="2017" />
          <INPUT name="month" type="hidden" value="12" />
          <INPUT name="inv_id" type="hidden" value="220" />
        </SPAN>
        <SPAN class="view-icons"><IMG class="edit" src="./img/edit.png" /> &nbsp; <IMG class="delete" src="./img/delete.png" /></SPAN>
        <SPAN class="edit-icons"><IMG class="save" src="./img/save.png" /> &nbsp; <IMG class="cancel" src="./img/cancel.png" /></SPAN>
      </SPAN>
    </FORM>
    Intended HTML:
    Code:
    <TR>
      <TD>X</TD>
      <TD>01</TD>
      <TD>$85.63</TD>
      <TD>American Family</TD>
      <TD></TD>
      <TD>Scheduled via 'Automated' (THRU March) (Renew in January)</TD>
      <TD class="action">
        <SPAN class="row-info">
          <INPUT name="year" type="hidden" value="2017" />
          <INPUT name="month" type="hidden" value="12" />
          <INPUT name="inv_id" type="hidden" value="220" />
        </SPAN>
        <SPAN class="view-icons"><IMG class="edit" src="./img/edit.png" /> &nbsp; <IMG class="delete" src="./img/delete.png" /></SPAN>
        <SPAN class="edit-icons"><IMG class="save" src="./img/save.png" /> &nbsp; <IMG class="cancel" src="./img/cancel.png" /></SPAN>
      </TD>
    </TR>
    Last edited by Triple_Nothing; December 27th, 2017 at 08:40 AM.
    He who knows not that he knows not is a fool, ignore him. He who knows that he knows not is ignorant, teach him. He who knows not that he knows is asleep, awaken him. He who knows that he knows is a leader, follow him.
  2. #2
  3. Impoverished Moderator
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    16,739
    Rep Power
    9646
    Code:
    $(this).closest('tr').serialize()
    Though that really should work, it doesn't: serialize() wants the set of elements to serialize but will handle forms specially. So you'd have to do something like
    Code:
    $(this).closest('tr').find('input').serialize()
    But we can make stuff even more magical.
    Code:
    <TR class="edit-form">
      <TD>X</TD>
      <TD>01</TD>
      <TD>$85.63</TD>
      <TD>American Family</TD>
      <TD></TD>
      <TD>Scheduled via 'Automated' (THRU March) (Renew in January)</TD>
      <TD class="action">
        <SPAN class="row-info">
          <INPUT name="year" type="hidden" value="2017" />
          <INPUT name="month" type="hidden" value="12" />
          <INPUT name="inv_id" type="hidden" value="220" />
        </SPAN>
        <SPAN class="view-icons"><IMG class="edit" src="./img/edit.png" /> &nbsp; <IMG class="delete" src="./img/delete.png" /></SPAN>
        <SPAN class="edit-icons"><IMG class="save" src="./img/save.png" /> &nbsp; <IMG class="cancel" src="./img/cancel.png" /></SPAN>
      </TD>
    </TR>
    Code:
    $(document.body).on('click', '.edit-form .save', function() {
    	var data = $(this).closest('.edit-form').find('input, select').serialize();
    	$(this).actionCall(???, ???, data);
    });
    I'm not sure where page comes from or where 'add' is decided, but I suggest putting them somewhere in the markup. Perhaps
    Code:
    <IMG class="save" src="./img/save.png" data-edit-page="whatever page" data-edit-action="add" />
    Code:
    $(this).actionCall($(this).data("edit-page"), $(this).data("edit-action"), data);
    The page value could be with the .edit-form, but I think the action should be on the .save action button itself.

    Now the AJAX form is much more generic and can be enabled simply by adding information into the markup - no extra code required.
  4. #3
  5. Wiser? Not exactly.
    Devshed God 2nd Plane (6000 - 6499 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    6,244
    Rep Power
    4150
    You can use jQuery's :input pseudo selector to catch all the form elements in the row then serialize that.

    Code:
    $(this).closest('tr').find(':input').serialize()
    I've used this kind of setup a few times for various things and it works well.
    Recycle your old CD's



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  6. #4
  7. No Profile Picture
    Super Moderator
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Jun 2009
    Location
    Hartford, WI
    Posts
    1,535
    Rep Power
    111
    Updated... I ended up going with :input in the add/delete function for now, as long as it appears to cover everything for the selection. Below is the final output, not that it's much an adjustment...
    Code:
    // Add new item
    $('.account').on('click', '.add', basicAction('account', 'add'));
    $('.invoice').on('click', '.add', basicAction('invoice', 'add'));
    
    // Cancel editing
    $('.account').on('click', '.cancel', basicAction('account', 'cancel'));
    $('.invoice').on('click', '.cancel', basicAction('invoice', 'cancel'));
    
    // Delete item
    $('.account').on('click', '.delete', basicAction('account', 'delete'));
    $('.invoice').on('click', '.delete', basicAction('invoice', 'delete'));
    The start of the universal basicAction() function...
    Code:
    // Basic function definitions
    function basicAction(page, action) {
      if(action == 'add') {
        return function() {
          $(this).actionCall(page, 'add', $(this).closest('tr').find(':input').serialize());
        }
      } else if(action == 'cancel') {
        return function() {
          $(this).closest('td').siblings().each(function(index, cell) {
            $(this).text($(this).find('input[type=hidden]').val());
          });
          $(this).closest('td').toggleClass('editing');
        }
      } else if(action == 'delete') {
        if(page == 'account') {
          return function() { alert("Accounts cannot be deleted due to references. If you wish, you may rename it to create a similar account, or mark it Inactive."); }
        } else {
          return function() {
            var result = confirm("Are you sure you wish to delete this "+page+"?");
            if(result) {
              $(this).actionCall(page, 'delete', $(this).closest('tr').find(':input').serialize());
              $(this).closest('tr').remove();
            }
          }
        }
      }
    }
    It was originally built a little differently for the Cancel call via Better way to group this?, but it needed to be handed the 'cancel' variable to suffice the if() condition, unless I left it to an else...
    Last edited by Triple_Nothing; December 29th, 2017 at 06:51 AM.
    He who knows not that he knows not is a fool, ignore him. He who knows that he knows not is ignorant, teach him. He who knows not that he knows is asleep, awaken him. He who knows that he knows is a leader, follow him.

IMN logo majestic logo threadwatch logo seochat tools logo