Content-Disposition with ng-file-upload and angularjs - javascript

Background:
I am using ng-file-upload to submit two files in separate ngf-selects and also a Javascript object literal. The issue i have is that when the request is sent the content-disposition of all the parts is set to form-data but what i would expect is for the content-disposition of the two files to be attachment.
Question:
Is there a way for me to override the content-disposition of the form parts so that it is attachment for the files instead of form-data?
CODE
Controller:
(function () {
'use strict';
angular
.module('poc.fileUpload')
.controller('SignupFileUpload', SignupFileUpload);
SignupFileUpload.$inject = ['$scope','Upload', '$log', '$timeout','$location','URLS','SignupService','usSpinnerService','$anchorScroll'];
function SignupFileUpload($scope, Upload, $log, $timeout, $location, URLS, SignupService,usSpinnerService,$anchorScroll) {
$log.debug('ENTERING SIGNUP UPLOAD CONTROLLER %s', JSON.stringify(this));
var params = $location.search();
var customerInfo = SignupService.getCustomerInfo();
var uploadData = {};
$log.debug('CUSTOMER INFO'+JSON.stringify(customerInfo));
if (typeof Object.keys(customerInfo)[0] === 'undefined') {
$log.debug('SIGNUP - Must provide customerInfo');
$location.path('/signup');
}
$scope.mobileUpload = function(form) {
usSpinnerService.spin('spinner');
$log.debug('Starting Mobile Upload Process to resource - ' + URLS.BASE + URLS.FILE_UPLOAD);
$log.debug('No Files are uploaded for mobile client');
$log.debug('Adding customerInfoPart to uploadData');
uploadData.customerInfoPart = Upload.jsonBlob(customerInfo);
$log.debug('Upload data - ' + JSON.stringify(uploadData));
$log.debug('Uploading data');
Upload.upload({
url: URLS.BASE + URLS.FILE_UPLOAD,
data: uploadData
}).then(function (response) {
// file is uploaded successfully
usSpinnerService.stop('spinner');
$log.debug('Mobile Upload Status - ' + response.status);
$timeout(function () {
$scope.serverMessage = response.data;
});
if (response.status===204) {
$location.path('/signup-confirmation');
SignupService.setCustomerSignupStatus(true);
}
}, function (response) {
// handle error
$log.debug('Signup failed with status ' + response.status);
handleError(response);
}, function (evt) {
$scope.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
$log.debug('Mobile Upload progress ' + $scope.progress);
});
};
$scope.uploadFiles = function(idFile,addressFile,form) {
usSpinnerService.spin('spinner');
$log.debug('Starting Upload Process to resource - ' + URLS.BASE + URLS.FILE_UPLOAD);
$log.debug('Checking for files to upload');
if (idFile) {
$log.debug('idFile found, adding to uploadData');
uploadData.idDocument = idFile;
}
if (addressFile) {
$log.debug('addressFile found, adding to uploadData');
uploadData.addressDocument = addressFile;
}
$log.debug('Adding customerInfoPart to uploadData');
uploadData.customerInfoPart = Upload.jsonBlob(customerInfo);
$log.debug('Upload data - ' + JSON.stringify(uploadData));
$log.debug('Uploading data');
Upload.upload({
url: URLS.BASE + URLS.FILE_UPLOAD,
data: uploadData
}).then(function (response) {
// file is uploaded successfully
usSpinnerService.stop('spinner');
$log.debug('Upload Status - ' + response.status);
$timeout(function () {
$scope.serverMessage = response.data;
});
if (response.status===204) {
$location.path('/signup-confirmation');
SignupService.setCustomerSignupStatus(true);
}
}, function (response) {
// handle error
$log.debug('Signup failed with status ' + response.status);
handleError(response);
}, function (evt) {
// progress notify
$scope.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
$log.debug('Upload progress ' + $scope.progress);
});
};
function handleError(error) {
usSpinnerService.stop('spinner');
scrollToServerMessage();
$scope.serverMessage = 'Signup failed with status ' + error.status;
}
function scrollToServerMessage() {
var old = $location.hash();
$location.hash('serverMessage');
$anchorScroll();
//reset to old to keep any additional routing logic from kicking in
$location.hash(old);
}
}
}());
HTML
<form name="signupForm">
<div class="panel panel-default no-bottom-margin">
<div class="hidden-md hidden-lg">
<div class="panel-heading no-border">
<h2 class="panel-title" translate>ID Documents</h2>
<hr/>
</div>
<div class="panel-body">
<span><p>Document upload facility is not supported on mobile devices. Please send your ID documents to <span>someone#somewhere.com</span> after you complete sign up.</p>
<p>You will need to scan and upload the following two documents:<br/>
- Proof of identity (passport or ID card)<br/>
- Proof of address (utility bill, bank statement or government issued letter within the last 3 months)</p></span>
</div>
<div class="panel-footer">
<div class="align-right">
<button type="button"
id="proceedBtn"
ng-click="mobileUpload(signupForm)" class="btn btn-sm xs-display-block"
translate>Complete Sign up
</button>
</div>
</div>
</div>
<div class="hidden-xs hidden-sm">
<div class="form-control-wrapper">
<div class="panel-heading no-border">
<h2 class="panel-title" translate>ID Documents</h2>
<hr/>
<p>Please upload a copy of your passport, drivers license, or any other government issued identification</p>
</div>
<div class="panel-body">
<div ng-class="{'has-error': signupForm.idfile.$invalid && signupForm.idfile.$dirty,
'has-success': signupForm.idfile.$valid}">
<div class="btn btn-sm btn-primary"
ngf-select=""
ngf-max-size="2MB"
ng-model="idFile"
accept="image/*,application/pdf"
ngf-pattern="'image/*,application/pdf'"
required="false"
id="idfile"
name="idfile"><span ng-if="signupForm.idfile.$valid">Change file</span><span ng-if="!signupForm.idfile.$valid">Add file</span>
</div>
<div class="popover-wrapper">
<a href=""
ng-show="!signupForm.idfile.$valid"
class="top-left"
role="button"
data-toggle="popover"
data-placement="top"
data-content-source="#popover-content"
data-trigger="click"
transcend-popover
content="{{'In order to set up your account, we need you to provide us with a copy of a valid national ID card or passport and a proof of address. These documents are kept safely for our records, and allow us to verify your identity. There is a limit of 2MB per file.' |translate}}">
<small><span class="icon-popover"></span> <span translate> Why is this needed?</span>
</small>
</a>
</div>
<div class="form-group has-error has-feedback" ng-show="signupForm.idfile.$error.maxSize">
<span class="input-status placement-left">File is too large, maximum size is 2MB</span>
</div>
<div ng-show="signupForm.idfile.$valid" class="form-control-wrapper">
<img ngf-thumbnail="idFile" class="thumb"/>
<div class="align-right">
<button ng-click="idFile = null" ng-show="idFile" class="btn btn-sm btn-warning">Remove</button>
</div>
</div>
</div>
</div>
<div class="panel-heading no-border">
<h2 class="panel-title" translate>Proof of address</h2>
<hr/>
<p>Please upload a copy of a utility bill or your driving licence</p>
</div>
<div class="panel-body">
<div ng-class="{'has-error': signupForm.addressfile.$invalid && signupForm.addressfile.$dirty,
'has-success': signupForm.addressfile.$valid}">
<div class="btn btn-sm btn-primary"
ngf-select=""
ngf-max-size="2MB"
ng-model="addressFile"
accept="image/*,application/pdf"
ngf-pattern="'image/*,application/pdf'"
required="false"
id="addressfile"
name="addressfile"><span ng-if="signupForm.addressfile.$valid">Change file</span><span ng-if="!signupForm.addressfile.$valid">Add file</span>
</div>
<div class="popover-wrapper">
<a href=""
ng-show="!signupForm.addressfile.$valid"
class="top-left"
role="button"
data-toggle="popover"
data-placement="top"
data-content-source="#popover-content"
data-trigger="click"
transcend-popover
content="{{'In order to set up your account, we need you to provide us with a copy of a valid national ID card or passport and a proof of address. These documents are kept safely for our records, and allow us to verify your identity. There is a limit of 2MB per file.' |translate}}">
<small><span class="icon-popover"></span> <span translate>Why is this needed?</span>
</small>
</a>
</div>
<div class="form-group has-error has-feedback" ng-show="signupForm.addressfile.$error.maxSize">
<span class="input-status placement-left">File is too large, max size is 2 MB</span>
</div>
<div ng-show="signupForm.addressfile.$valid" class="form-control-wrapper">
<img ngf-thumbnail="addressFile" class="thumb"/>
<div class="align-right">
<button ng-click="addressFile = null" ng-show="addressFile" class="btn btn-sm btn-warning">Remove</button>
</div>
</div>
</div>
</div>
<div class="panel-footer">
<div class="align-right">
<button type="button"
id="proceedBtn"
ng-click="uploadFiles(idFile,addressFile,signupForm)"
class="btn btn-primary"
translate>Complete Sign up
</button>
</div>
</div>
</div>
</div>
</div>
</form>
Current Request:

So although none of the libraries will allow me to do it i still needed to change the content-disposition and other things so i have managed to do it with help from the following question https://stackoverflow.com/a/28143262/844809
I am still using ng-file-upload for various useful functions in the UI, but in the controller i am constructing the post my self.
(function () {
'use strict';
angular
.module('poc.fileUploads')
.controller('SignupFileUpload', SignupFileUpload);
SignupFileUpload.$inject = ['$scope','Upload', '$log', '$timeout','$location','URLS','SignupService','usSpinnerService','$anchorScroll','$http'];
function SignupFileUpload($scope, Upload, $log, $timeout, $location, URLS, SignupService,usSpinnerService,$anchorScroll,$http) {
$log.debug('ENTERING SIGNUP UPLOAD CONTROLLER %s', JSON.stringify(this));
var params = $location.search();
var customerInfo = SignupService.getCustomerInfo();
var uploadData = {};
$log.debug('CUSTOMER INFO'+JSON.stringify(customerInfo));
if (typeof Object.keys(customerInfo)[0] === 'undefined') {
$log.debug('SIGNUP - Must provide customerInfo');
$location.path('/signup');
}
$scope.uploadFiles = function(idFile,addressFile,form) {
usSpinnerService.spin('spinner');
$log.debug('Starting Upload Process to resource - ' + URLS.BASE + URLS.FILE_UPLOAD);
$log.debug('Adding customerInfoPart to uploadData');
uploadData.customerInfoPart = Upload.jsonBlob(customerInfo);
$log.debug('Checking for files to upload');
if (idFile) {
$log.debug('idFile found, adding to uploadData');
uploadData.idDocument = idFile;
}
if (addressFile) {
$log.debug('addressFile found, adding to uploadData');
uploadData.addressDocument = addressFile;
}
$log.debug('Upload data - ' + JSON.stringify(uploadData));
$log.debug('Uploading data');
var epochTicks = 621355968000000000;
var ticksPerMillisecond = 10000;
var yourTicks = epochTicks + ((new Date()).getTime() * ticksPerMillisecond);
var boundary='---------------------------'+yourTicks;
var header='--'+boundary+'\r\n';
var footer='\r\n--'+boundary+'--\r\n';
var contenttype='multipart/form-data; boundary='+boundary;
var jsonContents=header+'Content-Disposition: form-data; name="customerInfoPart"\r\n';
jsonContents+='Content-Type: application/json\r\n';
jsonContents+='Content-Length: '+JSON.stringify(customerInfo).length+'\r\n\r\n';
jsonContents+=JSON.stringify(customerInfo)+'\r\n';
var idFileContents=header+'Content-Disposition: form-data; name="idDocument"; filename="'+$scope.idFile.name+'"\r\n';
idFileContents+='Content-Transfer-Encoding: binary\r\n';
idFileContents+='Content-Type: '+ $scope.idFile.type+'\r\n';
idFileContents+='Content-Length: '+ $scope.idFile.size +'\r\n\r\n';
var idFileReader = new FileReader();
// idFileReader.readAsArrayBuffer($scope.idFile);
var addressFileContents=header+'Content-Disposition: form-data; name="addressDocument"; filename="'+$scope.addressFile.name+'"\r\n';
addressFileContents+='Content-Transfer-Encoding: binary\r\n';
addressFileContents+='Content-Type: '+$scope.addressFile.type+'\r\n';
addressFileContents+='Content-Length: '+$scope.addressFile.size+'\r\n\r\n';
var addressFileReader = new FileReader();
// addressFileReader.readAsArrayBuffer($scope.addressFile);
var blob=new Blob([jsonContents,idFileReader.readAsArrayBuffer($scope.idFile),idFileReader,addressFileReader.readAsArrayBuffer($scope.addressFile),addressFileReader,footer]);
$log.debug(blob.toString());
$http.post(
URLS.BASE + URLS.FILE_UPLOAD,
blob,
{'headers':{'Content-Type':contenttype}}
).success(function (data, status, headers, config) {
// file is uploaded successfully
usSpinnerService.stop('spinner');
$log.debug('Upload Status - ' + status);
$timeout(function () {
$scope.serverMessage = data;
});
if (status===204) {
$location.path('/signup-confirmation');
SignupService.setCustomerSignupStatus(true);
}
}).error(function (data, status, headers, config) {
// handle error
$log.debug('Signup failed with status ' + status);
handleError(status);
});
};
function handleError(error) {
usSpinnerService.stop('spinner');
scrollToServerMessage();
$scope.serverMessage = 'Signup failed with status ' + error.status;
}
function scrollToServerMessage() {
var old = $location.hash();
$location.hash('serverMessage');
$anchorScroll();
//reset to old to keep any additional routing logic from kicking in
$location.hash(old);
}
}
}());

Related

jQuery click event isn't firing

The relevant Javascript follows below, but in short, the archive button works while the delete button does not. I've already tried moving the event handler to a different file which the HTML calls using script tags to see if that makes a difference, but it doesn't seem to, although I'm unsure if it's broken in the same way. Additionally, the actual functions associated with each event handler are practically the same, so it seems reasonable to rule out that the function itself causes the problem. Why are the two buttons performing differently?
const mongo = require('mongodb');
const config = require('../../javascripts/config.js'); //databaseAddress can now be found at config.databaseAddress()const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = config.databaseAddress();
$(document).ready(function () {
$('#navbar-userSearch').addClass('active');
$('.archive-button').click(function () {
var id = $(this).attr('id').split('-').slice(-1)[0] ;
console.log('id', id);
var username = $('#username-' + id).val();
var csrf = $('#csrf').val();
var action = $(this).attr('id').split('-')[0];
console.log('username', username);
$.ajax({
url: '/'+action+'/'+username,
type: 'PUT',
data: {username: username, _csrf: csrf},
success: function(data) {
if (data.success) {
addMessage(data.message, true);
if (typeof data.redirect === 'string') {
setTimeout(function(){
window.location = data.redirect;
}, 2500);
}
} else {
addMessage(data.message, false);
}
},
error: function(err) {
addMessage('A network error might have occurred. Please try again.', false);
}
});
});
$('.delete-button').click(function() {
console.log("stop pushing my buttons");
var id = $(this).attr('id').split('-').slice(-1)[0] ;
console.log('id', id);
var username = $('#username-' + id).val();
console.log('username', username);
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
const db = client.db("paxpopulidb");
const id_query = {_id: id};
const username_query = db.collection("users").find(id_query, {_id: 0, username: 1});
const username = username_query.username;
if (username) {
if (username === "superadmin"){
console.log("You cannot delete the superadmin account.");
} else {
db.collection("registrations").deleteOne(username_query);
db.collection("users").deleteOne(username_query);
db.collection("schedules").deleteOne(username_query);
console.log("Deleted " + username + " from database.");
}}})
})});
The HTML uses Handlebars for templating and is as follows:
{{#each users}}
<div class='col-xs-12 col-ms-6 col-sm-4 col-md-3 col-lg-4 user-container tile-container' id='user-container-{{_id}}'>
<div class='tile user-tile' name="user-{{_id}}" data-id='{{_id}}'>
<div class='tile-icon' style='float: left'><img class='icon' src="/images/user.gif"></img></div>
<div class='user-header tile-header'>
<a data-toggle="modal" data-target='#user-modal-{{_id}}'>
<h4 class='tile-title'>{{#if fullName}}{{fullName}}{{else}}{{firstName}} {{lastName}}{{/if}}</h4>
</a>
<p class='tile-subtitle'>{{role}}<h class='small-text'>{{#if archived}}(archived){{/if}}</h></p>
</div>
</div>
<div id="user-modal-{{_id}}" class="user-item-modal modal fade" role="dialog">
<div class="modal-messages"></div>
<div class="modal-dialog modal-xs">
<div class="modal-content">
<div class="modal-header modal-title">
<button type="button" class="close" data-dismiss="modal">×</button>
{{#if fullName}}{{fullName}}{{else}}{{firstName}} {{lastName}}{{/if}}'s Profile
</div>
<div class="modal-body">
{{> profileTable}}
</div>
</div>
</div>
</div>
<div>
<input id='username-{{_id}}' type="hidden" value="{{username}}"></input>
<input id='requestToken-{{_id}}' type="hidden" value="{{requestToken}}"></input>
<input id='csrf' type="hidden" name="_csrf" value="{{csrfToken}}">
<center>
{{#isRegularUser role}}
<button id='registration-button-{{_id}}' class='btn btn-info btn-hg registration-button'>View/Edit Registration</button>
<button id='schedule-button-{{_id}}' class='btn btn-info btn-hg schedule-button'>View/Edit Schedule</button>
{{/isRegularUser}}
{{#ifNot archived}}
<button id='archive-button-{{_id}}' class='btn btn-warning btn-hg archive-button'>Deactivate</button>
{{else}}
{{/ifNot}}
{{#isRegularUser role}}
<button id='delete-button-{{_id}}' class='btn btn-danger btn-hg delete-button'>Delete User</button>
{{/isRegularUser}}
</center>
</div>
</div>
{{/each}}
In short, the above makes a small box with appropriate buttons for each user depending on their role attribute, but the only working button so far is archive-button (no event handlers exist for the other two yet) However, the delete-button actually displays, it's just that clicking it does nothing.
Your bracketing is wrong. You have the delete button event handler inside the archive button click handler. So the delete handler isn't added until you click on an archive button (and if you click on archive multiple times, the delete buttons will execute their code multiple times).
You would see this if you'd indented your code correctly (every programming editor has options to automate this for you).
It should be:
$(document).ready(function() {
$('#navbar-userSearch').addClass('active');
$('.archive-button').click(function() {
var id = $(this).attr('id').split('-').slice(-1)[0];
console.log('id', id);
var username = $('#username-' + id).val();
var csrf = $('#csrf').val();
var action = $(this).attr('id').split('-')[0];
console.log('username', username);
});
$('.delete-button').click(function() {
console.log("stop pushing my buttons");
var id = $(this).attr('id').split('-').slice(-1)[0];
console.log('id', id);
var username = $('#username-' + id).val();
console.log('username', username);
});
});

Drag and Drop AngularJs with FileList

I am very new to front-end development and I thought it would be cool to add drag and drop to a current upload page. However after starting to hook everything up with ng-flow (a directive that assists with drag and drop) I cannot seem to make the connection on how to add the files to the file list. If you think I don't even need the directive and am just overkilling this and there is a simpler solution I would be willing to make changes as well. NOTE: I am giving only samples of the code so dont ding it for not compiling!
fileModelDirective:
app.directive('fileModel', ['$parse', '$log', '$confirm',
function ($parse, $log, $confirm) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
scope.sampleFile = model;
element.bind('change', function () {
// if the file open dialog is raised and the file name
// is cleared and cancel is pressed then a reset is needed
// document.getElementById('file-upload-name').innerHTML = "";
// document.getElementById('file-upload-btn').disabled = true;
// status always needs reset if choosing another file
scope.$apply(function () {
modelSetter(scope, element[0].files);
if (document.getElementById('file-upload').files) {
// This iterates over to see if the total files size is greater than 100MB
const maxFilesSize = 104857600;
var totalFilesSize = 0;
var numberOfDataSamples = element[0].files.length;
}
});
});
} // link
};
}]); // fileModel
fileMethod
$scope.uploadFile = function () {
console.log(flow)
var file = flow.file;
$scope.numberOfFiles = document.getElementById('file-upload').files.length;
$scope.filesTotalSize = 0;
for (var i = 0; i < document.getElementById('file-upload').files.length; i++) {
$scope.filesTotalSize = document.getElementById('file-upload').files[i].size + $scope.filesTotalSize;
}
fileUpload Service
app.service('fileUpload', ['$http', '$log',
function ($http, $log) {
this.uploadFileToUrl = function (file, uploadUrl) {
//$log.debug("file(s)");
//$log.debug(file);
var fd = new FormData();
angular.forEach(file, function (value, key) {
fd.append(key, value);
});
return $http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined,
'enctype': "multipart/form-data"
}
})
}; // uploadFileToUrl
}]); // fileUpload
html
<div flow-init flow-files-submitted="$flow.upload()" class="ng-scope">
<div flow-drop>
<span for="file-upload"
class="btn btn-primary" flow-btn style="margin-top: 10px; ">Upload File
<input id="file-upload" type="file" multiple="multiple" file-model="sampleFile"
style="visibility: hidden; position: absolute;"></span>
<p flow-prevent-drop
flow-drag-enter="style={border: '5px dashed purple'}"
flow-drag-leave="style={}"
ng-style="style"
style="margin-top: 10px;width: 100%;min-height: 50px;">
Drag And Drop your file here</p>
<br>
<span ng-repeat="file in $flow.files track by $index">
{{file.name + ", " }}
</span>
<div style="margin-left: 2px; margin-top: 10px;">
<button id="file-upload-btn" class="btn btn-primary"
ng-click="showMask(); uploadFile();">
Upload
</button>
<button class="btn btn-primary" style="float: right;"
ng-click="navigateTo('/startup')">
Cancel
</button>
<button style="float: right; margin-right: 6px;" class="btn btn-primary"
ng-click="$flow.cancel()">
Clear
</button>
</div>
</div>
</div>
I'm just experimenting with a similar service. Taking angular Array of files, and pushing the items onto the javascript "file-upload".FileList array, but no luck, as the 'files' property is a readonly FileList object.
A pre-packaged solution:
http://blueimp.github.io/jQuery-File-Upload/angularjs.html
and it has drag and drop on to the whole page working.
This one: http://angular-file-upload.appspot.com/ even has Paste and access to Camera on mobile.
Your solution for adding files to the formData is good and inline with jquery ajaxSubmit form code
Maybe you could create a Plnk to collaborate on ...
formdata.append(a[i].name, a[i].value);

upload multiple files using the same uploader angular

So i'm trying to get this uploader working, This is what i have at the moment
This is my html
<div class="row" ng-repeat="row in fileUploadRows">
<div ng-if="advanced_user" class="btn btn-info btn-sm" style="display:inline-block" ngf-select="uploadinv($file, $index)">Upload Attachment</div>
<p style="display:inline-block;" ng-if="row.fileName">Uploaded file: {{row.fileName}}
<button type="button" ng-click="deleteInvAttachment(event.filenameinv)" class="btn btn-danger btn-sm">
<i class="fa fa-trash-o"></i>
</button>
<button type="button" ng-click="addInvAttachment($index)" class="btn btn-info btn-sm">
<i class="fa fa-plus"></i>
</button>
<button type="button" ng-click="removeInvAttachment(row)" class="btn btn-danger btn-sm">
remove last attachment
</button>
</div>
And this is in my controller
$scope.fileUploadRows = [];
var fileDetails = {
fileName: $scope.event.filenameinv
}
$scope.fileUploadRows.push(fileDetails);
$scope.counter = 1;
$scope.addInvAttachment = function(index) {
var fileDetails = {
fileName: ''
}
$scope.fileUploadRows.push(fileDetails);
$scope.counter++;
}
$scope.removeInvAttachment = function(row) {
$scope.fileUploadRows.splice(row, 1);
}
Now what I've got at the moment works to an extent, I can click the plus button and it'll load a blank upload button on the html side, As well as a blank fileName in the {{fileUploadRows}} Now the issue i have is when i try and upload a new file. It replaces the old file (as well as the old string etc)
Heres my uploader
$scope.uploadinv = function (file, index) {
if (file && $scope.advanced_user) {
Upload.upload({
url: '',
data: {file: file}
}).then(function (resp) {
sweetAlert({title: "Attachment Saved", type: "success"});
}, function (resp) {
sweetAlert({title: "Attachment Not Saved", type: "error"});
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
$scope.event.filenameinv = evt.config.data.file.name
});
}
};
So how would i go about saving each file into the array?
Thanks
I strongly recommend you to use ng-file-upload : https://github.com/danialfarid/ng-file-upload
Very complete, supports drag and drop, image resizing, and many more.
It seems you might be using it (i noticed Upload service and the ngf-select directive)
If you are, check out ngf-change, and try binding your file input with ng-model, for $scope accessibility.

How to arrange properly my ChatHub Messages in SignalR?

I used this code so far but i don't receive properly ordered messages output so can any one help me for proper output.
ChatHub Code :
public class ChatHub : Hub
{
static List<UserDetails> ConnectedUsers = new List<UserDetails>();
static List<MessageDetails> CurrentMessage = new List<MessageDetails>();
static List<TestProject1.Models.MessageDetails> CurrentMessage1 = new List<TestProject1.Models.MessageDetails>();
private TestContext db = new TestContext();
public void Connect(string userName)
{
var id = Context.ConnectionId;
var data = db.MessageDetails.ToList();
foreach (var item in data)
{
ConnectedUsers.Add(new UserDetails { ConnectionId = id, UserName = item.UserName });
CurrentMessage1.Add(new TestProject1.Models.MessageDetails { UserName = item.UserName, Message = item.Message });
}
Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage1);
Clients.AllExcept(id).onNewUserConnected(id, userName);
}
public void Send(string name, string message, string connection)
{
AddMessageinCache(name, message);
db.MessageDetails.Add(new TestProject1.Models.MessageDetails { UserName = name, Message = message });
db.SaveChanges();
Clients.All.addNewMessageToPage(name, message, connection);
}
private void AddMessageinCache(string userName, string message)
{
CurrentMessage.Add(new MessageDetails { UserName = userName, Message = message });
if (CurrentMessage.Count > 100)
CurrentMessage.RemoveAt(0);
}
}
I also include details of my html code here And Code of CSHTML:
<div id="page-content">
<div id='wrap'>
<div id="page-heading">
<ol class="breadcrumb">
<li>Dashboard</li>
<li>Chat Room</li>
</ol>
<h1>Chat Room</h1>
</div>
<div class="container">
<div class="col-md-12">
<div class="panel panel-inverse">
<div class="panel-heading">
<h4>Chat Room</h4>
<div class="options">
<i class="fa fa-cog"></i>
<i class="fa fa-refresh"></i>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-8">
<div class="panel-chat well" id="chat">
</div>
<form class="form-inline" action="#">
<div class="input-group">
<input type="text" placeholder="Enter your message here" id="message" class="form-control">
<span class="input-group-btn">
<button type="button" id="sendmessage" class="btn btn-primary"><i class="fa fa-comments-o"></i></button>
</span>
</div>
</form>
<input type="hidden" id="displayname" />
<input type="hidden" id="connection" />
</div>
</div>
</div>
</div>
</div>
</div>
</div> <!--wrap -->
</div> <!-- page-content -->
#section Scripts
{
#Scripts.Render("~/bundles/jquery")
<script>
jQuery(function () {
$.connection.hub.url = 'http://localhost:34063//signalr';
// Reference the auto-generated proxy for the hub.
var chat = $.connection.chatHub;
chat.client.onConnected = function (id, userName, allUsers, messages) {
for (i = 0; i < messages.length; i++) {
AddMessage(messages[i].UserName, messages[i].Message);
}
}
// Create a function that the hub can call back to display messages.
chat.client.addNewMessageToPage = function (name, message, connectionid) {
// Add the message to the page.
$('#chat').append('<div class="chat-message me"><div class="chat-contact"><img src="/Content/assets/demo/avatar/avatar.png" alt=""></div><div class="chat-text">' + htmlEncode(name)
+ ': ' + htmlEncode(message) + '</div></div>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val('#Session["User"].ToString()');
$('#connection').val(#Session["UserID"]);
var name = $('#displayname').val();
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
var i = 0;
$.connection.hub.start().done(function () {
if (name.length > 0) {
if (i == 1) {
chat.server.connect(name);
}
}
$('#sendmessage').click(function () {
chat.server.send($('#displayname').val(), $('#message').val(), $('#connection').val());
$('#message').val('').focus();
});
});
i = i + 1;
$.connection.hub.disconnected(function () {
alert('Disconnected');
});
});
// This optional function html-encodes messages for display in the page.
function AddMessage(userName, message) {
$('#chat').append('<div class="chat-message me"><div class="chat-contact"><img src="/Content/assets/demo/avatar/avatar.png" alt=""></div><div class="chat-text">' + userName + ': ' + message + '</div></div>');
}
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
</script>
}
output is showing all messages but not showing in a sorted order and repeating messages on loading of a page. I want to remove it too.
Why you don't add DateTime stamps to messages. In your MessageDetails class add a property:
public DateTime ReceivedOn{get;set;}
Modify code that runs on receiving message:
private void AddMessageinCache(string userName, string message)
{
CurrentMessage.Add(new MessageDetails { UserName = userName, Message = message, ReceivedOn=DateTime.Now });
if (CurrentMessage.Count > 100)
CurrentMessage.RemoveAt(0);
}
On client side, you will need to sort messages on ReceivedOn property:
chat.client.onConnected = function (id, userName, allUsers, messages) {
$.sort(messages,function(a,b){
return a.ReceivedOn > b.ReceivedOn;
});
for (i = 0; i < messages.length; i++) {
AddMessage(messages[i].UserName, messages[i].Message);
}
}
Consult this question on sorting in jQuery.
EDIT:- On a side note, if only already received messages are a problem, then why don't fetch those sorted from database itself?

How to get file selection complete event in angularJS

Currently this is How brand list page looks like.
when user clicks on Pick Image button, i set updateMode=1, making delete and upload button visible.
Problem is sometime user does not select a image after clicking upload button, instead press cancel in file selection window. that time also delete and upload button becomes visible. I want to avoid that.
Also when user clicks on delete i want input text to become empty.
This is my HTML code.
<tr ng-repeat="b in Brands | filter:SearchText |orderBy:'name'">
<td>
<span data-ng-hide="editMode">{{b.name}}</span>
<input type="text" data-ng-show="editMode" data-ng-model="b.name" data-ng-required />
<input type="text" data-ng-show="editMode" data-ng-model="b.image" data-ng-required />
<br><br>
<input type="text" ng-model="b.files[0].name" readonly="readonly">
<button ngf-select ng-model="b.files" class="btn btn-success btn-sm" ng-click="uploadMode=1">
<span class="glyphicon glyphicon-picture"></span> Pick Image
</button>
<button data-ng-hide="!uploadMode" class="btn btn-danger btn-sm" ng-click="uploadMode=0">
<span class="glyphicon glyphicon-trash"></span> Delete
</button>
<button data-ng-hide="!uploadMode" class="btn btn-info btn-sm" ng-click="upload(b.files, b.image)">
<span class="glyphicon glyphicon-upload"></span> Upload
</button>
</td>
<td><img src="http://localhost/{{ b.image }}" alt="" border=3 height=75 width=75><br><br>
</td>
and this is file upload code.
$scope.upload = function (files, path) {
//alert ('upload');
//alert (path);
//alert (files);
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/cgi-bin/upload.pl',
fields: {
'FilePath': path
},
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
$scope.log = 'progress: ' + progressPercentage + '% ' +
evt.config.file.name + '\n' + $scope.log;
}).success(function (data, status, headers, config) {
$timeout(function() {
$scope.log = 'file: ' + config.file.name + ', Response: ' + JSON.stringify(data) + '\n' + $scope.log;
});
})
.error(function (data, status, headers, config) {
alert ('Error');
});
}
}
};
what changes i should made to get above said functionality.
please help.
You'll need to use ngf-change available in ng-file-upload plugin
Instead of the ng-click , change it to the ngf-change in the HTML markup
<button ngf-select ng-model="b.files" ngf-change="fileSelected($files, $event, b)">
<span class="glyphicon glyphicon-picture"></span> Pick Image
</button>
Pass along the ng-repeat object as the 3rd parameter to the fileSelected function , and in the controller defined it as
$scope.fileSelected = function(files, events, b) {
if (files.length) {
b.uploadMode = true;
} else {
b.uploadMode = false;
}
};
Here we check whether files object is empty or not (Note: ngf-change gets called when the file selection dialog opens and on successful file selection) and set the uploadMode parameter as true or false.
For the delete file functionality , create a function which gets called on the click of Delete button and pass along the ng-repeat object
<button ng-if="b.uploadMode" ng-click="removefile(b)">
<span class="glyphicon glyphicon-trash"></span> Delete
</button>
In the controller , defined the removefile function , where you delete the files object
$scope.removefile = function(b) {
delete b.files;
b.uploadMode = false;
};
See working demo at http://plnkr.co/edit/zmZwiqJOLVILaCmc4uBQ?p=preview

Categories

Resources