JS-NL
JS-NL

Reputation: 235

Use dynamic input fields in combination with php foreach

I'm trying to build a page with a few task lists. For this part, I want to use dynamic input fields. The form is being looped by a foreach, which looks to the number of users.

The problem now is that the tags (add, remove and reset) are not working except at the "first loop". And when I click on the on the first loop value, a field will be added at all the "loops", instead of only the first loop.

My PHP Code:

<?php 
    foreach (glob(/*user as file*/) as $filename) {
        echo '
            <div class="col-md-4 taskblock">
                <img class="taskimage" src="../../../'.$filename.'"/>
                <div class="name">User</div>
                <div class="dynamic-form">

                <a id="add">Add</a> | <a id="remove">Remove</a>  | <a id="reset">Reset</a>  

                    <form>
                    <div class="inputs">
                    <div><input name="dynamic[]" class="field" value="1" type="text"></div>
                    </div>
                    <input name="submit" class="submit" value="Submit" type="button">
                    </form>
                    </div>

                </div>
            ';
    }
?>

And my Script:

$(document).ready(function(){

    var i = $('input').size() + 1;

    $('#add').click(function() {
        $('<div><input type="text" class="field" name="dynamic[]" value="' + i + '" /></div>').appendTo('.inputs');
        i++;
    });

    $('#remove').click(function() {
        if(i > 1) {
            $('.field:last').remove();
            i--;
        }
    });

    $('#reset').click(function() {
        while(i > 2) {
        $('.field:last').remove();
        i--;
        }
    });

    // here's our click function for when the forms submitted

    $('.submit').click(function(){

        var answers = [];
        $.each($('.field'), function() {
            answers.push($(this).val());
        });

        if(answers.length == 0) {
            answers = "none";
        }

        alert(answers);

        return false;

    });

});

Upvotes: 2

Views: 1215

Answers (1)

spenibus
spenibus

Reputation: 4409

Preamble

Multiple things to fix here.

id vs class

An id property must be unique in a document. This is the reason add, remove and reset only affect the first item. We must change them to class.

<a class="add">Add</a> | <a class="remove">Remove</a>  | <a class="reset">Reset</a>

Counting the fields

Because you are using var i = $('input').size() + 1;, you are actually counting both the text fields and the submit buttons. As such, If you have 3 items and add a text field, it will be populated with the value 7 instead of 4. We must limit the counting to text fields by targeting them with their class .field:

var i = $('input.field').size() + 1;

Targeting the current item only

Because you use appendTo('.inputs');, you add a new text field to all items as they each have that element. You must limit the addition to the current item.

To achieve this, we make use of the this keyword, which will return the add element that triggered the event. From there, we reach the parent element, look for the .inputs element within it, then we inject the new element into it.

$(this).parent().find('.inputs')
    .append('<div><input type="text" class="field" name="dynamic[]" value="' 
    + i + '" /></div>');

That same basic logic must be applied to remove, but for reasons explained in the next part, we will do something slightly different:

var field = $(this).parent().find('.field:gt(0):last')
i -= field.length;
field.remove();

A better reset

Because the variable i is common to all items, its value is always larger than the number of text fields found in any item. Using reset will simply remove all text fields. Instead we must remove all fields except the first from the current item and alter i by subtracting the number of fields we remove.

We select all the fields except the first using the :gt() selector, subtract the number of returned fields from i and then remove the fields.

var fields = $(this).parent().find('.field:gt(0)');
i -= fields.length;
fields.remove();

Epilogue

A demo in available in this JSFiddle.

I'm also not quite sure about the purpose of the variable i and would promptly ditch it, due to its global nature.

Upvotes: 1

Related Questions