Block javascript execution and wait on event triggered in UI - javascript

I have a method in which I want to stop execution (do not return), wait on an event triggered by the UI, then continue that method.
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
var newHeaders;
//I need to stop here, wait on some user event, update the `newHeaders` variable with
//the content set by the user on the page
return {requestHeaders:newHeaders};
},
{urls: ["<all_urls>"]},
["blocking", "requestHeaders"]
);
What I'm doing: Developing a chrome plugin that intercepts requests, modify them by the input of the user from html, then send the request. Based on the docs, I assumed I have to modify it directly in the method and return it.

I hope this points you in the right direction:
The docs at: http://developer.chrome.com/trunk/extensions/webRequest.html say:
If the optional opt_extraInfoSpec array contains the string 'blocking'
(only allowed for specific events), the callback function is handled
synchronously. That means that the request is blocked until the
callback function returns. In this case, the callback can return a
BlockingResponse that determines the further life cycle of the
request. Depending on the context, this response allows cancelling or
redirecting a request (onBeforeRequest), cancelling a request or
modifying headers (onBeforeSendHeaders, onHeadersReceived), or
providing authentication credentials (onAuthRequired).
My guess is that you can specify "blocking" and then gather information from your user.

Related

Equivalent of jQuery ajaxStart in Angular 2

I want to know if there is an equivalent of ajaxStart or ajaxStop in Angular 2.
I want to check if there's an ajax which runs into the document.
According the official documentation of ajaxStart, it will be triggered when there is any Ajax Request. And I want something like this in Angular 2.
$( document ).ajaxStart(function() {
$( "#loading" ).show();
});
I do this:
into my app.component.ts, I show my loader
when my ajax is success, I hide my loader
But, some of my page doesn't have ajax call, so if I show my loader using my app.component.ts, it will be impossible to hide this, because, none of ajax request is present into this page.
I think, if I listen if ajax is not present into my page, if will hide my loader.
I use localStorage to save the status of ajax.
If the page has ajax, I set a value to that xhr
Otherwise, I remove the status stored into localStorage.
Each time, the user arrive in the page. My script check, if there is an ajax running into that page.
app.component.ts
if(localStorage.getITem("xhr")) {
// action here
}
request.service.ts
...
let checkForAjax: any = {
setXhr () {
localStorage.setItem("xhr", "1");
},
removeXhr () {
localStorage.removeItem("xhr");
}
}
...
into get request, I do this (before success callback):
checkForAjax.setXhr()
And into callback of get request, I just remove the status.
checkForAjax.removeXhr()
By the way, I haven't the xhr status, after my ajax is successed. So If I check it into my app.component.ts, I just test if there's a property xhrinto my localStorage.
I work now, but I want another way to listen for ajax with angular 2.
Is that way exist?
How can it will be done?
You could make use of Promises
https://stackoverflow.com/a/30008115/3152269 explains it better than i ever could, but it seems right up your alley
What i generally do when i shoot off an ajax request is to make a promise to run some code after it receives a response.
This makes Ajax calls easier to read and ensures the code doesn't run unless you want it to.

Angular: $http.get() only fires every second onpopstate trigger

I have an AngularJS app that makes a call to an API and returns a bunch of data that users can then filter by tags for greater granularity in the results. Each time a tag is clicked to filter the data, the app makes a new $http.get() call, and the URL is modified with the appropriate query parameters so that the user can save the permalink and come back to any particular data set.
I'm trying to give the app proper history handling with window.history.pushState(), and passing the relevant query parameters for each history object as state data. I'm using window.onpopstate to detect when the back/forward buttons are clicked, and using that to make the new $http.get() call with the relevant state data from the history.
For some reason, the $http.get() function only fires on every second popstate, and then it makes two calls. It's almost as if there's some caching going on, but I haven't been able to find the culprit. This behaviour persists in both directions, backwards and forwards, and is consistently every second event. I've verified that window.history.length is only incremented by 1 for every tag added/removed, that the state data is being successfully sent, that new search queries are being correctly assembled, and that the request path is correct. It's just not firing. What's going on??
To illustrate, the behaviour flow looks like this:
Load page at /default
Add first tag: URL is /default&tags=a, $http.get() returns new data
Add second tag: URL is /default&tags=a,b, $http.get() returns new data
Add third tag: URL is /default&tags=a,b,c, $http.get() returns new data
Add fourth tag: URL is /default&tags=a,b,c,d, $http.get() returns new data
First back button event
window.onpopstate fires, URL is now /default&tags=a,b,c
No network changes
Second back button event
window.onpopstate fires, URL is now /default&tags=a,b
$http.get() fires, sends network request for data with /default&tags=a,b,c
$http.get() fires again, sends network request for data with /default&tags=a,b
dataset for /default&tags=a,b loads
Third back button event
window.onpopstate fires, URL is now /default&tags=a
No network changes
Fourth back button event
window.onpopstate fires, URL is now /default
$http.get() fires, sends network request for data with /default&tags=a
$http.get() fires again, sends network request for data with /default
dataset for /default loads
Relevant code snippet:
$scope.apiRequest = function(options, callback) {
// Omitted: a bunch of functions to build query
// based on user-selected tags.
// I've verified that this is working correctly.
$http.get(path)
.then(function(response) {
console.log('http request submitted');
if (callback) {
callback(response.data.response, response.data.count, response.data.facets);
console.log('data returned');
}
}, function(response) {
console.log('there has been an error');
});
}
Neither the success nor error events fire. I've tried using $http.get().then().catch() to see if there might be something else going on, but for some reason I keep getting an error in my console that says that ...catch() is not a valid function, which is in and of itself bewildering. Any ideas?
Thanks!
This sounds indicative of a function not cycling through the $digest loop. In this case you may attempt to add $scope.$apply(); as the last line in your window.onpopstate handler function to kick the $digest cycle to execute your function call.
This article, Notes On AngularJS Scope Life-Cycle helped me to better understand the $digest cycle and how you can force the $digest cycle to run with $scope.$apply(); Keep in mind you want to use $scope.$apply() sparingly but in some cases you are forced to kick off the cycle, especially with async callbacks.

Use Remote Service (RPC) in XPages

I am trying to update a document using rpc service.
I have an xpage with a button. I want to click that button and by using CS javascript to setInterval and update a document field every 5 seconds.
I used the remote service control and the code is this:
<xe:jsonRpcService id="jsonRpcService1" serviceName="heartBeat">
<xe:this.methods>
<xe:remoteMethod name="send">
<xe:this.script><![CDATA[var db = session.getCurrentDatabase();
var heartView = db.getView("Heartbeats");
var doc:NotesDocument = heartView.getFirstDocument();
var vl = doc.getItemValueString();
if(vl==""){
doc.replaceItemValue("dummyH","z");
}else{
doc.replaceItemValue("dummyH",vl+"z");
}
doc.computeWithForm(false, false);
doc.save();]]></xe:this.script>
</xe:remoteMethod>
</xe:this.methods></xe:jsonRpcService>
The code of the button is this:
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[setInterval(function(){heartBeat.send()},3000);]]></xp:this.script>
</xp:eventHandler></xp:button>
It doesnt work. I get no error but i also get no updates in the document... What is wrong in the code?
UPDATE
if i replace rpc script with a simple print("aaaaa") it works perfectly (i also followed the suggestions of Tim in the answer below, for my client side code).
when i use again my previous code i get the following javascript error:
Unable to load /Databases/Test/Mike/my1.nsf/RPCpage.xsp/mm?$$viewid=!dqducrahog! status:400
how can i access the database and documents from a remote service?
The syntax of RPC calls is slightly unusual; your call to heartbeat.send(), for example, does not actually call the remote send method. Rather, it returns a handle on a remote method descriptor... to actually call the remote method, you need to add a callback:
var remoteMethod = heartbeat.send();
remoteMethod.addCallback(function(response){
// handle whatever came back from the server
});
If, for instance, you designed your remote method to return whether or not the heartbeat was successful, a more complete example would look like this:
var heartbeatInterval = 3000;
var periodicHeartbeat = function() {
var remoteMethod = heartbeat.send();
remoteMethod.addCallback(function(response){
if (response.stillAlive) {
setTimeout(periodicHeartbeat, heartbeatInterval);
}
});
}
setTimeout(periodicHeartbeat, heartbeatInterval);
It's generally recommended to use setTimeout to initially schedule a deferred function, and then call setTimeout again from within that deferred function to schedule its own next execution, instead of using setInterval.
In this use case, however, this is particularly true because each remote method call is asynchronous, so with setInterval, you would eventually end up with request overlap, because each call requires at least a few milliseconds to complete.
Additionally, the preferred pattern of scheduling the next execution from inside the current allows you to check what the server sent back to determine whether to even bother continuing to send subsequent requests. Right now you're not returning any value from your remote method; if you change just the last line to:
return { stillAlive: doc.save() };
...then that JSON object will be automatically passed to your callback function as its first argument. Taking another look at one line from the prior example:
if (response.stillAlive) {
...so the RPC call only reschedules itself if the prior call succeeded. This probably isn't the precise behavior you want, but given that you can return data from the remote method, and the data that was returned is passed to your callback function, you can design a call and response approach that best fits your business specifications for this functionality.
Having said all that, you may want to take a look at the keepAlive component from the XPages Extension Library... it doesn't store heartbeat data in Domino documents, but if all you're trying to do is prevent idle sessions from expiring, it's a much simpler solution.

order of events on click on <a> tag

So I have a normal link on my website, and I want to add tracking for it. I could envision a bunch of ways to do this, but I've settled on this as being really easy by writing a small jquery function, and dropping a small snippet in my tags:
click me!
javascript:
function saveClick(someparamhere){
$.ajax({
url: "somepage.php",
data: {param:someparamhere}
});
}
Now, I know my syntax might be bad, I'm just asking about the overall concept here. When you click the link, I want javascript to issue the call to saveClick which immediately makes an ajax call. There's no success handler because I don't really care if or what gets returned. I'll just have somepage.php log the event. Then, after all of that, I want the tag to go to it's href.
Is that the case? Will the ajax call be issued before the document goes to the other page? Will this work in all cases?
Has anybody ever done something like this? Any experience would be appreciated ....
If you want to make sure the AJAX call goes through you could do:
click me!
$('[data-parameters]').bind('click', function (event) {
//cache this element to use in AJAX function
var $this = $(this);
//prevent the default naviation
event.preventDefault();
$.ajax({
url: "somepage.php",
data: {param:$this.attr('data-parameters')}
success : function () {
//now navigate to the requested page
location = $this[0].href;
}
});
});
UPDATE
$.ajax() exposes a timeout function:
timeoutNumber
Set a timeout (in milliseconds) for the request. This will override
any global timeout set with $.ajaxSetup(). The timeout period starts
at the point the $.ajax call is made; if several other requests are in
progress and the browser has no connections available, it is possible
for a request to time out before it can be sent. In jQuery 1.4.x and
below, the XMLHttpRequest object will be in an invalid state if the
request times out; accessing any object members may throw an
exception. In Firefox 3.0+ only, script and JSONP requests cannot be
cancelled by a timeout; the script will run even if it arrives after
the timeout period.
So you could set a timeout and an error function that mimics the success function. The documentation does state that: it is possible for a request to time out before it can be sent but if your timeout is a very small (maybe zero) delay then it could reduce the lag between the user clicking the link and the browser loading the new page.
I simply wouldn't do that... it could bring to situation your onclick event isn't fired.
I think it would be better to call a javascript function on click that does your ajax call and then bring the user to the target page.
You can do this, for example, this way:
...
your javascript function then, shall be something like:
myfunc(paramofpageclickhere) {
//do ajax call
saveClick(someparamhere);
//go to target page
location.href = "target.htm";
}

How to detect when several AJAX requests have completed or failed?

I have an app that loads several resources when it's first run, which are stored in localStorage. I have a function that checks whether all the local storage variables are set, so that part is working okay.
My method of working is like this:
Display a loading message.
Initialize the AJAX requests.
Start a timer interval to check if everything has loaded.
When the data has loaded, initialize the application etc.
If the data did not load, display an error message.
The problem is with #5 - how to detect if there was an error? For example if there was a connection problem or the sever sent back invalid data for whatever reason. Here is my current code - downloadData just performs a basic AJAX request:
// check local storage and download if any missing
if ( !checkLocalStorage() )
{
$('#content').before( '<div class="notice" id="downloading">Downloading data, please wait...</div>' );
for ( var i in db_tables )
{
if ( localStorage[db_tables[i]] == null )
downloadData( db_tables[i] );
}
}
// check progress
var timer = setInterval( function() {
if ( checkLocalStorage() )
{
// everything is downloaded
$('#downloading').hide();
clearInterval(timer);
initApp();
}
}, 500 );
Could you turn it around a bit? Something like this (with sensible variable names and a "real" API) would simplify things:
Display a loading message.
Instantiate an application initializer, ai.
Crank up the AJAX requests:
Success handlers call ai.finished(task).
Error handlers call ai.error(task).
Register with the initializer, ai.register(task), in case a "you're taking too long" check is desired.
Once all the AJAX requests have called ai.finished, initialize the application etc.
If any of the AJAX tasks called ai.error, then display an error message and start cleaning things up.
This way you wouldn't need to setInterval() and the individual AJAX tasks will tell you when they have finished or fallen over. You might still want the interval to deal with tasks that are taking too long but most of the logic would be notification based rather than polling based.
Seeing your actual ajax calls in downloadData would help, but I suggest you look over the jquery AJAX API again. Ajax calls have callbacks not just for overall completion but specifically for success and failure including errors. Try to do something like retrying if there is an error and if it continues to fail you can warn the user. You can also use these callbacks to notify your application when the loading is done instead of using an interval timer.

Categories