Home > database >  unable to update input field after jquery append
unable to update input field after jquery append

Time:03-28

i have a small application that i need assistance with.

  1. I have a select and text input.
  2. when i select an item from the select menu, the value will display in the text input field.
  3. i can dynamically add extra select and text input fields with Jquery.
  4. But when I select an item from the newly added fields, the input field is not updated. can i send you the source code if this is something you can fix?

below is my code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA 058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script>
        $(function() {
            $(".std").change(function() {
                var agenum = $(this).find(":selected").val();
                // var stdID = $(this).val();
                // console.log(stdID);
                $(".age").html("<input type='text' class='form-control' name='age[]' readonly placeholder='Age1' value="   agenum   ">");
            });
        });
    </script>
   

</head>

<body>

    <div >

        <h2 >Age of Person</h2>

        <form action="">

            <div id="addrow">


                <div >

                    <div >
                        <select  id="std" name="std[]" required>
                            <option selected disabled>Select Student</option>
                            <option value="1">Michael</option>
                            <option value="2">Bridget</option>
                            <option value="3">Raphael</option>
                        </select>
                    </div>

                    <div  id="age">
                        <input type="text"  name="age[]" placeholder="Age" readonly>
                    </div>

                    <div >
                        <button type="button" name="add" id="addmore" > </button>
                    </div>

                </div>
            </div>

    </div>

    </div>

    </form>

    </div>

    <script type="text/javascript">
        $(document).ready(function() {
            // get button id and assign variable for autoincrement
            var i = 1;
            $('#addmore').click(function() {
                // Increment variable by 1
                i  ;
                //Append text field by ID
                $('#addrow').append('<div  id="addnewrow'   i   '"><div ><select class = "std' i  '" form-control" id = "std1' i  '" name = "std[]" required><option selected disabled>Select Student</option><option value="1">Michael</option><option value="2">Bridget</option><option value="3">Raphael</option></select></div><div class ="col mt-3 age' i  '" id="age' i  '"><input type="text"  name="age[]" placeholder="Age" readonly></div><div ><button  id='   i   '>-</button></div>');
            });



            //Remove input field when Remove is clicked
            $(document).on('click', '.remove', function() {
                var button = $(this).attr("id");
                $('#addnewrow'   button   '').remove();
            });
        });
    </script>

</body>

</html>

CodePudding user response:

Here you can check a solution https://jsfiddle.net/ywaohx8z/

There are a problem here:

$('#addrow').append('<div  id="addnewrow'   i   '"><div ><select class = "std form-control" id = "std1' i  '" name = "std[]" required><option selected disabled>Select Student</option><option value="1">Michael</option><option value="2">Bridget</option><option value="3">Raphael</option></select></div><div class ="col mt-3 age" id="age' i  '"><input type="text"  name="age[]" placeholder="Age" readonly></div><div ><button  id='   i   '>-</button></div>');

You must check the use of "i" because you have, for example, a class named "age" that you are adding as "age2". If you later search for the class "age", you don't find it.

Another problem is managing the change event. If you do:

$('.std').change(onStdChange);

You are attaching onStdChange function to any changes on std select, but only on current std elements. When you create another one, you must add the change event too.

There are another problem in the change function:

var onStdChange = function() {
var select = $(this).find(":selected");
     var agenum = select.val();
     var ageTag = select.closest('.form-row').find('.age input');                
     ageTag.val(agenum);
}

"this" is the select. I change to search the closes form-row and, from this point, search your age class input. Then, I update the input value.

CodePudding user response:

Problem

"But when I select an item from the newly added fields, the input field is not updated."

Note in the example, the "click" event is registered to the <form> not button.del.

$('form').on('click', '.del', function(e) {...

All delete buttons are dynamically added to the DOM and there are no static (ie. existing at page load) ones either. Any element that is dynamically added cannot have events registered to it. So by assigning an ancestor element (like <form>) as the event listener we leverage event bubbling to listen for every child element of <form>. We delegate the event to only what we want (in this case button.del) and the rest of the elements are ignored. The .on() method's second parameter (in example it is '.del') is a selector of the element we want to be considered this.

In the OP code there are <select>s adversely affected as well. Notice in the example, no event delegation is apparent for the dynamically added <select>s as it was for button.del. The reason is because they were cloned. jQuery method .clone() has two Boolean parameters:

const row = $(this).closest('.row').clone(true, true);
  • The first parameter if true will keep the data and any registered events to the cloned element.
  • The second parameter if true will keep data and any registered events to the clone's children as well.

Advice

Do not use #id because it will hinder the way you program. Get in the habit of using .class and familiarize yourself with properties and methods used to traverse the DOM. In the example there are no #ids and the .closest() method is used frequently. The .closest() method will start from one element and will climb up the DOM tree looking for the first instance of a given ancestor. Let's look at one from the example:

<section class='row'>// '.row'
  <div class='col'>       // 1.↖️ $(this).closest('.row')
    <select class='std'> // this   
      <option val='49'>zer00ne</option>
      ...
    </select>
  </div>   
// 2.⬇️          3.↘️ .find('.age')
   <div class='col'>
      <input class='age'>// '.age'
   </div>
</section>
  1. closest .row from this | 2. from .row | 3. find .age
$(this).closest('.row').find('.age');

It may seem like a lot but it's very flexible and book keeping #ids is tedious and makes code limited.

Details are commented in example below

/* 
This is an array of objects (typical structure of a what a 
JSON resembles. Each object represents a student and each 
student has "name", "age", "gender", "email", and "gpa" 
(only "age" is of any relevance).
*/
const students=[{name:"Lorens Ousby",age:16,gender:"Male",email:"[email protected]",gpa:2.1},{name:"Caria Garrigan",age:17,gender:"Female",email:"[email protected]",gpa:.4},{name:"Sutton Measom",age:16,gender:"Male",email:"[email protected]",gpa:3.4},{name:"Sybila Warlow",age:17,gender:"Female",email:"[email protected]",gpa:1.6},{name:"Selena Ossulton",age:15,gender:"Female",email:"[email protected]",gpa:3.2},{name:"Trina Habbon",age:18,gender:"Bigender",email:"[email protected]",gpa:2.8},{name:"Carlye Ferenc",age:18,gender:"Female",email:"[email protected]",gpa:.7},{name:"Teodor Abberley",age:15,gender:"Male",email:"[email protected]",gpa:1.2},{name:"Dayna Trase",age:16,gender:"Female",email:"[email protected]",gpa:2.6}];

/*
Upon page load, each student object's "name" and "age" will be 
interpolated into a htmlString of an <option> which in turn 
will be rendered within select.std.
*/
students.forEach(s => {
  $('.std').append(`<option value='${s.age}'>${s.name}</option>`);
});

/* Event Handling */
// Use `.on()` method instead of `.change()` or `.click()`
/*
Whenever a "change" event fires on any .sel, the event handler
showAge(e) will be invoked.
*/ 
$('.std').on('change', showAge);

// Whenever the user clicks button.add addRow(e) is called
$('.add').on('click', addRow);

/* 
form listens for any click event on button.del (2nd param 
designates '.del' as >this<. It gets the closest section.row 
from >this< and removes it.
*/
$('form').on('click', '.del', function(e) {
  $(this).closest('.row').remove();
});

/* 
The explinations above should give you a good idea of what's 
going on with the rest of the code, if not ask in comments 
*/
function showAge(e) {
  const ageV = $(this).val();
  const ageO = $(this).closest('.row').find('.age');
  ageO.val(ageV);
}

function addRow(e) {
  const row = $(this).closest('.row').clone(true, true);
  row.find('button')
.replaceWith(`<button  type="button">-</button>`);
$('form').append(row);
}
  
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <main >
    <form>
    <!--New Rows Here-->  
      <section >
        <div >
          <select  name="std[]">
            <option selected disabled>Select Student</option>
          </select>
        </div>
        <div >
        <output  name="age[]"></output>
        </div>
        <div >
          <button  type="button"> </button>
        </div>
      </section>
    </form>
  </main>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>

  • Related