0

I'm new in JQuery and I have a problem with dynamic forms. I would like to create a dynamic field, where a user will be able to create as many fields as he wants. Unfortunately, the options from the second field, generate after the first one is related to every dynamic field in the wrapper. How can I fix that?

Thank you in advance - I will be grateful for every answer!

<div class='input_fields_wrap'>
<button class='add_field_button'>Add more fields</button>
<div>
    <label for='service'>Usługa</label>
    <select name='service' class='service'>
        <option value='Wybierz' selected>Wybierz</opiton>
        <option value='Listy'>Listy</option>
        <option value='Paczki'>Paczki</option>
    </select>
    <select name='type' class='type'></select>

</div>

<script>
  $(document).ready(function() {
    var listy = [
                 {display: 'A', value: 'A'},
                 {display: 'B', value: 'B'}];
    var paczki = [
                  {display: 'C', value: 'C'},
                  {display: 'D', value: 'D'}];

    var max_fields = 20;
    var wrapper = $('.input_fields_wrap');
    var add_button = $('.add_field_button');
    var x = 1;

    $(add_button).click(function(e){
        e.preventDefault();
        if(x<max_fields){
            x++;
            $(wrapper).append("<div><label for='service'>Usługa</label>" +
                              "<select name='service' class='service'>" +
                              "<option value='Wybierz' selected>Wybierz</option>" +
                              "<option value='Listy'>Listy</option>" +
                              "<option value='Paczki'>Paczki</option>" +
                              "</select><a href='#' class='remove_field'>Remove</a>" +
                              "<select name='type' class='type'></select>" +
                              "</div>");
        }
    });

    $(wrapper).on('click', ".remove_field", function(e){
        e.preventDefault();
        $(this).parent('div').remove();
        x--;
    });
    $('.service').change(function(e){
        e.preventDefault();
        var parent = $(this).val();
        switch(parent){
            case 'Listy':
                list(listy);
                break;
            case 'Paczki':
                list(paczki);
                break;
        }
    });

    function list(array_list){
        $('.type').html("");
        $(array_list).each(function(i){
            $('.type').append("<option value="+array_list[i].value+">"+array_list[i].display+"</option>");
        });
    }

});

1
  • can you share the html? Commented Feb 17, 2017 at 8:04

2 Answers 2

1

Change $('.service').change(function(e){ to $(wrapper).on('change', '.service', function(e) {

$('.service').change(function(e){ will only listen to the classes that are present at the time. The latter, the .on(), listens to the wrapper and will execute whenever a .service changes.

I've noticed in your code that when you change one type, all of them are beeing replaced. You can fix this by adding a parameter to the list function. If this is however desired, just replace element with '.type'

This would look like this

  $(wrapper).on('change', '.service', function(e) {
    e.preventDefault();
    var parent = $(this).val();
    switch (parent) {
      case 'Listy':
        list(listy, $(this).next().next());
        break;
      case 'Paczki':
        list(paczki, $(this).next().next());
        break;
      // TODO: add case for Wybierz
    }
  });

  function list(array_list, element) {
    $(element).html("");
    $(array_list).each(function(i) {
      $(element).append("<option value=" + array_list[i].value + ">" + array_list[i].display + "</option>");
    });
  }

solution

$(document).ready(function() {
  var listy = [
               {display: 'A', value: 'A'},
               {display: 'B', value: 'B'}];
  var paczki = [
                {display: 'C', value: 'C'},
                {display: 'D', value: 'D'}];

  var max_fields = 20;
  var wrapper = $('.input_fields_wrap');
  var add_button = $('.add_field_button');
  var x = 1;

  $(add_button).click(function(e) {
      e.preventDefault();
      if (x < max_fields) {
        x++;
        $(wrapper).append("<div><label for='service'>Usługa</label>" +
          "<select name='service' class='service' <!-- here -->" +
          "<option value='Wybierz' selected>Wybierz</option>" +
          "<option value='Listy'>Listy</option>" +
          "<option value='Paczki'>Paczki</option>" +
          "</select><a href='#' class='remove_field'>Remove</a>" +
          "<select name='type' class='type'></select>" +
          "</div>");
      }
    })
    // create a button by default
    .trigger('click')

  $(wrapper).on('click', ".remove_field", function(e) {
    e.preventDefault();
    $(this).parent('div').remove();
    x--;
  });

  $(wrapper).on('change', '.service', function(e) {
    e.preventDefault();
    var parent = $(this).val();
    switch (parent) {
      case 'Listy':
        list(listy, $(this).next().next());
        break;
      case 'Paczki':
        list(paczki, $(this).next().next());
        break;
      // TODO: add case for Wybierz
    }
  });

  function list(array_list, element) {
    $(element).html("");
    $(array_list).each(function(i) {
      $(element).append("<option value=" + array_list[i].value + ">" + array_list[i].display + "</option>");
    });
  }

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='input_fields_wrap'>
<button class='add_field_button'>Add more fields</button>

Sign up to request clarification or add additional context in comments.

3 Comments

Hi! Thank you for help but it's half-way done. That's true, now the dynamic option appears only in selected option, but simultaneous changing in many fields is blocked. Furthermore, I cannot change anything in the first field created by default.
@Kleju_0011 I'm not sure what you mean by " simultaneous changing in many fields". I've updated the code to create a button by default, use the HTML from my example, don't have a default entry inside the HTML. I create a default entry by simulating a click at the beginning .trigger('click'), this is the way to do it.
Ok, now I see - I didn't notice the whole solution and trigger stuff. Now is working. Thanks!
0

Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future. Reference: https://learn.jquery.com/events/event-delegation/

You need to do following.

        $(wrapper).on('change','.service', function(e) {
            e.preventDefault();
            var parent = $(this).val();
            switch(parent){
                case 'Listy':
                    list(listy);
                    break;
                case 'Paczki':
                    list(paczki);
                    break;
            }
        });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.