I need to upload image and video files to the server in an Angular application using Laravel 5.1 as the back end. All Ajax requests need to go to the Laravel controller first, and we have the code there for how the file gets handled when it gets there. We have previously done normal HTML forms to submit file uploads to the controller, but in this case we need to avoid the page refresh of a form, so I am attempting this in Ajax through Angular.
What information do I need to send to the Laravel controller with Ajax that was being sent to the controller via an HTML form previously?
This is the code in the Laravel controller that handled the file information once it got there. That's what I need to figure out how to send, so I can hopefully reuse this code:
$promotion = Promotion::find($id);
if (Input::hasFile('img_path')){
$path = public_path().'/images/promotion/'.$id.'/';
$file_path = $path.'promotion.png';
$delete = File::delete($file_path);
$file = Input::file('img_path');
$uploadSuccess = $file->move($path, 'promotion.png');
$promotion->img_path = '/images/promotion/'.$id.'/promotion.png';
}
if (Input::hasFile('video_path')){
$path = public_path().'/video/promotion/'.$id.'/';
$file_path = $path.'promotion.mp4';
$delete = File::delete($file_path);
$file = Input::file('video_path');
$uploadSuccess = $file->move($path, 'promotion.mp4');
$promotion->video_path = '/video/promotion/'.$id.'/promotion.mp4';
}
As you can see above, we are converting whatever file we get to a PNG with the file name promotion.png so it's easy to fetch, and we are only accepting .mp4 video format. Because of that, we don't need to worry about checking if the file exists and is it ok to overwrite it. That's why you can see in the code we delete any existing file of that name before saving.
The HTML was just an input with a type of "file:
<input type="file" id="img_path" name="img_path" class="promo-img-path" accept="image/*">
We are using Angular now so I can't just send the above through an HTML form anymore. That's what I need to figure out how to do.
We are two developers just doing our best, so I'm sure there is a better way of doing this. However before I refactor this whole thing, I'm hoping I can use Angular (or jQuery as a last resort) to just send the controller whatever file data Laravel needs in order to make the above code work. The answer may be as simple as "send a PUT to the method in that controller above, but instead of a normal JSON payload, use file info in this format and you can gather that info with..."
I would also appreciate any tips on better ways I can do this in the future.
How to POST FormData Using the $http Service
When using the FormData API to POST files and data, it is important to set the Content-Type header to undefined.
var fd = new FormData()
for (var i in $scope.files) {
fd.append("fileToUpload", $scope.files[i]);
}
var config = {headers: {'Content-Type': undefined}};
var httpPromise = $http.post(url, fd, config);
By default the AngularJS framework uses content type application/json. By setting Content-Type: undefined, the AngularJS framework omits the content type header allowing the XHR API to set the content type. When sending a FormData object, the XHR API sets the content type to multipart/form-data with the proper boundaries and base64 encoding.
For more information, see MDN Web API Reference - XHR Send method
How did you get the file information into $scope.files?
How to enable <input type="file"> to work with ng-model
This directive also enables <input type="file"> to automatically work with the ng-change and ng-form directives.
angular.module("app",[]);
angular.module("app").directive("selectFilesNg", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-files-ng ng-model="fileArray" multiple>
<code><table ng-show="fileArray.length">
<tr><td>Name</td><td>Date</td><td>Size</td><td>Type</td><tr>
<tr ng-repeat="file in fileArray">
<td>{{file.name}}</td>
<td>{{file.lastModified | date : 'MMMdd,yyyy'}}</td>
<td>{{file.size}}</td>
<td>{{file.type}}</td>
</tr>
</table></code>
</body>
RECOMMENDED: POST Binary Files Directly
Posting binary files with multi-part/form-data is inefficient as the base64 encoding adds an extra 33% overhead. If the server API accepts POSTs with binary data, post the file directly.
See How to POST binary files with AngularJS (with DEMO)
Related
I have ASP.NET Core MVC back-end api. One controller returns File from server. Is there a way to make request to api route by [href] attribute of <a> tag? Looks like it tries to call React route but not make a request to server.
Also I made AJAX call to that controller and got back file as a string (screenshot is attached). Why is it a string, shouldn.t it be a byte array? How to build back file from that string? (it's a .pdf file). I have an empty PDF if use JavaScript new File([], 'name', {options}).
ASP.NET Core controller returns PDF this way:
return PhysicalFile(Path.GetFullPath(relativePath), "application/pdf", reportName);
In React I receive it as a string this way:
let stringPDFBinary = await ReportService.getReport(id, reportFileName)
I just need to download file from api by any way.
So, the answer is here: PDF is blank when downloading using javascript
The same problem. Let it be one more topic, easier to find for others. The AJAX response is encoded string. In request config set 'responseType = 'arraybuffer'' somehow and receiving pdf will not be blank. Solved.
I Just copied and pasted from the code source. The problem seems to be the same that i had:
Asp net controller:
[HttpGet]
[Route("File")]
[AllowAnonymous]
public IActionResult GetFile(string key)
{
var file = (FileCacheValue)_fileCache.Cache[key.Replace(" ", "+")];
if (file == null)
return NotFound();
Response.Headers["content-disposition"] = $"inline;filename={file.Name}.pdf";
return File(file.Data, "application/pdf");
}
In this case comes from a cache system. The data is a byte array.
Front-end React:
const onClick = () =>
{
window.open(pdfByteArray, '_blank', 'fullscreen=yes');
}
Exactly what i have. I just put the data on a new window and open the pdf.
The Ajax part is straight forward, get the value from the response and set it on a variable
I am using nervgh/angular-file-upload to upload files. As I know, this angular-file-upload has their own upload functions.
Currently I need only the files inside the uploader, and then I will use my custom http post
$scope.UploadUserFiles = function () {
$scope.UserFileRequest = {"File": uploader, "User": myUser}
$http.post(host + "/api/user", $scope.UserFileRequest).then(function (response) { });
}
Currently I am having the trouble of getting those files from the uploader since I have no idea about the properties and structure. But for User is my own class at the web api, so I have no problem to get any info that I want.
The main problem is I have no idea how to catch/initialize the uploader it into a variable after post to my web api.
[HttpPost]
[Route("api/user")]
public UserFileResponse GetUserFile(UserFileRequest userFileRequest)
{
//What should I do to get the Files from the request and save into the server?
}
My UserFileRequest contain the info of myUser, but I do not know what to do with the uploader since I do not have a class to hold it.
From what I understand in your question, you are having trouble getting the files in the queue into your own file upload function.
The functions within the FileUploader class have callbacks that you can use, but another way to easily expose the file queue would be to create your own callback once the 'upload' button is clicked.
someFxn(item) {
console.log(item);
_someUploadFxn(item)
}
<md-button class="md-blue" ng-click="$ctrl.someFxn(item)" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
Upload
</md-button>
This will allow you to view the file that has been queued up and from there you can pass it or whatever properties you need off that file object into your own uploader function.
The same goes for if you are wanting to upload a bunch of files at once.
i try to make angular CRUD app that is a bit like "dropbox". So, it must have file and folder hosting with sharing and access functionality. I'm stuck on a question how to upload image and video files? I used File API (FileReader, Blob) to make preview of files on the client side but i dont have idea how to POST this type of data to server.
Something like this should work well to send as multipart/form-data request to backend API:
var file = ... // get from file input;
var backendUrl = ...
var fd = new FormData();
fd.append('myFile', file, 'filename.ext');
$http.post(backendUrl, fd, {
// this cancels AngularJS normal serialization of request
transformRequest: angular.identity,
// this lets browser set `Content-Type: multipart/form-data`
// header and proper data boundary
headers: {'Content-Type': undefined}
})
.success(function(){
//file was uploaded
})
.error(function(){
//something went wrong
});
See here for reference:
FormData API Doc
Using FormData Objects (MDN)
multipart-formdata file upload with AngularJS
You can upload file using ngFileUpload or angularFileUpload directives.
In case of angularFileUpload, you use .upload in controller and in case of ngFileUpload, you use .http
Also, you can also use application/x-www-form-urlencoded content type instead of multipart provided your file is not huge. In case of application/x-www-form-urlencoded, you can just receive the value in rest webservice as normal InputStream thereby requiring no need of marshalling of multipart data.
You may refer the below for the possible ways to upload file using angular js and rest web service:
http://technoguider.com/2015/08/file-upload-using-angular-js-and-rest-web-service/
Folks I have a form on my website who's data I want to store in a json file.
Here is the code for the form:
<form>
<input ng-model="obj.firstname">
<input ng-model="obj.lastname">
<button ng-click="storedata()">Click here to store data</button>
</form>
My Angular code is as below:
var myApp = angular.module('app', ['ui.bootstrap.dialog','ngResource']);
myApp.controller('TestCtrl', function($scope,$dialog,TestResource) {
$scope.obj = {};
$scope.obj.firstname = "Mahatma";
$scope.obj.lastname = "Gandhi";
$scope.storedata = function() {
console.log("Storing Data now");
TestResource.save($scope.obj);
console.log("Data should have been stored");
}
});
myApp.factory('TestResource', ['$resource', function($resource) {
return $resource('test.json', {}, {} );
}]);
The problem is that the data does not get stored. Am I missing something here ?
Here is a plunkr : http://plnkr.co/edit/gist:3662702
ngResource is an Angular service designed to interact with RESTful server side data sources (see ngResource docs). The angular js tutorials tend to reference local JSON files since they're meant to be stand-alone examples which anyone can download and run locally without the need for a back-end server. But you'll notice the tutorials only read data from the JSON files, they cannot update them.
If you're looking to save data client side, check out LocalStorage (http://diveintohtml5.info/storage.html).
If you're trying to save the data server side, you'll need to setup some back end service (via NodeJS, PHP, .NET, Ruby, Python, and many other frameworks..)
I'm trying to upload a file to a RESTful PUT url with YUI3, but when I set upload to true in the config to io it sends the file as POST not PUT. If I remove the upload setting in the config I just get the filename, but it does go to the PUT url. Can I use PUT with a file upload? Is there another way to do this?
I'm assuming this is a failure/fault in YUI3 or rather my use of it.
Form:
<form id='GFileForm' method='PUT' onSubmit='return false;'>
<input type='file' name='gfile' id='GFileName'>
<input type='submit' name='gfileupload' value='Upload' id='GFileUpload_Button'>
</form>
JS:
var cfg = {
method: "PUT",
form: {id: 'GFileForm', upload: true},
content_type: "multipart/form-data",
};
var request = Y.io(sUrl, cfg);
Any help is here much appreciated.
I've also tried to find a resource on reading the file contents with javascript and then pushing that into the PUT data, but I can't seem to find anything about that. Does anyone know if that's a possiblilty?
Cheers,
Andy.
PUT is not a standard way of sending form data and most web browsers don't support it, unfortunately.
Check this example. https://github.com/chmouel/cors-swift-example
In this example, you can see how we can PUT files to RESTful PUT url.