Почему моя функция onchange вызывается дважды при использовании .focus ()? - PullRequest
3 голосов
/ 02 марта 2011

TLDR

  • Проверьте это пример в хром.
  • Введите someting и нажмите tab.покажется одно новое поле
  • , введите что-нибудь и нажмите enter.появляются два новых поля, где ожидается один.

Intro
Я заметил, что при использовании enter вместо tab для изменения полей моя функция onchangeна поле ввода стрелял дважды.Эта страница была довольно большой и все еще находилась в разработке (читай: множество других ошибок), поэтому я сделал минимальный пример, демонстрирующий это поведение, и в этом случае он даже делает это на «вкладке».Насколько я могу судить, это проблема только в Chrome .

Что он должен делать
Я хочу сделать новый ввод после того, как что-то введенов поле ввода.Это поле должно получить фокус.

Пример:

javascript - требуется jquery

function myOnChange(context,curNum){
      alert('onchange start');
      nextNum = curNum+1;
      $(context.parentNode).append('<input type="text" onchange="return myOnChange(this,'+nextNum+')" id="prefix_'+nextNum+'" >');
      $('#prefix_'+nextNum).focus();
      return false;
}

HTML-часть

<div>
    <input type="text" onchange="return myOnChange(this,1);" id="prefix_1">
</div>

полный код на вставке .вам нужно добавить свой путь к jquery в скрипте

Рабочий пример приведен здесь на jFiddle

Onchange вызывается дважды: функция myOnChangeвызывается, делает новый ввод, вызывает focus(), снова вызывается myOnChange, вводится новый ввод, «внутренний» myOnChange выходит, а затем «внешний» myOnchange выходит.

Я предполагаю, что это потому, что изменение фокуса вызывает onchange() ?.Я знаю, что в этом есть разница в поведении браузеров.

Я бы хотел, чтобы .focus () (что кажется проблемой) НЕ вызывало onchange(), поэтому myOnChange() не вызывается дважды.Кто-нибудь знает как?

Ответы [ 6 ]

6 голосов
/ 31 августа 2011

Есть более простое и разумное решение.Поскольку вы ожидаете, что onchange срабатывает, когда входное значение изменяется , вы можете просто явно проверить, действительно ли оно было изменено.

function onChangeHandler(e){
  if(this.value==this.oldvalue)return; //not changed really
  this.oldvalue=this.value;
  // .... your stuff
}
2 голосов
/ 02 марта 2011

Быстрое исправление (непроверенное) должно заключаться в том, чтобы отложить вызов на focus() через

setTimeout(function() { ... }, 0);

до тех пор, пока не завершится обработчик события.

Однако можно сделатьэто работает без такого взлома;Пример кода без jQuery:

<head>
<style>
input { display: block; }
</style>
<body>
<div></div>
<script>
var div = document.getElementsByTagName('div')[0];

var field = document.createElement('input');
field.type = 'text';
field.onchange = function() {
    // only add a new field on change of last field
    if(this.num === div.getElementsByTagName('input').length)
        div.appendChild(createField(this.num + 1));

    this.nextSibling.focus();
};

function createField(num) {
    var clone = field.cloneNode(false);
    clone.num = num;
    clone.onchange = field.onchange;
    return clone;
}

div.appendChild(createField(1));
</script>
1 голос
/ 02 марта 2011

Я могу подтвердить, что myOnChange дважды вызывается в Chrome. Но аргумент context является начальным полем ввода для обоих вызовов.

Если вы удалите оповещение, оно срабатывает только один раз. Если вы используете предупреждение только для тестирования, попробуйте вместо этого использовать консоль (хотя вам необходимо удалить его для тестирования в IE).

РЕДАКТИРОВАТЬ: Кажется, что событие изменения дважды срабатывает на клавишу ввода. Далее добавлено условие для проверки существования нового поля.

function myOnChange(context, curNum) {
      nextNum = curNum+1;

      if ($('#prefix_'+nextNum).length) return false;// added to avoid duplication

      $(context.parentNode).append('<input type="text" onchange="return myOnChange(this,'+nextNum+')" id="prefix_'+nextNum+'" >');
      $('#prefix_'+nextNum)[0].focus();
      return false;
}

Обновление:

$('#prefix_'+nextNum).focus(); не вызывается, потому что focus - это метод объекта dom, а не jQuery. Исправлено с помощью $('#prefix_'+nextNum)[0].focus();.

0 голосов
/ 05 июня 2013

может быть, это кому-нибудь поможет, по любой причине, в chrome, когда вы присоединяете цепочку событий к вводимому тексту, когда вы нажимаете клавишу ввода, функцию в событии, делайте это дважды, я решаю эту проблему, изменяю событиедля onkeypress и оценки кодов, если у меня есть ввод, тогда выполняйте функцию, потому что я жду только пользователя enterkey, который не работает для клавиши табуляции.

    input_txt.onkeypress=function(evt){ 
            evt = evt || window.event;
            var charCode = evt.which || evt.keyCode;
            if(charCode === 13)  evaluate( n_rows ); 
             };
0 голосов
/ 02 марта 2011

Проблема действительно в том, что из-за focus() onchange вызывается снова. Я не знаю, является ли это хорошим решением, но это добавление к функции быстрого решения:

context.onchange = "";

(onchange вызывается снова, но теперь он пустой. Это также хорошо, потому что эту функцию никогда не следует вызывать дважды. В конечном продукте будут некоторые изменения интерфейса, которые помогут с проблемами, которые могут возникнуть из-за этого (ошибки и все), но в конце концов это то, что я, вероятно, сделал бы в любом случае).

Раствор здесь: http://jsfiddle.net/k4WKH/2/

Как говорит @johnhunter, фокус не работает в примере, но работает в моем полном коде. Я не смотрел на то, что там происходит, но, похоже, это отдельная проблема.

0 голосов
/ 02 марта 2011

Попробуйте этот пример:

var curNum = 1;
function myOnChange( context )
{
    curNum++;

    $('<input type="text" onchange="return myOnChange( this )" id="prefix_'+ curNum +'" >').insertAfter( context );
    $('#prefix_'+ curNum ).focus();

    return false;
}

jsFiddle .

...