1

I have dynamic input fields generated from a jquery function. There is the ability to add or delete through button clicks these input fields. The fields are populated with data from mysql table. Each populated input has a unique ID fetched from the DB. When adding a new field I am getting the next AUTO_INCREMENT from an ajax request. I am then able to increment +1 but for all fields. I only want to do this for the new fields. If by some reason an insert query transaction is made from another app it will update start increment from field and then update the rest with the correct values (check to see what I mean jsFiddle(http://jsfiddle.net/f9XP8/2/).

The problems is how to put it all together. I just want to follow to able to add a new field and assign it the appropriate next person_id for db insert. LIVE EXAMPLE

<script>
$(document).ready(function () {
    var $increment_num = $('#increment_num');
    var interval = 100;  //3000 = 3 seconds
    function doAjax() {
        $.ajax({
            type: 'POST',
            url: 'personAutoIncrement.php',
            data: $(this).serialize(),
            dataType: 'json',
            success: function (data) {
                    var $cloned = $('#input_table tr');
                    var num = parseInt(data);
                    $increment_num.val(num);
                    $cloned.each(function(i){
                        $(this).find('[name^="increment_id"]').first().val(num+i);
                    })
            },
            complete: function (data) {
                // Schedule the next
                setTimeout(doAjax, interval);

        }
    });
    }
    setTimeout(doAjax, interval);
    var click_count = 0;
    $('#btnAdd').click(function () {
    click_count++;
        var $clones     = $('#input_table tr'),
            num         = $clones.size() + 1,
            next_num    = parseInt($clones.last().find('input[name^="increment_id"]').val()) + 1,
            $template   = $clones.first(),
            newSection  = $template.clone().attr('id', 'pq_entry_'+num),
            ident       = 'increment_id_'+num;
            person_id = 'person_id_'+num;
            person_fname = 'person_fname_'+num;
            person_lname = 'person_lname_'+num;

        // clear out all sections of new input
        newSection.find('input').not('[name^="increment_id"]').val('');

        newSection.find('input[name^="increment_id"]').attr({
            'id': ident,
            'name': ident
        }).val(/*next_num*/);
        newSection.find('input[name^="person_id"]').attr({
            'id': person_id,
            'name': person_id
        }).val(/*next_num*/);
        newSection.find('input[name^="person_fname"]').attr({
            'id': person_fname,
            'name': person_fname
        }).val(/*next_num*/);


        $('#input_table').append(newSection);
        $('#btnDel').prop('disabled', '');
        if (num == 100) $('#btnAdd').prop('disabled', 'disabled');
    });

    $('#btnDel').click(function () {
        var num = $('.clonedSection').length; // how many duplicate input fields we currently have
        $('#pq_entry_' + num).remove(); // remove the last element

        // enable the "add" button
        $('#btnAdd').prop('disabled', '');

        // if only one element remains, disable the "remove" button
        if (num - 1 == 1) $('#btnDel').prop('disabled', 'disabled');
    });

    $('#btnDel').prop('disabled', 'disabled');
});
</script>

html

<table>
    <thead>
        <tr>
            <th>ID from DB</th>
            <th>First Name</th>
        </tr>
    </thead>
    <tbody id="input_table">
        <tr id="pq_entry_1">
            <td><input type="text" id="increment_id_1" name="increment_id_1" readonly value="5" /></td>
            <td><input type="text" name="first_name" placeholder="First Name" /></td>
        </tr>
    </tbody>
</table>
<input type='button' id='btnAdd' value='add text box' />
<input type='button' id='btnDel' value='Delete' /></br>
</table>

enter image description here

  • Why can't you just delegate the AUTO_INCREMENT field to your db-layer? You shouldn't mess up with it on the client: even showing the ID field is a bad idea in general. I'd prefer to retrieve new ids after the final submit, directly from the server (i.e. the db-server). – alexcasalboni Dec 05 '13 at 23:59
  • Are you using MySQL or a similar RDBMS? – Rob M. Dec 06 '13 at 04:01
  • @RobM. I am using MySQL. WOuld you like me to paste the mysql/php code? –  Dec 06 '13 at 05:10
  • @RobM. Any ideas to get this accomplished? –  Dec 06 '13 at 06:47

1 Answers1

2

If I'm not mistaken, you are wanting to know how to increment certain rows, but allow others to be "frozen" (because they are saved to the database). I have changed your code a bit more, here are the important notes:

  1. I removed the dynamic name attributes. You don't need to dynamically generate field names, you can just assign data-* attributes to hold the id or refer to tr.find('input[name="person_id"]')
  2. Added a data-saved attribute to the tr to know whether or not it should be included in the updated auto increment id or if it should just stay as it is
  3. Added a save button next to each row, which as it is just sets the data-saved attribute on the row, you can add an AJAX call to save the record if you want

Updated Fiddle

The Javascript:

$(document).ready(function () {
    var $increment_num = $('#increment_num');
    var interval = 5000;  //3000 = 3 seconds
    function doAjax() {
        $.ajax({
            type: 'POST',
            url: 'personAutoIncrement.php',
            data: $(this).serialize(),
            dataType: 'json',
            success: function (data) {
                var $cloned = $('#input_table tr').not('[data-saved]');
                var num = parseInt(data);
                $increment_num.val(num);
                $cloned.each(function(i){
                    var $this = $(this);
                    $this.find('[name^="person_id"]').first().val(num+i);
                })
            },
            complete: function (data) {
                // Schedule the next
                setTimeout(doAjax, interval);
            }
        });
    }
    setTimeout(doAjax, interval);
    var click_count = 0;

    $('#btnAdd').click(function () {
        click_count++;
        var $clones     = $('#input_table tr'),
            num         = $clones.size() + 1,
            next_num    = parseInt($clones.last().find('input[name^="person_id"]').val()) + 1,
            $template   = $clones.first(),
            newSection  = $template.clone().attr('id', 'pq_entry_'+num),
            person_id   = 'person_id_'+num;
            person_fname = 'person_fname_'+num;
            person_lname = 'person_lname_'+num;

        newSection.removeAttr('data-saved');

        // clear out all sections of new input
        newSection.find('input[type="text"]').val('');

        newSection.find('input[name^="person_id"]').attr({
            'id': person_id
        }).val(next_num);

        newSection.find('input[name^="person_fname"]').attr({
            'id': person_fname
        });

        newSection.find('input[type="button"]').attr('data-ident', next_num);


        $('#input_table').append(newSection);
        $('#btnDel').prop('disabled', '');
        if (num == 100) $('#btnAdd').prop('disabled', 'disabled');
    });

    $('.save-button').click(function(){
        var $parent = $(this).parents('.clonedSection')
        var id = $parent.find('input[name="person_id"]').val();
        // do whatever else here, save to db
        $parent.attr('data-saved', '1');
    })

    $('#btnDel').click(function () {
        var num = $('.clonedSection').length; // how many duplicate input fields we currently have
        $('#pq_entry_' + num).remove(); // remove the last element

        // enable the "add" button
        $('#btnAdd').prop('disabled', '');

        // if only one element remains, disable the "remove" button
        if (num - 1 == 1) $('#btnDel').prop('disabled', 'disabled');
    });

    $('#btnDel').prop('disabled', 'disabled');
});

The HTML:

<form>
<strong>Start Increment from Next ID to be inserted in the DB:</strong><input id="increment_num" name="increment_num"  type="text" /></br>
<table>
    <thead>
        <tr><th>ID from DB</th><th></th>
        <th>First Name</th></tr>
    </thead>
    <tbody id="input_table" >
        <tr id="pq_entry_1" class="clonedSection" data-saved="1">
            <td><input type="text" name="person_id" value='1' readonly /></td>
            <td><input id="person_fname_1" name="person_fname" placeholder=" First Name" type="text" value='James'/></td>
            <td><input type="button" class="save-button" value="Save" />
        </tr>
        <tr id="pq_entry_2" class="clonedSection" >
            <td><input type="text" name="person_id" value='2' readonly /></td>
            <td><input id="person_fname_2" name="person_fname" placeholder=" First Name" type="text" value='Cynthia'/></td>
            <td><input type="button" class="save-button" value="Save" />
        </tr>
    </tbody>
</table>
<input type='button' id='btnAdd' value='add another Person' />
<input type='button' id='btnDel' value='Delete' /></br>
</form>

Having said all of that, I probably would approach this differently by having a hidden element:

<input type="hidden" name="person_id" value="1" />

That when a new row was generated was nullified:

<input type="hidden" name="person_id" value="" />

Then in my PHP, I would allow MySQL to handle auto incrementing the id in a manner like this:

<?php
    $params = $_POST;
    if(is_numeric($params['person_id'])){
       $sql = sprintf('UPDATE person SET fname = "%s", lname = "%s" WHERE person_id = %u LIMIT 1', 
          mysql_real_escape_string($params['fname']), 
          mysql_real_escape_string($params['lname']), 
          intval($params['person_id'])
       );
    } else {
       // the NULL tells MySQL to select the correct next increment id automatically
       $sql = sprintf('INSERT INTO person (id, fname, lname) VALUES (NULL, "%s", "%s")',
         mysql_real_escape_string($params['fname']),
         mysql_real_escape_string($params['lname']);
       );
    }

?>
Rob M.
  • 35,491
  • 6
  • 51
  • 50
  • This worked perfectly! thankyou. A small consultation: Since I am doing an ajax call every 3 seconds, should I consider doing [Server Sent Events](https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events)(SSE's)? –  Dec 06 '13 at 10:00
  • Glad I could help. Regarding SSE, I would personally opt for websockets, but if you have experience with SSE and it fits your use case then sure :) – Rob M. Dec 06 '13 at 14:22
  • Thank you. I would read more into it. Rob what would suggest for deleting a user from DB when clicking `delete` button? –  Dec 07 '13 at 06:08
  • I would move the delete button into each row (like the save button) and use logic very similar to the click handler I defined for `$('.save-button')` – Rob M. Dec 07 '13 at 06:10
  • Rob another consultation, in regards to the `delete new field button` (this is not related to the `delete user button`): How can I have the the fields populated from values from the DB not be able to be removed? Have them somehow locked in. A user can add new fields or delete those new fields but they cant, delete the fields there already. –  Dec 07 '13 at 21:32
  • I made a question to make it formal [HERE](http://stackoverflow.com/questions/20447448/deleting-input-fields-dynamically-that-dont-have-a-unique-attribute) –  Dec 07 '13 at 22:26
  • Using the same if(elem.not('[data-saved'])) check – Rob M. Dec 07 '13 at 22:33
  • I have an new question regarding something similar, would you please be able to assist me: http://stackoverflow.com/questions/20485967/add-values-to-select-field-dynamically –  Dec 10 '13 at 04:18
  • could you give me some guidance/help on this [QUESTION](http://stackoverflow.com/questions/20485967/add-values-to-select-field-dynamically)? It has more dynamic fields but the purpose is the same. –  Dec 10 '13 at 18:44