Updating the model with file URL to be saved on submit - angularjs

I have been able to successfully upload an image with a custom field template calling a function that handles the upload. It then gathers the return url and from there, i have no idea how to insert it back into the field for saving with the form.
Any help would be much appreciated :)
Here is my code:
var myApp = angular.module('myApp', ['ng-admin', 'backand', 'ngFileUpload']);
//myApp.directive('dashboardSummary', require('./dashboards/dashboardSummary'));
myApp.config(['BackandProvider', function(BackandProvider) {
BackandProvider.setAppName('');
BackandProvider.setSignUpToken('');
BackandProvider.setAnonymousToken('');
}]);
myApp.config(function(RestangularProvider) {
// add a response interceptor
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var extractedData;
// .. to look for getList operations
if (operation === "getList") {
// .. and handle the data and meta data
extractedData = data.data;
extractedData.meta = data.data.__metadata;
} else {
extractedData = data;
}
return extractedData;
});
});
myApp.config(['NgAdminConfigurationProvider','BackandProvider', function (nga, BackandProvider, $scope) {
// create an admin application
BackandProvider.setAppName('');
BackandProvider.setSignUpToken('');
BackandProvider.setAnonymousToken('');
var admin = nga.application('Pocket Release Admin Manager')
.baseApiUrl('https://api.backand.com/1/objects/'); // main API endpoint#
// Users
var user = nga.entity('users');
user.listView().fields([
nga.field('firstName').isDetailLink(true),
nga.field('lastName'),
nga.field('email')
]);
user.creationView().fields([
nga.field('firstName'),
nga.field('lastName'),
nga.field('email', 'email')
]);
user.editionView().fields(user.creationView().fields());
// add the user entity to the admin application
admin.addEntity(user);
// Platforms
var platforms = nga.entity('platforms');
platforms.listView().fields([
nga.field('id'),
nga.field('platform_name'),
]);
platforms.creationView().fields([
nga.field('id'),
nga.field('platform_name'),
nga.field('platform_id')
]);
platforms.editionView().fields(platforms.creationView().fields());
admin.addEntity(platforms);
var data = {};
// Games
var games = nga.entity('games');
games.listView().fields([
nga.field('id'),
nga.field('game_title').isDetailLink(true),
nga.field('game_url'),
nga.field('platforms', 'reference')
.targetEntity(platforms)
.targetField(nga.field('platform_name'))
.label('Platform')
]);
games.creationView().fields([
nga.field('game_title'),
nga.field('image').template('<img ng-src="{{game_url}}" ng-show="game_url">'),
nga.field('game_url', 'file').uploadInformation({'url':'', 'apifilename':'game_url'}).template('<div ng-controller="main"><label class="btn btn-default btn-file">Browse<input id="fileInput" field="::field" value="entry.values[{{main}}]" entry="entry" entity="::entity" form="formController.form" datastore="::formController.dataStore" type="file" style="display: none;" accept="*/*" ng-click="initUpload()" /></label></div>', true),
nga.field('platforms'),
nga.field('game_description'),
nga.field('game_boxart'),
nga.field('game_release_uk', 'date'),
nga.field('game_release_us', 'date'),
nga.field('game_release_eu', 'date')
]);
games.editionView().fields(games.creationView().fields());
admin.addEntity(games);
// Dash
admin.dashboard(nga.dashboard()
.addCollection(nga.collection(games)
.name('total_games')
.title('Total Games')
.fields([
nga.field('game_title')
])
.sortField('game_title')
.sortDir('DESC')
.order(1)
).template(`
<div class="row dashboard-starter"></div>
<dashboard-summary></dashboard-summary>
<div class="row dashboard-content">
<div class="col-lg-6">
<div class="panel panel-default">
<ma-dashboard-panel collection="dashboardController.collections.total_games" entries="dashboardController.entries.total_games" datastore="dashboardController.datastore"></ma-dashboard-panel>
</div>
</div>
</div>
`));
// Menu Customize
// customize menu
admin.menu(nga.menu()
.addChild(nga.menu(user).icon('<span class="glyphicon glyphicon-file"></span> ')) // customize the entity menu icon
.addChild(nga.menu(games).icon('<span class="glyphicon glyphicon-folder-open"></span> ')) // you can even use utf-8 symbols!
.addChild(nga.menu(platforms).icon('<span class="glyphicon glyphicon-tags"></span> '))
);
// attach the admin application to the DOM and execute it
nga.configure(admin);
}]);
myApp.controller('main', function ($scope, $rootScope, $location, $http, Backand) {
// Image upload stuff
$scope.initUpload = function(){
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
imageChanged(fileInput);
});
}
function imageChanged(fileInput) {
//read file content
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
upload(file.name, e.currentTarget.result).then(function(res) {
$scope.imageUrl = res.data.url;
$scope.filename = file.name;
return res.data.url;
}, function(err){
alert(err.data);
});
};
reader.readAsDataURL(file);
};
function upload(filename, filedata) {
// By calling the files action with POST method in will perform
// an upload of the file into Backand Storage
return $http({
method: 'POST',
url : Backand.getApiUrl()+'/1/objects/action/games',
params:{
"name": 'files'
},
headers: {
'Content-Type': 'application/json'
},
// you need to provide the file name and the file data
data: {
"filename": Math.floor(Date.now() / 1000) + ''+ filename.match(/\.[0-9a-z]+$/i),
"filedata": filedata.substr(filedata.indexOf(',') + 1, filedata.length) //need to remove the file prefix type
}
}).success(function(data, status, headers, config) {
//$scope.game_url = data.url;
//$("#game_url").addClass("ng-dirty ng-valid-parse ng-touched").removeClass("ng-pristine ng-untouched");
//$("#game_boxart").val(data.url).addClass("ng-dirty ng-valid-parse ng-touched").removeClass("ng-pristine ng-untouched");
return data.url;
});
};
});

Have you tried making a PUT call to backand in order to save this url in the relevant column?
return $http({
method: 'PUT',
url : Backand.getApiUrl()+'/1/objects/games/YOUR_GAME_ID',
headers: {
'Content-Type': 'application/json'
},
data: {
urlColumn:imageUrl
}
}).success(function(data, status, headers, config) {
.....
});

Related

How to manage validation in AngularJS of a file that has already been uploaded inside a form widget?

My AngularJS model has two properties, a file object, vm.profile.file, and a text value that contains a reference to the uploaded file on the server, vm.profile.resume. The vm.profile.file is validated as required with limited size. However, when the form is being updated, the reference which is acceptable and passed to the server is fine but there is not a need for the file object to be set to the server again. How do I validate the form if the reference to the file exists while the unneeded file object is empty?
I'm using ng-file-upload.
Here is what the form looks like:
Here is some of the code I'm using:
<div class="sj-section-content" flex="60">
<md-card>
<md-input-container>
<div layout="row" layout-align="start center">
<md-button class="md-primary md-raised"
style="max-width: 150px; color: white;"
ngf-select
required
name="resume"
ngf-min-size="0MB"
ngf-max-size="1MB"
ng-model="vm.profile.file">
<span>{{!vm.profile.resume ? 'Select file' : 'Change'}}</span>
</md-button>
<md-button ng-if="vm.profile.resume" ng-click="vm.profile.file = {}" class="md-icon-button">
<md-icon md-font-icon="clear">clear</md-icon>
</md-button>
</div>
<div ng-if="vm.profile.file.name" layout="row" layout-align="start center">
<md-button class="md-icon-button" md-no-ink>
<md-icon md-font-icon="attachment">attachment</md-icon>
</md-button>
<div>{{vm.profile.file.name}}</div>
</div>
<div ng-messages="profileForm.resume.$error"
ng-if="profileForm.resume.$error && (profileForm.$submitted || profileForm.resume.$dirty)"
role="alert">
<div ng-if="profileForm.resume.$error.maxSize"
ng-message="maxSize">Max file size is 10MB</div>
<div ng-if="profileForm.resume.$error.required"
ng-message="required">Resume is a required field</div>
</div>
</md-input-container>
</md-card>
</div>
The API service:
ProfileApi.prototype.update = function update(model) {
var deferred = $q.defer();
Upload.upload({
url: endpoint,
method: 'PUT',
data: model
}).then(function success(response) {
deferred.resolve(response.data);
}, function error(response) {
deferred.reject(response.data);
});
return deferred.promise;
};
And on the server:
exports.fileHandler = function(req, res, next) {
var MAX_FILE_SIZE = 10 * 1000000;
var FILE_FIELD = 'file';
var PARENT_DIRECTORY = 'files/resumes/';
// Validate here
var fileFilter = function fileFilter (req, file, callback) {
// allowed extensions .doc .docx .odt .pdf .txt
var allowedMimeTypes = [
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.oasis.opendocument.text',
'application/pdf',
'text/plain'
];
var validMimetype = allowedMimeTypes.some(function(mimetype) {
return file.mimetype == mimetype;
});
if (!validMimetype) return callback(new Error('Resume is not a valid file format'));
callback(null, true)
};
var fileOptions = {
fileFilter: fileFilter,
dest: 'tmp/',
limits: {
fileSize: MAX_FILE_SIZE
}
};
var upload = multer(fileOptions).single(FILE_FIELD);
upload(req, res, function(err) {
if (err) return res.status(400).send({message: err.message});
// We don't need a new file if req.body.resume has a value
console.log(typeof req.body.resume);
if (_.isEmpty(req.body.resume) && typeof req.file === 'undefined') {
return res.status(400).send({message: 'Resume file is required'});
}
// Make sure that if there is a resume file but no new file, the resume exists in the file system.
if (req.body.resume && typeof req.file === 'undefined') {
fs.stat('client/' + req.body.resume, function(err, stats) {
if (err) {
return res.status(400).send({message: 'Resume doesn\'t exist on file server'});
} else {
return next();
}
})
} else {
// Let's add the file path at req.body.resume.
// The idea is that if the save method on the model returns and error. Delete the file
// in the tmp folder. Then return an error. If the model validates and is saved. Move the
// file into the proper folder
req.body.resume = PARENT_DIRECTORY + req.user._id + '/' + req.file.originalname;
return next();
}
});
};
The update controller method:
exports.update = function(req, res) {
var crewListing = req.app.locals.crewListing;
// Protect information
delete req.body.author;
delete req.body.__v;
delete req.body._id;
// Merge objects
_.merge(crewListing, req.body);
crewListing.save({runValidators: true}, function(err, result) {
if (req.file) {
if (err) {
// Delete the req file
fs.unlink(req.file.path, function() {
return res.status(400).send(validationErrorHandler(err,true));
});
} else {
// Move the req file
console.log(req.file);
fs.move(req.file.path, 'client/' + crewListing.resume, {clobber: true}, function(err) {
if (err) return res.status(400).send({message: 'Unexpected error has occured'})
return res.json(result);
});
}
} else {
if (err) return res.status(400).send(validationErrorHandler(err, true));
return res.json(result);
}
})
};
ng-required directive on the file field can be conditional. If the resume text field has a value then the file field doesn't need to be required.
ng-required="!vm.profile.resume"

Data is stuck in $http .then method

Hi I am trying to display my data but when i tried to display it on my html using angular data wont pass through. checked the console and data was there. here is my html.
<ion-view view-title="">
<ion-content>
<!-- <div class="cards">
<div class="item item-image">
<img src="img/banner-children.jpg"></img>
</div>
</div> -->
<div class="list card padding" ng-repeat="charity in charityList">
<a href="#/app/charitypage/{{charity.charity_id}}" class="positive ">
<img class="char-logo img-thumb" ng-src="{{charity.logo}}">
<div class="char-info">
<h3 class="char-name text-pink">
<i class="ion-chevron-right text-pink btn-category"></i>
{{charity.charity_name}}</h3>
<p class="dark">{{charity.description}}</p>
</div>
</a>
</div>
</ion-content>
and here is my controller
angular.module('subCategory.controllers', [])
.controller('subCatCtrl', function($scope, $state, $http) {
$scope.getCategoryList = function(category){
$scope.charityList = {};
var categoryListData = {
charityCategory : category
}
$http({
method: 'POST',
header: {'Content-Type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost/filantrome/Main/getCategoryList',
data: categoryListData
}).then(
function success( response ) {
$scope.charityList= response.data;
console.log($scope.charityList);
$state.go('app.subcat');
},
function error( response ) {
$scope.charityList = response.data;
console.log($scope.charityList);
// handle error
}
);
console.log($scope.charityList);
};
});
i can see the data that i was requesting on the console.log() inside the success function. but when i get out of the .then(); function $scope.charityList is empty.
what am i missing here? thanks!
Seems problem is in state change. To fix this you can use service to store received JSON
angular.module('subCategory.controllers', []).service(charityService, charityService);
/* #ngInject */
function charityService($http) {
var charityList = [];
var service = {
getData: getData,
getCharityList: getCharityList
};
return service;
function getCharityList() {
return charityList ;
}
function getData(categoryListData) {
$http({
method: 'POST',
header: {'Content-Type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost/filantrome/Main/getCategoryList',
data: categoryListData
}).then(
function success( response ) {
charityList = response.data;
console.log(charityList );
$state.go('app.subcat'); // you can also change state here
},
function error( response ) {
$scope.charityList = response.data;
console.log($scope.charityList);
// handle error
}
);
}
}
then post data with controller function
$scope.getCategoryList = function(category){
var categoryListData = {
charityCategory : category
}
charityService.getData(categoryListData);
}
after state changes controller will get charityList from service
angular.module('subCategory.controllers', []) .controller('subCatCtrl',
function($scope, $state, $http, charityService) {
$scope.charityList = charityService.getCharityList();
// ...
As you have posted your console.log output, I can see that you have a single object receiving and assigning to charityList but you have an ng-repeat on the element. So, I think you should change $scope.charityList = {}; to $scope.charityList = []; or you can output this variable in the html to see whats going on like {{charityList}}.

AngularJS orderBy not working with trackBy

I don't know why orderBy is not working with trackBy, it is making me crazy :(
Here is my HTML code:
<div class="blocks-container" ng-init="loadProjects()" ng-controller="buildMonitorController">
<div class="row">
<!-- <div> -->
<div class="col-xs-12 col-sm-6 col-md-3 col-lg-2 block animate"
ng-if="!errorDialogActive"
ng-repeat="build in builds.builds.build track by build._id | orderBy:'lastBuildDetails.startDate' : true"
ng-class="{'running': project.running ,'block-green': build._status ==='SUCCESS','block-red': build._status==='FAILURE'}"
id="{{build._id}}">
<div class="title-container"><p>{{build._buildTypeId}}</p></div>
<div class="update-container col-xs-12">
<time>{{ build.lastBuildDetails.startDate | date : 'dd.MM.yyyy H:mm:s'}}</time>
</div>
</div>
</div>
<!--</div>-->
<!-- Start error state dialog -->
<div ng-include src="'views/main/error-dialog.html'"></div>
Everytime give me the same result even if i change the order to reverse
And Here my AngularJS code:
$scope.refreshBuilds = function () {
$scope.errorList.length = 0
//#TODO remove this part right after the API is working
//Init
var suffix = '';
var randomnumber = Math.floor(Math.random() * 3);
//simulate mock by random number
switch (randomnumber) {
case 1:
suffix = '-success';
break;
case 2:
suffix = '-less';
break;
default:
break;
}
var url = 'mock/builds'+suffix+'.xml';
console.log('url: ' + url)
$http({
method: 'GET',
url: url,
headers: {
Authorization: 'Basic AAA'
}
}).success(function (data, status) {
//Recive builds from xml and reset scope
var buildsToFilter = new X2JS().xml_str2json(data);
$scope.errorDialogActive = false;
//filter builds which have a no build API detail status
if (buildsToFilter.builds.build !== undefined) {
angular.forEach(buildsToFilter.builds.build, function (build, index) {
$http({
method: 'GET',
url: 'mock/build-'+build._id+'.xml',
headers: {
Authorization: 'Basic AAA'
}
}).success(function (buildDetailData) {
$scope.errorDialogActive = false;
//push detail data into build array
buildsToFilter.builds.build[index].lastBuildDetails = new X2JS().xml_str2json(buildDetailData).build;
console.log(buildsToFilter.builds.build[index]);
}).error(function (data, status) {
$scope.errorDialogActive = true;
//remove build from index if no build detail was found
buildsToFilter.builds.build.splice(index, 1);
$scope.setError(status, '', '');
}).then(function () {
//after filtering builds to display, setup builds $scope for FrontEnd
$scope.builds = buildsToFilter;
});
});
} else {
}
}).error(function (data, status) {
//active dialog if error happens & set error
$scope.errorDialogActive = true;
$scope.setError(status, 'builds', '');
}).then(function () {
$timeout(function () {
$scope.finishedRequest = true;
}, 5000);
//refresh right after proceed and a little delay
$timeout(function () {
console.log('Starting refresh');
$scope.refreshBuilds();
}, 21000);
})
};
If You need more code please let me know
Try reading the docs. It doesn't appear you are using it correctly.
https://docs.angularjs.org/api/ng/filter/orderBy
The last argument can only be "reverse".
Move 'track by build._id' to the end of the expression (after orderBy).
ng-repeat="build in builds.builds.build track by build._id | orderBy:'lastBuildDetails.startDate'

AngularJS inline edit inside of ng-repeat

Im working with AngularJS to display a table of app keys (app identifiers) and I would like to use an edit button to display a small form in that table row. Then the user can edit the fields and click "save" or "cancel"
Demo: http://jsfiddle.net/Thw8n/
I have the inline form working great. I click edit and a form appears. Cancel works great too.
My problem is
How do I connect the save button with a function that will make a $http call to an API
How do I get the data from that row to send to the $http call?
How do I disable editMode once the call comes back?
Here is the actual code Im using in my controller (in the JSFiddle Im not able to make the http call). The first $http fills out the form, the editAppKey function is what is called by the save button.
function AppKeysCtrl($scope, $http, $location) {
$http({
method: 'POST',
url: 'http://' + $location.host() + ':1111/sys/appkey/save',
data: {
// How do I get the data?
}
}).
success(function(data, status, headers, config) {
$scope.appkeys = data;
}).
error(function(data, status, headers, config) {
$scope.appkeys = [{ "appkey" : "ERROR", "name" : "ERROR", "created" : "ERROR" }];
});
$scope.editAppKey = function() {
$http({
method: 'POST',
url: 'http://' + $location.host() + ':1111/sys/appkeys'
}).
success(function(data, status, headers, config) {
alert("Success!");
$scope.editMode = false;
}).
error(function(data, status, headers, config) {
alert("There was an error.");
});
}
}
When we press on "Edit" button and change one of fields , we also change our main model appkeys. Its mean that on "Cancel" we need restore old model.
Its mean that we need at least:
So this is a snippets of HTML:
<td>
<button type="submit" data-ng-hide="editMode" data-ng-click="editMode = true; editAppKey(entry)" class="btn btn-default">Edit</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false; saveField()" class="btn btn-default">Save</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false; cancel()" class="btn btn-default">Cancel</button>
</td>
And our controller:
$scope.newField = {};
$scope.editing = false;
$scope.appkeys = [
{ "appkey" : "0123456789", "name" : "My new app key", "created" : tmpDate },
{ "appkey" : "abcdefghij", "name" : "Someone elses app key", "created" : tmpDate }
];
$scope.editAppKey = function(field) {
$scope.editing = $scope.appkeys.indexOf(field);
$scope.newField = angular.copy(field);
}
$scope.saveField = function() {
if ($scope.editing !== false) {
$scope.appkeys[$scope.editing] = $scope.newField;
$scope.editing = false;
}
};
$scope.cancel = function() {
if ($scope.editing !== false) {
$scope.appkeys[$scope.editing] = $scope.newField;
$scope.editing = false;
}
};
Demo Fiddle
[EDIT]
I you want to edit several rows at once, use array of newFields instead $scope.newField
You can pass e.g. current index as a parameter to the editAppKey() function:
... data-ng-click="editAppKey($index)"
and in the JS file:
$scope.editAppKey = function(index) {
window.console.log(appkeys[index]); // do what ever you want
}
as for the disabling once the request is back. If I undestand, you want to allow only one time edit and after editAppKey() is called once on some row, disable it, right? If so, maybe something like
<button type="submit" data-ng-hide="editMode" data-ng-click="editMode = true" class="btn btn-default"
data-ng-disabled="entry.isDisabled">Edit</button>
and in the editAppKey() function, something like
$scope.editAppKey = function(index){
$http.post(url, data).onsuccess(function(){
$scope.appkeys[index].isDisabled = true;
});
In case someone need multiple edit at once:
Just do the following:
on html cancel button, pass the index
data-ng-click="editMode = false; cancel($index)"
on JS side:
1) $scope.newField = {}; to $scope.newField = [];
2) inside editAppKey function, $scope.newField = angular.copy(field); to $scope.newField[$scope.editing] = angular.copy(field);
3) change the saveField function to:
$scope.saveField = function(index) {
$scope.appkeys[$scope.editing] = $scope.newField;
};
4) change the cancel function to:
$scope.cancel = function(index) {
$scope.appkeys[index] = $scope.newField[index];
$scope.editing = false;
};
Fiddle

$http upload file progress in AngularJS

How can I get a 'progress' event from my AngularJS $http POST request that is uploading an image? Is it possible to do this client-side, or do I need the server to report the progress as it receives the data?
Using pure angular:
function upload(data) {
var formData = new FormData();
Object.keys(data).forEach(function(key){formData.append(key, data[key]);});
var defer = $q.defer();
$http({
method: 'POST',
data: formData,
url: <url>,
headers: {'Content-Type': undefined},
uploadEventHandlers: { progress: function(e) {
defer.notify(e.loaded * 100 / e.total);
}}
}).then(defer.resolve.bind(defer), defer.reject.bind(defer));
return defer.promise;
}
and somewhere else ...
// file is a JS File object
upload({avatar:file}).then(function(responce){
console.log('success :) ', response);
}, function(){
console.log('failed :(');
}, function(progress){
console.log('uploading: ' + Math.floor(progress) + '%');
});
You can also use the simple/lightweight angular-file-upload directive that takes care of these stuff.
It supports drag&drop, file progress/abort and file upload for non-HTML5 browsers with FileAPI flash shim
<div ng-controller="MyCtrl">
<input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
$upload.upload({
url: 'my/upload/url',
file: $file,
progress: function(e){}
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
}
}];
I don't think $http.post() can be used for this.
As for client-side, it should work with an HTML5 browser, but you'll probably have to create your own XMLHttpRequest object and onprogress listener. See AngularJS: tracking status of each file being uploaded simultaneously for ideas.
I don't think Angular has something built-in to handle uploads.
I think your best bet is to use something like jQuery File Upload. An idea for a solution would to create a Service that returns {progress:0} as default and then inside itself, implements the jQuery File Upload's progress update callback, which then simply keeps updating the progress. Thanks to Angular's binding, the upload progress would be in sync.
angular.module('myApp.services', [])
.factory('Uploader', function() {
var uploaderService = {};
var status = { progress: 0 };
uploaderService.upload = function(inputEl) {
inputEl.fileupload({
/* ... */
progressall: function (e, data) {
status.progress = parseInt(data.loaded / data.total * 100, 10);
}
});
};
return uploaderService;
});
Here is another solution:
window.XMLHttpRequest = (function (orig) {
if (orig) {
var intercept = [],
result = function () {
var r = new orig();
if (r.upload) {
$(r).on(
'abort error load loadend loadstart progress',
function (e) {
$(document).trigger('upload.XHR', e);
}
);
}
if (intercept.length) {
intercept[0].push({
request:r
});
}
return r;
};
result.grab = function (f) {
intercept.unshift([]);
f();
return intercept.shift();
};
return result;
}
return function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}(window.XMLHttpRequest));
Notes:
AngularJS currently stores a reference to window.XMLHttpRequest as private XHR variable, then uses it like this: new XHR(). I doubt this will ever change, so the shim-like code above should work just fine.
Mozilla has some extensions: XMLHttpRequest accepts optional arguments. The code above does not handle this, but AngularJS does not use these extensions anyway.
One of possible uses (if you want to show all current requests, and maybe implement some "Cancel" button):
$(document).on('upload.XHR', function (_e, e) {
switch (e.type) {
// do your thing here
}
});
Another possible use:
var list = window.XMLHttpRequest.grab(function () {
// start one or more $http requests here, or put some code
// here that indirectly (but synchronously) starts requests
$http.get(...);
couchDoc.save();
couchDoc.attach(blob, 'filename.ext');
// etc
});
list[0].request.upload.addEventListener(...);
Or, you can combine both approaches with some modifications to the code above.
you can use this where Im using simple angular function to upload file and $scope.progressBar variable to check the progress of uploading...
$scope.functionName = function(files) {
var file = files[0];
$scope.upload = $upload.upload({
url: 'url',
method: 'POST',
withCredentials: true,
data: {type:'uploadzip'},
file: file, // or list of files ($files) for html5 only
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
$scope.progressBar = parseInt(100.0 * evt.loaded / evt.total);
}).success(function(data, status, headers, config) {
console.log('upload succesfully...')
}).error(function(err) {
console.log(err.stack);
})
}

Resources