Kuartz
Kuartz

Reputation: 302

How to keep javascript on DOM even if html change?

My code :

   
    $('#modify').on('click', function(e){
        e.preventDefault();
        var name = $('#name').text();
        var age = $('#age').text();
        $('#name').html("<input id='newName' value='" + name + "'/>");
        $('#age').html("<input id='newAge' value='" + age + "'/>");
        $('#modify').text('OK');
        $('#modify').attr('id', 'ok');
        $('#ok').on('click', function(e){
            e.preventDefault();
            var newName = $('#newName').val();
            var newAge = $('#newAge').val();
            alert($('#newName').val());
            alert($('#newAge').val());
            $('#name').html(newName);
            $('#age').html(newAge);
            $('#ok').text('Modify');
            $('#ok').attr('id', 'modify');
        })
    })
   
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
    <p>Test</p>
    
    <p>Name : <div id="name">Stan</div></p>
    <p>Age: <div id="age">20</div></p>
    <p><a href="" id="modify">Modify</a></p>
</html>

3 questions here :

Upvotes: 2

Views: 62

Answers (3)

Daniel Beck
Daniel Beck

Reputation: 21495

Why the 2 variables after clicking on "OK" are empty?

The #modify event is resetting them (because it's the same DOM node as the #ok element, you swap the ID but the previously bound events stay there.)

Why when we click again, the event is executed 2 times.. and 3... and...

Because every time you click again, you bind a new click event to '#ok', so the next time you click, all of the bound events will fire.

How could I do to have inputs when I click on "modifify", then, to have a "OK" instead of "modify"

Whenever possible, you usually want to avoid overwriting the DOM, because that destroys any bindings on existing elements and just generally makes things harder to debug.

In this case, you're switching between a form and the display of the form values -- so instead of overwriting the same DOM nodes, it'd be easier to draw them separately and toggle their display:

$('#modify').on('click', function() {
  $('#newName').val($('#name').text());
  $('#newAge').val($('#age').text());
  $('#form').show();
  $('#display').hide();
});

$('#ok').on('click', function() {
  $('#name').html($('#newName').val());
  $('#age').html($('#newAge').val());
  $('#display').show();
  $('#form').hide();
});
#form {display:none}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>Test</p>
   
<div id="display">
    <p>Name: <span id="name">Stan</span></p>
    <p>Age: <span id="age">20</span></p>
    <p><button id="modify">Modify</button></p>
</div>
    
<div id="form">
    <p>Name: <input id="newName"></p>
    <p>Age: <input id="newAge"></p>
    <button id="ok">Ok</button>
</div>

Upvotes: 1

creanium
creanium

Reputation: 647

So you've got core there, but there are a few details that are tripping you up:

  • Even though you're changing the ID, the #modify and #ok links are actually the same <a> tag in the DOM so it ends up having two click event listeners on it.
  • You're just changing the ID of the #modify link but the event listener is still there. So when you click on what looks like #ok, the original click event listener fires and it replaces your text box with an empty text box before the #ok event click event handler fires. So by the time you check the value of the text box, it has been cleared out.
  • Every time you click the modify link, you're creating a new listener for the #ok link. So when you click the Modify link the first time, it wires up one event listener. Then when you do it again, you get 2 event listeners, then again a 3rd gets wired up.

So what you need to do is create a second link for the #ok link and wire that up separately and just show and hide the correct buttons.

$('#ok').on('click', function(e){
    e.preventDefault();
    var newName = $('#newName').val();
    var newAge = $('#newAge').val();
    alert($('#newName').val());
    alert($('#newAge').val());
    $('#name').html(newName);
    $('#age').html(newAge);
    $('#ok').hide();
    $('#modify').show();
});

$('#modify').on('click', function(e){
    e.preventDefault();
    var name = $('#name').text();
    var age = $('#age').text();
    $('#name').html("<input id='newName' value='" + name + "'/>");
    $('#age').html("<input id='newAge' value='" + age + "'/>");
    $('#modify').hide();
    $('#ok').show()
});
   
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
    <p>Test</p>
    
    <p>Name : <div id="name">Stan</div></p>
    <p>Age: <div id="age">20</div></p>
    <p>
        <a href="" id="modify">Modify</a>
        <a href="" id="ok" style="display: none;">Ok</a>
    </p>
</html>

Upvotes: 1

Taplar
Taplar

Reputation: 24965

Used a delegate to perform the logic based on the id as it is when it is clicked.

var $name = $('#name');
var $newName = $('#newName');
var $age = $('#age');
var $newAge = $('#newAge');
var $button = $('#modify');

$('#container')
  .on('click', '#modify', function(e) {
    e.preventDefault();

    $newName.val($name.text());
    $newAge.val($age.text());

    $name.text('');
    $age.text('');

    $newName.attr('type', 'text');
    $newAge.attr('type', 'text');
    
    $button.text('Ok').attr('id', 'ok');
  })
  .on('click', '#ok', function(e) {
    e.preventDefault();

    $name.text($newName.val());
    $age.text($newAge.val());

    $newName.attr('type', 'hidden');
    $newAge.attr('type', 'hidden');
    
    $button.text('Modify').attr('id', 'modify');
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Test</p>

<div id="container">
  <p>Name :
    <div><span id="name">Stan</span><input type="hidden" id="newName" value=""></div>
  </p>
  <p>Age:
    <div><span id="age">20</span><input type="hidden" id="newAge" value=""></div>
  </p>
  <p><a href="" id="modify">Modify</a></p>
</div>

Upvotes: 1

Related Questions