Can't collate all the files sent to s3 in a batch - javascript

I have a React + Rails chat application and I want to add attachments to the same.
I'm using React Dropzone component to do attach images. Every time an image successfully gets added to the dropzone, it calls the attachToS3 function and posts that image to S3 as well. On successful posting it sets the state of new_message_content as the url of the file.
Once, the user has uploaded all the files, they can click on send which inserts the new_message_content as a new message in the conversation.
Since, I'm allowing users to add multiple files at the same time therefore my state only contains the url of the last uploaded file and not an array of all the URL's.
My dropzone is being rendered as follows:
renderFileDropzone() {
let componentConfig = { postUrl: 'random_url'},
djsConfig = { autoProcessQueue: true, addRemoveLinks: true },
eventHandlers = { addedfile: this.attachToS3.bind(this) };
return(
<div>
<div className="dashboard-modal">
<div className="dashboard-modal-content">
<div className="dashboard-modal-header">
<h5>Send files to {this.state.counterparty.name}</h5>
<span onClick={this.closeDropzone.bind(this)} className="icon-cancel modal-close"></span>
</div>
<form>
<div className="dashboard-modal-body">
<DropzoneComponent config={componentConfig} eventHandlers = {eventHandlers} djsConfig = {djsConfig} />
<button onClick={this.sendMessage.bind(this)} type="submit" className="btn btn-secondary">Send Files</button>
</div>
</form>
</div>
</div>
<div className="modal-bg bg-transparent-black"></div>
</div>
)
}
Now, my Dropzone component allows multiple file uploads at the same time but since I can't do a direct upload to Amazon S3 of multiple files at the same time so I pass the files, one by one.
attachToS3 function
attachToS3(file) {
let self = this;
API.get('user/s3_post_attachment', {filename : file.name}, function (s3_params) {
let formData = new FormData();
Object.keys(s3_params.formdata).forEach(function(k) {
formData.append(k, s3_params.formdata[k]);
});
formData.append('file', file);
$.ajax({
url: s3_params.url,
type: 'POST',
data: formData,
async: true,
dataType: "xml",
success: function (data) {
let file_url = $(data).find('Location').html();
self.setState({ new_message_content : file_url });
},
cache: false,
contentType: false,
processData: false
});
});
}
I tried adding a localStorage to my attachToS3 function, like this:
var url_array = JSON.parse(localStorage.getItem('allFiles'));
if (url_array == null) url_array = [];
var url = {
'url' : file_url
};
localStorage.setItem('url', JSON.stringify(url));
url_array.push(url);
localStorage.setItem('allURL', JSON.stringify(url_array));
But it's not working and I'm getting an error url_array.push is not a function.
Is there any way to get all the file url's in an array?

Related

Sending Parameter with Dropzone 'ProcessQueue' event

Heres my issue.
I'm currently building an application in Laravel and using DropZone for a user upload image. Now on a 'new user' page, I have both the user details and a dropzone dropbox, and these are both being processed separately.
I'm going to run the 'create user' method first, then if that goes ok, upload the images.
The issue comes with Dropzone not knowing the new user Id when its ready to upload (as it needs to assign to the correct user in the DB).
I somehow need to be able to pass the new user Id back to the dropzone 'processQueue' method, to use the new user id in the image upload, does anyone know if this is possible?
In a perfect world I would be able to pass the new id into the 'processQueue' function like processQueue(newUserId) and fetch it and add it into the form data to send with the image.
Here is my code so far
HTML
<div id="user_profile" class="dropzone dropzone-box">
<div class="dz-message needsclick">
<h3>Select Image</h3>
<hr>
<p>Click here or drag and drop image</p>
</div>
</div>
JS
//Bind dropzone to user profile image
var userProfile = new Dropzone('#user_profile',{
url: '/ajax/userProfileUpload',
autoProcessQueue:false,
maxFiles:1,
addRemoveLinks:true,
paramName: 'profile_pic', // The name that will be used to transfer the file
init: function(){
this.on("maxfilesexceeded", function(file) {
userProfile.removeFile(file);
});
this.on("success", function(file, returnedData, myEvent) {
console.log(returnedData);
});
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
});
Send new user request, when done, send images
$.ajax({
type: "POST",
url: '/users',
data: postData,
success: function(data){
userProfile.processQueue(/* pass user id from here */);
},
error: function(data){
//Didnt work
}
});
An option can be to add a custom attribute to the Dropzone object that holds the id, set this attribute when the ajax call succeeds and then access it on the sending event, the relevant part would be:
var userProfile = new Dropzone('#user_profile',{
...
userId: '', // Attribute to hold the user id
init: function(){
let thisDropzone = this; // Closure
...
this.on('sending', function(file, xhr, formData){
formData.append('userId', thisDropzone.userId);
});
}
});
ajax request:
$.ajax({
type: "POST",
url: '/users',
data: postData,
success: function(data){
userProfile.userId = 'yourId'; // set the id
userProfile.processQueue(); // process queue
},
error: function(data){
//Didnt work
}
});

I can't upload multiple images to Amazon S3 using Sails.js

I'm trying to upload multiple images to Amazon S3 and using Sails.js framework.This is my code:
Fotos.ejs (Is the view for uploading photos):
<form enctype="multipart/form-data" id="frmFotos">
<input id="fotos" name="fotos" type="file">
<button type="submit" id="btnUpload">Upload</button>
</form>
Fotos.js (Ajax call for upload)
$('#btnUpload').on('click',function(e){
e.preventDefault();
var formData=new FormData();
formData.append("fotos",$("#fotos")[0].files);
$.ajax({
url:"/upload",
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function(data){
console.log(data);
}
});
})
FotoController.js (Controller in Sails.js where I'm using skipper-s3 to upload files)
module.exports = {
upload:function(req,res){
var aws={
adapter:require("skipper-s3"),
bucket:"mybucket",
key:"mykey",
secret:"mysecret"
};
req.file("fotos").upload({aws},function whenDone(error,fotos){
if(error)
{
console.log(error);
} else{
fotos.forEach(function(foto){
console.log(foto);
});
}
});
}
}
I think that there is an additional task because I can't see my images in the bucket in S3. I test the code with a single image and this works fine.
You have to specify the region in which your bucket belongs. For instance:
var aws = {
...
region: 'us-west-2'
...
}
Your region may be located elsewhere than US West 2. In which case, either create a new bucket in US West 2, or find your region's code (e.g.: us-west-1, us-east-1).

Post cvs data with ajax

Im trying to post data with ajax but in console i recive something like.. Uncaught ReferenceError: file is not defined
This is my input with my button to upload data:
<div id='file_browse_wrapper'>
<input class="iconos" type="file" name="File Upload" id='file_browse' accept=".csv" />
</div>
<label id="url-archivo"><b>Selecciona tu archivo...</b></label>
<button class="btn btn-success" id="carga-archivo">Subir</button>
This is my jquery/ajax:
$("#carga-archivo").click(function () {
var fileUpload = document.getElementById("file_browse");
if (fileUpload .value != null) {
var uploadFile = new FormData();
var files = $("#file_browse").get(0).files;
// Add the uploaded file content to the form data collection
if (files.length > 0) {
uploadFile.append('file-'+i, file);
$.ajax({
url: "/2/delivery/client/massive",
contentType: false,
processData: false,
data: uploadFile,
type: 'POST',
success: function () {
alert("file upload successfuly");
}
});
}
}
});
But the data is not POST i think is something missing
You have created a variable called files, but are using a variable called file. Try changing this portion of your code:
var file = $("#file_browse").get(0).files;
// Add the uploaded file content to the form data collection
if (file.length > 0) {
uploadFile.append('file-'+i, file);
$.ajax({
url: "/2/delivery/client/massive",
contentType: false,
processData: false,
data: uploadFile,
type: 'POST',
success: function () {
alert("file upload successfuly");
}
});
}
This just renames the files variable to file and changes the one other place that used files.

File Upload without Form

Without using any forms whatsoever, can I just send a file/files from <input type="file"> to 'upload.php' using POST method using jQuery. The input tag is not inside any form tag. It stands individually. So I don't want to use jQuery plugins like 'ajaxForm' or 'ajaxSubmit'.
You can use FormData to submit your data by a POST request. Here is a simple example:
var myFormData = new FormData();
myFormData.append('pictureFile', pictureInput.files[0]);
$.ajax({
url: 'upload.php',
type: 'POST',
processData: false, // important
contentType: false, // important
dataType : 'json',
data: myFormData
});
You don't have to use a form to make an ajax request, as long as you know your request setting (like url, method and parameters data).
All answers here are still using the FormData API. It is like a "multipart/form-data" upload without a form. You can also upload the file directly as content inside the body of the POST request using xmlHttpRequest like this:
var xmlHttpRequest = new XMLHttpRequest();
var file = ...file handle...
var fileName = ...file name...
var target = ...target...
var mimeType = ...mime type...
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('Content-Disposition', 'attachment; filename="' + fileName + '"');
xmlHttpRequest.send(file);
Content-Type and Content-Disposition headers are used for explaining what we are sending (mime-type and file name).
I posted similar answer also here.
UPDATE (January 2023):
You can also use the Fetch API to upload a file directly as binary content (as also was suggested in the comments).
const file = ...file handle...
const fileName = ...file name...
const target = ...target...
const mimeType = ...mime type...
const promise = fetch(target, {
method: 'POST',
body: file,
headers: {
'Content-Type': mimeType,
'Content-Disposition', `attachment; filename="${fileName}"`,
},
},
});
promise.then(
(response) => { /*...do something with response*/ },
(error) => { /*...handle error*/ },
);
See also a related question here: https://stackoverflow.com/a/48568899/1697459
Step 1: Create HTML Page where to place the HTML Code.
Step 2: In the HTML Code Page Bottom(footer)Create Javascript: and put Jquery Code in Script tag.
Step 3: Create PHP File and php code copy past. after Jquery Code in $.ajax Code url apply which one on your php file name.
JS
//$(document).on("change", "#avatar", function() { // If you want to upload without a submit button
$(document).on("click", "#upload", function() {
var file_data = $("#avatar").prop("files")[0]; // Getting the properties of file from file field
var form_data = new FormData(); // Creating object of FormData class
form_data.append("file", file_data) // Appending parameter named file with properties of file_field to form_data
form_data.append("user_id", 123) // Adding extra parameters to form_data
$.ajax({
url: "/upload_avatar", // Upload Script
dataType: 'script',
cache: false,
contentType: false,
processData: false,
data: form_data, // Setting the data attribute of ajax with file_data
type: 'post',
success: function(data) {
// Do something after Ajax completes
}
});
});
HTML
<input id="avatar" type="file" name="avatar" />
<button id="upload" value="Upload" />
Php
print_r($_FILES);
print_r($_POST);
Basing on this tutorial, here a very basic way to do that:
$('your_trigger_element_selector').on('click', function(){
var data = new FormData();
data.append('input_file_name', $('your_file_input_selector').prop('files')[0]);
// append other variables to data if you want: data.append('field_name_x', field_value_x);
$.ajax({
type: 'POST',
processData: false, // important
contentType: false, // important
data: data,
url: your_ajax_path,
dataType : 'json',
// in PHP you can call and process file in the same way as if it was submitted from a form:
// $_FILES['input_file_name']
success: function(jsonData){
...
}
...
});
});
Don't forget to add proper error handling
Try this puglin simpleUpload, no need form
Html:
<input type="file" name="arquivo" id="simpleUpload" multiple >
<button type="button" id="enviar">Enviar</button>
Javascript:
$('#simpleUpload').simpleUpload({
url: 'upload.php',
trigger: '#enviar',
success: function(data){
alert('Envio com sucesso');
}
});
A non-jquery (React) version:
JS:
function fileInputUpload(e){
let formData = new FormData();
formData.append(e.target.name, e.target.files[0]);
let response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
let result = await response.json();
console.log(result.message);
}
HTML/JSX:
<input type='file' name='fileInput' onChange={(e) => this.fileInput(e)} />
You might not want to use onChange, but you can attach the uploading part to any another function.
Sorry for being that guy but AngularJS offers a simple and elegant solution.
Here is the code I use:
ngApp.controller('ngController', ['$upload',
function($upload) {
$scope.Upload = function($files, index) {
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
$scope.upload = $upload.upload({
file: file,
url: '/File/Upload',
data: {
id: 1 //some data you want to send along with the file,
name: 'ABC' //some data you want to send along with the file,
},
}).progress(function(evt) {
}).success(function(data, status, headers, config) {
alert('Upload done');
}
})
.error(function(message) {
alert('Upload failed');
});
}
};
}]);
.Hidden {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-controller="ngController">
<input type="button" value="Browse" onclick="$(this).next().click();" />
<input type="file" ng-file-select="Upload($files, 1)" class="Hidden" />
</div>
On the server side I have an MVC controller with an action the saves the files uploaded found in the Request.Files collection and returning a JsonResult.
If you use AngularJS try this out, if you don't... sorry mate :-)

AJAX $_FILES and $_POST simultaneously

I am trying to add products to a database, along with some pictures, server-side is PHP. I want to upload everything asynchronously via AJAX. I want the pictures saved in a directory name after the product id ( thumbs/productID ).
The first part, which is submiting the product information and retrieving its id is done. However, when uploading the files, I can't upload both files and strings, to inform my script in which folder to save. I can however send only the files.
Is there any way to send both files and text at the same time? Any help would be appreciated.
$('#register-product').on('submit', function ( evt ) {
evt.preventDefault();
var i = 0, len = document.getElementsByName("images").length-1, reader, file;
var myFiles = document.getElementsByName("images");
// Adds all files to formdata
for ( ; i < len; i++ ) {
file = myFiles[i].files[0];
if (!!file.type.match(/image.*/)) {
if ( window.FileReader ) {
reader = new FileReader();
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("images[]", file);
}
}
}
// Send data to the server.
if (formdata) {
$.ajax({
url: "upload.php",
type: "POST",
// data: formdata, // This is correct
data: {formdata, id: 1}, // This doesn't work
processData: false,
contentType: false,
success: function (res) {
console.log(res);
}
});
}
});
Just append another value to your formdata:
//...
formdata.append("id", 1);
if (formdata) { //...
You can access it as you wont through $_POST["id"].
You canĀ“t not send files with AJAX post request.
The header data for the files will not be sent.
So you need to do some iframe tricks or use the file API.

Categories

Resources