I am trying to upload a PDF file to Google Drive and insert the link to the file in Google Sheets. Here is the ajax:
$.ajax({
type: 'POST',
url: 'https://script.google.com/macros/s/AKfycbxyjjBv84uONFouZaiNeC2xwoMPP3p-3dzYxbQBCbJnEza0aPn-/exec',
data: serializedData,
success: function(result) {
var myMessage = $(document.activeElement).attr('id');
$('#sucessMessage2').html('<div class=\"successActive\">Your application has been successfully sent</div>');
document.getElementById("regform").reset();
},
error : function(error) {
alert('Error: Something went wrong. Please refresh the page and try again');
}
});
Here is the HTML:
<form id="regform">
<input id="FirstName" tabindex="1" name="FirstName" type="text" placeholder="First Name *" />
<input id="LastName" tabindex="2" name="LastName" type="text" placeholder="Last Name *" />
<input id="Occupation" tabindex="3" name="Occupation" type="text" placeholder="Occupation" />
<input name="Resume" type="file" tabindex="4" /><br/>
<div class="successMessage" id="sucessMessage2"></div>
<input class="btn-submit" id="submitFormTwo" tabindex="5" type="submit" value="Submit Application to Rent" />
</form>
And Code.gs:
var SHEET_NAME = "Sheet1";
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
function doGet(e){
return handleResponse(e);
}
function doPost(e){
return handleResponse(e);
}
function handleResponse(e) {
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
var headRow = e.parameter.header_row || 1;
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow()+1; // get next row
var row = [];
for (i in headers){
if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(e.parameter[headers[i]]);
}
}
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
}
Everything is populating in the Google Sheet, but I have no idea how to get the Resume to upload to Google Drive and add the link to the Google Sheet.
You can upload a file to drive with a combination of FileReader and google.script.run as following:
Modify <input name="Resume" type="file" tabindex="4" /><br/>
to
<input id = "pdf" name="Resume" type="file" tabindex="4" /><br/>
Modify
<input class="btn-submit" id="submitFormTwo" tabindex="5" type="submit" value="Submit Application to Rent" />
to
<input class="btn-submit" id="submitFormTwo" tabindex="5" type="submit" onClick="formSubmit()" value="Submit Application to Rent" />
Write the javascript function:
function formSubmit() {
var pdf = document.getElementById("pdf").files[0];
var reader = new FileReader();
if (pdf) {
reader.readAsDataURL(pdf);
reader.onloadend = function () {
google.script.run.getResume(reader.result);
}
}
}
In Code.gs, add the function
function getResume(pdf){
var mimeType = pdf.substring(5,pdf.indexOf(';'));
var bytes = Utilities.base64Decode(pdf.substr(pdf.indexOf('base64,')+7));
var title='my_pdf';
var blob = Utilities.newBlob(bytes, mimeType, title);
var file=DriveApp.createFile(blob);
var link = file.getUrl();
Logger.log(link);
}
Integrate link into your existing code as desired, e.g. push it into row and into the spreadsheet.
Explanation: You convert with FileReader the content of the pdf file
into a data URL. Apps Script can use this data URL to read the file as
a blob and convert the blob into a file on your drive.
UPDATE
A sample how to pass the form data completely with google.script.run without Ajax:
Index.html:
<form id="regform">
<input id="FirstName" tabindex="1" name="FirstName" type="text" placeholder="First Name *" />
<input id="LastName" tabindex="2" name="LastName" type="text" placeholder="Last Name *" />
<input id="Occupation" tabindex="3" name="Occupation" type="text" placeholder="Occupation" />
<input id = "pdf" name="Resume" type="file" tabindex="4" /><br/>
<input class="btn-submit" id="submitFormTwo" tabindex="5" type="submit" onClick="formSubmit()" value="Submit Application to Rent" />
</form>
<script>
function formSubmit() {
var firstName = document.getElementById("FirstName").value;
var lastName = document.getElementById("LastName").value;
var occupation = document.getElementById("Occupation").value;
var pdf = document.getElementById("pdf").files[0];
var reader = new FileReader();
if (pdf) {
reader.readAsDataURL(pdf);
reader.onloadend = function () {
google.script.run.withSuccessHandler(success).withFailureHandler(error).getResume(firstName, lastName, occupation, reader.result);
}
}
}
function success(){
alert ("Your application has been successfully sent");
}
function error(){
alert ("There was an error");
}
</script>
Code.gs
function doGet(){
return HtmlService.createHtmlOutput("index.html");
}
function getResume(firstName, lastName, occupation, pdf){
var mimeType = pdf.substring(5,pdf.indexOf(';'));
var bytes = Utilities.base64Decode(pdf.substr(pdf.indexOf('base64,')+7));
var title='my_pdf';
var blob = Utilities.newBlob(bytes, mimeType, title);
var file=DriveApp.createFile(blob);
var link = file.getUrl();
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
var values = [firstName, lastName, occupation, link];
var nextRow = sheet.getLastRow()+1;
sheet.getRange(nextRow, 1, 1, values.length).setValues([values]);
}
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
}
Related
I need to search two addresses on the same webpage, one for location, one for correspondence. The first Google API Address works fine, I then tried duplicating the function and form modifying it, but it doesn't populate the second address, it always tries to populate the first address, can anyone tell me where I am going wrong please? Thanks for your help.
function initMap() {
const componentForm = [
'street_number',
'route',
'location',
'locality',
'administrative_area_level_2',
'postal_code',
];
const autocompleteInput = document.getElementById('location');
const options = {
types: ['(cities)'],
componentRestrictions: { country: 'gb' }
};
const autocomplete = new google.maps.places.Autocomplete(autocompleteInput);
autocomplete.addListener('place_changed', function () {
const place = autocomplete.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert('No details available for input: \'' + place.name + '\'');
return;
}
fillInAddress(place);
});
function fillInAddress(place) { // optional parameter
const addressNameFormat = {
'street_number': 'short_name',
'route': 'long_name',
'locality': 'long_name',
'administrative_area_level_2': 'short_name',
'postal_code': 'short_name',
};
const getAddressComp = function (type) {
for (const component of place.address_components) {
if (component.types[0] === type) {
return component[addressNameFormat[type]];
}
}
return '';
};
document.getElementById('location').value = getAddressComp('street_number') + ' '
+ getAddressComp('route');
for (const component of componentForm) {
// Location field is handled separately above as it has different logic.
if (component !== 'location') {
document.getElementById(component).value = getAddressComp(component);
}
}
}
}
function initMapAddress2() {
const componentForm = [
'street_number',
'route',
'location',
'locality',
'administrative_area_level_2',
'postal_code',
];
const autocompleteInput = document.getElementById('location2');
const options = {
types: ['(cities)'],
componentRestrictions: { country: 'gb' }
};
const autocomplete2 = new google.maps.places.Autocomplete(autocompleteInput);
autocomplete2.addListener('place_changed', function () {
const place2 = autocomplete2.getPlace();
if (!place2.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert('No details available for input: \'' + place2.name + '\'');
return;
}
fillInAddress(place2);
});
function fillInAddress(place2) { // optional parameter
const addressNameFormat = {
'street_number2': 'short_name',
'route2': 'long_name',
'locality2': 'long_name',
'administrative_area_level_22': 'short_name',
'postal_code2': 'short_name',
};
const getAddressComp = function (type) {
for (const component of place2.address_components) {
if (component.types[0] === type) {
return component[addressNameFormat[type]];
}
}
return '';
};
document.getElementById('location2').value = getAddressComp('street_number2') + ' '
+ getAddressComp('route2');
for (const component of componentForm) {
// Location field is handled separately above as it has different logic.
if (component !== 'location2') {
document.getElementById(component).value = getAddressComp(component);
}
}
}
}
<div class="card-container">
<div class="panel">
<div>
<img class="sb-title-icon" src="https://fonts.gstatic.com/s/i/googlematerialicons/location_pin/v5/24px.svg" alt="">
<span class="sb-title">Correspondence Address</span>
</div>
<input type="text" placeholder="Search Address" id="location" />
<input type="text" placeholder="" id="street_number" />
<input type="text" placeholder="" id="route" />
<input type="text" placeholder="" id="locality" />
<div class="half-input-container">
<input type="text" class="half-input" placeholder="" id="administrative_area_level_2" />
<input type="text" class="half-input" placeholder="" id="postal_code" />
</div>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=****************Zv_k&libraries=places&callback=initMap&channel=GMPSB_addressselection_v1_cA" async defer></script>
<div class="card-container">
<div class="panel">
<div>
<img class="sb-title-icon" src="https://fonts.gstatic.com/s/i/googlematerialicons/location_pin/v5/24px.svg" alt="">
<span class="sb-title">Location Address</span>
</div>
<input type="text" placeholder="Search Address" id="location2" />
<input type="text" placeholder="" id="street_number2" />
<input type="text" placeholder="" id="route2" />
<input type="text" placeholder="" id="locality2" />
<div class="half-input-container">
<input type="text" class="half-input" placeholder="" id="administrative_area_level_22" />
<input type="text" class="half-input" placeholder="" id="postal_code2" />
</div>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=****************Zv_k&libraries=places&callback=initMapAddress2&channel=GMPSB_addressselection_v1_cA" async defer></script>
For anyone else having the same issue, I found a solution here Multiple Address on same page
I simply validate one input file and get the file name. but I can not do it with second one.
<div id="app">
<form action="#">
<label class="btn btn-xs btn-primary">
<input type="file" name="pic1" id="12" #change="onFileChangePic" multiple/>
Upload file
</label>
{{fileName}}
<div><input type="submit" value="submit" :disabled="vvv == false"></div>
</form>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
fileName:null,
vvv:false
},
methods:{
onFileChangePic(event){
var fileData = event.target.files[0];
this.fileName=fileData.name;
if(fileData.type == 'application/pdf'){
this.vvv = true
}else{
this.vvv = false
}
console.log(event);
}
}
})
</script>
i want to add
<input type="file" name="pic2" id="13" #change="onFileChangePic" multiple/>
how can I validate the second input too?
methods:{
onFileChangePic(event){
let isGoodToGo = true
let files = event.target.files
for (let i=0; i<files.length; i++) {
let file = files[i]
if(file.type != 'application/pdf'){
isGoodToGo = false
}
}
this.vvv = isGoodToGo
}
}
Fiddle link: https://jsfiddle.net/shivampesitbng/k3h1x0jq/11/
Loop through all the files to check its type for validation.
i haved trying to use ajax upload image. here is my code
$(function () {
var btnUpload = $('#post_pd_thumnail');
if ($("#id").val()) var post_id = $("#id").val();
else var post_id = 0;
new AjaxUpload(btnUpload, {
action: site_root_domain + "/product/upload_image/" + post_id,
name: 'file_upload',
onSubmit: function (file, ext) {
if ($('#post_pd_thumnail').val() != '') {
if (!(ext && /^(jpg|png|jpeg|gif)$/.test(ext))) {
jAlert(lang_error_upload_avatar, lang_alert_notice);
return false;
}
}
$('#preview').html('<img style="margin-left:45px;margin-top:45px;" border="0" width="16" height="11" src="' + site_root_domain + '/templates/images/icons/loading_2.gif" />');
},
onComplete: function (file, response) {
if (!response) {
jAlert(lang_error_upload_avatar, lang_alert_notice);
} else {
img_upload = 1;
$('#preview').html(response);
}
return;
}
});
});
And my HTML is:
<div id="preview">{$preview}</div>
<div class="fileupload">
<input type="file" name="post_pd_thumnail" id="post_pd_thumnail" value="" />
</div>
<input type="hidden" name="id" id="id" value="{$data['product']['post_id']}" />
and i got this error when upload image "el is undefined" and the function does not work correctly can anyone help me solve this problem please
Try to change the file element to button like,
<div class="fileupload">
<input type="button" name="post_pd_thumnail" id="post_pd_thumnail" value="" />
</div>
Here is the solution.
* Attaches event to a dom element
*/
function addEvent(el, type, fn){
// 610 BUG
if (el == undefined) return;
if (w.addEventListener){
el.addEventListener(type, fn, false);
} else if (w.attachEvent){
var f = function(){
fn.call(el, w.event);
};
el.attachEvent('on' + type, f)
}
}
I am validating two sections of a webpage the first validation section validates however the second validator is not for some reason.
$(function(){
/* first validation - works*/
jVal = {
//validate firstName
'firstName': function(){
//appends #firstNameInfo with .info to body
$('body').append('<div id="firstNameInfo" class="info"></div>');
//create variables
var firstNameInfo = $('#firstNameInfo');
var ele = $('#firstName');
var patt = /^[a-zA-Z][a-zA-Z]{1,20}$/;
if(!patt.test(ele.val())) {
jVal.errors = true;
firstNameInfo.removeClass('correct').addClass('error');
ele.removeClass('normal').addClass('wrong');
}else{
firstNameInfo.removeClass('error').addClass('correct');
ele.removeClass('wrong').addClass('normal');
}
},
//validate lastName
'lastName': function() {
$('body').append('<div id="lastNameInfo" class="info"></div>');
var lastNameInfo = $('#lastNameInfo');
var ele =$('#lastName');
var patt = /^[a-zA-Z][a-zA-Z]{1,20}$/;
if(!patt.test(ele.val())){
jVal.errors = true;
lastNameInfo.removeClass('correct').addClass('error');
ele.removeClass('normal').addClass('wrong');
}else{
lastNameInfo.removeClass('error').addClass('correct');
ele.removeClass('wrong').addClass('normal');
}
},
//validate phone
'phone' : function(){
$('body').append('<div id="phoneInfo" class="info"></div>');
var phoneInfo = $('#phoneInfo');
var ele = $('#phone');
var patt = /^((\+?1-)?\d\d\d-)?\d\d\d-\d\d\d\d$/;
if(!patt.test(ele.val())) {
jVal.errors = true;
phoneInfo.removeClass('correct').addClass('error');
ele.removeClass('normal').addClass('wrong');
}else{
phoneInfo.removeClass('error').addClass('correct');
ele.removeClass('wrong').addClass('normal');
}
},
//validate zipcode
'zip' : function() {
$('body').append('<div id="zipInfo" class="info"></div>');
var zipInfo = $("#zipInfo");
var ele = $('#content_form #zip');
var patt = /^\d\d\d\d\d$/;
if(!patt.test(ele.val())){
jVal.errors = true;
zipInfo.removeClass('correct').addClass('error');
ele.removeClass('normal').addClass('wrong');
}else{
zipInfo.removeClass('error').addClass('correct');
ele.removeClass('wrong').addClass('normal');
}
},
//submit button code
'sendForm':function(){
if(!jVal.errors){
$('#content_form').submit();
}
},
};
$('#content_form #submit').click(function(){
var obj = $.browser.webkit ? $('body') : $('html');
jVal.errors = false;
jVal.firstName();
jVal.lastName();
jVal.phone();
jVal.zip();
jVal.sendForm();
return false;
$('#firstName').change(jVal.firstName);
$('#lastName').change(jVal.lastName);
$('#email').change(jVal.email);
$('#content_form #zip').change(jVal.zip);
});
/**** Second Validation Does Not work ******/
kVal ={
'zip' : function() {
$('body').append('<div id="Infozip" class="info"></div>');
var Infozip = $("#Infozip");
var ele = $('#form #zip');
var patt = /^\d\d\d\d\d$/;
if(!patt.test(ele.val())){
kVal.error = true;
Infozip.removeClass('correct').addClass('error');
ele.removeClass('normal').addClass('wrong');
}else{
Infozip.removeClass('error').addClass('correct');
ele.removeClass('wrong').addClass('normal');
}
},
//submit button code
'send':function(){
if(!kVal.errors){
$('#form').submit();
}
},
};
$('#form button#submit').click(function(){
var obj = $.browser.webkit ? $('body') : $('html');
kVal.errors = false;
kVal.zip();
kVal.send();
return false;
$('#form #zip').change(kVal.zip);
});
}); /*main function closer*/
HTML FOR FIRST Validation -WORKING -
<div id="content_form">
<p>
<label class="block">
<input type="text" id="firstName" type="firstName" autocomplete="on" value="first name">
</label>
<label class="block">
<input type="text" id="lastName" type="lastName" autocomplete="on" value="last name">
</label>
<label class="block">
<input type="text" id="phone" type="phone" autocomplete="on" value="phone">
</label>
<label class="block">
<input type="text" id="zip" type="zip" autocomplete="on" value="zip code">
</label>
<button type="submit" id="submit" value="Submit" title="submit">submit</button>
</p>
</div><!-- end form -->
HTML FOR SECOND Validation
<div id="form">
<p>
<label class="block">
<input type="text" id="zip" type="zip" autocomplete="on" value="zip code">
</label>
<button type="submit" id="submit" value="CHECK NOW" title="check now">check now</button>
</p>
</div><!-- end form -->
You have the same id on both zip fields, which is probably causing your problems. The docs for the jQuery #id selector has this to say;
Each id value must be used only once within a document. If more than
one element has been assigned the same ID, queries that use that ID
will only select the first matched element in the DOM. This behavior
should not be relied on, however; a document with more than one
element using the same ID is invalid.
That is, your selection in $('#form #zip').change(kVal.zip); will not use the hierarchy under #form to find #zip, it will still find the first instance in the entire DOM.
I'm trying to use jquery to select some hidden fields to retrieve some values from a certain row in a a table to make an ajax call. The first variable (ebId) is retrieved fine, but all of the other ones don't ever get set. They're all null. I can't use the name of the hidden field because these hidden fields are dynamically created and would have the same same. So i'm trying to use a class. Any idea why the way that I'm selecting the last 3 variables (_product,_applicantType,_ssn) isn't working?
Here's the JQuery and the pertinent HTML
$('.submissionStatus').click(function () {
var _ebId = $(this).next('.ebId').val();
var _product = $(this).next('.product').val();
var _applicantType = $(this).next('.applicantType').val();
var _ssn = $(this).next('.ssn').val();
$.ajax({
type: 'GET',
data: { ebId: _ebId, product: _product, applicantType: _applicantType, ssn: _ssn },
url: '#Url.Action("GetSeverityErrors", "AppListing")',
success: function (data) {
alert('Call success')
$(this).next('.loaded').val(true);
},
error: function (xhr, status, error) {
alert('An Error Occured.');
}
});
});
<input type="hidden" class="ebId" value="#item.ElectedBenefitId" />
<input type="hidden" class="product" value="#item.Product" />
<input type="hidden" class="applicantType" value="#item.ApplicantType" />
<input type="hidden" class="ssn" value="#item.Ssn" />
A little more HTML insight:
<td align="left">
<a style="color:red;" class="submissionStatus" href="javascript: void(0)" title="SubmissionStatus">#item.SubmissionStatus.ToPrettyString()</a>
<input type="hidden" class="ebId" value="#item.ElectedBenefitId" />
<input type="hidden" class="product" value="#item.Product" />
<input type="hidden" class="applicantType" value="#item.ApplicantType" />
<input type="hidden" class="ssn" value="#item.Ssn" />
<input type="hidden" class="loaded" value="false" />
</td>
note that closest() selects closest parent element based on it's parameter, try this:
var _ebId = $(this).siblings('input.ebId').val();
var _product = $(this).siblings('input.product').val();
var _applicantType = $(this).siblings('input.applicantType').val();
var _ssn = $(this).siblings('input.ssn').val();
$('.submissionStatus').click(function () {
var storThis = this;
var _ebId = $(storThis).next('.ebId').val();
var _product = $(storThis).next('.product').val();
var _applicantType = $(storThis).closest('.applicantType').val();
var _ssn = $(storThis).closest('.ssn').val();