I have a website with is made in classic asp. On one page there are 5 textboxes and 5 labels. When users type some value in the textbox then using javascript (added on Onchange event) another asp page is called which done some calculations, fetches some database values based on the value typed and return the result to caller page to be displayed in the corresponding label. Same Page is called for all the textboxes for fetching result. My problem is if user types at normal speed and move to other textbox(using tab) at a normal speed the second page is called properly and result displayed properly in labels, but if the user type very fast then the request for the value of one textbox is not completed and other is send and as a result there is no result value coming for first one. Is there is any way to handle this.
Thanks
If you don't want to refactor the whole thing to use XHRequests, there's a simple solution. Have a "request in progress" flag that is checked in your onchange event. If a request is in progress, queue the current action. In the result display code, check the queue and execute the next action, if any. If there are no remaining actions, reset the flag.
Here's a basic outline in code:
var requestInProgress = false;
var pendingActions = [];
function OnChangeHandler(onChangeFunction) {
if(requestInProgress) {
pendingActions.push(onChangeFunction);
}
else {
requestInProgress = true;
onChangeFunction();
}
}
function ResponseHandler()
{
//Your regular response handling code
if(pendingActions.length > 0) {
var nextFunction = pendingActions.shift();
nextFunction();
}
else {
requestInProgress = false;
}
}
I'm no JS expert, so I'm sure that this could be cleaned up a little bit, but it should handle overlapping events just fine.
Related
Looking for your suggestion on a good way to handle the below.
Need a fast input form for a receive scan webform app. This will be collecting barcodes scanned off of packages one right after another.
the scans will be coming in from a bluetooth scanner into a input field.
after the scan the scanner will insert a CR.
At that point I just want to capture the data and pass it onto a controller for processing, clear the field and return control immediately back to the webpage for the next scan.
The biggest two problems are:
Speed – it has to be fast as they are doing real time scanning.
Keeping the input field the focus all the time so that when they
scan they are not in some other field on the screen. They will start off in the input field, I just need to make sure they go right back to it after each scan automatically.
Any thoughts on how you would best handle?
Here is my HTML:
<input type="text"
id="barcode"
name="barcode"
value=""
onchange="location.href='#Url.Action("scanned", "receiveScan")?barcode=' + $('#barcode').val()"><br>
And this is the controller action:
public ActionResult scanned(string barcode)
{
//code to process goes here
return Ok();
}
Afterwards it resets the webpage to a blank page.
Instead what I need to do is just blank the input field and put the focus back to it.
I do have it working by modifying the controller to be:
public ActionResult scanned(string barcode)
{
var test = barcode;
//code to process goes here
return RedirectToAction("receiveScan", "home");
}
But it has been pointed out that reposting the entire page is not a good idea.
I will try one of the solutions below as soon as I can get back to it.
Thanks for the help, here is the code that worked --
$('#textArea1').val('Scans - ');
$(function () {
$("#barcode").on("change", function (e) {
// get the current value
var barcode = $('#barcode').val();
// if there's no text, ignore the event
if (!barcode) {
return;
}
// clear the textbox
$("#barcode").val("");
// var holdit = $('#textArea1').val();
$('#textArea1').val($('#textArea1').val() +' '+ barcode);
// post the data using AJAX
$.post('#Url.Action("scanned", "receiveScan")?barcode=' + barcode);
});
})
Instead of performing a full postback, you should be using an AJAX call to ensure that the page is not completely reloaded.
Here's an example of how you could do this (untested, might have typos):
<input type="text" id="barcode" name="barcode"/>
$(function()
{
$("#barcode").on("change", function (e)
{
// get the current value
var barcode = $('#barcode').val();
// if there's no text, ignore the event
if (!barcode)
{
return;
}
// clear the textbox
$("#barcode").val("");
// post the data using AJAX
$.post('#Url.Action("scanned", "receiveScan")?barcode=' + barcode);
});
Note that this assumes that the device will actually paste the entire data at once. If you find that the event is firing too often, you will need to implement some throttling around the change event.
/*--------------------SUBMIT FORM -------------------*/
//Validate Form Fields
function FormValidation()
{
// validation fails if the input is blank
var verdba =document.getElementById('verdba').value;
if(verdba.value == "") {
alert("Error: VERDBA FIRST!");
verdba.focus();
return false;
}
// validation was successful
return true;
processForm();
}
function processForm() {
// window.alert("processForm Reached"); // (Stub)
// Collect Values from the Form
// First section and verification
var callback = document.getElementById('callback').value;
var verdba = document.getElementById('verdba').value;
var comments = document.getElementById('comments').value;
// Concatenate the Page Content
var pageBody = " CB#:"+callback+" "+verdba+comments;
pageBody += "";
window.clipboardData.setData('Text',pageBody);
//Hides table on submit
$("#forms").hide();
$(".myClass").hide();
//Copies pagebody to clipboard
var content = clipboardData.getData("Text");
document.forms["test"].elements["clipboard"].value = content;
}
// Hides table with clear button
function cleartable(){
$("#forms").hide();
$(".myClass").hide();
}
I have included a very bare bones example in a fiddle.
I noticed on the fiddle that it doesn't fully work but in the HTA I have it does work. What it does is collects input fields and option fields by id, concatenates them into what I call a note. It also copies the clipboard data to a text area.
What I want is to be able to click submit and have it collect the form data and check to see if two fields were used or not.
So in the phone number field I need to be sure a phone number is entered ( does not really matter to me if it checks that its a certain amount of digits or that it is digits at all as long as it isnt blank) and next check to see if the option box was selected, either yes or no, again not blank.
Upon discovering one or both were left blank or not selected I would like the process to stop and notify the user that it needs to be done. I would like it to give them a chance to fix it and then resubmit.
The problem I am having is that I can't get both to happen.
I have it where it collects the data and checks for the data, but the problem I ran into is that it doesnt care if its blank and you click ok, it still submits the request anyway and then clears the forms.
I just cant seem to figure out how to get both things working in one swing.
I hope someone can shed some light on this as it has been bugging me for days with endless online research and failed attempts.
https://jsfiddle.net/joshrt24/roqjoyhr/1/
At the end of your function FormValidation(),
// validation was successful
return true;
processForm();
}
You have put return true, before your function has chance to call the processForm, return will immediately exit your function.
Fix, just call processForm() first.
// validation was successful
processForm();
return true;
}
I have two filters where the first influences the second before querying data to a remote server.
I have a select, which has its options in $scope.locationCodes. This select relies on another dropdown (customer). Once the customer is selected, I have the ID, and then pass that to the returned promise in the first function.
The issue 1:
As soon as I select a customer, if I really quickly go to select a location code (in codes dropdown), the options will be blank. If i blur and then try to select again, the options will show up, indicating there was a bit of a delay. What's the best way to handle this delay in the array being populated?
The code:
HTML:
<select data-ng-options="locationCode in locationCodes"></select>
JS:
$scope.getShipAbbleLocations = function (terminalId) {
var customerId = $scope.customer.id;
return Service.getShipAbbleLocations(customerId, terminalId).then(function (data) {
getLocationCodes(data);
_.defer(function () {
$scope.$apply();
})
});
};
function getLocationCodes(data) {
for (var i = 0; i < data.locationCodes.length; i++) {
$scope.locationCodes.push(["(" + data.locationCodes[i].shipThruLocationCode + ")", data.locationCodes[i].shipThruLocationId]);
}
$scope.$apply();
}
The issue 2:
The kicker is that the codes dropdown should be disabled until a customer is selected. I have been relying on a timeout in my controller to handle the disable by setting a delay for the 'enable' which allows time for the array to be populated. This works, but the issue re appears once you change customers and don't have to worry about the initial disable case.
I am wondering if there is a better way than timeouts (that hopefully shows a better understanding of angularjs/promises) to handle this delay/asynchronicity.
The best way is to show LOADER and disable the UI until your AJAX call is complete.
It is always a better practice to implement loader for async ajax calls.
You can implement the loader code in interceptors, so that for every request the loader will show up and you dont have to implement for every AJAX call, since its in the interceptor.
I have this fiddle: http://jsfiddle.net/y8Uju/5/
I am trying to save the numbers, because, when I submit, the list of numbers gets erased. I am a little new to JavaScript so am not quite familiar to what is available. In PHP I would use sessions to save the list, but what can I do in JavaScript to do this?
Here is the JavaScript code:
function bindName() {
var inputNames = document.getElementById("names").getElementsByTagName("input");
for (i = 0; i < inputNames.length; i++) {
inputNames[i].onkeydown = function() {
if (this.value == "") {
setTimeout(deletename(this), 1000);
}
}
}
}
document.getElementById("addName").onclick = function() {
var num1 = document.getElementById("name");
var myRegEx = /^[0-9]{10}$/;
var itemsToTest = num1.value;
if (myRegEx.test(itemsToTest)) {
var form1 = document.getElementById("names");
var nameOfnames = form1.getElementsByClassName("inputNames").length;
var newGuy1 = document.createElement("input");
newGuy1.setAttribute("class", "inputNames");
newGuy1.setAttribute("id", nameOfnames);
newGuy1.setAttribute("type", "text");
newGuy1.setAttribute("value", num1.value);
form1.appendChild(newGuy1);
num1.value = "";
bindName();
}
else {
alert('error');
}
};
function deletename(name) {
if (name.value == "") {
document.getElementById("names").removeChild(name);
}
}
You can use localStorage: http://jsfiddle.net/y8Uju/8/
Loading:
var saved = JSON.parse(localStorage["numbers"] || "[]");
for(var i = 0; i < saved.length; i++) {
document.getElementById("name").value = saved[i];
add(false);
}
Saving:
var saved = JSON.parse(localStorage["numbers"] || "[]");
saved.push(num1.value);
localStorage["numbers"] = JSON.stringify(saved);
And define the function of the addName button separately, so that you can call it when loading as well.
Edit: You have to execute a function when the page is loading to fetch the stored numbers, and add some code to save the entered number when one clicks the Add button.
For storing you can use localStorage, but this only accepts Strings. To convert an array (an array containing the entered numbers), you can use JSON.
When loading, you need to add the numbers just like happens when the user fills them in. So you can set the name input box value to the saved number for each element in the array, and then simulate a click on the Add button.
So you need an add function that is executed when:
User clicks Add button
Page is loaded
However, when simulating the click the numbers should not get stored again. You need to distinguish between a real click and a simulated one. You can accomplish this by adding an argument to the add function which represents whether or not to store.
Not entirely sure what the question is, but one problem I see with the code - id's can't be numbers, or start with numbers
var nameOfnames = form1.getElementsByClassName("inputNames").length;
//....
newGuy1.setAttribute("id", nameOfnames);
That might be slowing you down somewhat. Perhaps set id to 'newguy' + nameOfnames
Jeff, the reason that the page keeps getting erased is because the form submission triggers a page reload. You need to place a listener on the form submit event and then send the data through AJAX. This way the data is POSTed to "text.php" without reloading the page with the form.
You could place the values in a cookie but that is not ideal because you have a fairly limited amount of space to work with (4kb). I also get the feeling that you're trying to hand them off to some server side script so HTML5 local storge wouldnt be a good solution, not to mention that your eliminating over half of the people on the internet from using your site that way.
Since browsers are inconsistent in how they attach event listeners AND how they make AJAX requests. I think that most people would recommend that you use a library like jQuery, dojo, or prototype which abstract the process into one function that works in all browsers. (my personal fav is jQuery)
There are a few options available to you:
Save it client side using cookies (http://www.quirksmode.org/js/cookies.html)
Save it client side using HTML5 local storage (http://diveintohtml5.ep.io/storage.html)
Save it server-side using Ajax
The Ajax solution involves a server side page (in PHP for example) that reads a request (a POST request for example) and saves it into a database or other. You then query that page in JavaScript using XmlHTTPRequest or your favorite library.
I have a page where search resuts are shown both in a grid and on a map (using KML generated on the fly, overlaid on an embedded Google map). I've wired this up to work as the user types; here's the skeleton of my code, which works:
$(function() {
// Wire up search textbox
$('input.Search').bind("keyup", update);
});
update = function(e) {
// Get text from search box
// Pass to web method and bind to concessions grid
$.ajax({
...
success: function(msg) {
displayResults(msg, filterParams);
},
});
}
displayResults = function(msg, filterParams) {
// Databind results grid using jTemplates
// Show results on map: Pass parameters to KML generator and overlay on map
}
Depending on the search, there may be hundreds of results; and so the work that happens in displayResults is processor-intensive both on the server (querying the database, building and simplifying the KML on the fly) and on the client (databinding the results grid, overlaying big KML files on the map).
I like the immediacy of getting progressively narrower results as I type, but I'd like to minimize the number of times this refreshes. What's the simplest way to introduce an N-second delay after the user stops typing, before running the update function?
Instead of calling update() directly, call a wrapper that checks to see if there are any pending delayed updates:
$('input.Search').bind("keyup", delayedUpdate);
function delayedUpdate() {
if (updatePending) {
clearTimeout(updatePending);
}
updatePending = setTimeout(update, 250);
}
function update() {
updatePending = false;
//$.ajax(...
}
You should also probably add:
$('input.Search').bind("blur", update);
This will do an immediate update when the user leaves the field. But make sure you also add handling for the case where the user leaves the field while there's a pending delayed update (cancel the delayed update first).
As a first approach, what about something like :
$('input.Search').bind("keyup", function() { setTimeout(update, 5) } );
(not sure about the exact setTimeout syntax).
You can also keep a variable to track whether the timeout has already been scheduled or not.
You can use Window.SetTimeOut(YourRefreshMethod) , when the YourRefereshMethod gets called, it will check number of characters being typed so far , and compare it to the some counter, the counter will starts with 0 value, so the initial call will do nothing other than updating the counter with the current characters typed count, the second time your method get called , it will check the number of characters typed, if it matches the previous number recorded by the counter , then it means the user didn't type anything new and you can fire your Refresh method, otherwise you will update the counter value