0

When a user starts typing in an empty input in a list I would like a new input to be appended to the list the for the next value to be added. Then, if they type in the new input, another new one is added and so on.

The code I have is..

$('.addNew').on('input', function(){
    var $parentUl = $(this).closest('ul');
    if($(this).val().length === 0){
        $(this).removeClass('addNew');
        $parentUl.append('<li class="catsLi"><input type="text" class="catItem addNew" name="reason[]" value=""/></li>');
    }
});

This works but it adds a new input every time the users type another character rather than just on the first one. I have tried using one instead of on but then it will only add extra input, if the user types in the new input nothing happens.

With this in mind I thought I would check if the input is empty before appending a new input so it only does it once per input but it isn't working.

I can see from chrome inspect that when I type in the input, it isn't actually changing it's value which is why it always adds a new input so I have tried checking for $(this).text().length instead but it still thinks it's empty.

tatty27
  • 1,553
  • 4
  • 34
  • 73
  • Possible duplicate of [Event binding on dynamically created elements?](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Taplar Jun 08 '18 at 18:12
  • Delegate bind on the parent ul, process the input event for the children that have the addNew class, and then removing the addNew class from the inputs will cause the handler to not execute for them again. New children with the addNew class will be processed by the delegate event handler. – Taplar Jun 08 '18 at 18:13
  • Use `$(.addNew)` in place of `$(this)` inside function (callback one), since you are inside a function and scope is changed. Or just log `this` to see what's inside `this` – Jay Jodiwal Jun 08 '18 at 18:15
  • used a combination of both your comments. I stored the length of $(this) in $chars before callback one and then if($chars === 1) so it only did the cal back if only character was in the input. I also delegated the the bind on the ul. Thank you both. – tatty27 Jun 08 '18 at 18:59

2 Answers2

1

Using .one() would be a good option, you just have to make sure you also add a listener to the new input field that you append. Here's a proof-of-concept:

// save a reference to the parent <ul> so we only have to look it up once
$parentUL = $('#parentUL');

function addNewField() {
  // create a new <li>
  var $newLI = $('<li class="catsLi"><input type="text" class="catItem" name="reason[]" value=""/></li>');

  // when the user first types in this new field, call addNewField() to add another "new" field to the list
  // (.one() ensures that the event will only fire once per field)
  $newLI.find('input').one('input', addNewField);

  // add the new <li> element to the end of the <ul>
  $parentUL.append($newLI);
}

// add a "new" field as soon as the page loads
addNewField();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<ul id="parentUL">
  <li class="catsLi"><input type="text" class="catItem" value="Existing One"/></li>  
  <li class="catsLi"><input type="text" class="catItem" value="Existing Two"/></li>  
</ul>
Briley Hooper
  • 1,271
  • 6
  • 16
  • perfect, I'd worked out another solution too which I'll post but yours is probably the better way to do it, thanks – tatty27 Jun 08 '18 at 18:53
0

Managed to create my own solution based on the comments from above

$('.posUl').on('input', '.addNew', function(){
    var $parentUl = $(this).closest('ul');
    var $entered = $(this).val().length;
    if($entered === 1){
        $parentUl.append('<li class="catsLi"><input type="text" class="catItem addNew" name="reason[]" value=""/></li>');
    }
});

By checking the value of $entered I discovered it was never empty on change (obviously) then binding it on the ul meant it worked on the new input which was a dynamic element

tatty27
  • 1,553
  • 4
  • 34
  • 73
  • Be careful: there are at least two situations where that code will probably not do what you want: (1) if you delete everything from any of the fields and start typing again then that code will end up appending a new field, and (2) if you paste something in an empty input field rather than type in it then that code won't append a new field. – Briley Hooper Jun 10 '18 at 03:25