javascriptjqueryhtmlclonenodejquery-clone

javascript cloneNode() doesn't work properly


I have in an html page a select element with an id="a" (for example). I have a function called f(). when I write

$("#a").on("change",f);

it works, meaning every time I change the selected value in the drop down list the function f() is called.

I want to clone this select in another place in the page. I have this code:

var oldSelect=$("#a")
var newSelect=oldSelect[0].cloneNode(true);
newSelect.id="b";
$("#b").on("change",f);

and when I change the selected value in the new dropdown list, the function f() isn't called.

I tried debugging it using the chrome's devTools and it apears that $("#a") is kind of an array length 1 that in the first place has the select itself. But $("#b") doesn't have the "0" property containing the select itself.

Does anyone know why does it happen? how can I clone a select element with all its options and callbacks?


Solution

  • Although you cloned the existing #a, you haven't inserted it into the document yet in the code you've shown, so $("#b") will not give you any elements in return. Either insert it before selecting it with $, eg:

    $(container).append(newSelect);
    $("#b").on("change",f);
    

    where container is the element you want to append the new <select> to.

    Or add the listener directly to the element, instead of selecting it again:

    var newSelect=oldSelect.clone(true);
    newSelect
      .prop('id', 'b')
      .on("change",f)
      .appendTo(container);
    

    (Note that in the above, newSelect is a jQuery collection, not an HTMLSelectElement.)

    const f = () => console.log('change');
    
    var oldSelect = $("#a");
    oldSelect.on("change",f);
    
    var newSelect = oldSelect.clone(true);
    newSelect
      .prop('id', 'b')
      .on("change", f)
      .appendTo('#container');
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div id="container">
      <select id="a">
        <option>Option A</option>
        <option>Option B</option>
      </select>
    </div>