Sending Parameter with Dropzone 'ProcessQueue' event - javascript

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
}
});

Related

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

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?

pass jQuery modal variable to PHP script

I do believe am over-complicating this, but I have a jQuery modal that talks with a PHP file. The file has all the form and validation, but it's included in the modal. The event is triggered on right-click (so a user right clicks the folder to edit, selects "Edit", the action below triggers. It's supposed to send the folder id to the modal, so the modal displays the edit form with the correct folder. Right now, it doesn't send anything.)
So I have the jquery (script.js):
"action": function(obj) {
var data = {'pid': obj.attr("id")};
$.post("/folder/edit.php", data, function (response) {
$('#modalEditFolder').modal('show');
});
}
// also tried this:
$.post("/folder/edit.php", data, function (response) {
$('#modalEditFolder').data('pid', obj.attr("id")).modal('show');
});
// and this
$.ajax({
type: "POST",
url: "/view/folder/edit.php",
data: {pid: obj.attr("id")},
success: function(html) {
$('body').append(html);
$('#modalEditFolder').modal('show');
}
});
The modal (modal.php):
<div class="modal-body">
<?php include_once("/folder/edit.php"); ?>
</div>
The PHP file (edit.php):
<?php echo $_POST['pid']; ?>
How can I get both the modal and php form to get the PID variable?
try this :
$.ajax({
type: "POST",
url: "/view/folder/edit.php",
cache: false,
data: {'pid': obj.attr("id")}
}).done(function(html) {
$('body').append(html);
$('#modalEditFolder').modal('show');
});

Django + Ajax | File Upload | Server doesn't recognise Ajax Request

I am trying to implement file upload using ajax with Django but facing some problem.
When the user tries to upload the files after selecting the file and submitting the form, then as per my understanding , an ajax request should be send to the server using POST method ,but in my case a POST request is being made to the server, but the server is not able to identify it as an ajax request and browser is redirected to http://<server>:<port>/upload/ and the contents on this page are as follows.
{"status": "error", "result": "Something went wrong.Try Again !!"}
Django Version: 1.6.2
Python Version: 2.7.5
Also, testing on Django Development Server.
views.py
def upload(request):
logging.info('Inside upload view')
response_data = {}
if request.is_ajax():
logging.info('Is_AJAX() returned True')
form = UploaderForm(request.POST, request.FILES)
if form.is_valid():
logging.info('Uploaded Data Validated')
upload = Upload( upload=request.FILES['upload'] )
upload.name = request.FILES['upload'].name
upload.save()
logging.info('Uploaded Data Saved in Database and link is %s' % upload.upload)
response_data['status'] = "success"
response_data['result'] = "Your file has been uploaded !!"
response_data['fileLink'] = "/%s" % upload.upload
return HttpResponse(json.dumps(response_data), content_type="application/json")
response_data['status'] = "error"
response_data['result'] = "Something went wrong.Try Again !!"
return HttpResponse(json.dumps(response_data), content_type='application/json')
Template
<form id="uploadForm" action="/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input id="fileInput" class="input-file" name="upload" type="file">
<input type="submit" value="Post Images/Files" />
</form>
Javascript 1:
$('#uploadForm').submit(function(){
var formData = new FormData($(this)[0]);
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
async: false,
success: function (data) {
alert(data)
},
cache: false,
contentType: false,
processData: false
});
return false;
});
Javascript 2
var options = {
url: '/upload/',
type: "POST",
error: function(response) {
alert('Something went Wrong. Try Again');
},
success: function(response) {
if ( response.status == 'success' ) {
alert('success');
}
}
};
$('#uploadForm').ajaxSubmit(options);
Question:
1) Why is Django not able to recognize the ajax request and value of request.is_ajax() is always False.
2) Even if the server doesn't recognize ajax request why is my browser getting redirected to another page ?
There is another similar question here but with no result.
This works for me. You need a jquery.form.js
$("#uploadForm").submit(function(event) {
$(this).ajaxSubmit({
url:'{% url upload_file %}',
type: 'post',
success: function(data) {
console.log(data)
},
error: function(jqXHR, exception) {
console.log("An error occurred while uploading your file!");
}
});
return false;
});
Here's the similar question here with answers.
Make sure that javascript code block
$('#uploadForm').submit(function(){
var formData = new FormData($(this)[0]);
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
async: false,
success: function (data) {
alert(data)
},
cache: false,
contentType: false,
processData: false
});
return false;
});
loaded after your uploadForm html form in DOM on page. In your case seems you trying to bind submit handler with form element which not yet loaded so when you click, it send simple POST request.
1) why is_ajax() not working?
Have you included the JQuery form plugin (jquery.form.js) ? ajaxSubmit() needs that plugin.
Take a look at http://jquery.malsup.com/form/
If it's already done, you might take a look at the HTTPRequest object
Django Documentation says HttpRequest.is_ajax()
Returns True if the request was made via an XMLHttpRequest. And if you are using some javascript libraries to make the ajax request, you dont have to bother about this matter. Still you can verify "HTTP_X_REQUESTED_WITH" header to see if Django received an XMLHttpRequest or not.
2) Why page redirects?
As I said above, JQuery form plugin is needed for handling the ajax request and its call back. Also, for ajaxSubmit() you need to override the $(#uploadForm).submit()
$('#uploadForm').submit( function (){
$(this).ajaxSubmit(options);
return false;
});
Hope this was helpful :)

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 :-)

CSRF protection always failing when trying to upload file with ajax

Few days before i learned that we can make file uploads with ajax. So i tried to build an app that uploads selected file when other parts of form being filled by user.
my app has two models:
class Post(models.Model):
image = models.ImageField(...)
title = ...
desc = ...
class TempImg(models.Model):
image = models.ImageField(...)
posted_by = ...
posted_at = ...
That form used to make a post, here you can see temp_image as hidden input:
class PostForm(forms.ModelForm):
temp_image = forms.IntegerField(widget=forms.HiddenInput)
class Meta:
model = Post
When user selects image, this javascript code uploads it and puts returning id value to temp_image field of form:
// here is a function that gets csrftoken, [which is taken from docs
// https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
csrftoken = ...
form = new FormData();
form.append("image", dataURLToBlob(resizedImgData));
form.append("csrftoken", csrftoken)
$.ajax({
url: '/upload/',
data: form,
processData: false,
contentType: false,
dataType: 'json',
type: 'POST',
beforeSend: function() {
$("#uploadingIndicator").show()
},
success: function(data){
$("#id_temp_image").val(data['id'])
$("#uploadingIndicator").hide();
}
});
Everything seems OK to me but, there is a problem that my view always return 403. CSRF verification error.
Can anybody have an idea where should i look at? I am going to use csrf_exemt if i can not find solution...
You should use
form.append("csrfmiddlewaretoken", csrftoken)
While you were trying to do form.append("csrftoken", csrftoken)

Categories

Resources