I'm still learning the best way to do things through jQuery and Javascript. I've got several input text boxes that I want to instantaneously update a record with when a change is made.
Handling a similar event from a Winforms perspective in the past, I would have handled this in the handler for a text change or got / lost focus event. I understand that "input" and "change" are the rough equivalents of these for input elements.
I want to ensure that 100% of the time that a change is made when the text is changed. My concern with using the "input" event is the possible overhead involved, while my concern with the "change" event is something out of the event's scope to handle (such as a browser closing, session expiration, etc.) would occur and prevent the update.
I'd prefer to use "input", but the thought of having a database hit every time someone types or deletes a character worries me. "Change" would be ok if I had a way to prevent the scenario I mentioned above.
The bottom-line is this: "Input" if overhead isn't a concern; "Change" if there is a way (which I'm not currently aware of) to ensure everything gets saved, possibly by handling another event as well.
What should I do? Thanks!
Related
I'm working with a form that may be a bit over-engineered, and I'm trying to write a script to step through the form and submit it. Most of the form is pretty hackable, but there's a 3-part date input which is just not responding to my attempts to manipulate it programmatically.
The date field works, if I click or tab to it and begin typing. But if I manually dispatch events, even ones that are identical to what it receives when I type and have exactly what the code seems to be looking for, I can't get it to hold onto its values and perform validation. I've tried a lot of variations of this. I've tried manually dispatching a custom event that matches a custom Vue event it should be listening for.
Is there a way to instead manipulate the data of the Vue component directly? To force it to have a certain "monthValue" for example, without intermediate events? I don't expect that there is, but hopefully I'm missing something. Please note that I do have the ability to refactor the form, but that should be an absolute last resort.
As far as I can tell, no, there isn't a way to do this. But it wasn't necessary.
The solution involved being more careful in looking at what the components were actually trying to do. In this case they were input elements using v-model, which is shorthand for a combination of #input (event listener) and :value attributes[1]. This meant that dispatching synthetic input events with the correct data attribute could convince Vue to accept the value and retain it (whereas any value dispatched in any keyboard event would be ignored entirely). This only addressed half of my problem with this particular form, but it is the correct solution for the question asked.
[1] https://vuejs.org/guide/essentials/forms.html
How do I completely unbind inline javascript events from their HTML elements?
I've tried:
undelegating the event from the body element
unbinding the event from the element
and even removing the event attribute from the HTML element
To my surprise at least, only removing the onchange attribute (.removeAttr('onchange')) was able to prevent the event from firing again.
<input type="text" onchange="validateString(this)"></input>
I know this is possible with delegates and that's probably the best way to go, but just play along here. This example is purely hypothetical just for the sake of proposing the question.
So the hypothetical situation is this:
I'm writing a javascript validation library that has javascript events tied to input fields via inline HTML attributes like so:
<input type="text" onchange="validateString(this)"></input>
But, I'd like to make the library a little better by unbinding my events, so that people working with this library in a single-page application don't have to manage my event handlers and so that they don't have to clutter their code at all by wiring up input events to functions in my hypothetical validation library... whatever. None of that's true, but it seems like a decent usecase.
Here's the "sample" code of Hypothetical Validation Library.js:
http://jsfiddle.net/CoryDanielson/jwTTf/
To test, just type in the textbox and then click elsewhere to fire the change event. Do this with the web inspector open and recording on the Timeline tab. Highlight the region of the timeline that correlates to when you've fired the change event (fire the change event multiple times) and you'll see the event listeners (in the window below) increase by 100 on each change event. If managed & removed properly, each event listener would be properly removed before rendering a new input, but I have not found a way to properly do that with inline javascript events.
What that code does is this:
onChange, the input element triggers a validation function
That function validates the input and colors the border if successful
Then after 1 second (to demonstrate the memory leak) the input element is replaced with identical HTML 100 times in a row without unbinding the change event (because I don't know how to do that.. that's the problem here). This simulates changing the view within a single-page app. This creates 100 new eventListeners in the DOM, which is visible through the web inspector.
Interesting Note. $('input').removeAttr('onchange'); will actually prevent the onchange event from being fired in the future, but does not garbage collect the eventListener/DOM stuff that is visible in the web inspector.
This screenshot is after change event fires 3 times. Each time, 100 new DOM nodes are rendered with identical HTML and I've attempted to unbind the onchange event from each node before replacing the HTML.
Update: I came back to this question and just did a quick little test using the JSFiddle to make sure that the answer was valid. I ran the 'test' dozens of times and then waited -- sure enough, the GC came through and took care of business.
I don't think you have anything to worry about. Although the memory can no longer be referenced and will eventually be garbage collected, it still shows up in the Web Inspector memory window. The memory will be garbage collected when the GC decides to garbage collect it (e.g., when the browser is low on memory or after some fixed time). The details are up to the GC implementer. You can verify this by just clicking the "Collect Garbage" button at the bottom of the Web Insepctor window. I'm running Chrome 23 and after I enter text in your validation box about 5 or 6 times, the memory usage comes crashing down, apparently due to garbage collection.
This phenomenon is not specific to inline events. I saw a similar pattern just by repeatedly allocating a large array and then overwriting the reference to that large array, leaving lots of orphaned memory for GC. Memory ramps up for a while, then the GC kicks in and does its job.
My first sggestion would have been to use off('change') but it seems you've already tried that. It's possible that the reason it's not working is because the handler wasn't attached with .on('change'). I don't know too much about how jQuery handles listener like this internally, but try attaching with .on('change', function ()... or .bind('change', function ()... instead.
I need to reliably detect the state change of radio buttons/checkboxes on my page in order to watch if the form was modified or not. Now, this is a completely separate script, I cannot modify anything that controls the form.
Right now, I can see only two ways of doing this:
onchange event handler, which helps with textboxes, textareas and selects, but is not fired for checkboxes/radiobuttons
onclick event handler, which is not reliable, because users often use hotkeys to change the values of these elements.
What am I missing here? Is there a way to reliably detect that checkbox was checked/unchecked?
UPDATE: As you guys pointed out, change event is really fired on checkboxes/radiobuttons, despite the fact that w3schools says it is only for text inputs
However, my problem turned out to be that the values of checkboxes/radiobuttons are set via setAttribute in scripts and in that case the event is not fired.
Is there anything I can do in this case?
See: http://www.quirksmode.org/dom/events/change.html.
It says that all major browsers support change event but the IE's implementation is buggy.
IE fires the event when the checkbox or radio is blurred, and not when it is activated. This is a serious bug that requires the user to take another action and prevents a consistent cross-browser interface based on the change event on checkboxes and radios.
I think you can overcome IE's bug with this trick. blur() elements when they focued! (Use something like $('input[type=radio]').focus(function(){$(this).blur();}); in jQuery or use pure javascript)
Ok, after some digging, here is what I found out. Note, this is applicable to Firefox, and, probably to Firefox only. Since in this case I was dealing with internal application, this was enough for me.
So, basically, in order to reliably detect changes in checkbox/radiobutton state in Firefox, you need to do two things:
Set up custom Firefox's event handlers CheckboxStateChange and RadioStateChange for checkbox and radiobutton respectively. These events will be fired when the user changes the inputs or when it is modified via script, using setAttribute, however, these events are not fired, when the state is changed in the script, using checked or selected properties of these elements, this is why we need ...
Watch the changes of the checked property using Object.watch
Standard onchange event is no good, since it only fired when user changes the value directly.
Damn, this thing is broken...
If people get interested, I'll post some code.
I have an interesting question, i hope..I have a textarea in my form..when a user comes to enter values in it it displays some cached values in an autocomplete format..thats fine..I want to call an ajax function after the user selects such a cached value in it..so that the ajax call should pass this selected value..so my question is on which can i get the final selected value, so i call ajax at that time,... i tried with onblur etc, but not worked..
help please..
thanks in advance...
If the user chooses by clicking, you want a 'click' handler on the element the user is selecting (or a containing element).
If the user can select in other ways, eg by the keyboard, then you'll need to observe other events as well.
You mean you want to detect if the user selects a value the browser's native Autocomplete lookup, instead of typing it in themselves?
I'm certain there is no event to catch this.
The only workaround that comes to mind is analyzing the keypress events the user makes in the input field. If the keys entered do not match the full string that is in the text field, and no onpaste event was fired, it stands to reason that the value was selected from an Autocomplete.
This is going to be tough to implement, though, and by no means 100% reliable.
As Pekka said above, there will likely be browser-specific events to handle for this kind of functionality, but it is possible.
For IE, check out Why does the javascript onchange event not fire if autocomplete is on? for a reference to the "onpropertychange" event within IE.
For Firefox, it looks like others have solved it through a combination of onBlur and onFocus (see FireFox capture autocomplete input change event).
If you do come up with a cross-browser solution, please let us know!
I need to send bunch of commands to the server on timer - like:
put(0,"hello")
del(4,1)
put(4," is around the corner")
so I need to monitor and record all of the user input and compile/flush it on the timeout (idle), something like macros.
I can record all things happening onKeyUp/onKeyDown/onMouseDown/onMouseUp using textarea cursor position and keys information (and make it cross-browser some time later) but I can't handle things like pasting using mouse right button and selecting 'Paste' or pasting from the menu (I can handle onChange, but I will have no information is it pasted or already recorded as pressed keys and it fires only after focus change). Even pasting from context menu fires some useful info, but the menu from the browser is the only thing, giving nothing for Javascript.
Is there any plugin for jQuery or something like that and do I really have no other ways to implement it without comparing current-document and document-a-second-before?
Upd.: There are events for handling cut/copy/paste: http://www.quirksmode.org/dom/events/cutcopypaste.html , but what about
the undo one?
P.S. I will show a macro-recording code when I'll finish, if someone really needs it. And to finish it properly, I just need the undo handling possibility. Current version is here: http://code.google.com/p/sametimed/source/browse/WebContent/module-editor.js, look for compileCommands method.
There are events for cut/copy/paste you may listen to, depending on browser. So if they are triggered you may use them, otherwise fall back to more tedious work-around.
See: http://www.quirksmode.org/dom/events/cutcopypaste.html