I need to download a file from server using Web API and angularJs. I am using below code for in API controller. When i hit the API through browser i can able to download the file. i don't have no idea, what to do with angualar
Web API
public HttpResponseMessage GetBrandByFilter(string filePath)
{
filePath = "C:\\Temp\\DTA 517280.pdf"; //Just hard coded for testing
var fileinfo = new FileInfo(filePath);
try
{
var excelData = File.ReadAllBytes(filePath);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(excelData);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = fileinfo.Name
};
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.ExpectationFailed, ex);
}
}
Angular Controller
$scope.downloadFile = function () {
var result = downloadFile(service, "URL path");
result.then(function (res, status, headers) {
//****
// looking for this code on success
//****
},
function (err) {
debugger;
handleException($scope, err);
})
};
If you want, you can use a directive like this:
angular.module('app')
.directive('fileDownload', [function () {
return {
restrict: 'A',
replace: true,
scope: {},
template: '<button class="btn btn-default" data-ng-click="download()"><span class="glyphicon glyphicon-download"></span></button>',
controller: ['$scope', '$element', '$attrs', '$timeout', function ($scope, $element, $attrs, $timeout) {
$scope.progress = 0;
function prepare(url) {
console.log("Please wait, Your download starts in a few seconds.", $scope.progress);
fakeProgress();
}
function success(url) {
console.log("download complete");
}
function error(response, url) {
console.log("Couldn't process your download!");
}
function fakeProgress() {
$timeout(function () {
if ($scope.progress < 95) {
$scope.progress += (96 - $scope.progress) / 2;
fakeProgress();
}
}, 250);
}
$scope.download = function () {
$scope.progress = 0;
$.fileDownload($attrs.href, { prepareCallback: prepare, successCallback: success, failCallback: error });
}
}]
}
}]);
and use it like this:
<a href="/yourfiletodownload.pdf" file-download></a>
Related
I'm trying to build the back and front end parts of files uploader in an app built with jhipster 4.0.0, with angularjs.
How can I proceed ? Jhipster is actually giving acess for creating blob type columns with the entities builder , but isn't it a bad idea to store image in the database?
So, how can I build that file uploader ?
Another option you can consider if you don't want to save the file/image as a blob to the database is to create a separate file upload/retrieval service (ours was using MongoDB gridFs as we were dealing with large files) and only send the file id (or file path) of the successfully uploaded file when you save/update the entity.
You can use ng-file-upload to help manage this, note that below code is using angularJS version 1.
<form name="editForm" role="form" novalidate ng-submit="save(userUploadedFile)" show-validation>
<div class="form-group">
<div ng-show="entity.image == null">
<label class="control-label" for="field_file">Image</label>
<input type="file" ngf-select ng-model="userUploadedFile" name="file" id="field_file"
ngf-max-size="8MB" ng-disabled="disableFile" ngf-change="upload($files)" ngf-accept="'image/*'"/>
<button type="button" ng-click="removeUserUploadedFile()" ng-show="userUploadedFile">Remove</button>
</div>
<div ng-show="editForm.file.$invalid">
<p class="help-block" ng-show="editForm.file.$error.maxSize">Error! Image exceeds 8MB file limit</p>
</div>
<my-server-file file-id="entity.image" on-delete="onRemoveServerFile()"/>
</div>
<!-- include submit button etc -->
</form>
The my-server-file directive:
angular.module('myApp')
.directive('myServerFile', function(UrlService, FileService, $log) {
return {
restrict: 'E',
scope: {
fileId: "=fileId",
callbackOnDelete: "&onDelete"
},
template : "<div ng-if='fileId'>" +
"<a ng-if='fileId' ng-href='{{serverFilePath}}' target='_blank' download='{{fileName}}'>{{fileName}}</a>" +
"<button type='button' ng-click='deleteServerFile()' ng-show='fileId'>Remove</button>" +
"</div>",
controller: ['$scope',
function($scope) {
$scope.getFile = function(fileId) {
if(fileId){
$scope.serverFilePath = UrlService.getContextPath() + '/api/file/' + fileId;
FileService.getFileMetaData(fileId).then(function(file){
$scope.fileName = file.name;
});
}
}
$scope.deleteServerFile = function(){
FileService.deleteFile($scope.fileId).then(function() {
$scope.callbackOnDelete();
});
}
}
],
link: function(scope, iElement, iAttrs, ctrl) {
scope.$watch('fileId', function(value) {
scope.getFile(value);
})
}
}
})
Your controller will need to upload the file before it saves.
'use strict';
angular.module('myApp').controller('myAppController',
['$scope', '$stateParams', '$uibModalInstance', 'entity', 'UrlService', 'Upload', '$timeout', 'MyEntity'
function($scope, $stateParams, $uibModalInstance, entity, UrlService, Upload, $timeout, MyEntity) {
$scope.entity = entity;
$scope.load = function(id) {
MyEntity.get({id : id}, function(result) {
$scope.entity = result;
});
};
$scope.onRemoveServerFile = function() {
//Need to remove the file reference from the entity.
$scope.entity.image = null;
if($scope.entity.id){
MyEntity.update($scope.entity);
}
}
$scope.removeUserUploadedFile = function() {
$scope.userUploadedFile = null;
}
var uploadFile = function(file){
file.upload = Upload.upload({
url: UrlService.getContextPath() + '/api/file',
file: file
});
file.upload.then(function (response) {
$timeout(function () {
file.result = response.data;
$scope.entity.image = file.result.fileId;
saveEntity();
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
var onSaveSuccess = function (result) {
$scope.isSaving = false;
$scope.$emit('myApp:entityUpdate', result);
$uibModalInstance.close(result);
};
var onSaveError = function (result) {
$scope.isSaving = false;
};
var saveEntity = function() {
$scope.isSaving = true;
if ($scope.entity.id != null) {
MyEntity.update($scope.entity, onSaveSuccess, onSaveError);
} else {
MyEntity.save($scope.entity, onSaveSuccess, onSaveError);
}
};
$scope.save = function (file) {
if(file != null){
uploadFile(file);
}
else {
saveEntity();
}
};
}]);
This does introduce some drawbacks though, when you delete the entity you will need to delete the file separately.
Create a simple FileSerivce to interact with the backend.
angular.module('myApp')
.factory('FileService', function ($http) {
return {
getFile: function(fileId) {
return $http.get('api/file/' + fileId).then(function (response) {
return response.data;
});
},
getFileMetaData: function(fileId) {
return $http.get('api/file/' + fileId + '/metaData').then(function (response) {
return response.data;
});
},
deleteFile: function(fileId) {
return $http.delete('api/file/' + fileId);
}
}
});
And finally your REST controller, here we are delegating to a custom wrapper for GridFs but you could just save it to the file system and return the full path as the id.
#RestController
#RequestMapping("/api/file")
public class FileController {
private final Logger log = LoggerFactory.getLogger(FileController.class);
#Inject
private GridFsService gridFsService;
#RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> upload(#RequestParam("file") MultipartFile file)
throws IOException {
GridFSFile storeFile = null;
if (!file.isEmpty()) {
storeFile = gridFsService.storeFile(file);
}
Map<String, String> map = new HashMap<>();
map.put("fileId", storeFile.getId().toString());
return map;
}
#RequestMapping(value="/{fileId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<InputStreamResource> getFile(
#PathVariable String fileId) throws IOException {
return gridFsService.getFile(fileId).map(f -> new ResponseEntity<> (
new InputStreamResource(f.getInputStream()),
HeaderUtil.createFileContentLengthAndContentTypeHeaders(f.getLength(), f.getContentType()),
HttpStatus.OK
)).orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
#RequestMapping(value="/{fileId}/metaData",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<Map<String, String>> getFileMetaData(
#PathVariable String fileId) throws IOException {
Optional<GridFSDBFile> optFile = gridFsService.getFile(fileId);
if(!optFile.isPresent()){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
GridFSDBFile file = optFile.get();
Map<String, String> map = new HashMap<>();
map.put("name", file.getFilename());
map.put("contentType", file.getContentType());
map.put("size", String.valueOf(FileUtils.byteCountToDisplaySize(file.getLength())));
return ResponseEntity.ok()
.body(map);
}
#RequestMapping(value="/{fileId}", method = RequestMethod.DELETE)
public void deleteFile(
#PathVariable String fileId) throws IOException {
log.debug("REST request to delete File : {}", fileId);
gridFsService.deleteFile(fileId);
}
}
I have an AngularJS Directive defined in a Javascript file that looks like this:
(function () {
'use strict';
angular
.module('ooApp.controllers')
.directive('fileUploader', fileUploader);
fileUploader.$inject = ['appInfo', 'fileManager'];
function fileUploader(appInfo, fileManager) {
var directive = {
link: link,
restrict: 'E',
templateUrl: 'views/directive/UploadFile.html',
scope: true
};
return directive;
function link(scope, element, attrs) {
scope.hasFiles = false;
scope.files = [];
scope.upload = fileManager.upload;
scope.appStatus = appInfo.status;
scope.fileManagerStatus = fileManager.status;
}
}
})();
and in the template URL of the directive there is a button that calls a Javascript function which looks like this:
function upload(files) {
var formData = new FormData();
angular.forEach(files, function (file) {
formData.append(file.name, file);
});
return fileManagerClient.save(formData)
.$promise
.then(function (result) {
if (result && result.files) {
result.files.forEach(function (file) {
if (!fileExists(file.name)) {
service.files.push(file);
}
});
}
appInfo.setInfo({ message: "files uploaded successfully" });
return result.$promise;
},
function (result) {
appInfo.setInfo({ message: "something went wrong: " +
result.data.message });
return $q.reject(result);
})
['finally'](
function () {
appInfo.setInfo({ busy: false });
service.status.uploading = false;
});
}
Once I select files for upload and click the upload button I need to reload the directive or somehow get it back to it's initial state so I can upload additional files. I'm relatively new to AngularJS and I'm not quite sure how to do this. Any help is much appreciated.
Thanks,
Pete
You just need to create a reset method. Also, you may want to call the parent controller function.
Using answer from this
ngFileSelect.directive.js
...
.directive("onFileChange",function(){
return {
restrict: 'A',
link: function($scope,el){
var onChangeHandler = scope.$eval(attrs.onFileChange);
el.bind('change', onChangeHandler);
}
}
...
fileUploader.directive.js
(function () {
'use strict';
angular
.module('ooApp.controllers')
.directive('fileUploader', fileUploader);
fileUploader.$inject = ['appInfo', 'fileManager'];
function fileUploader(appInfo, fileManager) {
return {
link: link,
restrict: 'E',
templateUrl: 'views/directive/UploadFile.html',
scope:{
onSubmitCallback: '&',
onFileChange: '&'
}
};
function link(scope, element, attrs) {
scope.reset = reset;
scope.fileChange = fileChange;
reset();
function reset() {
scope.hasFiles = false;
scope.files = [];
scope.upload = fileManager.upload;
scope.appStatus = appInfo.status;
scope.fileManagerStatus = fileManager.status;
if(typeof scope.onSubmitCallback === 'function') {
scope.onSubmitCallback();
}
}
function fileChange(file) {
if(typeof scope.onFileChange === 'function'){
scope.onFileChange(file);
}
}
}
}
})();
UploadFile.html
<form>
<div>
...
</div>
<input type="submit" ng-click="reset()" file-on-change="fileChange($files)" />Upload
</form>
parent.html
<file-uploader on-submit-callback="onUpload" on-file-change="onFileChange" ng-controller="UploadCtrl" />
upload.controller.js
...
$scope.onUpload = function() {
console.log('onUpload clicked %o', arguments);
};
$scope.onFileChange = function(e) {
var imageFile = (e.srcElement || e.target).files[0];
}
...
Is there a way to make a copy button with a copy function that will copy all the contents of a modal and you can paste it to notepad
I needed this functionality in my Controller, as the text to be copied is dynamic, here's my simple function based on the code in the ngClipboard module:
function share() {
var text_to_share = "hello world";
// create temp element
var copyElement = document.createElement("span");
copyElement.appendChild(document.createTextNode(text_to_share));
copyElement.id = 'tempCopyToClipboard';
angular.element(document.body.append(copyElement));
// select the text
var range = document.createRange();
range.selectNode(copyElement);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
// copy & cleanup
document.execCommand('copy');
window.getSelection().removeAllRanges();
copyElement.remove();
}
P.S.
You're welcome to add a comment now telling me how bad it is to manipulate DOM from a Controller.
If you have jquery support use this directive
.directive('copyToClipboard', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.click(function () {
if (attrs.copyToClipboard) {
var $temp_input = $("<input>");
$("body").append($temp_input);
$temp_input.val(attrs.copyToClipboard).select();
document.execCommand("copy");
$temp_input.remove();
}
});
}
};
});
Html
Copy text
if you don't want to add a new library to your project, and you create it by your self, here is a simple, easy solution:
note: I created it with promise functionality (which is awesome)
here is CopyToClipboard.js module file
angular.module('CopyToClipboard', [])
.controller('CopyToClipboardController', function () {
})
.provider('$copyToClipboard', [function () {
this.$get = ['$q', '$window', function ($q, $window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
return {
copy: function (stringToCopy) {
var deferred = $q.defer();
deferred.notify("copying the text to clipboard");
textarea.val(stringToCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = $window.document.execCommand('copy');
if (!successful) throw successful;
deferred.resolve(successful);
} catch (err) {
deferred.reject(err);
//window.prompt("Copy to clipboard: Ctrl+C, Enter", toCopy);
} finally {
textarea.remove();
}
return deferred.promise;
}
};
}];
}]);
that's it, thanks to https://gist.github.com/JustMaier/6ef7788709d675bd8230
now let's use it
angular.module('somthing')
.controller('somthingController', function ($scope, $copyToClipboard) {
// you are free to do what you want
$scope.copyHrefToClipboard = function() {
$copyToClipboard.copy(/*string to be coppied*/$scope.shareLinkInfo.url).then(function () {
//show some notification
});
};
}
and finally the HTML
<i class="fa fa-clipboard" data-ng-click="copyHrefToClipboard($event)"></i>
hope this saves your time
You can use a module I made, ngClipboard. Here's the link https://github.com/nico-val/ngClipboard
You can use either ng-copyable directive, or the ngClipboard.toClipboard() factory.
In HTML:
</img>
In Controller:
$scope.copyToClipboard = function (name) {
var copyElement = document.createElement("textarea");
copyElement.style.position = 'fixed';
copyElement.style.opacity = '0';
copyElement.textContent = decodeURI(name);
var body = document.getElementsByTagName('body')[0];
body.appendChild(copyElement);
copyElement.select();
document.execCommand('copy');
body.removeChild(copyElement);
}
document.execCommand is now deprecated. Instead you can do:
HTML:
<i class="fa fa-copy" ng-click="copyToClipboard('some text to copy')"></i>
Controller:
$scope.copyToClipboard = function(string) {
navigator.clipboard.writeText(string)
.then(console.log('copied!'));
}
try this:
app.service('ngCopy', ['$window', function ($window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
return function (toCopy) {
textarea.val(toCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful)
throw successful;
} catch (err) {
window.prompt("Copy to clipboard: Ctrl+C, Enter", toCopy);
}
textarea.remove();
}
}]);
You need to call this service to your controller. You can do like this:
controllers.MyController = ['$scope', 'ngCopy',
function ($scope, ngCopy) {
ngCopy(copyText);
}];
I searching for a way to enable the user select a file exists on the server and download it using angularjs , I found this code which didn't work , so does anyone have a way that works right
var content = 'file content';
var blob = new Blob([content], { type: 'text/plain' });
$scope.download = function () {
$window.location = (window.URL || window.webkitURL).createObjectURL(blob);
}
<input type="button" value="download" download="content.txt" ng-click="download()"/>
I do it this way:
Download
and use the directive:
angular.module('app')
.directive('fileDownload', [function () {
return {
restrict: 'A',
replace: true,
template: '<button class="btn btn-default" data-ng-click="download()"><span class="glyphicon glyphicon-download"></span></button>',
controller: ['$rootScope', '$scope', '$element', '$attrs', 'dialogs', '$timeout', function ($rootScope, $scope, $element, $attrs, dialogs, $timeout) {
$scope.progress = 0;
function prepare(url) {
dialogs.wait("Please wait", "Your download starts in a few seconds.", $scope.progress);
fakeProgress();
}
function success(url) {
$rootScope.$broadcast('dialogs.wait.complete');
}
function error(response, url) {
dialogs.error("Couldn't process your download!");
}
function fakeProgress() {
$timeout(function () {
if ($scope.progress < 95) {
$scope.progress += (96 - $scope.progress) / 2;
$rootScope.$broadcast('dialogs.wait.progress', { 'progress': $scope.progress });
fakeProgress();
}
}, 250);
}
$scope.download = function () {
$scope.progress = 0;
$.fileDownload($attrs.href, { prepareCallback: prepare, successCallback: success, failCallback: error });
}
}]
}
}]);
this uses the jQuery fileDownload function to download the file. (note: there is also the dialogs class in effect)
Prettyphoto stopped working after I changed the href url to an angular tag: {{something.uri}}
Javascript:
jQuery(".prettyphoto").prettyPhoto({
theme: 'pp_default',
overlay_gallery: false,
social_tools: false,
deeplinking: false,
theme: 'dark_rounded'
});
$("a[rel^='prettyPhoto']").prettyPhoto();
HTML:
<div ng-show="model.fileList" ng-repeat="fileList in model.fileList">
<a ng-href="{{fileList.uri}}" class="prettyphoto">
<img ng-src="{{fileList.uri}}" class="img-thumbnail" width="100" alt="" />
</a>
</div>
Angular scope from blobstorage:
fileList: [
{
parentContainerName: documents
uri: https://xxxxxx.blob.core.windows.net/documents/20140702.jpg
filename: 20140702.jpg
fileLengthKilobytes: 293
}
]
app.factory('storageService',
["$http", "$resource", "$q",
function ($http, $resource, $q) {
//resource to get summaryRoles
var resourceStorageManager = $resource('/api/storageManager/:id', { id: '#id' });
return {
getFileList: function () {
var deferred = $q.defer();
resourceStorageManager.query(, function (data) {
deferred.resolve(data);
}, function (status) {
deferred.reject(status);
}
);
return deferred.promise;
}
};
}]);
app.controller('startController', ['$scope', '$http', '$timeout', '$upload', 'storageService', 'settings',
function startController($scope, $http, $timeout, $upload, storageService, settings, profileRepository, notificationFactory, $q) {
$http.defaults.headers.common = { 'RequestVerificationToken': $scope.__RequestVerificationToken };
$scope.model = {};
$scope.model.fileList = null;
$scope.model.roundProgressData = {
label: 0,
percentage: 0.0
};
$scope.$on("pic_profileone_main", function (event, profileExtInfo1) {
$scope.changeprofilepicmodel1 = angular.copy(profileExtInfo1);
refreshServerFileList();
});
$scope.$on("pic_profiletwo_main", function (event, profileExtInfo2) {
$scope.changeprofilepicmodel2 = angular.copy(profileExtInfo2);
refreshServerFileList2();
});
$scope.onFileSelect = function ($files, callernumber, foldername, blobtype) {
if (callernumber == 1) {
$scope.blobModel = angular.copy($scope.changeprofilepicmodel1);
$scope.blobModel.folderName = foldername;
$scope.blobModel.blobTypeCode = blobtype;
} else if (callernumber == 2) {
$scope.blobModel = angular.copy($scope.changeprofilepicmodel2);
$scope.blobModel.folderName = foldername;
$scope.blobModel.blobTypeCode = blobtype;
}
$scope.selectedFiles = [];
$scope.model.progress = 0;
// Assuming there's more than one file being uploaded (we only have one)
// cancel all the uploads
if ($scope.upload && $scope.upload.length > 0) {
for (var i = 0; i < $scope.upload.length; i++) {
if ($scope.upload[i] != null) {
$scope.upload[i].abort();
}
}
}
$scope.upload = [];
$scope.uploadResult = [];
$scope.selectedFiles = $files;
// Ok, we only want one file to be uploaded
// let's take the first one and that's all
var $file = $files[0];
// Only first element, single file upload
(function (index) {
$scope.upload[index] = $upload.upload({
url: settings.constants.uploadURL,
headers: { 'myHeaderKey': 'myHeaderVal' },
method: 'POST',
data: $scope.blobModel,
file: $file,
fileFormDataName: 'myFile'
}).then(function (response) {
var look = response;
$scope.model.progress = 100;
// you could here set the model progress to 100 (when we reach this point we now that the file has been stored in azure storage)
$scope.uploadResult.push(response.data);
$scope.$emit('ClearUploadPics');
refreshServerFileList();
}, null, function (evt) {
// Another option is to stop here upadting the progress when it reaches 90%
// and update to 100% once the file has been already stored in azure storage
$scope.model.progress = parseInt(100.0 * evt.loaded / evt.total);
$scope.model.roundProgressData.label = $scope.model.progress + "%";
$scope.model.roundProgressData.percentage = ($scope.model.progress / 100);
});
})(0);
};
function refreshServerFileList() {
storageService.getFileList().then(function (data) {
$scope.model.fileList = data;
}
);
}
function initialize() {
refreshServerFileList();
}
initialize();
$scope.$on("ClearProgressBar", function (event) {
$scope.selectedFiles = null;
});
}]);
I hope this is okay and more readable.