Robert Heller
Robert Heller

Reputation: 19

Renumbering input tag name fields after using jQuery sortable

I am using sortable method of jQuery to re-order groups of input tags. The name attribute of these tags are of the form foo[n] (when there is one input in the group) or foo[n][fieldname] (where there are multiple inputs in the group), where n is some number.

I am having the problem is that when the overall form is submitted, the order of the input groups that get stored in the database by the PHP code is in the order of the indexes, not in the order on the screen. I need to update the name indexes to reflect the results of the screen sort order. I am not sure exactly how to do this. The documentation for jQuery is not especially helpful.

The generated HTML would look something like this:

<ul id="deepwoods_meta_rightbutton-repeatable" class="deepwoods_metabox_repeatable">
  <li><span class="sort hndle">||</span><textarea name="deepwoods_meta_rightbutton[0]" id="deepwoods_meta_rightbutton" cols="60" rows="4">(some text)</textarea><a class="repeatable-remove button" href="#">-</a></li>
  <li> (same as above, except [0] replaced with [1]) </li>
  ...
  <li> (same as above, except [0] replaced with [n]) </li>
</ul>

Or it could be like this:

<ul id="deepwoods_meta_buybuttons-repeatable" class="deepwoods_metabox_repeatable">
  <li><span class="sort hndle">||</span>
    <div class="form-table deepwoods-metabox div-as-table">
       <div class="div-as-table-row">
          <span class="span-as-th"><label for="deepwoods_meta_buybuttons">Link</label</span>
          <span class="span-as-td"><input type="text" name="deepwoods_meta_buybuttons[0][thelink]" id="deepwoods_meta_buybuttons" value="..." size="60" class="scrollable" /></span></div>
       <div class="div-as-table-row">
          <span class="span-as-th"><label for="deepwoods_meta_buybuttons">Button</label></span>
          <span class="span-as-td"><input type="text" name="deepwoods_meta_buybuttons[0][thebutton]" id="deepwoods_meta_buybuttons" value="..." size="60" class="scrollable" /></span></div>
       <div class="div-as-table-row">
           <span class="span-as-th"><label for="deepwoods_meta_buybuttons">Text</label></span>
           <span class="span-as-td"><textarea name="deepwoods_meta_buybuttons[0][text]" id="deepwoods_meta_buybuttons" cols="60" rows="4">...</textarea></span></div></div><a class="repeatable-remove button" href="#">-</a></li>
   <li> (much like the previous list item, but [0] replaced with [1] ) </li>
   ...
   <li> nth ([n]) item </li>
</ul>

That is each of the sortable list items could contain either a single input field (input, textarea, or select tag) or each list item could contain a group of input, textarea, or select items that go together. Think of it as either a vector of simple scaler values or a vector of object values.

I have multiple (separately sortable) blocks in the form. I am using a pierce of jQuery code that looks like:

jQuery('.deepwoods_metabox_repeatable').sortable({
            opacity: 0.6,
            revert: true,
            cursor: 'move',
            handle: '.sort',
            containment: 'parent'
});

I think I need to add an update event handler, but I am not sure how to procede from there. The jQuery documentation is not clear (to me).

Upvotes: 0

Views: 2913

Answers (2)

Robert Heller
Robert Heller

Reputation: 19

After a couple of hours groveling with Firebug, I worked out a solution that appears to work. Probably not especially elegant and probably excessively verbose.

jQuery('.deepwoods_metabox_repeatable').sortable({
    opacity: 0.6,
    revert: true,
    cursor: 'move',
    handle: '.sort',
    containment: 'parent',
    update: function(event,ui){ renumber(ui.item); }
});

function renumber(item) {
  ul = item[0].parentNode;
  jQuery('li',ul).each(function(index,element) { 
    renumber_helper(index,element); 
  });
}

function renumber_helper(index,element) {
  inputs = jQuery('input', element);
  for (j = 0; j < inputs.length; j++) {
    input = inputs[j];
    name = input.name;
    input.name = name.replace(/(\d+)/,index);
  }
  textareas = jQuery('textarea',element);
  for (j = 0; j < textareas.length; j++) {
     textarea = textareas[j];
     name = textarea.name;
     textarea.name = name.replace(/(\d+)/,index);
  }
  selects = jQuery('select',element);
  for (j = 0; j < selects.length; j++) {
    select = selects[j];
    name = select.name;
    select.name = name.replace(/(\d+)/,index);
  }
}

Upvotes: 0

charlietfl
charlietfl

Reputation: 171669

You have 2 choices:

Remove all indexes from input tags and form will send them in order by default

OR

Use stop event to change names:

jQuery('.deepwoods_metabox_repeatable').sortable({
   stop: function (event, ui) {
        updateNames($(this))
    }
})

function updateNames($list) {
    $list.find('li').each(function (idx) {
        var $inp = $(this).find('input');
        $inp.each(function () {
            this.name = this.name.replace(/(\[\d\])/, '[' + idx + ']');            
        })
    });
}

DEMO: http://jsfiddle.net/gszfD/

Upvotes: 4

Related Questions