Javascript in VisualForce page - form submit success, trigger apex? - javascript

Right now, the code below upon submit, first inserts a file THEN submits the form. This is problematic - I need for it to verify the form was successfully posted to Amazon S3 then insert the (token) file so it can link to it.
I basically need to reverse SubmitFile and InsertFile, but I'm not sure how to have (If form successfully sent, then run another javascript function). See very bottom for an attempt...Is this possible?
<apex:pageMessages id="pageErrors"></apex:pageMessages>
<form name="s3Form" action="https://s3.amazonaws.com/mybucket" method="post" enctype="multipart/form-data">
<input type="hidden" name="key"/>
<input type="hidden" name="AWSAccessKeyId" value="{!key}"/>
<input type="hidden" name="policy" value="{!policy}"/>
<input type="hidden" name="signature" value="{!signedPolicy}"/>
<input type="hidden" name="acl" value="private"/>
<input type="hidden" name="x-amz-meta-FileId" value="{!File__c.id}"/>
<input type="hidden" name="x-amz-meta-OrderId" value="{!OrderId}"/>
<input type="hidden" name="x-amz-meta-CustomerId" value="{!CustomerId}"/>
<input type="hidden" name="success_action_redirect" value="{!serverUrl}{!OrderId}"/>
<apex:pageBlock title="New File Upload" mode="maindetail" tabStyle="File__c"> <!-- rendered="{!open}"-->
<apex:pageBlockSection title="File Information" columns="2" collapsible="false" showHeader="false">
<apex:pageBlockSectionItem >
<apex:outputLabel value="Select File" for="selectFile"/>
<input id="selectedFile" type="file" size="25" name="file" onChange="setFileName(this.value)"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
<apex:pageBlockButtons location="bottom">
<input class="btn" type="button" value="Upload File" onClick="checkFile();return false;"/>
<input class="btn" type="button" value="Cancel" onClick="cancelFile();return false;"/>
<input class="btn" type="button" value="Complete Order" onClick="completeFile();return false;"/>
</apex:pageBlockButtons>
</apex:pageBlock>
<apex:outputText styleClass="footer" value="Please click Complete Order when all the required files are uploaded. Thank you." />
</form>
<apex:form id="sfForm"><!-- rendered="{!open}"-->
<apex:inputHidden id="hiddenServerURL" value="{!serverURL}"/>
<apex:inputHidden id="fileName" value="{!fileName}"/>
<apex:inputHidden id="contentType" value="{!contentType}"/>
<apex:inputHidden id="fileType" value="{!fileType}"/>
<apex:actionFunction name="insertFile" action="{!insertFile}" oncomplete="submitFile();return false;"/>
<apex:actionFunction name="completeOrder" action="{!completeOrder}"/>
<script type="text/javascript">
var sendFile = false;
document.getElementById('{!$Component.hiddenServerURL}').value = '{!$Api.Enterprise_Server_URL_140}';
function setFileName(file) {
var f = file.replace(/\\/g, "");
f = f.replace(/C\:fakepath/g, ""); <!--Required for IE8-->
document.s3Form.key.value = "{!CustomerName}/{!OrderName}/" + f;
document.getElementById('{!$Component.fileName}').value = f;
suffix = f.lastIndexOf(".") + 1;
contentType = f.slice(suffix);
document.getElementById('{!$Component.contentType}').value = contentType;
}
function setFileType(type) {
document.getElementById('{!$Component.fileType}').value = type;
}
function checkFile() {
if (document.s3Form.file.value=="") {
alert("Please, select a file.");
return false;
}
else if (document.s3Form.fType.value=="--None--") {
alert("Please, select a file type.");
return false;
}
else {
alert("Uploading...Please click OK and wait for page to refresh.");
insertFile();
sendFile = true;
}
}
function submitFile() {
if(sendFile = false) {
return false;
}
else {
document.s3Form.submit();
}
}
function completeFile() {
completeOrder();
}
</script>
</apex:form>
In the controller (extension):
//SF File insert on an object (passed from page)
public PageReference insertFile() {
this.file.Name = fileName;
this.file.Type__c = fileType;
this.file.Content__c = contentType;
insert this.file;
return null;
}
Here is the javascript section i tried to alter, but i can't find anything after extensive searches on if this works...
function checkFile() {
if (document.s3Form.file.value=="") {
alert("Please, select a file.");
return false;
}
else if (document.s3Form.fType.value=="--None--") {
alert("Please, select a file type.");
return false;
}
else {
alert("Uploading...Please click OK and wait for page to refresh.");
document.s3Form.submit({
success: function(){
alert("Testing!");
insertFile();
},
});
}
}

So if I'm understanding you correctly you want to:
Validate file
Upload file to amazon s3
Save file token to salesforce
Not to throw a wrench in your plans but you might try completing the whole routine in apex. Here's some pseudo code. Salesforce also has developed a toolkit for working with Amazon S3 so you shouldn't have to develop everything from scratch.
Visualforce Page:
<apex:page controller="MyController">
<apex:form>
<apex:inputFile value="{!file.body}" filename="{!file.name}"/>
<apex:commandButton value="Submit" action="{!submitFile}"/>
</apex:form>
</apex:page>
Apex Controller:
public class MyController {
public Document file { get; set; } { file = new Document(); } // dummy object for storing binary file data
public void submitFile() {
if(!validateFile())
return;
String s3Token = submitToS3();
if(s3Token != null) {
File__c newFile = new File__c(name = file.name, s3_token__c = s3Token);
insert newFile;
}
}
}

+1 on doing the work in Apex as opposed to Javascript.
But to continue with a potentially successful hack, try using apex:actionPoller for your form submit. When it wakes up it checks for success on your file insert. If after a few polls you still don't have success then flag a timeout.
Javascript novelties in Visualforce can be perilous, unless time is not a factor for you. Best exhaust Visualforce/Apex options first and only then venture into custom JavaScript in special cases or for lightweight UI tweaks, imo.

Related

Form Submission with two buttons

I am using Razor Pages. I have a form that allows you to either buy or sell. I need to change a value of the OrderType field in the OrderPlacement model, depending on whether the user buys or sells. I accomplish this using javascript.
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="button" value="Buy" asp-page-handler="Buy" onclick="SubmitBuyOrder();" />
<input class="btn-primary" type="button" value="Sell" asp-page-handler="Sell" onclick="SubmitSellOrder();" />
And here is my JavaScript:
function SubmitSellOrder() {
document.getElementById('OrderPlacement_OrderType').value = 'Sell';
document.getElementById('OrderForm').submit();
}
function SubmitBuyOrder() {
document.getElementById('OrderPlacement_OrderType').value = 'Buy';
document.getElementById('OrderForm').submit();
}
Here are my backend methods:
public async Task<IActionResult> OnPostBuyAsync()
{
OrderPlacementResponse response = new OrderPlacementResponse();
try
{
if (!ModelState.IsValid)
return Page(); //Display User Errors
else
{
//Do Some Stuff
}
}
catch (Exception ex)
{
//TODO: Log Errors
//TODO: Redirect to Error Page
return RedirectToPage("/Error"); //show errors
}
}
public async Task<IActionResult> OnPostSellAsync()
{
OrderPlacementResponse response = new OrderPlacementResponse();
try
{
if (!ModelState.IsValid)
return Page(); //Display User Errors
else
{
//Do Some Stuff
}
}
catch (Exception ex)
{
//TODO: Log Errors
//TODO: Redirect to Error Page
return RedirectToPage("/Error"); //show errors
}
}
The backend methods are not being hit. But I see the javascript methods being hit.
I tried using the regular method of having the buttons submit directly where type="submit". But I still need to have the OrderType change depending on which button is pressed, so I still need the type to remain as "button" and the onclick to call the javascript methods.
Also, I cannot set this value (OrderType) in the backend because there is validation that is run before the backend method is hit.
What is wrong with my existing code, that it will not submit?
Here is a working demo you could follow:
View
#page
#model IndexModel
<form id="OrderForm" method="post">
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="submit" value="Buy" asp-page-handler="Buy"
onclick="SubmitBuyOrder(event)" />
<input class="btn-primary" type="submit" value="Sell" asp-page-handler="Sell"
onclick="SubmitSellOrder(event);" />
</form>
#section Scripts
{
<script>
function SubmitSellOrder(e) {
e.preventDefault();
document.getElementById('OrderPlacement_OrderType').value = 'Sell';
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
}
function SubmitBuyOrder(e) {
e.preventDefault();
document.getElementById('OrderPlacement_OrderType').value = 'Buy';
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
}
</script>
}
Be sure your backend contains such property with [BindProperty] attribute:
[BindProperty]
public OrderPlacementResponse OrderPlacement { get; set; }
Besides, you can also combine to one function like below:
#page
#model IndexModel
<form id="OrderForm" method="post">
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="submit" value="Buy" asp-page-handler="Buy" />
<input class="btn-primary" type="submit" value="Sell" asp-page-handler="Sell" />
</form>
#section Scripts
{
<script>
$("#OrderForm").on("submit",function(e){
e.preventDefault();
var orderType= $(this).find("input[type=submit]:focus").val();
document.getElementById('OrderPlacement_OrderType').value = orderType;
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
})
</script>
}

HTML <input> Required Attribute Fails to Prevent Form from Submitting in Apps Script App

I'm testing some code I wrote in Google Apps Script. I've required my fields to have text, but when I test it with null fields, the sever side code is run anyway. The code fires the pop-up stating that fields are required, but submits the form when clicking "OK" on the pop-up. I've tested it where I've filled out all the fields and then submitted which uploads perfectly. I think I just have my coding backwards or something in my "onclick". I have a basic knowledge of coding so I'm sorry if this is a dumb question. Thank you, thank you, thank you in advance.
<p>
<form id="myForm">
<h1>NHD Paper Upload</h1>
<label>Name</label>
<input type="text" name="myName" class="required" placeholder="Enter your full name..">
<label>Division</label>
<input type="text" name="myDivision" class="required" placeholder="(ex. Junior or Senior)">
<label>School</label>
<input type="text" name="mySchool" class="required" placeholder="Enter your school..">
<label>Affiliate</label>
<input type="text" name="myAffiliate" class="required" placeholder="Enter your affiliate..">
<label>Select file to upload. Make sure your file is labeled in the following manner <b>LastName_Division_School_State.pdf</b></label>
<input type="file" name="myFile">
<input type="submit" value="Submit File"
onclick="validateForm();
this.value='Please be patient while your paper is uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;">
<br />
<label><b>Once upload is successful please stay on this window to copy and paste the URL produced on the next screen into registration.</b></label>
<br />
<label><b>If you have any issues or questions please send an email to elaine#nhd.org.</b></label>
</form>
</p>
<div id="output"></div>
<script>
function validateForm() {
var x=document.getElementsByClassName('required');
for(var i = 0; i <x.length; i++){
if (x[i].value == null || x[i].value == "")
{
alert("All fields must be filled out.");
return false;
}
}
}
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 15px; }
p {margin-left:20px;}
</style>
and here is the javascript
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function uploadFiles(form) {
try {
var dropbox = "NHD Papers";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName + ", Division: " + form.myDivision + ", School: " + form.mySchool + ", State: " + form.myState);
return "<h2>File uploaded successfully!</h2><p>Copy and paste the following URL into registration:<br /><br /><strong>" + file.getUrl() + '</strong></p>';
} catch (error) {
return error.toString();
}
}
Right now, google.script.run is being called directly from the submit button.
Current set up:
<input type="submit" value="Submit File"
onclick="validateForm();
this.value='Please be patient while your paper is uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;">
If you want to prevent google.script.run from being run when a required input field is not filled in, I'd try running the submit event from the <form> tag.
<form id="myForm" onsubmit="validateForm();
this.value='Please be patient while your paper is uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this);
return false;">
Make sure to change this.parentNode to just this, for using this set up.
As a personal preference, I like to put google.script.run it's own function. You are already using a separate function for validateForm(), you could put the google.script.run in that function:
Simplify the form tag to:
<form id="myForm" onsubmit="validateForm()">
Script
function validateForm() {
var x=document.getElementsByClassName('required');
for(var i = 0; i <x.length; i++){
if (x[i].value == null || x[i].value == "")
{
alert("All fields must be filled out.");
return false;
}
this.value='Please be patient while your paper is uploading..';
var myFormObject = document.getElementById('myForm');
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(myFormObject);
}
}
Since the function is outside of the form, you can't use this.parentNode anymore. Get the form by your id. One option is shown in the example code.

Javascript prompt alert and submit form with value

I want to submit the form using javascript when clicking on a image. Clicking the actual submit button works, but not the javascript submit.
<img class='File' src="imagehere" onclick="editFileName()"/>
<script>
function editFileName() {
var fileName = prompt("Type in name:");
if (fileName != null) {
document.getElementById('editNameField').value = fileName;
//tried these two
document.EditFileName.submit();
document.getElementById('test').submit();
}
}
</script>
#using (Html.BeginForm("EditUploadedFileName", "Folder", new { name = "EditFileName", id = "test" }))
{
<input type="hidden" id="editNameField" value="a">
<input type="hidden" id="blobName" value="a">
<input type="submit"/>
}
Edit
Corrected the button typo. It has nothing to do with this not working, was a typo when I inserted the code. Any reason for downvoting? Geez
Came up with a working but not so good looking solution..
<script>
function editFileName() {
var fileName = prompt("Type in name");
if (fileName != null) {
document.getElementById('editFileName').value = fileName;
document.getElementById("SubmitEdit").click();
}
}
</script>
#using (Html.BeginForm("EditUploadedFileName", "Folder", new { blobName = file.BlobName }))
{
<input type="hidden" name="editFileName" id="editFileName" />
<input type="submit" id="SubmitEdit" style="display:none;" />
}
<input type="submit"/>
Change the button to an input and it should work.
Try this
document.forms["test"].submit();

Check file type when form submit?

I have the form having the follwing fields,
<form onsubmit="return checkcreateform()" action="/gallery/create" method="post" enctype="multipart/form-data">
<label>Type:*</label>
<label for="type-1">
<input type="radio" checked="checked" value="1" id="type-1" name="type">Image
</label>
<br>
<label for="type-2">
<input type="radio" value="2" id="type-2" name="type">Video
</label>
<label class="itemdetailfloatL required" for="file">File:*</label>
<input type="hidden" id="MAX_FILE_SIZE" value="8388608" name="MAX_FILE_SIZE">
<input type="file" tabindex="5" class="text-size text" id="file" name="file">
<input type="submit" value="Create" id="submit" name="submit">
</form>
I want to validate before form submit. Here how can i validate if user select type as Image and upload video or select type as video and upload image ?
We can achieve this by javascript or jquery.Any quick way to validate this ?
Kindly help me on this.
Instead of using onsubmit, use jQuery's submit handler, and validate using some javascript like the following:
function getExtension(filename) {
var parts = filename.split('.');
return parts[parts.length - 1];
}
function isImage(filename) {
var ext = getExtension(filename);
switch (ext.toLowerCase()) {
case 'jpg':
case 'gif':
case 'bmp':
case 'png':
//etc
return true;
}
return false;
}
function isVideo(filename) {
var ext = getExtension(filename);
switch (ext.toLowerCase()) {
case 'm4v':
case 'avi':
case 'mpg':
case 'mp4':
// etc
return true;
}
return false;
}
$(function() {
$('form').submit(function() {
function failValidation(msg) {
alert(msg); // just an alert for now but you can spice this up later
return false;
}
var file = $('#file');
var imageChosen = $('#type-1').is(':checked');
if (imageChosen && !isImage(file.val())) {
return failValidation('Please select a valid image');
} else if (!imageChosen && !isVideo(file.val())) {
return failValidation('Please select a valid video file.');
}
// success at this point
// indicate success with alert for now
alert('Valid file! Here is where you would return true to allow the form to submit normally.');
return false; // prevent form submitting anyway - remove this in your environment
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="/gallery/create" method="post" enctype="multipart/form-data">
<label>Type:*</label>
<label for="type-1">
<input type="radio" checked="checked" value="1" id="type-1" name="type">Image
</label>
<label for="type-2">
<input type="radio" value="2" id="type-2" name="type">Video
</label> <br />
<label class="itemdetailfloatL required" for="file">File:*</label>
<input type="hidden" id="MAX_FILE_SIZE" value="8388608" name="MAX_FILE_SIZE">
<input type="file" tabindex="5" class="text-size text" id="file" name="file">
<br/>
<input type="submit" value="Create" id="submit" name="submit">
</form>
tested in IE8, RockMelt (based on Chrome) and Firefox 7: http://jsfiddle.net/Ngrbj/4/
Every File type has a 'type' property, for example: 'image/jpeg', 'audio/mp3' and so on...
This is an example for one way to check the type of the file by using the 'match' method (of strings):
function getFileType(file) {
if(file.type.match('image.*'))
return 'image';
if(file.type.match('video.*'))
return 'video';
if(file.type.match('audio.*'))
return 'audio';
// etc...
return 'other';
}
You can also write it the boolean way:
function isImage(
return !!file.type.match('image.*');
}
The answer provided works, but something that will run a little faster with a lot fewer lines for the validation code, using javascript array functions:
var extensionLists = {}; //Create an object for all extension lists
extensionLists.video = ['m4v', 'avi','mpg','mp4', 'webm'];
extensionLists.image = ['jpg', 'gif', 'bmp', 'png'];
// One validation function for all file types
function isValidFileType(fName, fType) {
return extensionLists[fType].indexOf(fName.split('.').pop()) > -1;
}
Then, the if statement in the submit code is just swapped with:
if (imageChosen && !isValidFileType(file.val(), 'image')) {
return failValidation('Please select a valid image');
}
else if (!imageChosen && !isValidFileType(file.val(), 'video')) {
return failValidation('Please select a valid video file.');
}
Using files property on input:file you can loop through file objects and check type property
$('#upload').on("change", function(){
var sel_files = document.getElementById('upload').files;
var len = sel_files.length;
for (var i = 0; i < len; i++) {
var file = sel_files[i];
if (!(file.type==='application/pdf')) {
continue;
}
}
});
<div class="modal">
<form id="form-upload">
<input type="file" name="upload" id="upload" multiple>
<br/>
</form>
</div>
As already said, a file has a type property.
You could compare the file type to a list of supported types like this:
const validFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
const fileTypeValid = (file, fileTypes) => {
return fileTypes.some((fileType) => fileType === file.type);
}
// ... call fileTypeValid with the two parameters
you can try this:
function getFile(fieldId) {
var fileInsert = document.getElementById(fieldId).value;
fileName = fileName.split('/');
fileName = fileName[fileName.length];
extentions = fileName.split('.');
extentions = extentions[extentions.length];
return extentions;
}
You can use this function in your checkcreateform()
First you should change your html like this:
<input type="file" tabindex="5" class="text-size text" id="file" name="file" onchange="checkeExtension(this.value,"submit");">
Then, you need a function like this:
///image 1 and video 2
//you can extend file types
var types= {
'jpg' :"1",
'avi' :"2",
'png' :"1",
"mov" : "2",
}
function checkeExtension(filename,submitId) {
var re = /\..+$/;
var ext = filename.match(re);
var type = $("input[type='radio']:checked").val();
var submitEl = document.getElementById(submitId);
if (types[ext] == type) {
submitEl.disabled = false;
return true;
} else {
alert("Invalid file type, please select another file");
submitEl.disabled = true;
return false;
}
}

How to validate a file upload field using Javascript/jquery

How can I validate if the user has selected a file to upload?
Edit: bumped
Check it's value property:
In jQuery (since your tag mentions it):
$('#fileInput').val()
Or in vanilla JavaScript:
document.getElementById('myFileInput').value
My function will check if the user has selected the file or not and you can also check whether you want to allow that file extension or not.
Try this:
<input type="file" name="fileUpload" onchange="validate_fileupload(this.value);">
function validate_fileupload(fileName)
{
var allowed_extensions = new Array("jpg","png","gif");
var file_extension = fileName.split('.').pop().toLowerCase(); // split function will split the filename by dot(.), and pop function will pop the last element from the array which will give you the extension as well. If there will be no extension then it will return the filename.
for(var i = 0; i <= allowed_extensions.length; i++)
{
if(allowed_extensions[i]==file_extension)
{
return true; // valid file extension
}
}
return false;
}
Building on Ravinders solution, this code stops the form being submitted. It might be wise to check the extension at the server-side too. So you don't get hackers uploading anything they want.
<script>
var valid = false;
function validate_fileupload(input_element)
{
var el = document.getElementById("feedback");
var fileName = input_element.value;
var allowed_extensions = new Array("jpg","png","gif");
var file_extension = fileName.split('.').pop();
for(var i = 0; i < allowed_extensions.length; i++)
{
if(allowed_extensions[i]==file_extension)
{
valid = true; // valid file extension
el.innerHTML = "";
return;
}
}
el.innerHTML="Invalid file";
valid = false;
}
function valid_form()
{
return valid;
}
</script>
<div id="feedback" style="color: red;"></div>
<form method="post" action="/image" enctype="multipart/form-data">
<input type="file" name="fileName" accept=".jpg,.png,.bmp" onchange="validate_fileupload(this);"/>
<input id="uploadsubmit" type="submit" value="UPLOAD IMAGE" onclick="return valid_form();"/>
</form>
In Firefox at least, the DOM inspector is telling me that the File input elements have a property called files. You should be able to check its length.
document.getElementById('myFileInput').files.length
I got this from some forum. I hope it will be useful for you.
<script type="text/javascript">
function validateFileExtension(fld) {
if(!/(\.bmp|\.gif|\.jpg|\.jpeg)$/i.test(fld.value)) {
alert("Invalid image file type.");
fld.form.reset();
fld.focus();
return false;
}
return true;
} </script> </head>
<body> <form ...etc... onsubmit="return
validateFileExtension(this.fileField)"> <p> <input type="file"
name="fileField" onchange="return validateFileExtension(this)">
<input type="submit" value="Submit"> </p> </form> </body>
Simple and powerful way(dynamic validation)
place formats in array like "image/*"
var upload=document.getElementById("upload");
var array=["video/mp4","image/png"];
upload.accept=array;
upload.addEventListener("change",()=>{
console.log(upload.value)
})
<input type="file" id="upload" >

Categories