I want to make a chat program like Google Wave that shows what is typed in real-time. For the moment I'm just using a textarea. I just want to know what change the user made to the textarea (either one character or pasted text) without having to perform a diff on the whole textarea. I was something along the lines of using a setTimeout with the oninput event but I believe this could only give me the "before text" and the "after text". Any ideas?
this type of functionality is most likely accomplished using a message batching type setup.
here's how it would break down:
attach event handlers to a text area to track modifications on the character level (think, keydown, keypress, keyup, etc..) and log these into a message buffer
you'll want to have a backup for "end transaction" type events like "onchange", "onpaste", etc.. that serve to check the integrity of you're state and be prepared to run a "full re-sync" (eg. signal other clients to do a full "pull") if you think you have a mismatch
on an interval (every 0.3 - 1 second), you empty the message buffer and re-transmit the messages to other clients (direct connect [websockets?], or indirect via server)
when a client receives messages, they process them in the same order they've received them [hopefully] ending up with the same state, error or conflict fallback: signal full sync
on a full sync client should re-pull the full state and attempt to place the focus/carrot as close to the last position as possible
on a side note: this is greatly simplified with a concept of "regions" where you can do clean full swaps on your region without affecting mine...
hope this helps -ck
You will want to look at the key events: keydown, keypressed, keyup
W3C keyboard events
But you also need to consider pasted text – which might not have a key press.
One strategy, to simplify event handeling, would be to have a 'submit' button. Then you will know when the user is done with their statement.
Track the value of your text area with setInterval and compare it against itself to see if it changes. This works for pastes, normal key presses, etc.
Example:
var lastVal = $("#myTextInput").val();
setInverval(function(){
if($("#myTextInput").val() != lastVal) {
lastVal = $("#myTextInput").val();
// the text changed, do something with the current value (AJAX, whatever)
}
}, 300);
Related
I have a barcode gun scanner reading, barcodes, of course, into input fields. At the moment, I am able to read the barcode but it is returning every digit separately. I need it as a whole string. I have been breaking my skull about this.
For example, I read a bottle of water's barcode, the input field catches the number correctly (i.e. 688267022760). When I console log it, I get independent instances for each digit.
My template (VueJS) triggers the scanner event on input. Which I am not entirely sure if that is the correct event. I tried keydown and keyup as well. Not exactly sure which is the recommended event listener for a scan gun. Anyway this is what I have in my template:
<input id="packageInput" type="text" #input="onBarcodeScanned" />
And in my script:
onBarcodeScanned(barcode) {
let numbers = barcode.data; //data is the object property I need
console.log(numbers); //this shows me values I need
let newarr = []; //creating an emprty array where I assume I need to push data to
// looping through the data and pushing it to the new array, which does not do what I want but it was my logic
for (var i = 0; i < numbers; i++) {
newarr.push(numbers);
}
},
The desired effect would be to get those independent values in an array and then joined as a string.
P.S.
Reading the barcode property returns a series of objects with lots of handlers for several functions. The property of interest is data. See below an example of the barcode objects
How can I do this? I'm stumped
P.P.S
I understand the scanner itself comes with a series of instructions to program it. Some of which I don't understand too well. Perhaps there is a type of barcode that returns as a string instead of each digit as an object? The scanner I am using is a Wasp CCDScanner WCS3900
onInput runs every time the value changes. Most barcode scanners will simulate keypresses to enter the values they scan, so as far as your app is aware, each digit is a keypress that's changing the value and so it reports each as an input event. An input event's data property is just the part of the input that's changed -- so you're getting one at a time.
You need a way to determine when the input is finished, not whenever it happens. I believe most barcode scanners will simulate pressing ENTER or TAB after a full scan is complete, so that might be what you want to detect, not with an input event, but with a keypress or keyup event.
Can anybody explain in plain English what RxJS Observable debounce function does?
I imagine it emits an event once in a while depending on the parameters, but my code below doesn't work as I expected.
var x$ = Rx.Observable.fromEvent(window, 'click')
.map(function(e) {return {x:e.x, y:e.y};})
.debounce(1000)
.subscribe(function(el) {
console.log(el);
});
and the JsBin version.
I expected that this code would print one click once per second, no matter how fast I am clicking. Instead it prints the click at what I think are random intervals.
Debounce will emit a value after a specified time interval has passed without another value being emitted.
Using simple diagrams the following may provide greater help:
Stream 1 | ---1-------2-3-4-5---------6----
after debounce, the emitted stream looks like as follows:
Stream 2 | ------1-------------5---------6-
The intermediate items (in this case, 2,3,4) are ignored.
An example is illustrated below:
var Rx = require('rx-node');
var source = Rx.fromStream(process.stdin).debounce(500);
var subscription = source.subscribe(
function (x) {
console.log('Next: %s', x);
}
);
I used node to illustrate this... assuming you have node installed, you can run it by typing
$node myfile.js (where the aforementioned code is in myfile.js)
Once this node program is started you can type values at the console -- if you type quickly items are ignored, and if type intermittently fast and slow items will appear after a gap in typing (in the example above I have 500ms) at the console ("Next: ")
There is also some excellent reference material at https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md
Long story short:
debounce waits for X time that the stream isn't emitting any new value, then let the latest value pass.
Long story:
Once a value is emitted, debounce will pause its emission for X time to see if another value is emitted, in fact blocking the stream during this time. If a new value is emitted during the debounce time then the timer is restarted and debounce waits again for the full time.
If its timer expires without any new value being emitted, it let the latest value pass.
Let's say that you want to add autocomplete to an input box. If the user insert "a" you may want to show him the choices "acorn, alaska", but if the user right after press "l" you would propose just "alaska". In this case it's better to wait for the user to stop pressing the keyboards to avoid doing unnecessary work. debounce it's the right tool here: it waits for X time the the stream isn't emitting any new value
.debounce() produces the last received value if no values were received within the specified interval.
It means that as soon as you click within a second - nothing will be produced.
If you want to throttle values to be emitted no more frequent than every second you need to use .sample(1000) instead.
I've been dissatisfied with the way Dijit's FilteringSelect widget works for some time and have been tinkering using the Dojo 1.10 trying to improve it for my use case. Unfortunately it seems no combination of settings is quite right, largely because they don't work together.
Setting queryExpr: '*${0}*' is nice, but it make auto-complete go loony.
Setting autoComplete: true is nice as long as you want to type the whole text starting from the beginning until you find your match. Unfortunately if you want to start in the middle somewhere it becomes a pain in the butt. Sure you can set searchDelay: N to to something large enough to catch all your typing, but as soon as you let it return incremental results in the menu, BAM your ability to keep typing and maybe end up with a match somewhere else in the word goes out the window.
What I really want is something that completes much like a fuzzy-finder does in a shell or decent text editor (e.g. fzf). Such finders skip over intermediate characters, basically splitting your input by character and adding implicit wild-cards between them. You keep typing until the first match is the one you want, then end the finder and let it replace the value.
I started messing with a way to implement this, but didn't get very far. I thought about hijacking _patternToRegExp(), but quickly discovered that my store (an instance of dojo/data/ItemFileReadStore with some JSON data) sets the _oldAPI flag and that never gets executed. I'm happy to update stores, but it isn't readily apparent to me that will make this easier. Hacking on my store, things spiraled out of control and I decided to take a less involved but more hackish approach.
If you turn off auto complete and set the options to do matching in the middle of words, you get a results list pretty close to what is needed. All that remains for the user to do is hit Down once after they type in enough input to get a match and before they Tab away. The question then becomes how to avoid requiring this manual intervention and become more forgiving.
define(["dijit/form/FilteringSelect"], function(FilteringSelect){
return declare("alerque.FuzzyFilter", [FilteringSelect], {
autoComplete: false,
highlightMatch: 'all',
ignoreCase: true,
queryExpr: '*${0}*',
searchDelay: 0,
_patternToRegExp: function(qs) {
// If this ever actually got called, maybe we could
// return qs split with wild cards between all characters
return this.inherited(arguments);
},
onblur: function() {
this._autoCompleteText(this.get('displayedValue'));
// Pick first match from menu
return this.inherited(arguments);
}
})});
Hijacking the onblur() function seems to be the right place to make a widget that defaults to the first match if you tab or click away, but I can't figure out how to actually use the first match from the menu.
How should I proceed to get more robust fuzzy searching with auto-completion of the best match? I don't want a ComboBox, the value has to end up being one of the values in my JSON data set. At the same time I want input options to be much sloppier than typing the value from the beginning or having to manually select a match.
maybe a workaround/solution for your onBlur :
set the queryExpr="\${0}"
no delay and autocomplete off
On onkeyup of the filteringSelect you store the first value from the popup matches somewhere, then after onblur change the displayedValue/value of your filteringselect to the value from the first popup (if it was found & matches...)
To get the first value from the popup:
The first shown value can be found in a element with id = YOUR_FILTERING_SELECT_ID + "_popup0"
so if your id = "mySearchData" then look for id "mySearchData_popup0"
if that element exists then store the innerHTML somewhere (hidden element or var ...)
Adjust value from innerHTML to match value from store:
From the value you get from the innerHTML, remove the span elements from it so it matches one of the values of your datastore
if your id from your filteringselect = "mySearchField" and if you are searching "123" and the first match in popup shows "test 123 number"
then the innerHTML value from the first popup will look like this
<li id="mySearchField_popup0" class="dijitReset dijitMenuItem" role="option">
test
<span class="dijitComboBoxHighlightMatch">123</span>
number
</li>
So, little bit of String doodling (just remove the span tags out of the innerHTML value) and you will have a value that matches your first result after onblur.
Is there a way to apply a mask in a input using yui3 ?
Is it possible to have a field where the user can only enter a phone number?
And if so, how?
Thx a lot
I would say that your best bet is to have an onChange or onKeyup (or even onValuechange - a YUI construct) handler listening on that input. Whenever it detected a change, you would run a formatting function on the current value of the input, which formatted it in the way you wanted.
if you want to be light-handed about it, just put the dashes in where they go, for example :
"1105551212" --> "110-555-1212"
if you want to be heavy-handed about it, the event handler could literally strip out any non-numeric, or non-dash characters, which effectively prevents the user from entering bad input, though they could of course put in a non-existent phone number.
one step further: do both. strip out invalid characters, and do auto-formatting.
I'm new here so please go easy on me. This is somewhat of a confusing situation. :)
I'm working on a search input in which a user enters a name of another user (or part of a name) in a search text box and then a list of users matching that search string is returned. The problem is that it is a bit slow when there are tens of thousands of users involved. Due to this slowness, when the user quickly enters a name into the search input, the screen will begin to flash search results for each key stroke (well after the user has already entered the search string in). It's like a severely delayed reaction.
For instance, if I enter in the name 'Wendy', the search results for the search string 'W' (the first character I entered) will not even be displayed yet. The search results for the letter 'W' will then be displayed, followed by 'We' and so on and so forth even though i've already typed the full name and just want to see the results for 'Wendy'.
What I want to do is only perform the search when the user has not entered anything for a certain period of time (i'm thinking two seconds). Otherwise, the word 'Searching' will be displayed. The code of the Javascript method is below. Just as a note, that code currently works for searching through the users, I just need to implement the delayed execution.
function updateSearchResults() {
if($F('searchString').length > 0){
Element.update($('searchResultsScrollBox'), '<h3>Searching...</h3>');
$('searching').style.display = 'block';
var url = '<c:url value='ajaxFrontGetUsers.html'/>';
var ajax = new Ajax.Updater({success: 'searchResults'}, url,
{method: 'post', parameters: $('searchForm').serialize(true)});
$('searching').style.display = 'none';
}
}
I hope this all makes sense. Thanks in advance for anyone that can help.
Try the following steps:
Every few milliseconds, check to see if the textbox has new data in it.
If the textbox has new text, execute your Ajax, and copy the text to a variable (for comparison in step 1).
If you want to improve performance from there, activate the timer whenever the user types something, and deactivate it when the Ajax call is made.
Hey, thanks for your answer.
I ended up setting 500 millisecond intervals in which a javascript function would continuously check to see if new characters were entered in the search string within that 500 millisecond time period. If they were, the search function would be called to search on the string the user had entered. Otherwise, it would wait another 500 milliseconds until the user had stopped typing. In the end, it's very similar to what you proposed.
Thanks again!
Or you could put an "onkeypress"event handler on the item that clears some global variable or cancels a timer to keep the AJAX event from firing. I know Prototype implements this for you via it's in-place editor and the "frequency" option. (I believe it sets a timeout timer that it cancels after every key press.)
I know this is an old question, but for others taking a look, I think your going about this the wrong way. I think you should date/time stamp each ajax call, and keep track of the data time stamps in your javascript. Then, when an ajax call is returned you can check the date/time stamp and make sure it is the result set for the most resent ajax call. This way you do make the ajax call for each keystroke immediately, but only display results if the ajax results catches up to the typing.
Also, are you sending over ALL matching results? Like thousands for just the letter W? To speed up the javascript side maybe you should rank the results on the database and return only the top 10-20. The doesn't want to see more than 10-20 results anyways.
Additionally, is your SQL query optimal? Seems like the query is taking too long. If your doing a one sided like search (ie. like input+'%') not a two sided like search (ie. like '%' + input + '%') then there are some really good indexes you can put on the table to help you out.