Is this a bug with Internet Explorer 8's onpropertychange event? - javascript

I'm using the onpropertychange event to detect changes to a textbox while the user is typing (i.e. before the box looses focus). This is working, however there appears to be a bug which occurs when I set the textbox value using using code. Doing so causes the onpropertychange event to fire, as it should, however the next change that the user makes to the textbox will not cause the event to fire. The change after the next change does fire the event however, and it continues to work normally until the textbox value is set using code again.
Steps to reproduce:
1) Add onpropertychange event as either an attribute of the textbox HTML element, or using the DOM. (document.form.TextboxName.onpropertychange = myHandler)
2) Observe that onpropertychange events are firing when textbox changes
3) Set textbox value using code (document.form.TextboxName.value = "New value")
4) Observe that this causes the event to fire
5) Change the textbox value using the keyboard (insert a latter, backspace or delete, etc)
6) Observe that no event is fired this time
7) Change the textbox value using the keyboard again. Events continue to fire as normal
First of all I'd like to get confirmation that this is indeed an IE bug, and that my code isn't to blame. I'm also looking for advise on how to work around this issue. I want to track all changes to the textbox value as they are made. The other events such as onkeydown are all limited in that they don't detect non-keyboard methods of modifying the value. This only needs to work in IE 8.
Edit: Code below. Running on my browser at home (IE9), the stated issue does not occur. However IE9 exhibits a bug where backspaces do not fire the onpropertychange event at all! Switching modes to IE8 standards (press F12 and choose browser mode) causes the code to run as stated in this post (events fire until the control's text value is set using code, in which case the next character entered will not fire the event.)
<!doctype html>
<html>
<head>
<script type="text/javascript" language="javascript">
var changingValue = false;
function onpropchange(){
if (window.event.propertyName == "value" && !changingValue) {
// Do stuff here
alert("Changed via user input");
}
}
function setTextBoxValue(val) {
var textBox = document.getElementById("foo");
changingValue = true;
textBox.value = val;
changingValue = false;
}
window.changeValue = function() {
setTextBoxValue("NEW VALUE");
}
</script>
</head>
<body>
<input id="foo" onpropertychange="onpropchange();">
<input type="button" value="change value" onclick="changeValue()">
</body>
</html>

This one worked for me with JQuery:
$('#foo').focus().val(val).blur();
Or
var textBox = document.getElementById("foo");
textBox.focus();
textBox.value = val;
textBox.blur();
The idea was to focus first before changing the value and then remove the focus after the value has been changed by the code. The next time the user presses a key, the onpropertychange will fire.

Related

input change event on enter key not working in IE

$("#inputBoxWidth").change(function() {
var curValue = $("#inputBoxWidth").val();
alert(curValue);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<input type="text" id="inputBoxWidth">
</form>
When I press enter key in all browsers I get the alert function working except IE. In IE I have to click outside of the input element so the input looses focus and than it works. I need IE behave the same as other browser when pressing enter the alert popup shows up with the current value. How to do achieve that?
What you can do is use the keyup event.
Which gives you :
$("#inputBoxWidth").keyup(function() { // Your code });
Don't use the keydown event because if you want to get the value of the input it will give the value before the key was pressed.
:)
https://developer.mozilla.org/en-US/docs/Web/Events/change
According to QuirksMode Chrome and Firefox have been compatible for some time, but IE9 and earlier versions of IE10 have incomplete support.
You're going to have to write some conditional code that explicitly checks if the browser is IE and write a work-around.

javascript onblur in ie allowing other text to be clicked and then fires the event

I have a form in which i have used asp.net validators. Along with the by default behavior of Asp.net validators i need them to fire onblur and gain the focus back so that user should not escape from that box. I did the following method in javascript and called them.
The following is my js function
function callMyValidators(a,b) {
var validator = document.getElementById(a);
ValidatorValidate(validator);
if ((document.getElementById(a)).style.visibility == "visible")
document.getElementById(b).focus();
}
I call them in each textbox onblur by
onblur="callMyValidators('RangeValidator2','txtPOBOX')"
In google chrome its working fine. But in IE it allows other text boxes to be clicked and then only firing the onblur event of current textbox. Since the second text box is being clicked the onblur event of both the textboxes fire and they mutually fight each other to focus, leaving the page hanged up.
How can I solve it. Please help. Any help much appreciated.

DOMAttrModified doesn't fire

I'm trying to trigger an event handler when a script modifies an input element (text field.) On Internet Explorer, I can use the onpropertychange event, but on Firefox and other browsers there is no such event. So, according to the W3C docs, it seems the DOMAttrModified event does exactly what I want. But it doesn't fire in Firefox 11.
Here's a simple code snippet which reproduces the problem. I have an input text field, and a button which adds a character to the value attribute of the input text field. Clicking on the add char button should cause the DOMAttrModified event to fire:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function addChar() {
var q = document.getElementById("query");
q.value += "X";
}
function loadevents() {
var q = document.getElementById("query");
q.addEventListener("DOMAttrModified", function() {alert("DOMAttrModified event!");
}, false);
}
</script>
</head>
<body onLoad="loadevents()">
<input type="text" id="query">
<br>
<input type="submit" value="add char" onclick="addChar()">
</body>
</html>
But it doesn't. Any idea what I'm doing wrong? (I know that DOM Level 3 deprecates this event, but there doesn't seem to be a viable alternative right now. As far as I know, Firefox 11 still supports it.)
Changing the value in an input doesn't fire the DOMAttrModified event, that's all..
You need to change the attribute of the input node, not the property of the variable.
It's like the difference between the two jQuery functions: .prop and .attr
Read:
Which HTMLElement property change generates DOMAttrModified?
this forum discussion
(repeating my answer from Which HTMLElement property change generates DOMAttrModified? here, because it's relevant to this question):
Please also note that NO DOMAttrModified events will be fired when the 'disabled' attribute is set. So if your event is not firing, that could be the reason. This also goes for the IE-only 'onPropertyChange' event.

DOM problem with click initiating a focusout event on a different input

I have an <input type=text> with focusout event handler
I have a <button> with click event handler
Focusout checks whether format in input box is correct. It does so by testing input value against a regular expression. If it fails it displays a message (a div fades-in and -out after some time) and refocuses my input by calling
window.setTimout(function() { $(this).focus(); }, 10);
since I can't refocus in focusout event handler. focusout event can't be cancelled either. Just FYI.
Click collects data from input elements and sends it using Ajax.
The problem
When user TABs their way through the form everything is fine. When a certain input box failes formatting check it gets refocused immediately after user presses TAB.
But when user doesn't use TAB but instead clicks on each individual input field everything works fine until they click the button. focusout fires and sets time-out for refocusing. Since time-out is so short focusing happens afterwards and then click event fires and issues an Ajax request.
Question
I have implemented my formatting check as an independent jQuery plugin that I want to keep that way. It uses .live() to attach focusout on all input fields with a particular attribute where format regular expression is defined.
Data submission is also generic and I don't want to make it dependant on formatting plugin. They should both stay independent.
How can I prevent click event from executing without making these two plugins dependant?
Example code I'm fiddling with
After some searching I've seen that all major browser support document.activeElement but I can't make it work in Chrome. FF and IE both report this being the active element, but Chrome always says it's BODY that is active even though click fired on the button element.
Check this code http://jsfiddle.net/Anp4b/1/ and click on the button. Test with Chrome and some other browser and see the difference.
You could use a flag...
Live demo: http://jsfiddle.net/Anp4b/4/
So your question is:
How can I prevent click event from executing without making these two plugins dependent?
Well, you obviously cannot prevent the click event. If the user wants to click the button, he will, and the click event will trigger. There's nothing you can do about that.
So the answer to the above question is: You cannot.
Based on the current conditions, you have to - inside the click handler - retrieve the validation result, and based on that result, decide if form submission should or should not occur.
JS Code:
$("#Name").focusout(function(){
var that = this;
valid = this.value.length ? true : false;
!valid && window.setTimeout(function() {
$(that).focus();
}, 0);
});
$("#Confirm").click(function(e) {
if ( !valid ) { return false; }
e.preventDefault();
alert('AJAX-TIME :)');
});
HTML Code:
<input type="text" id="Name">
<button id="Confirm">OK</button>
Is there are reason you use .focusout instead of .blur?
Using a flag is a good idea, but I would rather use a class on the element. By using classes to determine the state you can also style it accordingly. Here's my example based on your fiddle.
Another solution that hopefully gives the result you are looking for.
1) Create a named click handler:
var clickHandler = function(e){ /** submit form or whatever you want to do**/ };
$("button").click(clickHandler);
2) Add the following to the focusout event when it's failing validation:
$("button").unbind("click", clickHandler).one("click", function(){ button.click(clickHandler); return false;});
You can find an example of this here.

Crossbrowser equivalent of explicitOriginalTarget event parameter

Does anyone know of crossbrowser equivalent of explicitOriginalTarget event parameter? This parameter is Mozilla specific and it gives me the element that caused the blur. Let's say i have a text input and a link on my page. Text input has the focus. If I click on the link, text input's blur event gives me the link element in Firefox via explicitOriginalTarget parameter.
I am extending Autocompleter.Base's onBlur method to not hide the search results when search field loses focus to given elements. By default, onBlur method hides if search-field loses focus to any element.
Autocompleter.Base.prototype.onBlur = Autocompleter.Base.prototype.onBlur.wrap(
function(origfunc, ev) {
var newTargetElement = (ev.explicitOriginalTarget.nodeType == 3 ? ev.explicitOriginalTarget.parentNode: ev.explicitOriginalTarget); // FIX: This works only in firefox because of event's explicitOriginalTarget property
var callOriginalFunction = true;
for (i = 0; i < obj.options.validEventElements.length; i++) {
if ($(obj.options.validEventElements[i])) {
if (newTargetElement.descendantOf($(obj.options.validEventElements[i])) == true || newTargetElement == $(obj.options.validEventElements[i])) {
callOriginalFunction = false;
break;
}
}
}
if (callOriginalFunction) {
return origFunc(ev);
}
}
);
new Ajax.Autocompleter("search-field", "search-results", 'getresults.php', { validEventElements: ['search-field','result-count'] });
Thanks.
There is no equivalent to explicitOriginalTarget in any of the other than Gecko-based browsers. In Gecko this is an internal property and it is not supposed to be used by an application developer (maybe by XBL binding writers).
2015 update... you can use event.relatedTarget on Chrome. Such a basic thing, hopefully the other browsers will follow...
The rough equivalent for Mozilla's .explicitOriginalTarget in IE is document.activeElement. I say rough equivalent because it will sometimes return a slightly different level in the DOM node tree depending on your circumstance, but it's still a useful tool. Unfortunately I'm still looking for a Google Chrome equivalent.
IE srcElement does not contain the same element as FF explicitOriginalTarget. It's easy to see this: if you have a button field with onClick action and a text field with onChange action, change the text field and move the cursor directly to the button and click it. At that point the IE srcElement will be the text field, but the explicitOriginalTarget will be the button field. For IE, you can get the x,y coordinates of the mouse click from the event.x and event.y properties.
Unfortunately, the Chrome browser provides neither the explicitOriginalTarget nor the mouse coordinates for the click. You are left to your own devices to figure out where the onChange event was fired from. To do this, judicious use of mousemove and mouseout events can provide mouse tracking which can then be inspected in the onChange handler.
Looks like it is more designed for extension writers than for Web design...
I would watch the blur/focus events on both targets (or potential targets) and share their information.
The exact implementation might depend on the purpose, actually.
For IE you can use srcElement, and forced it.
if( !selectTag.explicitOriginalTarget )
selectTag.explicitOriginalTarget = selectTag.srcElement;
In case of form submit events, you can use the submitter property in all modern browser (as of 2022).
let form = document.querySelector("form");
form.addEventListener("submit", (event) => {
let submitter = event.submitter; //either a form input or a submit button
});

Categories