Interested in building my own drag'n'drop file uploader using JQuery/AJAX/PHP.
Basically I want a file-uploader that users of my site can just drag the file from their computer into a div I created, and it will then upload the file for them to the selected destination.
I would like to build this from scratch, and not use any plugins so that I can better manipulate the restrictions (file types, size, destination folders, etc.)
Have scoured google with no luck, only plugins. Can anyway steer me in the right direction?
UPDATE
Ok, so I figured out how to do what I want. Just set the file input field opacity to 1 so it is hidden, and you can still drag a file into that general area and if you hit the text field it will catch it. HOWEVER, I would like to know how to increase the height/width on the file input field (tried basic css on the file, but it only increases the 'browse' button size and not the actual field where you can drop the file into. Any ideas how to do this?
I basically want a big square div that says 'Drop file here'. So I need to resize the input field.
Just to chime in here, as I've been doing this as well the last couple of days. From what I understand if you're binding the drop event through jQuery you need to access that event.dataTransfer object by going through the event.originalEvent object in the event provided by jQuery.
Example:
In this I bind to both the dragover as well as drop events, as this was necessary to prevent it from performing the default action (found that solution here: Prevent the default action. Working only in chrome )
$('#dropzone').bind('dragover drop', function(event) {
event.stopPropagation();
event.preventDefault();
if (event.type == 'drop') {
console.log(event.originalEvent.dataTransfer.files);
}
});
Also there seems to be a bug where if you console.log() the event.dataTransfer (or event.originalEvent.dataTransfer) it's files array is empty, it's pointed out here: event.dataTransfer.files is empty when ondrop is fired?
To better answer the OPs question (I just noticed the rest of it, and I know it's old but some one might find this helpful):
My implementation is in jQuery, so I hope that's alright:
var files = [];
// Attaches to the dropzone to pickup the files dropped on it. In mine this is a div.
$("#dropzone").bind('dragover drop', function(event) {
// Stop default actions - if you don't it will open the files in the browser
event.stopPropagation();
event.preventDefault();
if (e.type == 'drop') {
files.push(event.originalEvent.dataTransfer.files);
}
});
// Attach this to a an input type file so it can grab files selected by the input
$("#file-input").bind('change', function(event) {
files.push(event.target.files);
});
// This is a link or button which when clicked will do the ajax request
// and upload the files
$("#upload-button").bind('click', function(event) {
// Stop the default actions
event.stopPropagation();
event.preventDefault();
if (files.length == 0) {
// Handle what you want to happen if no files were in the "queue" on clicking upload
return;
}
var formData = new FormData();
$.each(files, function(key, value) {
formData.append(key, value);
});
$.ajax({
url: 'upload-ajax',
type: 'POST',
data: formData,
cache: false,
dataType: 'json',
processData: false, // Don't process the files - I actually got this and the next from an SO post but I don't remember where
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function(data, textStatus, jqXHR) { /* Handle success */ },
error: function(jqXHR, textStatus, errorThrown) { /* Handle error */ }
});
});
You could also bind to the other events in the accepted answer for doing effects like making the dropzone fade in so you can see it (that's on my todo list for my library). This is the core of the actual ajax file uploading I use, however.
I don't really have a convenient way to test that, but that's in essence how I did it (I essentially took all that code from the library I've been making and adapted it to fit a general code block on here in an easy to understand way). Hopefully this helps some people out. Starting from here it was actually really easy to go ahead and add in a file queue list, with the ability to delete files from the queue, so this should be a pretty good starting point.
You can use the HTML5 dragenter and dragleave events to create a dropzone.
Then by placing a file input inside the dropzone, and hiding it with CSS, you can upload the file when the change event for the input fires, like this
var dropzone = $("#dropzone"),
input = dropzone.find('input');
dropzone.on({
dragenter : dragin,
dragleave : dragout
});
input.on('change', drop);
function dragin(e) { //function for drag into element, just turns the bix X white
$(dropzone).addClass('hover');
}
function dragout(e) { //function for dragging out of element
$(dropzone).removeClass('hover');
}
function drop(e) {
var file = this.files[0];
$('#dropzone').removeClass('hover').addClass('dropped').find('img').remove();
// upload file here
}
FIDDLE
For those interested, I found this tutorial/demo to be helpful: http://www.viget.com/inspire/custom-file-inputs-with-a-bit-of-jquery/
Basically uses a <span> to cover the default input field.
Related
.on('complete', function(id, name, response) {
console.log(id);
console.log(response);
console.log(name);
$("input").attr({
type: 'hidden',
name: id
}).val(name).appendTo('form');
})
.on('deleteComplete', function(id, xhr, isError) {
console.log(name);
$('input[name=' + id + ']').remove();
});
I'm using latest FineUploader to upload images and add the image filenames as hidden fields (correct way) to post their location to PHP for further processing.
The issue is id is common between the two callbacks but it returns an object and I'm sure how to handle it. I just need to store/post the filename location to PHP.
The parameters for your callbacks are incorrect. If you are using the jQuery plug-in wrapper for Fine Uploader, each event handler always has an initial parameter of Event. That is, the jQuery event object associated with the event you are handling.
Just to be clear, you code should look like this:
.on('complete', function(event, id, name, response) {
...
})
.on('deleteComplete', function(event, id, xhr, isError) {
...
});
This is one of many reasons why I have advised users to avoid using the jQuery plug-in wrapper. It makes working with Fine Uploader callbacks more confusing, and provides absolutely no benefits. In light of this, if you still want to use the jQuery plug-in wrapper for some reason, you should consider declaring your callback handlers as part of a callback option passed as part of the initial configuration options when constructing a Fine Uploader instance.
I want to create images using imagejpeg() but they seem to take longer to render than the time it takes to load the page, therefore the images are either not displaying or they are truncated.
I have tried to delay the loading of the page until the images are completely created without resolve so now I am attempting to get the images created prior to page load.
My fail is as follows:
function createimages(x) {
$.post("image-dev.php?curID=" + x, function(rdata) {
console.log(rdata);
});
setTimeout(function() {
window.location = "image-review.php?curID=" + x;
}, 5000);
}
image-dev.php is my image creation file that pulls all necessary data from my DB then uses imagejpeg to create and save my folder.
If I navigate directly to image-dev.php with the proper ID associated. My images are created and saved properly.
My hopes were that I could use AJAX to call image-dev.php sometime before loading the image review page. I hoped that this would 'pre-develop' the images so that they would load properly when reviewed.
My console.log of the rdata shows that the image-dev.php is loading and executing, but the files aren't being created.
Is there an issue with creating images behind the scene?
When image is already created php can return "true".
With ajax you can do that.
function createimages(x){
$.ajax({
url: "image-dev.php?curID="+x,
beforeSend: function( xhr ) {
//here you can hide elements or other DOM manipulations
}
}).done(function( rdata) {
console.log(rdata);
//when php is ready you can show images or other DOM manipulations
}
});
});
kristiyan, Thanks!
I have decided to give up on the idea of predeveloping my images and used your tactic.
Since the images were still truncating when displayed, I now have placeholder images on the image review page and am loading the new images in after they complete.
I'm not yet sure how to see if an image is truncated, so I had to add in a delay before resetting the placeholders src attribute.
$.ajax({
type: 'POST',
url: "image-dev.php?curID="+x,
success: function(rdata) {
console.log(rdata);
setTimeout(function(){
$('#placeholder').attr('src', 'newImage.jpg');
},5000);
}
});
This seems to be working acceptably!
OK, If you need me to post any more of my code I have come up with then let me know. I am not sure this is even possible. But what I want to do is stop PHP from making a Zip file when the user selects a cancel button / link.
Now what I have set up is all the files upload per user are listed in a form, the user then can selected which files they wish to zip and download. Once the files are selected and the download button clicked, the div holding the form is changed via a Jquery AJAX call, which works fine no issues.
But I have a 'Cancel' / 'Stop' button / link which sort of works. Once clicked I call the .abort on the AJAX request and then loads new HTML content saying the user cancelled the zip making progress. However, all the message works fine, it seems like the server is still making the zip in the background and any links will not respond (most are also AJAX requests to load in new users requests) until the zip has been made.
The base of my site is using the CakePHP framework. But I am sure this is just standard Jquery / PHP issue.
Any ideas on how to get my AJAX request to stop PHP from making the zip?
This is how I am building my AJAX :
$(document).ready(function() {
$(".MAKEMYZIP").click(function(e) {
e.preventDefault();
$('.DIV-HOLDER').load('/PAGE-PREVIEWER');
var MakeNewZipFile = $.ajax({
url: '/makezip',
type: 'post',
dataType:'html', //expect return data as html from server
data: $('.FILE_DATA').serialize(),
success: function(response, textStatus, jqXHR){
$('.DIV-HOLDER').html(response); //select the id and put the response in the html
},
error: function(jqXHR, textStatus, errorThrown){
console.log('error(s):'+textStatus, errorThrown);
}
}); //End of AJAX call
//Below line makes the 'text' link visible once the make zip but clicked.
$('.ZipLinkHolder').css("visibility","visible");
$( ".Can_Zip_This_Zip" ).click(function() {
MakeNewZipFile.abort();
$('.DIV-HOLDER').html('<br/><br/><div class="CenterTxt">User has canceled Zip making process.</div>');
});
});
});
So I'm struggling a bit to find what I'm looking for and how to implement it.
I have a basic PHP file uploader working, in that a user presses a custom upload button, selects a file and then using JS, it checks for a change (Ie. the user selecting a file) and then submits the form which uploads the image fine.
What I also want now is a drag & drop to upload area. So the user can drag an image from their file explorer and drop it in a designated place (not the whole page) and then once that image has been dropped for the form to submit automatically with their image and use the same PHP processing.
Is this possible and realistic?
This is absolutely realistic and possible without using any third parties plugin.
The following snippets should give you an idea of how it could work:
Drop area
$(".drop-files-container").bind("drop", function(e) {
var files = e.originalEvent.dataTransfer.files;
processFileUpload(files);
// forward the file object to your ajax upload method
return false;
});
the processFileUpload()-Method:
function processFileUpload(droppedFiles) {
// add your files to the regular upload form
var uploadFormData = new FormData($("#yourregularuploadformId")[0]);
if(droppedFiles.length > 0) { // checks if any files were dropped
for(var f = 0; f < droppedFiles.length; f++) { // for-loop for each file dropped
uploadFormData.append("files[]",droppedFiles[f]); // adding every file to the form so you could upload multiple files
}
}
// the final ajax call
$.ajax({
url : "upload.php", // use your target
type : "POST",
data : uploadFormData,
cache : false,
contentType : false,
processData : false,
success : function(ret) {
// callback function
}
});
}
form example
<form enctype="multipart/form-data" id="yourregularuploadformId">
<input type="file" name="files[]" multiple="multiple">
</form>
Feel free to use something like this as a starting point. The browser support of this you can find here http://caniuse.com/#feat=xhr2
Of course you can add any extras you wish like progress bar, preview, animation...
I am making a page that when you click on a "story" it loads the text and the media for that story, I have a seperate PHP script for the story text and the media (video or image) loading. both scripts work and actually it all works.
My problem is that when you click the story it is supposed to load the text, and then slide the media down when it's loaded However, it slides down even when the text is still loading.
newspaper.nmyster.co.uk/ is the site in question. click on the vimeo story on the left and see what I mean.
The code for the AJAX that loads the story and media is:
$.ajax({
url: './scripts/storyLoader.php?storyid='+storyId,
success: function(result){
$('#storycontainer').hide();
$('#loading').remove();
$('#storycontainer').hide(0).html(result).fadeIn(1000);
}
});
$.ajax({
url: './scripts/mediaLoader.php?storyid='+storyId,
success: function(result){
$('.martefact').hide();
$('#loading').remove();
$('.martefact').html(result).slideDown(1000);
}
});
Basically, I only want the media div to slide down once the video or image has finished loading.
Thanks
I would use something like this:
var requestHandle;
function loadPage(url, vars) {
//cancel pending
if (requestHandle!=null)
requestHandle.abort();
//load page..
requestHandle = $.get(url, vars, function(data) {
$('#storycontainer').hide();
$('#loading').remove();
$('#storycontainer').hide(0).html(data).fadeIn(1000);
});
}
Your request is asynchronous. It means that the script won't wait for data to load before executing the aesthetics bit.
You need to add async: false to your $.ajax call (look up other options over at jQuery documentation). That way, browser will wait for data to arrive first before executing the rest of JS.
What does your mediaLoader.php script do? Does it just check the database whether there are any media entries for the given story and if so format them properly and output them? Because currently I don't think you can slide down after the video is completely loaded, since you are embedding a vimeo video container, which handles the loading of the video itself and you have no access to it...
You need to use an 'on complete' callback function on the first animation.
Have a look jQuery api documentation for .fadeIn()
It should look something like:
$('#book').fadeIn('slow', function() {
// Code to run after animation completed...
});