0

Would there be a better, cleaner way to write this conditional script? It's doing the same thing basically, except if cloneVar has the class "before", it changes which row it's grabbing (first or last) and changes .insertAfter to .insertBefore.

var cloneVar = $(this).parent().parent('.sortable');

if ($(cloneVar).hasClass('before')) {
    var cloneRow = $(cloneVar).find('.sort-group .row:first');

    $(cloneRow).clone(true).insertBefore(cloneRow)
    .addClass('add').removeClass('first')
    .find('input[type=text], textarea').val('')
    .attr('name', function(index, name) {
        return name.replace(/(\d+)/, function(fullMatch, n) {
            return Number(n) + 1;
        });
    }).parent().find('input, textarea').attr('id', function(index, id) {
        return id.replace(/(\d+)/, function(fullMatch, n) {
            return Number(n) + 1;
        });
    }).parent().find('.delete').removeClass('visible');

    return false;
} else {
    var cloneRow = $(cloneVar).find('.sort-group .row:last');

    $(cloneRow).clone(true).insertAfter(cloneRow)
    .addClass('add').removeClass('first')
    .find('input[type=text], textarea').val('')
    .attr('name', function(index, name) {
        return name.replace(/(\d+)/, function(fullMatch, n) {
            return Number(n) + 1;
        });
    }).parent().find('input, textarea').attr('id', function(index, id) {
        return id.replace(/(\d+)/, function(fullMatch, n) {
            return Number(n) + 1;
        });
    }).parent().find('.delete').removeClass('visible');

    return false;
}
Ryan Palmer
  • 405
  • 2
  • 9
  • 26

2 Answers2

1
// move this out to clean up, since you're doing the same thing in both spots
function incrementProp(index, prop) {
    return prop.replace(/(\d+)/, function (fullMatch, n) {
        return Number(n) + 1;
    });
}

var cloneRow;
if (cloneVar.hasClass('before') {
    cloneRow = $(cloneVar).find('.sort-group .row:first');
    insert = "insertBefore";
} else {
    cloneRow = $(cloneVar).find('.sort-group .row:last');
    insert = "insertAfter";
}

cloneRow.clone(true)[insert](cloneRow) // dynamically call function
    .addClass('add').removeClass('first')
    .find('input[type=text], textarea').val('')
    .attr('name', incrementProp).end()
    .find('input, textarea').attr('id', incrementProp)
    .end().find('.delete').removeClass('visible');

return false;

Actual question:

  • you can build the selector dynamically depending on whether cloneVar has the relevant class. Then just run the common code
  • Use bracket notation with a string to call insertBefore/insertAfter depending on where the new element is going

Additional pointers:

  • cloneVar/cloneRow are already jQuery objects, so you don't need to wrap in jQuery again
  • You may want to use end instead of parent - it reverts to the collection you had before calling find and you won't need to change it if you modify your DOM
  • You're doing a lot of chaining, but moving the replacement function out can clean it up a lot
Dennis
  • 32,200
  • 11
  • 64
  • 79
0

You can just do the if for the one part that changes:

var cloneRow = $(cloneVar).find('.sort-group .row:' + 
     /* do the check here */ (cloneVar.hasClass('before') ? 'first' : 'last'));

$(cloneRow).clone(true).insertBefore(cloneRow)
.addClass('add').removeClass('first')
.find('input[type=text], textarea').val('')
.attr('name', function(index, name) {
    return name.replace(/(\d+)/, function(fullMatch, n) {
        return Number(n) + 1;
    });
}).parent().find('input, textarea').attr('id', function(index, id) {
    return id.replace(/(\d+)/, function(fullMatch, n) {
        return Number(n) + 1;
    });
}).parent().find('.delete').removeClass('visible');

return false;

The a ? b : c syntax is just shorthand for

if (a) { b }; else { c };
dave
  • 62,300
  • 5
  • 72
  • 93