API Call after user selection - angularjs

Um Currently working on an old angular js application.
This has a series of checkboxes where the user can select an option/ several options. for every selection, it does a backend api call. but I want to avoid making a backend call for every selection but allow the user to do his selection for a couple of seconds and then do a backend call at once. I tried to achieve it via a $timeout function, even though it wait for a couple of seconds until the user does the selection, but it does call for the backend API for the number of time I select/deselect the options.
plunker : sample plunker
much appreciate if someone could suggest me a solution.
Thanks

How about just keeping track of whether you are waiting to call the backend. If you are waiting, don't call your function again. Untested code example:
var waiting = false
$scope.toggleCheck = function (option, optionArray, channel) {
var index = optionArray.indexOf(option);
optionArray[index].checked = !(optionArray[index].checked);
if (waiting == false) {
waiting = true //set to true so backend will not be called multiple times
$timeout(function () {
waiting = false
//call the backend api
//access the statuses by $scope.statuses
alert('backend call ' + $scope.statuses);
}, 2000);
}
}

I think what you are looking for is a debounce function. Given a delay in ms, calling the debounce function will start a timer and execute after the timer has reached 0. If we call the same function again, before the timer has reached 0, the timer restarts.
This will prevent the backend from being spammed with API calls if the user frequently clicks the checkboxes.
For more information about debounce, please check out this link (where throttle is also explained): https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf

Related

How to prevent browser window from closing in AngularJS until the promise is resolved

I have the following code:
$window.onbeforeunload = function (event) {
event.preventDefault();
// some asynchronous code
};
I want the onbeforeunload event to wait until the asynchronous code is executed. Not sure if this can be achieved across all browsers supporting AngularJS.
Regardless of whether you are using AngularJS, or any other framework, delaying window unload until an async action completes is not something that modern browsers support anymore, as it creates a bad user experience.
However, assuming that the async thing you want to do is make an API request, then the modern solution is to use the navigator.sendBeacon() method instead. It is guaranteed to be sent in a non-blocking fashion by the browser, even after the window has been unloaded. It is a nicer solution for everyone.
Note that beacon requests have to be sent as POST requests, so your API needs to support this method for any endpoints you wish to use in an unload handler.
One can create a handler that looks at a spinner flag:
var spinnerFlag = false;
$window.addEventListener('beforeunload',unloadHandler);
$scope.$on("$destroy", function() {
$window.removeEventListener('beforeunload',unloadHandler);
});
function unLoadHandler(e) {
if (spinnerFlag) {
// Cancel the event
e.preventDefault();
// Chrome requires returnValue to be set
e.returnValue = '';
};
});
Then one can set and clear the flag:
spinnerFlag = true;
var promise = promiseBasedAPI(arguments).finally(function() {spinnerFlag = false;});
This will set the flag before starting the asynchronous operation and clear the flag when the promise either succeeds or rejects.
The user will be prompted to confirm the page unload if the promise has not resolved.
For more information, see
MDN Web API Reference - onbeforeunload
Prevent a webpage from navigating away using JavaScript — this answer
How to show the "Are you sure you want to navigate away from this page?" when changes committed?
Can beforeunload/unload be used to send XmlHttpRequests reliably

Autosave form fields for every 15 sec in AgularJS without using $watch

I want to save a form field values every 15 sec with out using $watch and also it should stop executing once it has been moved to a different form. In the form I will be having many fields so I think $ watch will be having performance issue and also am not sure how to call all fields at once for %watch. So I decided to use $interval but I want to stop this execution once I moved to different controller or different form. If user comes back again to this form again this interval function should start automatically. please would you suggest me best way to handle this.
Use $interval like you are planning to do but assign it to a variable
with $scope.on('$destroy', function() { }); callback you can destroy the interval when switching to a different controller.
var intervalPromise = $interval(function() { // your code }, 15000);
$scope.$on('$destroy',function(){
if(intervalPromise)
$interval.cancel(intervalPromise);
});

Find duration of a REST call in Angular.js

I want to find out the time taken by a REST service to send back the promise object. If a REST service takes more than lets say x seconds, I need to show user a spinner and once the promise object is obtained the normal flow should proceed.
Any ideas?
Thanks
Recording the time of the request seems unnecessary.
Why not just always setup a timeout that will trigger the spinner after x seconds.
In the success callback of the promise you can just destroy the timeout object preventing it from triggering the spinner if it's before x seconds. Then remove the spinner if it exists.
var duration = 1000 * 1; //1 sec
var timeout = setTimeout(releaseTheSpinner, duration);
var releaseTheSpinner = function() {
//Make spinner
}
Something.update(data).
success(function {
clearTimeout(timeout);
//kill spinner
})
Using setTimeout should suffice. For example:
$scope.useHttp = function() {
$http.get('path/to/stuff')
.success(function(data) {
hideSpinner();
//do stuff with data
});
setTimeout(showSpinner,1000); //will show the spinner after a second (1000 milliseconds).
};
Have a look at the ngProgress directive or the angular loading bar directive, which place a progress at the top of the page. This creates a general, uniform method of displaying progress. Even if the service responds quickly (which is when you don't want to show a progress), the bar moves very quickly. This isn't a direct answer to your question, but a suggested alternative to added complexity around timing and showing a spinner.

Event when list of uploads has changed

I'm integrating Fine Uploader into an existing workflow. The user needs to provide a bit of metadata and select a file, then click Upload.
The Upload button should be disabled until a file is selected. If the user deletes the file, it should go back to disabled. I have autoUpload:false.
I'm using AngularJS so I'm binding to a function which invokes $("#fine-uploader").fineUploaderS3('getUploads'), and seems like a nice way to handle it.
However, I need a way to get notified when the list has changed, so I can trigger the digest cycle and update the UI. I've tried registering callbacks for the submitted and cancel events, which works – except that cancel is called when the upload is still in the list.
Is there a cleaner way to get a callback when the user adds or removes a file from the list of uploads?
In your case, listening for the "cancel" event is not appropriate. Why? Because the file/upload is not actually cancelled when your cancel callback is invoked due to the fact that you are able to abort the cancel attempt via your callback handler's return value.
You can be sure that the file has been cancelled internally by listening for the statusChange event. When it has truly been cancelled, your statusChange event handler will be called with the file ID and a newStatus parameter of qq.status.CANCELED.
You can read more on status change handling in the docs.
UPDATE: Since you are using Fine Uploader UI, the file is not removed from the UI until just after this status is updated. This doesn't seem like an issue for you though, since you are utilizing the getUploads method to determine file status.
Here's my working solution, in case it's useful to someone else:
$scope.uploader = $('#fine-uploader').fineUploaderS3({
...
}).on('statusChange', function (event, id, oldStatus, newStatus) {
$timeout(function () {
$scope.$digest();
});
});
$scope.has_selected_file = function () {
if (!$scope.uploader) return false;
var uploads = $scope.uploader.fineUploaderS3('getUploads');
var result = _(uploads).some(function (item) {
return item.status !== qq.status.CANCELED;
});
return result;
};
(Uses Underscore.js)

extjs datefilter question

In extjs GridFilters.js, we have :
onStateChange : function (event, filter) {
......
...
if ((this.autoReload || this.local) && !this.applyingState) {
//alert('Firing reload');
this.deferredUpdate.delay(this.updateBuffer);
}
}
I thought this means that whenever the
`this.deferredUpdate.delay(this.updateBuffer);`
was executed, the reload function would be called. But by putting alerts, I discover that this is not the case. reload is called only once as it should be) despite the
alert('Firing reload');
popping up multiple times. I am using a Date Filter for this example.
Why is this so? does not a call to deferredUpdate.delay automatically trigger the reload as per the GridFfilters.js class?
The GridFilter is using Ext's DelayedTask delay method (here) which cancels any pending delayed methods and queues a new one. Hence you are getting multiple alerts, but only one refresh.

Resources