LP13
LP13

Reputation: 34089

How to refocus on input element after reloading html

I have few input html elements. On change event (tab-out) of input im making a ajax post and get back html. and then i replace the existing html with this new html. Doing so looses the focus on next input element. However before i make the ajax post im storing id of the currently focused element so that i can refocus the same input after html is replaced. But its not working

below is my code

<div id="mycontainer">
    <input id="input1" />
    <input id="input2" />
    <input id="input3" />
</div>


$(function () {
     $("input").change(function () {
        $.ajax(
            {
                data: "somedata",
                url: "someurl",
                method: "POST"
            })
            .done(function (response) {
                    var currentElement = $(':focus').attr("id");
                    $("#mycontainer").html(response)
                    $("#" + currentElement).focus();
                })
    })
})

Upvotes: 0

Views: 2100

Answers (2)

Ruan Mendes
Ruan Mendes

Reputation: 92274

Change event fires after the blur event, so focus has moved. If you want to focus on the element that was changed, you can use event.target to get a reference to the input that changed.

$("input").change(function (event) {
      $.ajax({
            data: "somedata",
            url: "someurl",
            method: "POST"
        }) .done(function (response) {
               var currentElement = event.target.id;
                $("#mycontainer").html(response)
                $("#" + currentElement).focus();
        });
})

If you want focus to remain where it is, your code should work, here's the proof.

const HTML = `
    <input id="input1" />
    <input id="input2" />
    <input id="input3" />
`;

$(() => {
  $("input").change(() => {
    // Add async code to fake ajax
    new Promise((resolve, reject) => {
      setTimeout(() => resolve(HTML), 100);
    }).then(response => {
      const currentElement = $(':focus').attr("id");
      $("#mycontainer").html(response)
      $("#" + currentElement).focus();
    });
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mycontainer">
  <input id="input1" />
  <input id="input2" />
  <input id="input3" />
</div>

However, as mentioned in my comment, this is poor approach because you lose the handlers, so you'll have to reset the handlers too and maybe scroll position. To avoid this, you can make your AJAX return data and update only the bits that need to be updated.

Upvotes: 2

Bulent Vural
Bulent Vural

Reputation: 2688

When you click somewhere on the page (including the button / link that loads your ajax content), the clicked element immediately takes the focus. So just before changing the html, it is already too late to store the focused id. You need to store it on focus change instead.

Edit: Since there is no 'click' involved in the OP's question, I'm proposing an updated version of the above solution: Storing the changed input and running ajax stuff in focus handler.

let changedInput;
$(document).on('focus', 'input', function() {
  if (changedInput) {
    // do whatever with changedInput.val() needed here
    changedInput = null;
    const currentElement = $(this).attr('id');
    $.ajax({
        data: "somedata",
        url: "someurl",
        method: "POST"
      })
      .done(function(response) {
        $("#mycontainer").html(response);
        $("#" + currentElement).focus();
      })
  }

});

$(document).on('change', 'input', function() {
  changedInput = this;
})



/* BEGIN FAKE AJAX STUFF
 *
 */
let counter = 0;
$.ajax = function(params) {
  $('#msg').text("Fake AJAX Loading...");
  return {
    done: function(cb) {
      setTimeout(function() {
        $('#msg').text("");
        cb(`
      <div id="mycontainer">
        <input value="${counter}" id="input1" />
        <input value="${counter}" id="input2" />
        <input value="${counter++}" id="input3" />
      </div>
      `);
      }, 300);
    }
  }
}
/* END FAKE AJAX STUFF */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="height:20px;" id="msg"></div>
<div id="mycontainer">
  <input value="" id="input1" />
  <input value="" id="input2" />
  <input value="" id="input3" />
</div>

Upvotes: 1

Related Questions