views:

191

answers:

6

I have a HTML snippet as follows, I want to take the 'article-form' div, clone it, and increment the numbers for the attributes for, id, and name.

<div class="article-form">
    <label for="id_form-0-section">Section:</label>
    <select id="id_form-0-section" name="form-0-section">
        <option selected="selected" value="">---------</option>
        <option value="1">News</option>
        <option value="2">Originals</option>
    </select>
    <label for="id_form-0-slug">Slug:</label>
    <input type="text" maxlength="255" name="form-0-slug" id="id_form-0-slug">
    <input type="hidden" id="id_form-0-collection" name="form-0-collection">
    <input type="hidden" id="id_form-0-order" name="form-0-order">
    <input type="hidden" id="id_form-0-id" name="form-0-id">
</div>

I have the cloning part so far, but I need to take what I have cloned an traverse the elements inside have the attribute for, id, and name.

var $articeForm = $('.article-form').clone();

Let me add, the increment part isn't the problem. I plan on doing the following. I am not sure what is the best way to traverse by attribute.

var newNumber = parseInt($('#id_form-0-id').attr('id').split('-')[1]) + 1;

One more thing, the fact that this started at 0 is meaningless, in some situations it could start with 5 and then the next fields that follow should be 6.

A: 

You may want to keep a variable that tells you how many clones you made so far.

  var count = 0;

Then every time you make a clone you increment the count.

   count++;
   $articleForm.children().each(function(){
          newId = $(this).attr("id") + count;
          $(this).attr("id", newId);
   });
Vincent Ramdhanie
You're going to want your count variable inside the each function so that way it increments after every time it finds a child of $articleForm
Catfish
@catfish I don't think you want each itemn on the form to have a different id. Each articleForm will have an id and all its children will share the id. So articleForm2 will have a label with id label2 and so on.
Vincent Ramdhanie
A: 
var counter = 0;

$('myElement').each (function(index)) {
    $(this).attr('id'+counter);
    counter++;
});
Catfish
+1  A: 

You could grab a little regex and parseInt() for this. E.g.

element.attr('name', element.attr('name').replace(/(.*form\-)(\d+)(\-.*)/, function(f, p1, p2, p3) {
    return p1 + (parseInt(p2) + 1) + p3;
}));

There's however only one huge caveat: Changing name attr of cloned input element in jQuery doesn’t work in IE6/7

BalusC
Wow, that is some caveat, but in this case I can ensure only FF, Chrome, and Safari will be used.
Jason Christa
A: 

take a look at this link: http://stackoverflow.com/questions/416081/jquery-clone-duplicate-ids. Its a simple find and replace on the id's.

var $articleForm = $(".article-form").clone(false);
$articleForm.find("#id_form-0-section").attr("id", "id_form-" + counter + "-section");
... etc ...
Steven Pardo
This looks like it is on the right track but I was hoping for something a little more general purpose. I know the format is form-number-name for the attributes for, id, and name. I just want to increment the number part and piece the attribute name back together using the form, incremented number and name parts.
Jason Christa
+1  A: 

Assuming you have an area of your page that will hold these cloned divs:

<div id="articles"></div>

Start with a page-wide counter variable:

<script type="text/javascript">
    var articleFormCount = 0;
<script>

Create a function that builds the HTML for you:

<script type="text/javascript">
    function buildArticleFormDiv()
    {
        var html = "<div class=\"article-form\">" + 
        "<label for=\"id_form-" + articleFormCount + "-section\">Section:</label>" + 
        "<select id=\"id_form-" + articleFormCount + "-section\" name=\"form-" + articleFormCount + "-section\">" +
        "<option selected=\"selected\" value=\"\">---------</option>" +
        "<option value=\"1\">News</option>" +
        "<option value=\"2\">Originals</option>" +
        "</select>" +
        "<label for=\"id_form-" + articleFormCount + "-slug\">Slug:</label>" +
        "<input type=\"text\" maxlength=\"255\" name=\"form-" + articleFormCount + "-slug\" id=\"id_form-" + articleFormCount + "-slug\">" +
        "<input type=\"hidden\" id=\"id_form-" + articleFormCount + "-collection\" name=\"form-" + articleFormCount + "-collection\">" +
        "<input type=\"hidden\" id=\"id_form-" + articleFormCount + "-order\" name=\"form-" + articleFormCount + "-order\">" +
        "<input type=\"hidden\" id=\"id_form-" + articleFormCount + "-id\" name=\"form-" + articleFormCount + "-id\">" +
        "</div>";

        articleFormCount++;

        $("div#articles").append(html);
    }
</script>

Call the function on page load:

<script type="text/javascript">
    $(document).ready(function()
    {
        buildArticleFormDiv();
    });
</script>

Then, whatever mechanism you use to add the new div (say, a hyperlink click event), call the buildArticleFormDiv() function.

Tim S. Van Haren
A: 

Here is the solution I have come up with so far. Anything look horribly wrong with it?

   function incAttrName(name) {
        return name.replace(/(.*form\-)(\d+)(\-.*)/, function(f, form, number, label) {
            return form + (parseInt(number) + 1) + label;
        });
    };

    $articleForm.find('[for]').attr('for', function() {
        var name = $(this).attr('for');
        return incAttrName(name);
    });

    $articleForm.find('[id]').attr('id', function() {
        var name = $(this).attr('id');
        return incAttrName(name);            
    });

    $articleForm.find('[name]').attr('name', function() {
        var name = $(this).attr('name');
        return incAttrName(name);            
    });
Jason Christa