skip to Main Content

Hello i have made a dynamic add and remove input fields and the code works great except the part when you reach the maximum limit to delete fields, this is my code:

function rmv()
    {
        var count = document.getElementsByTagName('input');
        if(count.length > 6){
            $(document).on('click', '#rmvbtn', function () {
                $(this).closest('#dynamic').remove();
            });
        }else{
            alert('Order must have minimum one product-1');
        }
    }

When the alert shows up and i click okay the last field is deleted, i tried debugging the code to see if it enters in the delete function after i press okay but it does not.
The reason there is a 6 is because there are 6 fields by default and user can add more and delete the new added but not the 6 default ones. So this error is deleting fields from the default part.

This is the html part its an edit panel where user can edit orders made for a client, this part is made with Laravel. The rows are printed as much times as many order prodcuts exist so each duplicated row has a button next to it to delete that specific row, this is the code:

@foreach($orders->products as $product)
                                <div id="olddynamic">
                                <div class="row mb-3">
                                    <label for="products" class="col-md-4 col-form-label text-md-end">{{ __('Product') }}</label>
                                    <div class="col-md-6">
                                        <select name="products[]" id="products" type="text" class="form-control @error('products') is-invalid @enderror" required autocomplete="products">
                                            <option value="" selected="true" disabled>{{$product->name}}</option>

                                            @foreach($productList as $item)
                                                <option value="{{$item->id}}">{{$item->name}}</option>
                                            @endforeach
                                        </select>

                                        @error('products')
                                        <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                        </span>
                                        @enderror
                                    </div>
                                </div>

                                <div class="row mb-3">

                                    <label for="amount" class="col-md-4 col-form-label text-md-end">{{ __('Amount') }}</label>

                                    <div class="col-md-6">
                                        <input id="amount" type="text" class="form-control @error('amount') is-invalid @enderror"
                                               name="amount[]" value="{{ $product->pivot->amount }}" required autocomplete="amount">

                                        @error('amount')
                                        <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                        </span>
                                        @enderror
                                    </div>
                                </div>
                                <div class="col"><button type="button" id="oldrmvbtn" onclick="oldrmv()" class="btn btn-primary"><span class="bi bi-dash-lg"></span></button></div>
                                </div>
                            @endforeach

There is also this add row button that adds new rows to the existing order this is the code:

<div class="col"><button type="button" id="addbtn" onclick="add()" class="btn btn-primary"><span class="bi bi-plus"></span></button></div>

This is the whole Javascript code:

<script>
    function add()
    {
        $('#amm').append(
            '<div id="dynamic"><div class="row mb-4"><label for="products" class="col-md-4 col-form-label text-md-end">{{ __("Product") }}</label><div class="col-md-6"><select name="products[]" id="products" type="text" class="form-control @error("products") is-invalid @enderror" required autocomplete="products">@foreach($productList as $item)<option value="{{$item->id}}">{{$item->name}}</option>@endforeach</select>@error("products")<span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>@enderror</div></div>  <div class="row mb-3"><label for="amount" class="col-md-4 col-form-label text-md-end">{{ __("Amount") }}</label><div class="col-md-6"><input id="amount" type="text" class="form-control @error("amount") is-invalid @enderror" name="amount[]" required autocomplete="amount">@error("amount")<span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>@enderror</div></div> <div class="col"><button type="button" id="rmvbtn" onclick="rmv()" class="btn btn-primary"><span class="bi bi-dash-lg"></span></button></div> </div>'
        );
    }

    function rmv()
    {
        var count = document.getElementsByTagName('input');
        if(count.length > 6){
            $(document).on('click', '#rmvbtn', function () {
                $(this).closest('#dynamic').remove();
            });
        }else{
            alert('Order must have minimum one product-1');
        }
    }

    function oldrmv()
    {
        var count = document.getElementsByTagName('input');
        if(count.length > 6){
            $(document).on('click', '#oldrmvbtn', function () {
                $(this).closest('#olddynamic').remove();
            });
            alert(count.length);
        }else{
            alert('Order must have minimum one product-2');
        }
    }
</script>

2

Answers


  1. The main issue is due to the nested click event handler within the rmv() function. You should remove that and use a single delegate event handler for the dynamic content.

    That being said, there’s quite a few other things you can do to improve the code quality here:

    • Avoid putting HTML in your JS. If you do include HTML in the JS, it should absolutely not be an entire multi-line structure. Use a <template> to store it.
    • Remove the id attributes in the content which can be dynamically repeated, otherwise you’ll create duplicates which will cause problems. Change them to classes instead.
    • The ‘Remove’ logic is broken, assuming that your intention is to ensure there is always at least 1 item added – as the error message states.

    With that said, try this working version:

    const $container = $('#amm');
    const $template = $('#amm-template');
    
    $('#add').on('click', () => {
      $container.append($template.html());
    });
    
    $container.on('click', '.rmvbtn', e => {
      if ($('.amm-item').length > 1) {
        $(e.target).closest('.amm-item').remove();
      } else { 
        alert('Order must have minimum one product-1');
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
    <button id="add">Add</button>
    <div id="amm"></div>
    
    <template id="amm-template">
      <div class="amm-item">
        <div class="row mb-4"><label for="products" class="col-md-4 col-form-label text-md-end">{{ __("Product") }}</label>
          <div class="col-md-6">
            <select name="products[]" type="text" class="product form-control @error("products") is-invalid @enderror" required autocomplete="products">
              @foreach($productList as $item)
                <option value="{{$item->id}}">{{$item->name}}</option>
              @endforeach
            </select>
            @error("products")
              <span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>
            @enderror
          </div>
        </div>
        <div class="row mb-3">
          <label for="amount" class="col-md-4 col-form-label text-md-end">{{ __("Amount") }}</label>
          <div class="col-md-6">
            <input type="text" class="amount form-control @error("amount") is-invalid @enderror" name="amount[]" required autocomplete="amount">
            @error("amount")
              <span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>
            @enderror
          </div>
        </div>
        <div class="col">
          <button type="button" class="rmvbtn" class="btn btn-primary">
            <span class="bi bi-dash-lg">REMOVE</span>
          </button>
        </div>
      </div>
    </template>
    Login or Signup to reply.
  2. Please delete onclick="add()", onclick="rmv()" and onclick="oldrmv()" in HTML.

    After change Javascript

    $(document).ready(function() {
        $(document).on('click', '#addbtn', function () {
            $('#amm').append(
                '<div id="dynamic"><div class="row mb-4"><label for="products" class="col-md-4 col-form-label text-md-end">{{ __("Product") }}</label><div class="col-md-6"><select name="products[]" id="products" type="text" class="form-control @error("products") is-invalid @enderror" required autocomplete="products">@foreach($productList as $item)<option value="{{$item->id}}">{{$item->name}}</option>@endforeach</select>@error("products")<span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>@enderror</div></div>  <div class="row mb-3"><label for="amount" class="col-md-4 col-form-label text-md-end">{{ __("Amount") }}</label><div class="col-md-6"><input id="amount" type="text" class="form-control @error("amount") is-invalid @enderror" name="amount[]" required autocomplete="amount">@error("amount")<span class="invalid-feedback" role="alert"><strong>{{ $message }}</strong></span>@enderror</div></div> <div class="col"><button type="button" id="rmvbtn" onclick="rmv()" class="btn btn-primary"><span class="bi bi-dash-lg"></span></button></div> </div>'
            );
        });
    
        $(document).on('click', '#rmvbtn', function () {
            let count = document.getElementsByTagName('input');
            if(count.length > 6){
                    $(this).closest('#dynamic').remove();
            }else{
                alert('Order must have minimum one product-1');
            }
        });
    
        $(document).on('click', '#oldrmvbtn', function () {
            let count = document.getElementsByTagName('input');
            if(count.length > 6){
                $(this).closest('#olddynamic').remove();
            }else{
                alert('Order must have minimum one product-2');
            }
        });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search