Google App Scripting Progress Bar - google-apps-script

I'm trying to create a progress bar in Google app scripting , which when some one click a button (Go) it will be automatically, slowly go to start to end . Something you see in Firefox download window.
this is my code.
function doGet(e) {
var app = UiApp.createApplication();
var progressPanel = app.loadComponent("progressbar_auto");
var gobutton =app.getElementById("go_btn");
var go_btn_handler =app.createServerHandler("updateProgressbar");
go_btn_handler.addCallbackElement(gobutton);
gobutton.addClickHandler(go_btn_handler)
app.add(progressPanel);
return app;
}
//function time(i){
// Utilities.sleep(5);
// }
function updateProgressbar(){
var app = UiApp.getActiveApplication()
for(var i =1 ; i < 250 ; i++ ){
app.getElementById("progress").setWidth(i + 'px');
time();
}
Logger.log(i);
return app;
}
But according to this code for loop will execute very speedy & ,progress bar completed very quick . Is there any way to slow this.
You can find the my application here.
https://sites.google.com/a/macros/dewdynamics.net/exec?service=AKfycbztKB_ljMBGi_55RrK_DH3x_pRZQ993bDoAHSsxDA
Is there any way to add a slide bar , to control the progress bar. Something we can do in php or HTML 5.
Thanks

Why don't you use HtmlServices for this. Just try it:
Click Here
You can use jquery to implement this.

Updated answer: to get the status of scripts running server side, you need to store progress to the cache. Then the client side can call a server-side function to retrieve it. https://developers.google.com/apps-script/reference/cache/cache-service

No, there isn't a real way to do a progress bar on Apps Script.
There's some workarounds though. You can add multiple handlers to the same button, and in each one, with a different sleep time, you can update the GUI many times. Or, as most do, show an endless progress gif animation in a client handler (for instant feedback) and after your second handler finishes, a ServerHandler where you actually do the work, you hide the image and return the results.

I worked out a solution by storing data in the cache on the server side and reading the cache on the client side as suggested by Greg.
Screenshot
Video
Caching progress data server side
var cache = CacheService.getScriptCache();
async function updateCacheProgress(current, total, student) {
// cache for 10 seconds
cache.put("total", total, 10);
cache.put("current", current, 10);
cache.put("student", student, 10);
}
Script on client side
window.addEventListener('load', getUpdatedProcess);
function updateProgress(data) {
console.log('#student: ' + data.student)
console.log('#current: ' + data.current)
console.log('#total: ' + data.total)
var ProgressBar = document.getElementById('progressBar');
var Progress = document.getElementById('progress');
var ProgressStatus = document.getElementById('progressStatus');
var percent = 0.1
percent = data.current / data.total *100;
percent = percent.toFixed(1);
Progress.style.width = percent + '%';
Progress.innerText = percent + '%';
ProgressStatus.innerHTML = data.student + ` (${data.current} of ${data.total})`
if(percent < 100) getUpdatedProcess()
}
function getUpdatedProcess() {
google.script.run.withSuccessHandler(updateProgress).getProgress();
}
Apps Script that retrieves stored cache executed via client
function getProgress() {
var total = cache.get("total");
var current = cache.get("current");
var student = cache.get("student");
return {total: total, current: current, student: student}
}
Client HTML
<html>
<head>
<base target="_top">
<style>
* {
font-family: 'Arial';
}
#progressBar {
width: 100%;
background-color: silver;
}
#progress {
width: 0%;
height: 30px;
line-height: 32px;
text-align: center;
color: white;
background-color: green;
}
#progressStatus {
}
</style>
</head>
<body>
<div id="progressBar">
<div id="progress"></div>
</div>
<br><br>
<div id="progressStatus"><?= student ?> (<?= progress ?>)</div>
</body>
</html>

Related

Code not working like it should,can you find out the problem?

Hello so i did online classes and the teacher tried to teach us an bubble animation like this: https://drinkcann.com/ but like it was more simple he only wanted to make the bubble animated but for some reason my code doesn't work:
var numberOfbubbles = 10
for (let i = 0; i < numberOfbubbles; i++) {
newBubble()
}
function newBubble() {
let bubble= document.createElement("div");
bubble.classList.add("bubble");
let x = randomNumber(100);
let delay= randomNumber(3000)
bubble.style.left = x + "vw";
bubble.style.animationDelay = delay + "ms";
document.querySelector("body").appendChild(bubble);
}
function randomNumber() {
return Math.floor(Math.random() * max)
}
```
the html code has an html:5 standard and just a div so can you tell me where is the problem in my code?,let me know if you want to post something else too
css code: https://codeshare.io/5Nn8PJ
You have multiple problems :
1- you code isn't properly indented, i lead to errors, here is a more readable code :
var numberOfbubbles = 10
for (let i = 0; i < numberOfbubbles; i++) {
newBubble()
}
function newBubble() {
let bubble= document.createElement("div");
bubble.classList.add("bubble");
let x = randomNumber(100);
let delay= randomNumber(3000)
bubble.style.left = x + "vw";
bubble.style.animationDelay = delay + "ms";
document.querySelector("body").appendChild(bubble);
}
function randomNumber(max) {
return Math.floor(Math.random() * max)
}
2- On your randomNumber() function, you did not specified max argument
3- Did you load the script after the page is loaded. You can add defer to your script declaration like
<script defer src="script.js" charset="utf-8"></script>
It make that the script is loaded and executed after everything else is loaded
Without that you try to reach the body before it can be accessed
document.querySelector("body")
4- When you posting a question, make sure to help us understand what you did, for exemple, you use JS, so show us the errors you have in console

Google Calendar Authorization Apps Script - Standalone Web App

I am new to Apps Script and Web Development. I thought it would be nice to make a simple app to get started.
Goal: Display the future events of the user.
Problem: I am stuck on getting user authorization. Currently, the script is displaying my events. Instead, I want the script to display the user's (who is accessing the web app) events.
I found this sample from the documentation. This function gets the list of events of the user. https://developers.google.com/calendar/quickstart/apps-script
Then I wrote a basic index.html file to display the string populated by this above function to the user.
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
function getEventsOnClick() {
google.script.run.withSuccessHandler(changeDisplay).listAllEvents();
}
function changeDisplay(display) {
var div = document.getElementById('output');
div.innerHTML = display;
}
</script>
<div id="output"> Hello! </div>
<button onclick="getEventsOnClick()">Run Function</button>
</body>
</html>
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function listAllEvents() {
var calendarId = 'primary';
var now = new Date();
var display = ""
var events = Calendar.Events.list(calendarId, {
timeMin: now.toISOString(),
maxResults: 2500,
});
if (events.items && events.items.length > 0) {
for (var i = 0; i < events.items.length; i++) {
var event = events.items[i];
if (event.start.date) {
// All-day event.
var start = new Date(event.start.date);
var end = new Date(event.end.date);
display = display + 'Start: ' + start.toLocaleDateString() + '; End: ' + end.toLocaleDateString() + ". ";
} else {
var start = new Date(event.start.dateTime);
var end = new Date(event.end.dateTime);
display = display + 'Start: ' + start.toLocaleString() + '; End: ' + end.toLocaleString() + ". ";
}
}
} else {
display = 'No events found.';
}
Logger.log("%s", display)
return display
}
Again, nothing is wrong with the above code. It does display events as expected. The problem is that it is displaying my events rather than the user. So, if I give a user URL for the app, then I want this app to request authorization and display their event. How would I do that?
Thanks!
When you deploy the app, make sure you choose to execute as the user rather than as yourself. (as yourself is the default).

Pass array from server side function using google script and html

I have an html page that will be served to a google sheet app to be used as a UI. I would like to access an array from a server side function within the html file. I am having trouble accessing a returned array. Here is what I have:
in html file:
<div id="id1">
Starting 1
</div>
<div id= "id2">
Starting 2
</div>
<script type="text/javascript">
document.getElementById("id1").innerHTML = "A change";
</script>
<script type="text/javascript">
function onSuccess(numUnread) {
alert('You have ' + numUnread[0]
+ ' unread messages in your Gmail inbox.');
document.getElementById("id2").innerHTML = numUnread[0];
}
google.script.run.withSuccessHandler(onSuccess)
.getPermits();
</script>
In code.gs:
function getPermits()
{
var permits = [];
for(var i = 0; i < 10; i++)
{
permits.push('Element ' + i);
}
return permits;
}
Right now I am just trying to figure out why the div with id = "id2"
does not get changed to the first element from the passed array. Instead, it is not changed. Also, there is no alert. If I change the return of the gePermits() function to a string, both the div and the alert work as I would expect.
Thanks in advance!
Some types are not passed trough HTMLService, but you can always STRINGFY and PARSE it, try:
return JSON.stringify(permits);
and in the html:
function onSuccess(numUnread) {
numUnread = JSON.parse(numUnread);

HTML5 Local save/load

Im trying to follow tutorial from this site " Link to Tutorial " to make a idle game.
It shows easy way to make simple local save function, but I can't make it work for some reason. He tells to make a function this and that, but doesn't show how it should look like.
I searched google and saw many different ways, I got some to work but not fully and they weren't simple enough for my lack of knowledge in HTML.
Any help is welcome and appreciated :) thanks in advance.
function save(){
var save = {
cookies: cookies,
cursors: cursors
}
localStorage.setItem("save",JSON.stringify(save));
};
function load(){
var savegame = JSON.parse(localStorage.getItem("save"));
if (typeof savegame.cookies !== "undefined") cookies = savegame.cookies;
};
var cookies = 0;
function cookieClick(number) {
cookies = cookies + number;
document.getElementById("cookies").innerHTML = cookies;
};
var cursors = 0;
function buyCursor() {
var cursorCost = Math.floor(10 * Math.pow(1.1, cursors)); //works out the cost of this cursor
if (cookies >= cursorCost) { //checks that the player can afford the cursor
cursors = cursors + 1; //increases number of cursors
cookies = cookies - cursorCost; //removes the cookies spent
document.getElementById('cursors').innerHTML = cursors; //updates the number of cursors for the user
document.getElementById('cookies').innerHTML = cookies; //updates the number of cookies for the user
};
var nextCost = Math.floor(10 * Math.pow(1.1, cursors)); //works out the cost of the next cursor
document.getElementById('cursorCost').innerHTML = nextCost; //updates the cursor cost for the user
};
function save() {
var save = {
cookies: cookies,
cursors: cursors
}
localStorage.setItem("save", JSON.stringify(save));
};
function load() {
var savegame = JSON.parse(localStorage.getItem("save"));
if (typeof savegame.cookies !== "undefined") cookies = savegame.cookies;
}
window.setInterval(function() {
cookieClick(cursors);
}, 1000);
<html>
<head>
<link rel="stylesheet" type="text/css" href="interface.css" />
</head>
<body>
<button onclick="cookieClick(1)">Click Me!</button>
<br />Cookies: <span id="cookies">0</span>
<br />
<button onclick="buyCursor()">Buy Cursor</button>
<br />Cursors: <span id="cursors">0</span>
<br />Cursor Cost: <span id="cursorCost">10</span>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Your browser may not support localstorage.
You can check broswer's localstorage support using Modernizr.
Read about it here: http://diveintohtml5.info/detect.html
Also make sure, that you are calling save() method in your code (I don't see it in your code)

Web Database - tx.executeSql callback not running every time

I have an HTML5 website built using jQuery Mobile.
On my index.htm page I have an ahref. When I click on that link I run a function which does a tx.executeSql and the callback method is run which then navigates to the new page.
The works fine the first time.
If I navigate to more pages and then come back to the index.htm page, the functions are run when the link is clicked, however the callback on the tx.executeSql isn't ever run.
Any ideas would be greatly appreciated. I have used all different mechanisms for calling the functions from javascript to jquery, but it makes no difference.
To be clear - the first function called is setFeaturedRecruiter() - you can see the code below. The second time I come back here the "renderResults" callback function isn't run.
// when we click on the actual featured recruiter link we copy from this table to the featured recruiter table to overwrite its contents
function setFeaturedRecruiter() {
alert('setFeaturedRecruiter()');
retrieveActualFeaturedRecruiter();
return true;
}
function retrieveActualFeaturedRecruiter() {
alert('retrieveActualFeaturedRecruiter()');
db.transaction(function (tx) {
alert('select * from featuredRecruiterActual...');
tx.executeSql('SELECT * FROM featuredRecruiterActual', [], renderResults, pnetOnError);
});
}
pnetOnError = function (tx, e) {
alert('Something unexpected happened: ' + e.message);
}
function renderResults(tx, rs) {
alert('renderResults()');
var idNo;
var name;
var logo;
var totalAds;
for (var i = 0; i < rs.rows.length; i++) {
r = rs.rows.item(i);
idNo = r.idNo * 1;
name = r.name;
logo = r.logo;
totalAds = r.totalAds;
}
writeToFeaturedRecruiter(idNo, name, logo, totalAds);
}
I've worked around this problem by disabling ajax when navigating between pages. This was done by adding to the ahref tag: data-ajax="false". This caused the page to load correctly and overcomes the problem.