I want to upload images with ajax. I convert the image to a base64 string. Posting the data works, but how do I get it on the server (I'm using Laravel 5.4)? I can do $request->all() what gives me an array with all the images base64 strings combined. I cannot do anything with that because whatever I do with that array will result in a 500 error.
This is my script to convert the images and post them.
let queue = [];
function addFile(input) {
let files = input.files,
j = files.length,
file;
for (i = 0; i < j; i += 1) {
let reader = new FileReader();
reader.onloadend = function (e) {
$('#upload-InnerPanel').append(
"<div class='upload-ItemPanel'><img class='upload-ImagePreview' src='" + e.target.result + "' > </div>");
queue.push(reader.result);
};
file = files[i];
reader.readAsDataURL(file);
}
}
$('#upload-ButtonSelect').on("click" , function () {
$('#upload-UploadInput').click();
});
$('#upload-UploadInput').change(function () {
addFile(this);
});
$('#upload-ButtonUpload').click(function () {
$.ajax({
url: "/admin/upload",
type: "POST",
data: queue,
processData: false,
error: function(xhr, status, error) {
let err = xhr.responseText;
//console.log(err);
$('#upload-InnerPanel').append("<iframe width='600' height='500' src='" + err +"'> </iframe>")
},
success: function (xhr) {
console.log(xhr);
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
});
This is my controller:
public function upload(Request $request)
{
return var_dump($request->all());
}
That works, sort of, because My response is one long base64 in an array with just 1 item. Even if I add multiple images I just get one item in the array instead of three. It now combines them all in to one. Also, as I said. I cannot do anything with that array what does not result in a 500 error.
So my question is:
How do I get it to work so I can post multiple items instead of one and get the data on the backend?
You could add each file as a new input on your form, so that you have them separately on the back end.
In your addFile Javascript, instead of queue.push(reader.result), append a hidden input with the results:
reader.onloadend = function (e) {
// ... your code
// Update the form selector to suit your form
$('form').append('<input type="hidden" name="files[]" value="' + reader.result + '">');
};
Then in your ajax form submission:
$('#upload-ButtonUpload').click(function () {
// Again update the form selector to suit your form
var data = $('form').serialize();
$.ajax({
url: "/admin/upload",
type: "POST",
data: data,
// ... etc
Related
$(document).ready(function () {
//Define an array
var fileCollection = new Array();
$('#file').on('change', function (e) {
var files = e.target.files;
$.each(files, function (i, file) {
fileCollection.push(file);//I'm adding the previewed pictures into the series.
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
var template = '<li>' +
'<img src="' + e.target.result + '" width="50" height="50"> ' +
'<label>' + file.name + file.size + '</label> <input type="text" name="title">' +
' <button class="btn btn-sm btn-info upload">Yükle</button>' +
' Sil' +
'</li>';
$("#prewiew").append(template);
$("#file").val('');
}
});
});
How can I get the data of the image I added with the name of the upload class and post it ?
I want the user to submit the data to the database by clicking the upload button after previewing.
I want to submit without using a form tag, is this possible ? Because using a form tag I will post a lot of data with an image.
That's why I want to dynamically send only the pictures in the preview section ?
$(document).on("click", ".upload", function () {
/* I want to submit without using a form tag, is this possible? Because using a form tag I will post a lot of data with an image.
* That's why I want to dynamically send only the pictures in the preview section. */
//If the user clicks the upload button, I want to send the values in the array. But I'm having trouble. Do you have any ideas?
$.ajax({
url: '/Home/ImagePost/',
type: 'POST',
data: fileCollection, //I cannot send the defined array and its values.
contentType: false,
processData: false,
success: function () {
},
});
});
$(document).on("click", ".remove", function () {
var removeDelete = $(this).closest("li");
removeDelete.remove();
});
Yes you can Use the following code to send only the picture
var pictureData = new FormData(document.getElementById("yourFileID"));
pictureData.append("label", "myPicture"); //this is to identify on server
$.ajax({
url: "/Home/ImagePost/",
type: "POST",
data: pictureData,
processData: false,
contentType: false,
success: function () {
}
})
I was working on making a facial recognition system. I used the API called Kairos.The response I got back is the data of the feature of a face or an error message from a nonface image. How can I change the response and display them on the screen, such as "success! It's a face" or "There's no face". I tried to if/else statement, but it seems that there's no response from it. How should I do it?
<script>
$("#testDetect").click(function () {
var file = $('#imageFile')[0].files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = function () {
var imageData = parseImageData(reader.result);
var data = {};
data.image = imageData;
$.ajax({
url : "http://localhost/Karios/simple-detect/form-post.php",
type : "POST",
data : data,
dataType : 'text'
}).done(function(response) {
console.log(response);
if (!response) { // Something unexpected happened. The message body is empty.
alert('Hmm, unexpected response from Kairos');
} else if (response['Errors'] && response['Errors'].size() > 0) { // If Errors is defined in the response, something went wrong.
if (response['Errors'][0]['ErrCode'] == 5002) { // This appears to be the error when no faces are found.
alert(response['Errors'][0]['Message']);
} else {
alert('Some other error occurred:\n' + response['Errors']['ErrorCode'] + ': ' + response['Errors']['Message']);
}
} else { // If there are no errors in the response, can we assume it detected a face? I guess so.
alert('Face(s) detected');
// The response has a ton of information about what it saw, including gender, age, ethnicity
// and more.
}
})
}
});
Based on the response that you receive, you can write what you want to be displayed:
if(response === true){
alert('success!');
}
else{
alert('fail!');
}
EDIT
To redirect to another page, use: window.location = http://mywebsite.com;
To make a button unclickable, you will need to set the disabled attribute: document.querySelector('button').setAttribute('disabled',true);
EDIT
If this is your response: {"Errors":[{"Message":"no faces found in the image","ErrCode":5002}]} then you will have to parse it first because it will most likely be a string. Then in your conditional statement, check to see if it exists.
var obj = '{"Errors":[{"Message":"no faces found in the image","ErrCode":5002}]}';
obj = JSON.parse(obj);
if(obj.Errors){
console.log("errors exist");
}
In addition to .done(), you can call .fail() which will run when the ajax was unsuccessful.
$("#testDetect").click(function() {
var data = {}
$.ajax({
url: "http://localhost/Karios/simple-detect/form-post.php",
type: "POST",
data: data,
dataType: 'text'
}).done(function(response) {
alert(response)
}).fail(function(error) {
alert("Not a face")
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="testDetect">Test</button>
I have a problem uploading files using jQuery Ajax and Web API. When I make a POST to my API, I am not getting uploaded files in my controller.
In my HTML I have several file inputs with class="file" like this:
<form id="edit" enctype="multipart/form-data">
<input class="file" type="file" name="field_custom_file" accept='image/*' />
<input class="file" type="file" name="field_custom_file" accept='image/*' />
<input class="file" type="file" name="field_custom_file" accept='image/*' />
</form>
In addittion, I have a button which executes a Javascript function:
function send() {
var files = $('.file')[0].files;
if (files.length > 0) {
if (window.FormData !== undefined) {
var data = new FormData();
for (var x = 0; x < files.length; x++) {
data.append("file" + x, files[x]);
}
$.ajax({
type: "POST",
url: '/api/tripgroups',
contentType: false,
processData: false,
data: data,
success: function (result) {
toastr.success('Trip Group was updated!');
},
error: function (xhr, status, p3, p4) {
var err = "Error " + " " + status + " " + p3 + " " + p4;
if (xhr.responseText && xhr.responseText[0] == "{")
err = JSON.parse(xhr.responseText).Message;
console.log(err);
},
enctype: 'multipart/form-data',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
});
} else {
alert("This browser doesn't support HTML5 file uploads!");
}
}
}
Finally, in my web api controller, if I try to access HttpContext.Current.Request.Files I get an empty collection, and if I try to access content like this:
var streamProvider = new MultipartFormDataStreamProvider("images");
await Request.Content.ReadAsMultipartAsync(streamProvider);
Then I get this error:
Invalid 'HttpContent' instance provided. It does not have a content
type header starting with 'multipart/'. Parameter name: content
Thanks in advance.
You are using API so your request is an HttpResponseMessage.
If you are not in a hurry I would suggest absorbing this article. http://www.asp.net/web-api/overview/advanced/sending-html-form-data-part-2
If you are indeed on a deadline, I would suggest posting 1 file at a time and explain the limitations of uploading many files at once. Otherwise use a third party API to learn from and reverse engineer it for yourself.
I finally figured it out.
I changed my Ajax call as #guest271314 suggests to get all file inputs:
var files = $('.file');
if (files.length > 0) {
if (window.FormData !== undefined) {
var data = new FormData();
for (var x = 0; x < files.length; x++) {
data.append("file" + x, files[x].files[0]);
}
$.ajax({
type: "POST",
url: '/api/tripgroups',
contentType: false,
processData: false,
data: data,
success: function (result) {
toastr.success('Trip Group was updated!');
}
});
} else {
alert("This browser doesn't support HTML5 file uploads!");
}
}
And the main issue was on my controller, because I had another parameter
public async Task<HttpResponseMessage> Post(SomeClass param)
when I removed that parameter it receives files correctly.
I still don't know how to receive a JSON object and files in the same request (if it is possible) but I split out into 2 different controllers and works well.
Thanks everyone for your help!
I am able to upload an image file to SharePoint, but it is not being recognized as an image. I have tried utilizing the following directive based on research that states images need to be base64 encoded when uploaded into SharePoint, but it still uploads a file that appears to be corrupt: https://github.com/adonespitogo/angular-base64-upload
I am happy to use this directive, but am unsure of how to pass what I need into SharePoint's REST API.
The original iteration I had does not use this directive, but is more of a straight upload attempt.
What I need to achieve is as follows:
1) Successfully upload an image without it being "corrupted", and does this require base64 encoding/how do I achieve this?
2) Upload images by their name (not "test.jpg") and have some metadata (ex. upload an image with the title or department name it belongs to)
Iteration 1: No Directive
Here is my HTML (Please note that the controller is tied to the page via ng-route):
<div class="col-md-12">
<form>
<input type="file" onchange="angular.element(this).scope().filesChanged(this)" data-ng-model="files" multiple>
<button data-ng-click="upload()">Submit</button>
<li data-ng-repeat="file in files">{{file.name}}</li>
</form>
</div>
Here is my controller:
$scope.filesChanged = function (elm) {
$scope.files = elm.files
$scope.$apply();
}
$scope.upload = function () {
var fd = new FormData()
angular.forEach($scope.files,function(file){
fd.append('file',file)
})
$http.post("/sites/asite/_api/web/lists/getByTitle('Images')/RootFolder/Files/add(url='test.jpg',overwrite='true')", fd,
{
transformRequest: angular.identity,
headers: {
'Content-Type':undefined, 'X-RequestDigest': $("#__REQUESTDIGEST").val()}
}).success(function (d) {
console.log(d);
});
}
UPDATE: I believe the issue is isolated to my $http post to SharePoint. Using the directive mentioned above, I am able to output the base64, but am unsure how to pass this into my post for upload.
Iteration 2: Using Directive
Here is my current HTML using the https://github.com/adonespitogo/angular-base64-upload directive:
<form>
<input type="file" data-ng-model="files" base-sixty-four-input>
<button data-ng-click="upload()">Submit</button>
</form>
My controller that is posting the corrupted image files to SharePoint:
$scope.upload = function () {
console.log($scope.files); // Output result from upload directive
$http({
method: 'POST',
url: "/sites/ens/_api/web/lists/getByTitle('Report Images')/RootFolder/Files/add(url='" + $scope.files.filename +"',overwrite='true')",
headers: {
'Content-Type': false ,
'X-RequestDigest': $("#__REQUESTDIGEST").val()
},
data: $scope.files,
}).success(function (data) {
console.log(data);
});
}
Update 2: Using SP.RequestExecutor as follows creates the same result. A file upload but not rendering. This happens for images and documents:
Iteration 3: Using Directive and SP.RequestExecutor
$scope.upload = function () {
var dataURL = 'data:' + $scope.files.filetype + ';' + 'base64,' + $scope.files.base64;
var createitem = new SP.RequestExecutor("/sites/asite");
createitem.executeAsync({
url: "/sites/asite/_api/web/lists/getByTitle('Images')/RootFolder/Files/add(url='" + $scope.files.filename + "')",
method: "POST",
binaryStringRequestBody: true,
body: dataURL,
success: fsucc,
error: ferr,
state: "Update"
});
function fsucc(data) {
alert('success');
}
function ferr(data) {
alert('error\n\n' + data.statusText + "\n\n" + data.responseText);
}
}
Update 3: Using .ajax as follows, it will successfully post the image, but when using $http, it corrupts the image.
Iteration 3: Using .Ajax (works)
function uploadFileSync(spWebUrl , library, filename, file)
{
var reader = new FileReader();
reader.onloadend = function(evt)
{
if (evt.target.readyState == FileReader.DONE)
{
var buffer = evt.target.result;
var completeUrl = spWebUrl
+ "/_api/web/lists/getByTitle('"+ library +"')"
+ "/RootFolder/Files/add(url='"+ filename +"',overwrite='true')?"
+ "#TargetLibrary='"+library+"'&#TargetFileName='"+ filename +"'";
$.ajax({
url: completeUrl,
type: "POST",
data: buffer,
async: false,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"content-length": buffer.byteLength
},
complete: function (data) {
//uploaded pic url
console.log(data.responseJSON.d.ServerRelativeUrl);
$route.reload();
},
error: function (err) {
alert('failed');
}
});
}
};
reader.readAsArrayBuffer(file);
}
Iteration 4: Using $http (corrupts image)
function uploadFileSync(spWebUrl , library, filename, file)
{
var reader = new FileReader();
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) {
var buffer = evt.target.result;
var completeUrl = spWebUrl
+ "/_api/web/lists/getByTitle('" + library + "')"
+ "/RootFolder/Files/add(url='" + filename + "',overwrite='true')?"
+ "#TargetLibrary='" + library + "'&#TargetFileName='" + filename + "'";
$http({
url: completeUrl,
method: "POST",
data: buffer,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"content-length": buffer.byteLength
}
}).success(function (data) {
//uploaded pic url
//console.log(data.responseJSON.d.ServerRelativeUrl);
$route.reload();
}).error(function (err) {
alert(err);
});
}
};
reader.readAsArrayBuffer(file);
}
Yes, you must do the base64 encoding.
Following this article, your filesChanged will be function for base64 encoding:
$scope.filesChanged = function (input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
//Sets the Old Image to new New Image
$('#photo-id').attr('src', e.target.result);
//Create a canvas and draw image on Client Side to get the byte[] equivalent
var canvas = document.createElement("canvas");
var imageElement = document.createElement("img");
imageElement.setAttribute('src', e.target.result);
canvas.width = imageElement.width;
canvas.height = imageElement.height;
var context = canvas.getContext("2d");
context.drawImage(imageElement, 0, 0);
var base64Image = canvas.toDataURL("image/jpeg");
//Removes the Data Type Prefix
//And set the view model to the new value
$scope.data.Photo = base64Image.replace(/data:image\/jpeg;base64,/g, '');
}
//Renders Image on Page
reader.readAsDataURL(input.files[0]);
}
};
My advice to you is also to change ng-model from $scope.files to $scope.data.Photo to avoid problems with scope and add an id in your input tag. (in this case id="photo-upload")
So, your HTML for upload will look like:
<input type="file" onchange="angular.element(this).scope().filesChanged(this)" data-ng-model="data.Photo" id="photo-upload" multiple>
And for representing your uploaded pic, in your case, you can use this:
<img ng-src="data:image/jpeg;base64,{{data.Photo}}" id="photo-id"/>
I'm just not sure for multiple upload, but for single upload it works great for me.
Hope this will help you to solve your problem with SharePoint.
Good luck!
I need some help here..
Im trying to save a canvas image after drawing..
following this example (http://www.dotnetfunda.com/articles/article1662-saving-html-5-canvas-as-image-on-the-server-using-aspnet.aspx)
$("#btnSave").click(function () {
var image = document.getElementById("canvas").toDataURL("image/png");
image = image.replace('data:image/png;base64,', '');
$.ajax({
type: 'POST',
url: "../../Home/UploadImage?imageData=" + image,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (msg) {
alert('Image saved successfully !');
}
});
});
the controller:
public void UploadImage(string imageData)
{
string fileNameWitPath = path + DateTime.Now.ToString().Replace("/", "-").Replace(" ", "- ").Replace(":", "") + ".png";
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(imageData);
bw.Write(data);
bw.Close();
}
}
}
But when im trying to convert form base64 the string that is passed like parameter in method, throw an error
Invalid length for a character array Base-64.
You can't post data with querystring parameters
Try this;
$("#btnSave").click(function () {
var image = document.getElementById("canvas").toDataURL("image/png");
image = image.replace('data:image/png;base64,', '');
$.ajax({
type: 'POST',
url: "../../Home/UploadImage",
data: '{ "imageData" : "' + image + '" }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (msg) {
alert('Image saved successfully !');
}
});
});
In that example, the author has posted the image data using a hidden field, notice below line of code in his article
<input type="hidden" name="imageData" id="imageData" />
http://www.dotnetfunda.com/articles/show/2665/saving-html-5-canvas-as-image-in-aspnet-mvc
And on click of the button, he is submitting the form after getting canvas data to the hidden field so follow the same approach. As written by Mehmet, querystring has limitations and its prone to be modified as it goes via url.
Instead of this
image = image.replace('data:image/png;base64,', '');
use this:
image = image.substr(23, image.length);
remove the leading characters up to the first comma (use any dev tool to see what you posted).