I have the code below that will grab an RSS feed and display it as a custom html feed shows these as scrolling text on a page.
" I would like to know how to make a timed call back to the RSS URL to display new information and drop out non current information. " Basically refresh the page on a timer..
function OnLoad() {
// Create a feed instance that will grab Digg's feed.
var feed = new google.feeds.Feed("http://131940.qld.gov.au/DMR.Modules/TTIEvents/RSS/RSS.aspx?regionid=0&eventcause=Incident");
feed.setNumEntries(15);
feed.includeHistoricalEntries();
// Calling load sends the request off. It requires a callback function.
feed.load(feedLoaded);
}
any help would be great.
Thanks in advance.
You need to use window.setInterval. Here's an example:
window.setInterval(OnLoad, 1000);
The first parameter is the name of your function, and the second parameter is the number of milliseconds that the browser should wait before calling that function again.
This example would call the function OnLoad once a second.
Related
I am trying to build a Gmail addon which includes 2 external API calls. The first one is fast (~200ms) and the second one is slow (~5s). Because of this I would like to first build the card with the results of the first fetch, and then update the card after the second call finishes.
Would it be possible to either:
Call fetchAll and build and render the card each time a request finishes
Trigger a function after the initial rendering is done (after return card.build())
Update the root card without returning it (I tried CardService.newNavigation().popToRoot().updateCard(card.build()) without success)
Any preferred way to render a card and then update it after data is fetched would be appreciated!
Below is an example function if useful.
function onGmailMessage(e) {
// Fetching email
var messageId = e.gmail.messageId;
var accessToken = e.gmail.accessToken;
GmailApp.setCurrentMessageAccessToken(accessToken);
var message = GmailApp.getMessageById(messageId);
// Preparing requests
var data = {
'text': message.getPlainBody(),
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
// Fetching responses. Here I would love to first display
// createCard(response_1) and then when the second call finishes
// return createCard(response_1 + '/n' + response_2)
var response_1 = UrlFetchApp.fetch('http://API_1/', options);
var response_2 = UrlFetchApp.fetch('http://API_2/', options);
return createCard(response_1 + '/n' + response_2);
Answer:
Unfortunately, this is not possible to do.
More Information:
This is a bit tricky so I'll split this answer down into your three points:
[Is it possible to] call fetchAll and build and render the card each time a request finishes?
A fetchAll function could be made to get all API responses, but you'll still end up waiting for API 2 to respond before updating what can be seen in the card.
The problem with this is that in order to display the rendered card, you need to make a return of some kind. Once you return the response of the first API your second API won't be made at all as the function will have already executed. Which leads onto point two:
[Is it possible to] trigger a function after the initial rendering is done (after return card.build())
I did a test with this, instead of returning API 1's response directly I stored its value in a Script Property and made a trigger execute 200 ms later with the call to API 2:
function onGmailMessage(e) {
// previous code
var response_1 = UrlFetchApp.fetch('http://API_1/', options);
ScriptApp.newTrigger("getSecondResponse").timeBased().after(200).create();
PropertiesService.getScriptProperties().setProperty('response1', response_1);
return createCard(response_1);
}
function getSecondResponse() {
// options 2 definition here;
var response_1 = PropertiesService.getScriptProperties().getProperty("response1");
var response_2 = UrlFetchApp.fetch('http://API_2/', options);
return createCard(response_1 + '/n' + response_2);
}
and adding the correct scopes in the manifest:
{
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.locale",
"https://www.googleapis.com/auth/gmail.addons.current.action.compose",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://mail.google.com/",
"https://www.googleapis.com/auth/script.scriptapp"
]
}
And which this did call the first API, display the response in the card and make the trigger, the card didn't update. I presume this is because the trigger acts as a cron job being executed from somewhere which isn't the add-on itself, so the second card return is never seen in the UI.
[Is it possible to] update the root card without returning it (I tried CardService.newNavigation().popToRoot().updateCard(card.build()) without success)
updateCard() is a method of the Navigation class. There's a whole page in the documentation which details the uses of Card navigation but the important parts to take away here is that the navigation methods are used in response to user interaction. From the documentation:
If a user interaction or event should result in re-rendering cards in the same context, use Navigation.pushCard(), Navigation.popCard(), and Navigation.updateCard() methods to replace the existing cards.
The following are navigation examples:
If an interaction or event changes the state of the current card (for example, adding a task to a task list), use updateCard().
If an interaction or event provides further detail or prompts the user for further action (for example, clicking an item's title to see more details, or pressing a button to create a new Calendar event), use pushCard() to show the new page while allowing the user to exit the new page using the back-button.
If an interaction or event updates state in a previous card (for example, updating an item's title from with the detail view), use something like popCard(), popCard(), pushCard(previous), and pushCard(current) to update previous card and the current card.
You can create multiple cards which have different content - for example one which contains response_1 and one which contains response_1 + "\n" + response_2, but some kind of interaction from a user is still needed to switch between the two views, and it won't get around the wait time you need to get a response from API 2.
Feature Request:
You can however let Google know that this is a feature that is important and that you would like to request they implement it. Google's Issue Tracker is a place for developers to report issues and make feature requests for their development services. I would suggest using the feature request template for G Suite Add-ons for this, rather than Apps Script directly.
References:
Class Navigation | Apps Script | Google Developers
Card navigation | G Suite Add-ons | Google Developers
I have a GMail add-on which uses CardService for UI. Some of the callback functions for the Card actions take over than 30 sec. Thus, I'm getting the following error.
Gmail could not perform this add-on action.
Is there, any way to run Google Apps Script functions on the Server side asynchronous way, so I can return to a user some notification and continue work behind the scenes.
I have tried using some libraries like this one but with no luck, I'm able to use syntactically the Promises but functionally it's still synchronous.
As of now, there is no asynchronous execution for the Gmail add-on. Even if there is something, there is no way to refresh the UI without user action.
But, there is a hack. What you can do is, if there is a long running process is there, just create a "openlink" action (set link), which should open a url (https://yourhtmlpageurl?redirect_uri=) with html response. This html can have jquery ajax call, which can wait for some time. Once you get the response in the html window, redirect the page to the redirect_uri that is passed by passing the response data. So, our add on will get a callback to the function with parameter as json object with all the query parameters to the redirect_uri. Once you get the expected response, cache the response by using CacheService. return some html success template, which should automatically close the window by itself.
For Creating openlink action:
For generating redirect script URI with state token:
function generateNewStateToken(callbackName, user_info) {
return ScriptApp.newStateToken()
.withMethod(callbackName)
.withArgument("user_info", JSON.stringify(user_info))
.withTimeout(3600)
.createToken();
}
function getRedirectURI() {
return "https://script.google.com/macros/d/" + ScriptApp.getScriptId() + "/usercallback";
}
var htmlUrl = <your_html_url> + "?redirect_uri="+ getRedirectURI() + "&state=" + generateNewStateToken("asyncCallback", {});
CardService.newOpenLink().setUrl(htmlUrl).setOpenAs(CardService.OpenAs.OVERLAY).setOnClose(CardService.OnClose.RELOAD_ADD_ON);
function asyncCallback(data) {
data.response; // response which you can pass from script
CacheService.getUserCache().put("long_running_process_resp", data.response);
data.user_info; // user_info passed during state token creation
// cache the data using cache service
return HtmlService.createHtmlOutputFromFile("success");
}
success.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<div class="sidebar">
<p>Long running Process completed.</p>
</div>
</body>
<script>
setTimeout(function() {
top.window.close();
}, 2000);
</script>
</html>
Once the success.html is closed by itself, there will be a refresh of the gmail add on. So, you can lookup for the long running response data from CacheService.
Let me know if you have any more questions on this process.
Sabbu's answer is pretty good. But, if you want to trigger the long running process without expecting the user to click on the openlink, you can render an image using:
CardService.newImage().setImageUrl('https://yourservice.com/pixel/action.png?name=value&_nocache='+new Date().getTime())
On the server side, you can map the path '/pixel/action.png' to the long running code which returns a tiny transparent pixel (1x1) on complete:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==
I am using the Youtube Api for AS3 and i used the function player.getCurrentTime so that I can get the current time of the video. I have been running into this error https://code.google.com/p/gdata-issues/issues/detail?id=6215 and I really need to get this fixed is there any solutions to this problem or a way around it. I am just trying to save the current video progress to a variable and access that variable later here is my code used for this function
mis_player = new my_players(vidSource, mis_players.my_play.getCurrentTime());
and here is the code used for using the var both work fine at first then display the second value as the end of the video
my_play.seekTo(currTime1)
I figured it out, by sending the variable through the function I was able to pass the variable through to the function.
I've read many posts about this but still can't wrap my head around fixing my problem. I've looked at jQuery.when but not sure how to use it. I get data from the server via ajax and then it updates the page. Sometimes, it might take a few seconds depending on how much data is being returned. I don't want that same ajax function to run until all html has loaded on the page. Is that possible?
I have a timer to run a function that calls an ajax request.
setInterval( "update()", 25000 );
This is the ajax inside the update function
$.ajax({
type: "POST",
url: "/ajax/modify.php",
data: "id="+ id +"& action="+ act,
success: function(response){
//update the html on the page
}
});
There is a way for the user to get more posts by clicking on a link. Well problem is, if they click that link to get more posts and the timer happens right after, it refreshes the page and interrupts the users request and reloads the div container with what was there before. So I need it to wait until the response has completed and the page has been updated before allowing more requests.
An example what be appreciated.
JQuery's ajax method returns a promise, which you can use to attach callbacks. You can store away this promise into a variable. On success/fail of the function, you can clear the variable. This way you know if a request is currently active or not. Just make sure the variable is outside the function scope or it won't do anything to help you. For example:
var currentRequest = null;
function doUpdate() {
// don't do anything if there's an active request
if (currentRequest)
return;
currentRequest = $.ajax({
type: "POST",
url: "/ajax/modify.php",
data: "id="+ id +"& action="+ act
}).then(function(response) {
// do your UI updates here.
}).always(function() {
// whether the call succeeds or not, still clear out the request
// so that the next call into the function makes a new request
currentRequest = null;
});
}
have a look at this SO question jQuery deferreds and promises - .then() vs .done()
jQuery Deffered Object
doing async:false kills the purpose of it, you can fire the next ajax request in the success call back of the first one but that is not a clean approach IMO
I have two combo boxes in my JSP page named combo1 and combo2. I have a table in mysql called ZoneData. In this table there are two columns called zone and subzone. When the web page loads I want that when I select a zone name from combo1, all subzones of the selected zone should be extracted from ZoneData table and added in combo2. I am unable to do this. Should I use any combo1's event. Please help I am a newbie in web programming.
The usual way to do this type of things is to use javascript to manage combo1 onChange event.
I recommend you to use jQuery framework, as it eases a lot the basics of javascript client coding http://jquery.com
What you do when the event is fired is to capture it on a javascript function and make an AJAX call to your server, where you have some server method to filter the combo2 values that has to be loaded into your combo2 depending on the value of combo1. When this method returns, the AJAX call will receive the values from the method and will allow you to update data in combo2
This is a brief example of the jQuery code you'll need to manage the change event and make the AJAX call:
$("#combo1").change(function () {
$.ajax({
url: herePutTheUrlToYourServerMethod,
data: $("#combo1").val(),
success: function (returnedValueFromYourServerMethod) {
//Here use returnedValueFromYourServerMethod data to reload combo2 info
//There are several differents ways to do it that depends on what will
// your server method return
}
});
});