javascriptinput-field

How to add number of input fields based on value entered on a different input field


After searching a lot on Stackoverflow, I couldn't find a solution where only Javascript used code was achieving to do the task that I wanted to create.

I have a form created on React where I am generating input fields with the help of add and remove buttons. On the other hand, what I want is based on the user input on the field, there will be other inputs as well. To clarify more let's take a look at the example picture below to draw the frontend profile:

Front end of the Webpage

When the user enters the quantity of products, new fields will be automatically generated based on the input value without the need for clicking any button. For example if the quantity is 5, I need 5 input fields for that product as in the image below

Dynamic Input Fields

I want to achieve this using Javascript functions but since I am a beginner, I don't know what to use or apply. I would appreciate a lot for your advises and solutions. Cheers!


Solution

  • My answer is not strictly a component but it shows more or less how you can deal with a confined structure (package) capturing the input event listener for all the quantity input text controls.

    Every time the event fires (when the user inputs data inside the field), the given number of "products" are created and added to the corresponding element in the package where the event originated.

    Styling wise it's terrible but I did the bare minimum to deliver something worth seeing.

    I styled the product number in the list using css counters and a ::before pseudo element just for the sake of adding maybe useful ideas to the game:

    //add input event listener to qty input
    [...document.querySelectorAll('.package .qty')]
      .forEach( qtyEl => {
        qtyEl.addEventListener('input', (event)=>{
          const qtyEl = event.target;
          const qty = event.target.value;
          clearProducts(qtyEl);
          addProducts(qtyEl, qty);
        });
      })
    
    //removes the products in the given package  
    function clearProducts(from){
      const target = from.closest('.package').querySelector('.products');
      target.innerHTML = '';
    }
    
    //adds a number of products in the given package
    function addProducts(from, n){
      const target = from.closest('.package').querySelector('.products');
      for(let i = 0; i<n; i++){
        const product = createProduct();
        target.append(product);
      }  
    }
    
    //creates and returns a product
    function createProduct(){
      const product = document.createElement('div');  
      const input = document.createElement('input');  
      product.classList.add('product');
      input.classList.add('product-name');
      product.append(input);
      
      return product;
    }
    .package{
      display: flex;  
      flex-wrap: wrap;
      gap: 1em;
      border: solid purple;
      padding: 1em;
      margin-bottom: 1em;
      
      counter-reset: product;
    }
    
    .package .type{
      width: 50%;
      height: 2rem;
    }
    
    .package .products{  
      width: 100%;
      display: flex;
      flex-direction: column;
      padding: 1em;
    }
    
    .product{
      position: relative;
      margin-bottom: 1em;
      border: solid 1px darkgray;  
      padding: 1em;
    }
    
    .product::before {
      counter-increment: product; 
      position: absolute;
      content: "Product " counter(product) ": ";
      top: -13px;
      left: 10px;
      font-size: 1rem;  
      color: darkgray;
      background: white;
      padding: 2px;
    }
    
    .product input{
      width: 100%;
      border: none;
    }
    <div class="package">
      <input type="text" class="type">
      <input type="number" class="qty">
      <div class="products">
      </div>
    </div>
    
    <div class="package">
      <input type="text" class="type">
      <input type="number" class="qty">
      <div class="products">
      </div>
    </div>