onchange isn't working - javascript

I am learning JavaScript through the Head First series book by O'Reilly media, and I just reached a chapter where I have to use the onchange event.
I'm testing using Safari/OS X Lion, Firefox, Chrome, Opera, and IE/Windows, but got the same result.
Given this code:
<html>
<head>
<title>onChange Test</title>
<script type="text/javascript">
function itWorks(){
alert("it works!");
}
</script>
</head>
<body>
<form>
<input type="text" onchange="itWorks();" />
<input type="text" onchange="itWorks();" />
</form>
</body>
<html>
Is it correct to say that the onchange event works whenever we change from one field to another, whether it is activated only by clicking or by using the TAB key?

The onchange event fires when:
Focus leaves the field
if the value has changed since focus was gained
It doesn't matter how focus was lost, and focus doesn't need to move to another field (a link could be focused, or nothing in the document could be, etc).

"we change from one field to another, whether its by clicking or by
using the TAB key" -
Thats onblur.
the event you have coded fires whenever you change the value of the input, then leave the field. EG: Enter something into the field, then press the TAB key.
Your example code works as expected for me.

The behaviors you described is onfocus. onchange executes when the value of the input changes.
If you type something into the field, it should run.

"Just to clarify, the onchange event works whenever we change from one field to another, whether its by clicking or by using the TAB key, right?"
Yes - as long as the value has changed
I'm not sure what the question is tbh - your code works!
I tested it on jsfiddle.net - which is great for learing / testing javascript.
(you should close your html tag btw)...

This is what the HTML5 draft spec says:
The unfocusing steps are as follows:
If the element is an input element, and the change event applies
to the element, and the element does not have a defined activation
behavior, and the user has changed the element's value or its list of
selected files while the control was focused without committing that
change, then fire a simple event that bubbles named change at the
element.
Unfocus the element.
Fire a simple event named blur at the element.
Note that change can fire at other times too. The spec also says:
... any time the user commits a change to the element's value or list of
selected files, the user agent must queue a task to fire a simple
event that bubbles named change at the input element.
And goes on to provide a couple of examples of "committing a change"
An example of a user interface with a commit action would be a File
Upload control that consists of a single button that brings up a file
selection dialog: when the dialog is closed, if that the file
selection changed as a result, then the user has committed a new file
selection.
Another example of a user interface with a commit action would be a
Date control that allows both text-based user input and user selection
from a drop-down calendar: while text input might not have an explicit
commit step, selecting a date from the drop down calendar and then
dismissing the drop down would be a commit action.

Related

Android Espresso WebView webClick() and webKeys() does not trigger blur event on input field

I'm trying to test a WebView using Espresso. The WebView contains some input fields and a button to continue to the next page. I am able to enter the text in the input fields. After leaving the input field a blur event should get called that performs some additional formatting and validation. However the blur event never gets called and therefore I cannot continue to the next page.
It looks like webKeys() is just injecting some text and that webClick() simply triggers a click event. That's probably why focus never changes and the blur event never gets called. When I physically press the input field myself the event does get triggered and I also see the Android input cursor. When the test case is running I don't see the cursor when text is entered in the input fields.
Is there a way to trigger the blur event programmatically or set focus to an element within the WebView using Espresso?
This is the code I'm using for inserting text.
public static void insertText(String label, String content)
{
onWebView().withElement(findElement(Locator.XPATH, "//div[preceding::span[.='" + label + "']]/input")).perform(clearElement()).perform(webClick())
.perform(webKeys(content));
}
Edit: Added relevant dependencies.
implementation "androidx.test.espresso:espresso-idling-resource:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-intents:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-web:3.2.0"
androidTestImplementation "androidx.test.espresso:espresso-contrib:3.2.0"
You can send any javascript to your Web view.
Every "atom" (webKeys is one of atoms) is just some javascript code, which is sent to your Web View. webKeys atom probably sends keypress events, which does not fire focus/blur/change events in browsers. This is sort of standard browsers behaviour for userspace code dispatched events.
As you can manually trigger keypress, you can trigger focus too etc. You can create and dispatch focus by using:
onWebView().withElement(...)
.perform(SimpleAtom("function(elem) {\n" +
"var e = document.createEvent('Event');\n" +
"e.initEvent('focus', true, true);\n" +
"elem.dispatchEvent(e);}"
))
This should set focus to given element. You are sending function, which is then invocated with yours element as first argument.
You should create some classes like SetFocusAtom or RemoveFocusAtom etc. which will extend SimpleAtom instead of copy&paste whole javascript everywhere.
Be aware:
You can send any javascript to WebView, but you probably don't want. You're free to edit values of currently invisible inputs etc. You're writing UI test, so you could test only visible parts of UI. Original atoms (webClick, webKeys etc.) are checking items for actual visibility. You should everytime use some of original atom or at least match for visibility.
You can do only what is possible in userspace Javascript. There are some limitations. Like current question for example. In projects with complex WebViews, you should consider using UIAutomator or some implementation of Selenium (using chromedriver). Espresso-web is not "acting as real user would". This is not achievable by javascript injections only. Chromedriver is much powerfull in user-like acting.
My answer is not generic. Sometimes you don't need to set focus/blur on inputs. Sometimes you want to send change event for example, which is also not triggered by webKeys.

Click vs Input vs Change for checkboxes?

I have a form. I want to only allow form submit if the user checks precisely 4 out of 8 available checkboxes; and once the user checks 4 checkboxes I want to disable the remaining unchecked ones.
Should I add a hook to the click event? Or maybe the input event? Or perhaps the change event?
I'm overwhelemed by the amount of events that seem to duplicate each other's functionality.
I'm also confused by the documentation.
MDN docs about input:
For <input> elements with type=checkbox or type=radio, the input event should fire whenever a user toggles the control, per the HTML5 specification. However, historically this has not always been the case. Check compatibility, or use the change event instead for elements of these types.
MDN docs about change:
Unlike the input event, the change event is not necessarily fired for each alteration to an element's value.
And below:
Depending on the kind of element being changed and the way the user interacts with the element, the change event fires at a different moment:
When the element is :checked (by clicking or using the keyboard) for <input type="radio"> and <input type="checkbox">;
MDN docs about click:
An element receives a click event when a pointing device button (such as a mouse's primary mouse button) is both pressed and released while the pointer is located inside the element.
Practice:
The below JS fiddle seems to hint that all 3 events are equivalent. Clicking the checkbox, clicking the label, focusing the checkbox and pressing space on keyboard seem to all fire all three events.
const checkbox = document.querySelector('input[type=checkbox]');
for (const event of ['input', 'click', 'change']) {
checkbox.addEventListener(event, () => {
log.textContent = `${event}\n${log.textContent}`
})
}
<label>Toggle <input type="checkbox" name="" id="">
</label>
<pre id="log"></pre>
As per the docs change and input seem equivalent; click does not seem equivalent to the other 3 as per the docs but in practice it seems equivalent.
Do we really have 3 events that duplicate each other's functionality? Does it matter in any way which event I use?
Or am I missing something?
These 3 events duplicate each other's functionality because you are looking at a checkbox which happens to be a special case.
For example, if you were to take a text field
The event input will fire whenever the text in an element is changed using the user interface.
The event change will fire (on most browsers) whenever the text element loses focus. It would only be triggered once instead of after every keystroke.
The event click will fire whenever a user clicks on the text field.
If we were to apply this to checkboxes (keeping in mind there is only one thing a checkbox can be changes into: either checked => unchecked orunchecked => checked)
The event input will fire whenever the checked state is changed using user interface.
The event change will fire whenever the checked state has changed
in an element (or when the checkbox loses focus in IE).
The event click will fire after the check state has finished changing .
The 3 events have very similar functionality (almost duplicates) because they are all trying to do something different that functionally does the same thing on checkboxes. The only differences being subtle implementation details.
I would use click to avoid having issues from the user of diffrent browsers.
They are not duplicated. There are subtle differences.
change happens once the value or state changes, and the element loses focus.
$('input').on('change', function(){
console.log('changed');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" value="1">
<input type="text">
click happens once the element is clicked.
input happens IMMEDIATELY once the value or state changes, before it loses focus. This happens regardless of if the state changes as per a mouse or keyboard event. A checkbox can change state by clicking it, or focusing on it and hitting the spacebar. A click event would not catch the spacebar state change.
$('input').on('change', function(){
console.log('changed');
});
$('input').on('input', function(){
console.log('input');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" value="1">
<input type="text">
To test the lack of focus change and the spacebar change on the checkbox, you can click the input box and then shift+tab to focus the checkbox to hit spacebar. It appears from the fiddle that for checkboxes, the change and input events both happen any time it changes, even without the focus being lost.
This differs from how the text field behaves. So there appears to be some behavioral differences between the two elements in when the events are generated. The checkboxes appear to follow a less strict implementation of the pattern, as opposed to input boxes.

The weird event capturing in IE

I just test same code on IE10 and Chrome Browser.
jsfilddle link
<div id='a'><input onclick="console.log('a');"/></div>
<div id='b'><button onclick="alert('b');"/></div>`
I put two different tags which are input and button in two different div tags.
both elements(input, button) have onclick attribute.
what I do is simple
put a cursor in input tag
press enter key
I tried this on IE10 and Chrome.
In chrome browser the event handler attached on button has not executed.
but in IE event handler attached on button has executed.
can anyone tell me why this disaster happens
IE is handling like a brain damaged boy the "enter" key press. Pressing Enter in textbox/input/etc in IE will click the completely unrelated button near it. Is the only browser with this approach.
It's related with the IE's algorithm for selecting submit buttons. Your button is considered one, even when no form tag is present.
<button onclick="alert('b');"/> has default type = "submit"
You can change that by changing the type with the button one.
<button type="button" onclick="alert('b');"/>
Working fiddle : http://jsfiddle.net/k1bkcx43/
This behaviour is related to implicit form submission which is correctly implemented by Chrome as per HTML5 spec. You can go through the spec here.
In short 'hitting the enter key' while a text field is focussed invokes browser controlled implicit form submission which in turn looks for first submit button under the 'form' element and invoke the attached handler.
In your case the 'button' element is defaulted to 'submit' type but since it is not a decendent of 'form' element hence it will not be invoked.
You can assume that current IE behaviour is not as per spec.

Pass additional information into event handler

I have an event handler that is executed when an option in a selectbox is clicked.
$('#my-select').live('change', function(evt) {
....
});
Is there a way to pass the status of the Ctrl-key (pressed/not pressed) into the event handler ? evt does not contain this information because all key related attributes are undefined.
change event and the keys used to enter the value
The change event is not something that has keys associated. Please read jQuery's .change() documentation:
The change event is sent to an element when its value changes. This event is limited to elements, boxes and elements. For select boxes, checkboxes, and radio buttons, the event is fired immediately when the user makes a selection with the mouse, but for the other element types the event is deferred until the element loses focus.
The example is this:
You have some input field.
You enter "some name" text into the field.
Before going to some other field, you decide to change it to "some test", eg. by hitting backspace couple times, then you navigate to next field (eg. by using Tab key, or by tapping Next on iOS keyboard etc.),
The onchange event handler is fired, when you navigate to other field (or rather, as soon as the field loses focus), so the information about all keys used to enter value are pretty unrelated.
Solution using keypress event
To solve that problem, you would need to implement your solution using keypress event, eg. thanks to jQuery's .keypress() function. In such case, event object's ctrlKey attribute (listed eg. here) lets you know about the status of the Ctrl key. Example usage is here: https://stackoverflow.com/a/4604093/548696
Demo for saving keys on keypress/keydown/keyup and reading on change
It is available here:
http://jsfiddle.net/tadeck/vPu94/
The demo clears the recorded keys on focus, saves them on every keypress event (you can easily edit that and test different cases) and reads them (and outputs on the screen) whenever change event is fired (so when the changed field leaves focus).

Selecting from a drop down ( browser cached drop down ) - which event gets triggered?

Gist
Which event gets triggered when we select from a dropdown which is populated from the cache ( such as usernames and other form values ) in a <input type="text"> .
Detailed
In a form, we can login with multiple username say A,B,ABC . And the browser caches all these values ( w.r.t password remember ). So,if we try to login with A - a drop down pops up giving multiple option say A , ABC -- which event gets triggered once we select any of the options provided.
oninput, onchange, onblur -- none of which seems to get triggered if we select from browser provided drop down.
Help,
Beginner
You can use these events with select.
Cache has nothing to do with the drop down.
What you need is depending on your use.
Generally onchange is used to get the value or call a function when the value changes.
onblur would trigger a function when the drop down losses focus. eg, when you use tab or other methods.
This question is answered here: On input change event?
In modern browsers use the input event. This event will fire when the user is typing into a text field, pasting, undoing, basically anytime the value changed from one value to another.
easily use select event
example:
$('#test').select(function(){ alert('data changed'); });

Categories

Resources