Использование javascript MutationObserver для обнаружения изменения значения в теге ввода

Я хочу определить, когда изменяется текст/значение в поле ввода. Так что я прочитал много примеров и попробую выполнить следующий код. Но он не работает .here просмотр скрипта. Даже если я меняю значение на js-код, я хочу обнаружить, что изменения.

HTML

<input type="text" id="exNumber"/>

Javascript

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    // console.log('Mutation type: ' + mutation.type);
    if ( mutation.type == 'childList' ) {
      if (mutation.addedNodes.length >= 1) {
        if (mutation.addedNodes[0].nodeName != '#text') {
//        console.log('Added ' + mutation.addedNodes[0].tagName + ' tag.');
        }
      }
      else if (mutation.removedNodes.length >= 1) {
       // console.log('Removed ' + mutation.removedNodes[0].tagName + ' tag.')
      }
    }
     if (mutation.type == 'attributes') {
      console.log('Modified ' + mutation.attributeName + ' attribute.')
    }
        });   
});

var observerConfig = {
        attributes: true,
        childList: false,
        characterData: false
};

// Listen to all changes to body and child nodes
var targetNode = document.getElementById("exNumber");
observer.observe(targetNode, observerConfig);

Ответ 1

Чтобы понять, что происходит, необходимо прояснить разницу между атрибутом (атрибутом контента) и свойством (атрибутом IDL). Я не буду расширять это, так как в SO уже есть отличные ответы, охватывающие тему:

Когда вы меняете содержимое input элемента, введя или используя JS:

targetNode.value="foo";

браузер обновляет свойство value но не атрибут value (который вместо этого отражает свойство defaultValue).

Затем, если мы посмотрим на спецификацию MutationObserver, мы увидим, что атрибуты являются одним из членов объекта, которые можно использовать. Поэтому, если вы явно value атрибут value:

targetNode.setAttribute("value", "foo");

MutationObserver уведомит об изменении атрибута. Но в списке спецификации нет ничего похожего на свойства: свойство value не может быть обнаружено.

Если вы хотите определить, когда пользователь изменяет содержимое вашего элемента ввода, input событие является самым простым способом. Если вам нужно поймать модификации JS, перейдите на setInterval и сравните новое значение со старым.

Проверьте этот вопрос, чтобы узнать о различных альтернативах и его ограничениях.

Ответ 2

Значение свойства можно наблюдать, не тратьте свое время.

function changeValue (event, target) {
    document.querySelector("#" + target).value = new Date().getTime();
}
 
function changeContentValue () {
    document.querySelector("#content").value = new Date().getTime();
}
 
Object.defineProperty(document.querySelector("#content"), "value", {
    set:  function (t) {
        alert('#changed content value');
        var caller = arguments.callee
            ? (arguments.callee.caller ? arguments.callee.caller : arguments.callee)
            : ''
 
        console.log('this =>', this);
        console.log('event => ', event || window.event);
        console.log('caller => ', caller);
        return this.textContent = t;
    }
});
<form id="form" name="form" action="test.php" method="post">
        <input id="writer" type="text" name="writer" value="" placeholder="writer" /> <br />
        <textarea id="content" name="content" placeholder="content" ></textarea> <br />
        <button type="button" >Submit (no action)</button>
</form>
<button type="button" onClick="changeValue(this, 'content')">Change Content</button>

Ответ 3

Это работает, сохраняет и объединяет исходный установщик и получатель, так что все остальное в вашей области все еще работает.

var registered = [];
var setDetectChangeHandler = function(field) {
  if (!registered.includes(field)) {
    var superProps = Object.getPrototypeOf(field);
    var superSet = Object.getOwnPropertyDescriptor(superProps, "value").set;
    var superGet = Object.getOwnPropertyDescriptor(superProps, "value").get;
    var newProps = {
      get: function() {
        return superGet.apply(this, arguments);
      },
      set: function (t) {
        var _this = this;
        setTimeout( function() { _this.dispatchEvent(new Event("change")); }, 50);
        return superSet.apply(this, arguments);
      }
    };
    Object.defineProperty(field, "value", newProps);
    registered.push(field);
  }
}