Server-side function does not want to run - javascript

I'm building a sidebar for Google Sheets using Apps Script, it is a tool to import data from Google Calendar. The script is not that complicated:
A form to choose the calendar, a start and end date, and a checkbox to include a header
Some client-side javascript
Some server-side functions
1. I have a file Code.gs in charge of creating a custom menu and rendering the sidebar
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.createMenu('Custom Menu')
.addItem('Show sidebar', 'showSidebar')
.addToUi();
}
function showSidebar() {
var html = HtmlService.createTemplateFromFile('index').evaluate()
.setTitle('Extract data from calendar')
.setWidth(300);
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showSidebar(html);
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
2. Index.html: the content of the sidebar
<!DOCTYPE html>
<html>
<head>
</head>
<body style="margin: 10px;">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<div class="row">
<form class="col s12">
<!-- CHOOSE CALENDAR ROW -->
<div class="row">
<div class="input-field col s12">
<select id='calendar'>
<? var calendars = CalendarApp.getAllOwnedCalendars();
calendars.forEach((calendar) => { ?>
<option value="<?= calendar.getId() ?>"><?= calendar.getName() ?></option>
<? }) ?>
</select>
<label>Calendar</label>
</div>
</div>
<!-- START TIME ROW -->
<div class="row">
<div class="input-field col s12">
<input placeholder="Start date" id="startDate" type="date" class="validate">
<label for="startDate">Start date</label>
</div>
</div>
<!-- END TIME ROW -->
<div class="row">
<div class="input-field col s12">
<input placeholder="End date" id="endDate" type="date" class="validate">
<label for="endDate">End Date</label>
</div>
</div>
<!-- INCLUDE HEADER -->
<div class="row">
<label>
<input type="checkbox" class="filled-in" checked="checked" id="includeHeader" />
<span>Include Header</span>
</label>
</div>
<!-- EXTRACT BUTTON -->
<div class="row">
<button class="btn waves-effect waves-light" id="extractBtn">EXTRACT</button>
</div>
</form>
</div>
<?!= include('index-js') ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {});
});
</script>
</body>
</html>
3. index-js.html: add an event to the extract button and call the server-side function
<script>
var extractBtn = document.getElementById('extractBtn');
extractBtn.addEventListener('click', function(e) {
e.preventDefault();
var calendarId = document.getElementById('calendar').value;
var startDate = new Date(document.getElementById('startDate').value);
var endDate = new Date(document.getElementById('endDate').value);
var includeHeader = document.getElementById('includeHeader').checked;
if(startDate.getTime() < endDate.getTime()) {
e.target.textContent = 'Extracting...';
google.script.run.withSuccessHandler(extractCompleted).writeData(calendarId, startDate, endDate, includeHeader);
} else {
M.toast({html: "Please enter an end date starting after the selected start date"});
}
});
function extractCompleted(){
M.toast({html: 'Extract completed'});
extractBtn.textContent = 'Extract';
}
</script>
4. extractCalendar.gs in charge of getting the data and adding it to the Google sheet
function extractCalendar(calendarId, startDate, endDate) {
var calendar = CalendarApp.getCalendarById(calendarId);
var events = calendar.getEvents(startDate, endDate);
// Initialize variables that will hold information
var rows = [];
events.forEach((event) => {
// Get basic information
var eventTitle = event.getTitle();
var startTime = event.getStartTime();
var endTime = event.getEndTime();
var description = event.getDescription();
var isRecurring = event.isRecurringEvent();
// Get the guest list
var guests = event.getGuestList();
var emailsParticipantsArray = [];
var emailsParticipants = '';
// Add each guest email to the array
guests.forEach(guest => emailsParticipantsArray.push(guest.getEmail()));
// Convert the array to a string
emailsParticipants = emailsParticipantsArray.join(',');
rows.push([eventTitle, startTime, endTime, emailsParticipants, description, isRecurring]);
}
);
return rows;
}
function writeData(calendarId, startDate, endDate, includeHeader=True){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rows = extractCalendar(calendarId, startDate, endDate);
var numRows = rows.length;
var lastRow = sheet.getLastRow();
(includeHeader) && rows.unshift(['Title', 'Start Date', 'End Date', 'Participants Email', 'Description', 'Recurring']);
sheet.getRange(lastRow + 1, 1, numRows, 6).setValues(rows);
}
The line below does not run and generate the error message: Uncaught TypeError: Failed due to illegal value in property: 12769757186-mae_html_user_bin_i18n_mae_html_user.js:61
google.script.run.withSuccessHandler(extractCompleted).writeData(calendarId, startDate, endDate, includeHeader);
What's happening right here, why is the server-side function not running?
Thank you for your help !

Parameters and Return Values
You can pass year,month and day or the date in a standard string format and use the Date() constructor to recreate the date.

Related

How can I save dropdown list value imported from Google Sheets when I submit form?

I have a form with some fields and one of them is a dropdown list of names imported from google sheets.
The form works fine, the dropdown retreive the available values on google sheet but when i submit it, the field with values from dropdown stays in blank. It seems that is missing the save of value before the submit task.
I already try some solutions presented on web but they didn´t worked and i am stuck. Can you help me to find what is missing? Thank you.
My code.gs file is
function doGet() {
var html = HtmlService.createTemplateFromFile('Index.html').evaluate();
return html.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
function getList() {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var nameSheet = ss.getSheetByName("NAMES");
var getLastRow = nameSheet.getLastRow();
return nameSheet.getRange(2, 1, getLastRow - 1, 1).getValues();
}
function startForm()
{
var form = HtmlService.createHtmlOutputFromFile('Droplist');
SpreadsheetApp.getUi().showSidebar(form);
}
function addMenu()
{
var menu = SpreadsheetApp.getUi().createMenu('Custom');
menu.addItem('Dropdown Form', 'startForm');
menu.addToUi();
}
function onOpen(e)
{
addMenu();
}
function myFunction() {
var form = FormApp.getActiveForm();
var firstResponse = form.getResponses()[0];
var dropdownResponse = firstResponse.getItemResponses()[0].getResponse();
Logger.log(dropdownResponse);
}
And my html is:
<!doctype html>
<script>
function loadnames() {
google.script.run.withSuccessHandler(function(ar)
{
var nameSelect = document.getElementById("name");
console.log(ar);
let option = document.createElement("option");
option.value = "";
option.text = "";
nameSelect.appendChild(option);
ar.forEach(function(item, index)
{
let option = document.createElement("option");
option.value = item[1];
option.text = item[0];
nameSelect.appendChild(option);
});
}).getList();
};
function onSelect()
{
var nameID = document.getElementById("name").value;
};
</script>
<script>
$(document).ready(function() {
$("#submit").click(function() {
var value = $("#name option:selected");
alert(value.text());
});
});
</script>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Form</title>
</head>
<body>
<div class="container">
<h1>Registo</h1>
<form method="post" autocomplete="off" name="google-sheet">
<div class="mb-3">
<label class="form-label">Data</label>
<input type="date" class="form-control" name="date"/>
</div>
<div class="mb-3">
<label class="form-label">Trabalhador</label>
<select id="name" onchange="onSelect()" ></select><br>
<script>loadnames();</script>
</div>
<div class="mb-3">
<label class="form-label" for="project">Projeto:</label>
<select id="project" name="project">
<option value="IS054" selected>IS054</option>
<option value="IS058">IS058</option>
<option value="IS064">IS064</option>
<option value="IS077">IS077</option>
<option value="IS999">IS999</option>
</select>
</div>
<div class="mb-3">
<label class="form-label" for="epi">EPI:</label>
<select id="epi" name="epi">
<option value="Luvas finas" selected>Luvas Finas</option>
<option value="Luvas Grossas">Luvas Grossas</option>
<option value="Oculos">Oculos</option>
<option value="Mascaras">Mascaras</option>
<option value="Botas Trabalho">Botas Trabalho</option>
<option value="Botas Agua">Botas Agua</option>
<option value="Calças Trabalho">calças</option>
<option value="Fato Chuva">Fato Chuva</option>
<option value="Colete">Colete</option>
<option value="Roupa Termica">Roupa Termica</option>
<option value="Outros">Outros</option>
</select>
</div>
<div class="mb-3">
<label class="form-label" for="notes">Obs:</label>
<textarea type="text" class="form-control" name="notes" placeholder="Escrever" rows="4" style="resize: vertical;"></textarea>
</div>
<button id="submit" type="submit" class="btn btn-primary">Submeter</button>
</form>
</div>
<!-- Optional JavaScript; choose one of the two! -->
<script>
//Send submit data to google sheet
const scriptURL = 'https://script.google.com/macros/s/AKfycbzPb4TfaNqZBNBBUiIoSUibekC4iiTWiP5bJZH-yIpQNHAxePK9jJQYRltBiMWkzQxk/exec'
const form = document.forms['google-sheet']
form.addEventListener('submit', e => {
e.preventDefault()
fetch(scriptURL, { method: 'POST', body: new FormData(form)})
.then(response => alert("Registo Efetuado. Obrigado!"))
.catch(error => alert("Registo já existe na base de dados!!"))
//Clear ao form fields
form.reset()
})
</script>
<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
-->
</body>
</html>
To keep value from dropdown list and be abble do send it to google sheet when submit the form.

materializecss autocomplete onchange

I am trying to use the materialize autocomplete element
I retrieve properly the autocomplete elements but they don't appear while I enter begining of sentence :
It seemed data is loaded but when I try to refresh the instance (instance.open for instance) if fail.
how could I handle it ?
regards
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
<div class="row">
<div class="col s12">
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">textsms</i>
<input type="text" id="autocomplete-input" class="autocomplete" onkeypress="valueChange(this);">
<label for="autocomplete-input">Autocomplete</label>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.autocomplete');
var instances = M.Autocomplete.init(elems, {});
});
function valueChange(elem) {
var instance = M.Autocomplete.getInstance(elem);
console.log("search for " + elem.value);
axios.post("<%= test_autocomplete_search_path %>", {
search: elem.value,
authenticity_token: '<%= form_authenticity_token %>',
})
.then(function (response) {
var map = new Object();
for (bcl = 0; bcl < response.data.length; bcl ++) {
map[response.data[bcl].town] = null;
}
if (response.data.length > 0) {
console.log(map);
instance.updateData(map);
instance.open(); FAIL HERE
}
})
.catch(function (error) {
alert(error);
});
};
</script>

Keep value of date to a default one if no date is selected

I want to keep the value of a Date to a default value that I specified. If no date is selected when user click submit button.
what I need the functionality to be. If user select a date and submit the form, after submission the form selected date value must be the value on the date field which works perfectly so. I have the problem ie. when date is not selected and user submit form the date field have the today's date by default Select Date
My code is as follows
HTML
<body onload="CovertDateToString()">
<form action="searchDate" method="post" id="searchDate" class="searchDate" modelAttribute="searchDate">
<!-- Select type selectDateRange-->
<div class="form-group ">
<div class="col-md-3 selectContainer">
<div class="input-group">
<input type="text" class="form-control" name="selectDateRange" id="selectDateRange" value="${newDate}">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
</div>
</div>
</div>
<!-- Select type search button with input-->
<div class="form-group">
<div class="col-md-3 inputGroupContainer">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-success" type="submit">
<div class="up" style="margin-top: -8%; color: white;">Search</div></button>
</span>
</div>
<!-- /input-group -->
</div>
</div>
</form>
</body>
Js code
function CovertDateToString() {
var date = <%=request.getParameter("selectDateRange")%>;
var myDate = new Date();
var selectDate = myDate.toDateString();
var selectDate = "Select Date";
document.getElementsByName('selectDateRange')[0].value = selectDate;
selectDate = date;
document.getElementsById('selectDateRange')[0].value = date;
console.log("Set Date to Select Date ",selectDate);
console.log("Set Date to Selected Date ",date);
}
daterangepicker
$(function() {
$('input[name="selectDateRange"]').daterangepicker({
locale: {
format: 'YYYY-MM-DD'
}
});
});
function CovertDateToString() {
var date = "${newDate}";
var myDate = new Date();
var selectDate = myDate.toDateString();
document.getElementsByName('selectDateRange')[0].value = selectDate;
selectDate = date;
document.getElementById('selectDateRange').value = date;
console.log("Set Date to Select Date ",selectedDate);
console.log("Set Date to Selected Date ",date);
}
$(function() {
$('input[name="selectDateRange"]').daterangepicker({
locale: {
format: 'YYYY-MM-DD'
}
});
});
After more hours on this issue I final got it to work. Removing the request.getParamter was the mean reason date got removed after
Please check the following code i have used static values at the place of dynamic values so manage it and code is working fine at snnipet.
function CovertDateToString() {
var date = "${newDate}";
var arr = date.split(" ");
if(arr != "null"){
$("#selectDateRange").data('daterangepicker').setStartDate(arr[0]);
$("#selectDateRange").data('daterangepicker').setEndDate(arr[2]);
}
}
$(function() {
$('input[name="selectDateRange"]').daterangepicker({
locale: {
format: 'YYYY-MM-DD'
}
});
});
<script src="https://cdn.jsdelivr.net/jquery/1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" rel="stylesheet"/>
<body onload="CovertDateToString()">
<form action="searchDate" method="post" id="searchDate" class="searchDate" modelAttribute="searchDate">
<!-- Select type selectDateRange-->
<div class="form-group ">
<div class="col-md-3 selectContainer">
<div class="input-group">
<input type="text" class="form-control" name="selectDateRange" id="selectDateRange" >
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
</div>
</div>
</div>
<!-- Select type search button with input-->
<div class="form-group">
<div class="col-md-3 inputGroupContainer">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-success" type="submit">
<div class="up" style="margin-top: -8%; color: white;">Search</div></button>
</span>
</div>
<!-- /input-group -->
</div>
</div>
</form>
</body>

Select the next div after the current form on click submit button jQuery

I'm trying to get the next div with class comment-replies after the current form and prepend data. There are more divs with the same class on the page and forms.
<div class="hide">
<br>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"],ENT_QUOTES,"utf-8")?>" method="post">
<div class="form-group">
<textarea class="form-control comment" rows="6" name="comment"></textarea>
</div>
<div class="form-group">
<div class="col-sm-3" style="padding-left: 0px;">
<input hidden class="reply-comment-id" value="23">
<input class="form-control btn-xs add-reply" type="submit" name="reply" value="REPLY">
</div>
</div>
</form>
</div>
<div class="comment-replies">
<!--replies-->
<?php $this->get_replies($comment['comment_id']); ?>
</div>
jQuery code for the button.
$('.add-reply').on('click', function (e) {
e.preventDefault();
var upId = $('#upload-id').val();
var usId = $('#user-id').val();
var cId = $(this).prev('input').val();
var the_form = $(this).closest("form");
var textComment = the_form.find('textarea[name="comment"]');
var com = textComment.val();
$.post('add_comment.php',{cid:cId,upId:upId,usId:usId,reply:com},function(data){
the_form.nextUntil('div').prepend(data);
//$('.comment-replies').prepend(data); this append to every div with the current class.
the_form.addClass('hide');
});
});
example on jsfiddle
Here is the code that worked for me.
$('.add-reply').on('click', function (e) {
e.preventDefault();
var upId = $('#upload-id').val();
var usId = $('#user-id').val();
var cId = $(this).prev('input').val();
var the_form = $(this).closest(".myDiv");
var textComment = the_form.find('textarea[name="comment"]');
var com = textComment.val();
//$.post('add_comment.php',{cid:cId,upId:upId,usId:usId,reply:com},function(data){
var data = 'Dummy data';
the_form.next('.comment-replies').prepend(data);
//$('.comment-replies').prepend(data); this append to every div with the current class.
// the_form.addClass('hide');
//});
});
https://jsfiddle.net/bhdk9s28/4/

Javascript Date var to Razor DateTime

I have a jquery datepicker in my .NET MVC5 application. I need to convert the javascript Date var to a Razor DateTime var, after a user selects the correct date. Then I can send it back to the controller. Since Razor is server side and javascript client side, how can we solve this? Check out my code below:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-inline">
<h4>Reservation</h4>
<hr />
<div class="form-group">
<p>Date:<input type="text" id="date1" class="datefield" /></p>
<p>Date:<input type="text" id="date2" class="datefield" /></p>
<script type="text/javascript">
$(document).ready(function () {
$("#date1").on('click', function () {
var minDate = $("#date1").val();
})
$("#date2").on('click', function () {
var maxDate = $("#date2").val();
})
});
</script>
#{DateTime minDateCC = DateTime.Now; DateTime maxDateCC = DateTime.Now;}
<script type="text/javascript">
minDate = Date(#minDateCC);
maxDate = Date(#maxDateCC);
</script>
#Html.ActionLink("Show Available Campingspots Per Date", "ShowAvailableSpotsPerDate", new { minDateCC, maxDateCC })
</div>
</div>
}

Categories

Resources