DEV Community

Cover image for Build a Raffle with Google Sheet (Part 2)
Jorge
Jorge

Posted on

1

Build a Raffle with Google Sheet (Part 2)

In the first part of this serie we've learnt how to build a simple Raffle using Google Sheet ( https://dev.to/jagedn/build-a-raffle-with-google-sheet-5da )

In this second part we'll refactor some parts of the code and improve it with new features

Separate business logic from UI

Open the script editor (as explained in the previous post) and create a new html file called Client.html and another file called Dialog.html

Client.html

Paste this code into the Client.html

<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
<h1><?!= LanguageApp.translate('Bienvenido','',Session.getActiveUserLocale()) ?></h1>
<div>
<p>
<?!= LanguageApp.translate('Total Participantes activos','',Session.getActiveUserLocale()) ?>
</p>
<p>
<?!= totalRemains ?>
</p>
</div>
<? for(var i in prizzes){ ?>
<div>
<? for(var c=0; c < prizzes[i][1]; c++){ ?>
<p>
<input type="button" value="<?!=prizzes[i][0]?>" onclick="google.script.run.raffle('<?!=prizzes[i][0]?>')"/>
</p>
<? } ?>
</div>
<? } ?>
</body>
</html>
view raw Client.html hosted with ❤ by GitHub

This will render the sidebar once the user select the Raffle option in the menu.

We'll show how many participants remains to participate and we'll build a list of buttons, once per prizze. In this way the admin can choose what prizze to raffle in every moment

As you can see, when the admin click a prizze button we'll call a remote function sending the prizze selected.

Dialog.html

Paste this code into the Dialog.html

<script>
var suertudoIdx = <?=suertudo[0]?>;
var prizze = '<?=prizze?>';
function yepes(){
google.script.run.withSuccessHandler(google.script.host.close).yepes(suertudoIdx,prizze)
}
function nopes(){
google.script.run.withSuccessHandler(google.script.host.close).nopes(suertudoIdx,prizze)
}
function notPresent(){
google.script.run.withSuccessHandler(google.script.host.close).notPresent(suertudoIdx,prizze)
}
</script>
<h1>
Congratulations <?=suertudo[1]+" "+suertudo[2]?>
</h1>
<p>
<image src="https://media.giphy.com/media/11sBLVxNs7v6WA/giphy.gif"/>
</p>
<p>
<div>
<input type="button" value="Yepes" onclick="yepes()" />
&nbsp;
<input type="button" value="Nopes" onclick="nopes()" />
&nbsp;
<input type="button" value="No Present" onclick="notPresent()" />
</div>
</p>
view raw Dialog.html hosted with ❤ by GitHub

This file is the template to render the winner of a prizze and let to choose an action (accept, denied, and not pressent)

Once the admin click one of buttons following actions happen:

  • the dialog call a remote function to notify the action selected
  • when the remote function is executed the dialog is closed.

For example if the winner accept the prizze the dialog will execute this:

google.script.run.withSuccessHandler(google.script.host.close).yepes(suertudoIdx,prizze)

where yepes is a remote function

Business

Paste this code into the Code.gs (replace all the code if you followed the previous post)

//Called by Google Sheet
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createAddonMenu().addItem('Raffle', 'raffleUI').addToUi();
}
// Read G3:H999 searching prizzes (title and quantity)
function getPrizzes(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var ret = [];
for(var i=3; i<ss.getLastRow()+1; i++){
var row = ss.getRange("G"+i+":H"+i).getValues()[0];
if( !row[0] ){
break
}
// extract the title and the quantity
ret.push( [row[0],row[1]] )
}
return ret;
}
// Write the G3:H999 range with new prizzes status
function updatePrizzes(prizzes){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
ss.getRange("G3:H"+(2+prizzes.length)).setValues(prizzes)
}
// Search particpants without prizzes in range A3:D999
function getRemains(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var ret = [];
for(var i=3; i<ss.getLastRow()+1; i++){
var row = ss.getRange("A"+i+":D"+i).getValues()[0];
if( !row[0] ){
break
}
if( !row[3] ){
// rowIndex, name and surname
ret.push( [i,row[0],row[1]] )
}
}
return ret;
}
// The winner accept the prizze:
// update their cell and decrement the prizze
function yepes(idx, prizze){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getRange("D"+idx);
cell.setValue("winner of "+prizze);
var prizzes = getPrizzes();
for(var i in prizzes){
if( prizzes[i][0] === prizze ){
prizzes[i][1]--;
updatePrizzes(prizzes)
break;
}
}
raffleUI();
}
// the winner decline the prizze: do nothing
function nopes(idx, prizze){
raffleUI();
}
// the winner is not pressent: bad guy
function notPresent(idx){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getRange("D"+idx);
cell.setValue("no present");
raffleUI();
}
// Show the winner and ask if they want the prizze
function raffle(prizze){
var remains = getRemains();
var suertudoIndex = Math.floor(Math.random()*remains.length);
var suertudo = remains[suertudoIndex];
var template = HtmlService.createTemplateFromFile('Dialog');
template.suertudo = suertudo;
template.prizze = prizze;
var html = template.evaluate();
var htmlOutput = HtmlService
.createHtmlOutput(html)
.setWidth(640)
.setHeight(480);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Wooaaaaa');
}
// main: prepare a sidebar with prizzes
function raffleUI(){
var remains = getRemains();
var template = HtmlService.createTemplateFromFile('Client');
template.totalRemains = remains.length;
template.prizzes = getPrizzes();
var html = template.evaluate();
html.setTitle("Raffle")
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(300);
SpreadsheetApp.getUi().showSidebar(html);
}
view raw Code.gs hosted with ❤ by GitHub

Prepare your Raffle

In a clean sheet write the participants and the prizzes following this screen:

Alt Text

Pay attention to use the same rows and columns or if you want to use different ranges remember to adjust them into the Code.gs file

See in action

In this video you can see the raffle in action

Top comments (0)

This post blew up on DEV in 2020:

js visualized

🚀⚙️ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! 🥳

Happy coding!