IE 10, 11. How to prevent the triggering of input events on focus from text input with placeholder?
Asked Answered
V

3

9

In IE 11 if I have an empty email input with a placeholder, then on clicking (focusing) it, the input event is being triggered.

Does anyone know why and is there a solution to this, since the input value hasn't really changed?

var el = document.getElementById('myEmail');
el.addEventListener("input", myFunction, true);
function myFunction()
{
    alert("changed");
}
<input id="myEmail" type="email" placeholder="Email">
    
Vague answered 7/1, 2018 at 15:53 Comment(1)
See my explanation with very short solution and set my answer as accepted please – so could all users have profit from my correct answer.Diablerie
L
8

I came very late to the party, but I had the same problem, and I came to a workaround to fix this behavior on IE. In fact, there's two different bugs (or rather, only one bug but with two behavior depending on whether the target is an input or a textarea).

  • For input : the event is triggered each time the visual content of the field change, including keyboard inputting (naturally), but also when a placeholder appears/disappears (blur when no content), or when a visible placeholder is changed programmatically.
  • For textarea: it's basically the same, exepts that the event don't trigger when the placeholder disapears.

function onInputWraper(cb) {
    if (!window.navigator.userAgent.match(/MSIE|Trident/)) return cb;


    return function (e) {
        var t = e.target,
            active = (t == document.activeElement);
        if (!active || (t.placeholder && t.composition_started !== true)) {
            t.composition_started = active;
            if ((!active && t.tagName == 'TEXTAREA') || t.tagName == 'INPUT') {
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        }
        cb(e);
    };
}

var el = document.getElementById('myEmail');
el.addEventListener("input", onInputWraper(myFunction), true);
function myFunction() {
    alert("changed");
}
<input id="myEmail" type="email" placeholder="Email">

And there's a full-working example, where you can also change placeholders value

function onInputWraper(cb) {
  if (!window.navigator.userAgent.match(/MSIE|Trident/)) return cb;


  return function (e) {
    var t = e.target,
        active = (t == document.activeElement);
    if (!active || (t.placeholder && t.composition_started !== true)) {
      t.composition_started = active;
      if ((!active && t.tagName == 'TEXTAREA') || t.tagName == 'INPUT') {
        e.stopPropagation();
        e.preventDefault();
        return false;
      }
    }
    cb(e);
  };
}

function handle(event) {
  console.log('EVENT', event);
  document.getElementById('output')
    .insertAdjacentHTML('afterbegin', "<p>" + event.type + " triggered on " + event.target.tagName +
                        '</p>');
}

var input = document.getElementById('input'),
    textarea = document.getElementById('textarea');

input.addEventListener('input', onInputWraper(handle));
textarea.addEventListener('input', onInputWraper(handle));
// input.addEventListener('input', handle);
// textarea.addEventListener('input', handle);

// Example's settings

function removeListeners(elem) {
  var value = elem.value,
      clone = elem.cloneNode(true);
  elem.parentNode.replaceChild(clone, elem);
  clone.value = value;
  return clone;
}

document.querySelector('#settings input[type="checkbox"]').addEventListener('change', function (event) {
  if (event.target.checked) {
    document.getElementById('output').insertAdjacentHTML('afterbegin', '<p>Filter enabled !</p>');

    //input = removeListeners(input);

    console.log(input.value.length, (input == document.activeElement));

    input = removeListeners(input);
    input.addEventListener('input', onInputWraper(handle));
    input.composing = input.value.length > 0 || (input == document.activeElement);

    textarea = removeListeners(textarea);
    textarea.addEventListener('input', onInputWraper(handle));
    textarea.composing = textarea.value.length > 0 || (textarea == document.activeElement);

  } else {
    document.getElementById('output').insertAdjacentHTML('afterbegin', '<p>Filter disabled !</p>');

    input = removeListeners(input);
    input.addEventListener('input', handle);
    input.composing = void 0;

    textarea = removeListeners(textarea);
    textarea.addEventListener('input', handle);
    textarea.composing = void 0;

  }
});

document.getElementById('input_cfg').addEventListener('click', function () {
  document.getElementById('input').setAttribute('placeholder', document.getElementById(
    'input_placeholder').value);
});
document.getElementById('textarea_cfg').addEventListener('click', function () {
  document.getElementById('textarea').setAttribute('placeholder', document.getElementById(
    'textarea_placeholder').value);
});
* {
  font: 15px arial, sans-serif;
}

dd {
  background: FloralWhite;
  margin: 0;
}

dt {
  padding: 15px;
  font-size: 1.2em;
  background: steelblue;
  color: AntiqueWhite;
}

p {
  margin: 0;
}

button,
label {
  width: 300px;
  margin: 5px;
  padding: 5px;
  float: left;
  color: DarkSlateGray;
}

#settings label {
  width: 100%;
  margin: 15px;
}

#forms input,
#forms textarea,
#settings input:not([type]) {
  display: block;
  width: calc(100% - 340px);
  padding: 7px;
  margin: 0;
  margin-left: 320px;
  min-height: 25px;
  border: 1px solid gray;
  background: white;
  cursor: text;
}

::placeholder {
  /* Chrome, Firefox, Opera, Safari 10.1+ */
  color: LightBlue;
  opacity: 1;
  /* Firefox */
}

::-ms-input-placeholder {
  /* Microsoft Edge */
  color: LightBlue;
}

:-ms-input-placeholder {
  /* Internet Explorer 10-11 */
  color: LightBlue;
}
<dl>
  <dt>Forms</dt>
  <dd id="forms">
    <label for="input">Input: </label>
    <input id="input" name="input" class="testing" placeholder="Type some text" />
    <label for="texarea">Textarea: </label>
    <textarea id="textarea" name="textarea" placeholder="Type some text"></textarea>
  </dd>
  <dt>Settings</dt>
  <dd id="settings">
    <p>
      <label><input type="checkbox" checked>Enable filtering script</label>
      <button id="input_cfg">Change input's placeholder to</button><input id="input_placeholder" />
    </p>
    <p>
      <button id="textarea_cfg">Change textarea's placeholder to</button>
      <input id="textarea_placeholder" />
    </p>
  </dd>
  <dt>Output</dt>
  <dd id="output"></dd>
</dl>

or on jsfiddle

Lepidus answered 22/8, 2019 at 10:14 Comment(1)
This works. Thanks for the solution and the explainationVague
S
2

It seems like a bug. oninput has been supported since IE9 should only fire when the value is changed. An alternate approach would be to use onkeyup

https://developer.mozilla.org/en-US/docs/Web/Events/input

If you want to handle input and validation you can just add a second eventlistener (assuming your html is the same as above).

var el = document.getElementById('myEmail');
function myFunction() {
  console.log("changed");
}
el.addEventListener("keyup", myFunction, true);
function validation() {
  console.log("validated");
}
el.addEventListener("keyup", validation, true);
Subulate answered 7/1, 2018 at 18:23 Comment(4)
Hmm. Cant take that approach as I am using a validation library which relies on input event. The validation is supposed to happen on input event but in IE 11 its happening on focusVague
What about the onchange event?Subulate
onchange only triggers once focused out. I need 'input' event since the validation needs to happen as you typeVague
Why not just add multiple eventlisteners onkeyup. I'll update my answer.Subulate
D
2

The solution is very short!

At first we don't need so much of code what we can see in accepted answer. At second you have to understand why it is happening:

  1. Fake oninput event triggers only on inputs with a placeholder on getting a focus and only if the input value is empty. It happens because bad developer from IE had thought that the input value changes from placeholder value to real value, but it is misunderstanding from this bad developer from IE.
  2. An input without placeholders doesn't have this problems.

The first solution is very simple: do not use a placeholder if you do not really need it. In most cases you can add a title to the element instead of a placeholder. You could also write your placeholder text before, below or above the input.

If you have to use a placeholder

The second solution is also very simple and short: save the previous value on the input object and compare it with a new value – if it was not changed then return from the function before your code.

Life examples

var input = document.querySelector('input[type=search]');
input.addEventListener('input', function(e)
{
    if(this.prevVal == this.value /* if the value was not changed */
        || !this.prevVal && '' == this.value) //only for the first time because we do not know the previous value
        return; //the function returns "undefined" as value in this case

    this.prevVal = this.value;

    //YOUR CODE PLACE

    console.log('log: ' + this.value)

}, false);
<input type="search" placeholder="Search..."/>

Or if you use it as inline JavaScript:

function onSearch(trg)
{
    if(trg.prevVal == trg.value /* if the value was not changed */
        || !trg.prevVal && '' == trg.value) //only for the first time because we do not know the previous value
        return; //the function returns "undefined" as value in this case

    trg.prevVal = trg.value; // save the previous value on input object

    //YOUR CODE PLACE

    console.log('log: ' + trg.value);
}
<input type="search" placeholder="Search..." oninput="onSearch(this)"/>
Diablerie answered 23/7, 2020 at 17:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.