1

I have a button that adds a new div with a select tag, every option has custom attributes. my problem is when I create a several divs the function only refers to the last div I have created when I am trying to change the first select tag the function not responding.

I have tried to give all of the divs and the input a different id's but that doesn't work.

 <button type="button" class="cam_field_button btn waves-effect waves-light btn-outline-info" >הוסף צלם</button>


var max_fields = 25; //maximum input boxes allowed
var wrapper = $(".camera_men"); //Fields wrapper
var add_button = $(".cam_field_button"); //Add button ID

var x = 0; //initlal text box count
$(add_button).click(function (e) { //on add input button click
    e.preventDefault();
    if (x < max_fields) { //max input box allowed
        x++; //text box increment
        $(wrapper).append('<div>   <br> <select name="cam[]"  id="cam_select'+x+'"  class="form-control" >\n' +
            '                                            <option email="email" phone="phone"  value="צלם 1">צלם 1</option>\n' +
            '                                            <option email="email2" phone="phone2" value="צלם 2">צלם 2</option>\n' +
            '                                            <option email="email3" phone="phone3" value="צלם 3">צלם 3</option>\n' +
            '                                        </select><a href="#" class="remove_field">הסר צלם ' + x + '</a><div>  <input type="hidden" name="cam_email[]" id="cm_email' + x + '">\n' +
            '                                        <input type="hidden" name="cam_phone[]" id="cm_phone' + x + '">'); //add input box
        $('#cam_select'+x).on('change',function () {


            var email =  $('#cam_select'+x+' option:selected').attr("email");
            var phone =  $('#cam_select'+x+' option:selected').attr("phone");

            $('#cm_email'+x).val(email);
            $('#cm_phone'+x).val(phone);
        })
    }
kukkuz
  • 41,512
  • 6
  • 59
  • 95
dror shalit
  • 318
  • 2
  • 12

3 Answers3

1

So I have made some changes to your code -

  1. Use classes instead of ids - because you can't have mutliple id's.
  2. I have used template literals here because I like it :)
  3. See how I am using a dynamic jquery listener using $(document).on('change', '.cam_select' + x, function(e) { - the off('change') to ensure that there are no duplicate listeners though here there isn't any.
  4. Also we can get the clicked element using e.target where e is the event object.
  5. Note that I have added one more wrapper to the appended markup - cam and how I am using it using the closest function and then find methods to find siblings and cousins in the cam wrapper which was dynamically inserted.

Check out the demo below illustrating these:

$(document).ready(function() {
  var max_fields = 25;
  var wrapper = $(".camera_men"); 
  var add_button = $(".cam_field_button");
  var x = 0; 
  $(add_button).click(function(e) {
    e.preventDefault();
    if (x < max_fields) {
      x++;
      $(wrapper).append(`
        <div class="cam">
          <div>
            <select name="cam[]" class="form-control cam_select">
              <option email="email" phone="phone" value="צלם 1">צלם 1</option>
              <option email="email2" phone="phone2" value="צלם 2">צלם 2</option>
              <option email="email3" phone="phone3" value="צלם 3">צלם 3</option>
            </select>
         <a href="#" class="remove_field">הסר צלם ${x}</a>
    <div>
          <input type="input" name="cam_email[]" class="cm_email">
          <input type="input" name="cam_phone[]" class="cm_phone">
        </div>`);
      $(document).off('change').on('change', '.cam_select', function(e) {
        var email = $(e.target).find('option:selected').attr("email");
        var phone = $(e.target).find('option:selected').attr("phone");
        $(e.target).closest('.cam').find('.cm_email').val(email);
        $(e.target).closest('.cam').find('.cm_phone').val(phone);
      });
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" class="cam_field_button btn waves-effect waves-light btn-outline-info">הוסף צלם</button>

<div class="camera_men"></div>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
  • thank you!!! this is working great!! one more question, please. if I am adding a div selecting the option and then click the button again and selecting the option it workes great. but if I am adding multiple divs before I am selecting an option only the last div getting the values – dror shalit Feb 02 '19 at 13:05
  • @drorshalit the issue was using`x` inside `$(document).off('change').on('change', '.cam_select', function(e) {` - by the time another `cam` is added the value of `x` changed... fixed it now... have a look.. thanks! – kukkuz Feb 02 '19 at 13:42
0

You can use class selector instead of ids

Example:

...
$(wrapper).append(<select class="form-control cam_select" >...</select>...)
...
$('.cam_select').on('change',function () {

  var email =  $('option:selected',this).attr("email");
  var phone =  $('option:selected',this).attr("phone");

  $(this).parent().children('.cm_email').val(email);
  $(this).parent().children('.cm_email').val(phone);
})

I have not tried the code, sorry if there are errors

  • sorry...not woking :) – dror shalit Feb 02 '19 at 11:44
  • thank you very much! I can see now that the change function is referring to each div but my problem now is that I don't get the attribute values to my input with this line $(this).parent().children('.cm_email').val(email); – dror shalit Feb 02 '19 at 12:22
0

@Allesandro made a move in the right way.

You can detach the event handler code from the creation method (button click) and just supply the event handler logic in the script so it is available to the document and controls we are talking about.

But, you have to make this a so-called jQuery delegated event handler that will work for newly created controls on-the-fly (which is your scenario) and for controls matching the selector that were in the html already when the document was initially loaded: it looks like this:

$(document).on('change', '.cam_select', function () {
  ...
})

You can also be more specific off course and use wrapper for the initial selector instead of document.

Event delegation:

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.

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59