Assigning a id+index value to a form field for manipulation using Alpine Js / Javascript in Laravel

Viewed 434

Environment: Laravel 9, Alpine Js, TailWinds CSS, Vanilla Js

I am trying to do value replacement in a form field when a user enter " to inch or ' to ft. I have implemented an 'add another row' functionality to the page which ends up giving me multiple fields with the same id.

I don't know how to highlight a particular line of code so I added <!-- HERE ----> (2 places) to the description field code below...

<!--  PO Lines Below  -->

<!--  Row 1 Fields  -->
    <div class="row" x-data="handler()">
        <div class="col">

         <template x-for="(field, index) in fields" :key="index">

            <div id="po_line" class="my-4">

               Line: <strong x-text="index + 1"></strong>
                    <label for="qty">Qty: </label>
                    <input x-model="field.qty" type="number" class="form-control rounded-lg text-sm" name="qty[]" value="" style="width:90px" />
                       <label for="part_num" class="ml-3">Part #: </label>
                       <input x-model="field.part_num" type="text" class="form-control rounded-lg text-sm" name="part_num[]" value="" style="width:200px"   />
                         <label for="descrip" class="ml-3">Descrip: </label>

                      <!-- HERE ---->    <input x-model="field.descrip" type="text" class="form-control rounded-lg text-sm" name="descrip[]" value="" style="width:300px"  id="descrip_id"   onblur="replaceQuotes()" />

                        <label for="cost" class="ml-3">Cost: </label>
                        <input x-model="field.cost" type="number" class="form-control rounded-lg text-sm" name="cost[]" value=""  style="width:110px"  step="0.01" min = "0"  />
                         <a href="#scroll" class="bg-red-600 hover:bg-red-500 text-white h-9 py-1 px-2 rounded-lg inline-flex items-center"  @click="removeField(index)">
                    <i class="fa-solid fa-trash mx-1" style="font-size: 0.9rem;"></i>

                                        </a>
                                </div>
<!--  Row 2 Fields  -->

                  <div id="po_line" class="my-4">

                  Line: <strong x-text="index + 1"></strong>
                  <label for="qty">Qty: </label>
                  <input x-model="field.qty" type="number" class="form-control rounded-lg text-sm" name="qty[]" value="" style="width:90px" />
                  <label for="part_num" class="ml-3">Part #: </label>
                  <input x-model="field.part_num" type="text" class="form-control rounded-lg text-sm" name="part_num[]" value="" style="width:200px"   />

                       <label for="descrip" class="ml-3">Descrip: </label>

                <!-- HERE ---->   <input x-model="field.descrip" type="text" class="form-control rounded-lg text-sm" name="descrip[]" value="" style="width:300px" id="descrip_id"     onblur="replaceQuotes()" />
                 
               <label for="cost" class="ml-3">Cost: </label>
                 <input x-model="field.cost" type="number" class="form-control rounded-lg text-sm" name="cost[]" value=""  style="width:110px"  step="0.01" min = "0"  />
                <a href="#scroll" class="bg-red-600 hover:bg-red-500 text-white h-9 py-1 px-2 rounded-lg inline-flex items-center"  @click="removeField(index)">
                <i class="fa-solid fa-trash mx-1" style="font-size: 0.9rem;"></i>

                                        </a>
                                </div>

The line of code in question is this:

<label for="descrip" class="ml-3">Descrip: </label>
<input x-model="field.descrip" type="text" class="form-control rounded-lg text-sm" name="descrip[]" value="" style="width:300px" id="descrip_id"     onblur="replaceQuotes()" />

Here is the working javascript code for replaceQuotes() - Works with first instance only

<script>

<!-- Replace Quotes in Form -->

function replaceQuotes() {
                  
        var x = document.getElementById("descrip_id");
                 
        x.value = x.value.replace(/\"/g, " inch ")
        x.value = x.value.replace(/\'/g, " ft ")

<!-- Add a row of fields -->

function handler() {
                return {
                  fields: [],
                  addNewField() {
                      this.fields.push({
                           qty: '',
                           part_num: '',
                           descrip: '',
                           cost: ''
                       });
                    },
                    removeField(index) {
                       this.fields.splice(index, 1);
                     }
                  }
             }
                           }

             </script>

This code use REGEX matching to replace " with inch and ' with ft.

This code works fine on the first id='descrip_id' which is the first row or first instance of id='descrip_id'. But on any subsequent rows do not get changed.

I have tried to concatenate the index from Line # which uses Alpine JS x-text.

I have also tried to pass this.id inside the function like replaceQuotes(this.id) and then add an id argument inside the function, but can't get either to work.

So questions are:

1) How can I concatenate index onto id='descrip_id' to get a unique id such as id='descrip_id_1' ?

I have tried id='descrip_id'.<x-text="index"> and id='descrip_id'+<x-text="index">

I would assume then I would just need to pass index with the function call?

-OR-

2) How can I pass the active ID to the function and have it manipulate the data in the CURRENT descrip_id field only?

Also tried, replaceQuotes(this.id) then in Javascript function replaceQuotes(id) and replaceQuotes($id) with x being assigned to id in the body of the function.

Thanks!

1 Answers

Inside an Alpine.js attribute you can use any JS (but not HTML the way you tried). So the correct method to create dynamic id attributes is just to use template literals and pass the active item's index to the replaceQuotes function.

<input x-model="field.descrip" 
       type="text" 
       class="form-control rounded-lg text-sm"
       name="descrip[]" 
       value="" 
       style="width:300px" 
       :id="`descrip_id${index}`" 
       @blur="replaceQuotes(index)" />


<script>
function replaceQuotes(id) {
  var x = document.getElementById(`descrip_id${id}`)

  x.value = x.value.replace(/\"/g, " inch ")
  x.value = x.value.replace(/\'/g, " ft ")
}
</script>
Related