0

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!

Alex
  • 5
  • 2
  • Are you looking for a solution in plain javascript without React or with React? – Harish Jan 17 '23 at 12:48
  • I think you should better focus the question following the title. Otherwise it seems you are asking for that exact form and it would be too broad in my opinion – Diego D Jan 17 '23 at 12:57
  • @Harish I built this project on Vite + React so react based JS approach would be quite nice – Alex Jan 17 '23 at 13:21
  • @DiegoD Yeah you are right, but I just gave it as an example, any basic approach would still be fine for me to advance on that subject since I can't deduct any algorithm or approach on this task. – Alex Jan 17 '23 at 13:23
  • Ok then.. but one question: since you said _"When the user enters the quantity of products, new fields [...] without the need for clicking any button"_ can you elaborate? do you mean the action must be triggered as soon as the user leaves the quantity input focus? are you sure? wouldn't it better if there was a button? and in case you preferred the first option, is the adding of elements something permanent? or if you change that number the elements just get replaced with the new ones? ***EDIT*** actually in the pictures there are buttons add and remove on custom types – Diego D Jan 17 '23 at 13:27
  • @DiegoD Thanks a lot for noticing that particular section. Actually yes, what I need is to track the users input lively where if their mind is changed and wanted to enter 3 instead of 5, 3 input fields will be generated. It is not important for me whether the info in them lasts or gets removed. I'm only curious about the number of inputs are tracked live with the change of that value given by the user. **EDIT** The first picture is where you input the quantity, the second one is the input fields based on that quantity value – Alex Jan 17 '23 at 13:31

1 Answers1

1

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>
Diego D
  • 6,156
  • 2
  • 17
  • 30
  • This is exactly what I was asking for! You are a great and fast problem solver! Thank you for your effort and time. Cheers! – Alex Jan 17 '23 at 14:15