AngularJS photo/file upload - javascript

Uploading file and photo seems to be working fine on other browsers apart from FF. It seems to be its failing somewhere in the form.append but I don't get why its working on Chrome and IE but not FF.
Can someone shed a light on this one please.
controller:
$scope.uploadProfilePhoto = function() {
$timeout(function(){
var form = new FormData();
form.append("fileName", vm.profilePhoto.fileName);
form.append('file', vm.profilePhoto.file);
ProfileService.uploadProfilePicture(form)
.then(function(response){
vm.ProfilePictureUrl = api.getQualifiedUrl('image/' + response.data.ImageId);
})
});
}
Input:
<label for="profilePhoto" class="photo-upd" >
<img data-ng-src="{{vm.ProfilePictureUrl}}" id="profile-picture_image" alt="Candidate profile photo" onchange="angular.element(this).scope().uploadProfilePhoto(this)" class="img-responsive">
<span><i class="fa fa-upload"></i> Upload Photo</span>
</label>
<input id="profilePhoto" type="file" name="profilePhoto" valid-file data-oh-file fileread="vm.profilePhoto.file" filename="vm.profilePhoto.fileName" class="hidden"onchange="angular.element(this).scope().uploadProfilePhoto(this)">
Error:
vm.profilePhoto is undefined
Profile/$scope.uploadProfilePhoto/

I just notice that the vm object must be the self or this of the object/controller.
And you need to declare the vm.profilePhoto object as well:
var vm = this;
vm.profilePhoto = {};
JS:
example here:
https://jsfiddle.net/alvarojoao/v9rfn301/
var app = angular.module("turingApp", []);
app.controller("turingController", ["$scope","$timeout", function($scope,$timeout) {
var vm = this;
vm.profilePhoto = {};
$scope.uploadProfilePhoto = function() {
$timeout(function() {
var form = new FormData();
form.append("fileName", vm.profilePhoto.fileName);
form.append('file', vm.profilePhoto.file);
ProfileService.uploadProfilePicture(form)
.then(function(response) {
vm.ProfilePictureUrl = api.getQualifiedUrl('image/' + response.data.ImageId);
})
});
};
}]);

Shouldn't you be using $scope.vm In the upload function?

Related

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);

ng-change is not firing when changing value from service

I need to reflect some changes to controller B (inside some event) when I make change at controller A. For that I am using a service.
When I am changing service value from FirstCtrl, ng-change is not firing at SecondCtrl. Is there anything I have missed or need to change?
Please note that I am using angular 1.5.6. and don't want to use watch or even scope.
Below is my code.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
debugger
self.changeM = function() {
debugger
Data.FirstName = self.FirstName;
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.FirstName = Data;
self.changeM = function() {
alert(1);
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="FirstCtrl as c">
<input type="text" ng-model="c.FirstName" data-ng-change="c.changeM()">
<br>Input is : <strong>{{c.FirstName}}</strong>
<div ng-controller="SecondCtrl as c1">
Input should also be here: {{c1.FirstName}}
<input type="text" ng-model="c1.FirstName" data-ng-change="c1.changeM()">
</div>
</div>
<hr>
</div>
As you dont want to use $scope trying modifying the code in order to use $emit and $on feature in angular js to communicate between two controllers. You can refer this link.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
debugger
self.changeM = function() {
debugger
//Data.FirstName = self.FirstName;
Data.$on('emitData',function(event,args){
Data.FirstName=args.message
document.write(Data.FirstName)
})
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.FirstName = Data;
self.changeM = function() {
Data.$emit('emitData',{
message:Data.FirstName
})
};
}
]);
The only way then is to directly copy the reference of the data object within the controller. Note that you don't need ng-change to update the value then.
If you want something else, either wrap the FirstName in a sub object of Data and do the same i did :
Data = {foo:'FirstName'};
Or use $watch since it's the whole purpose of that function.
Here is a working code with copying the Data object in the controller.
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {
FirstName: ''
};
});
myApp.controller('FirstCtrl', ['Data',
function(Data) {
var self = this;
self.Data=Data;
debugger
self.changeM = function() {
debugger
};
}
]);
myApp.controller('SecondCtrl', ['Data',
function(Data) {
var self = this;
self.Data = Data;
self.changeM = function() {
alert(1);
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="FirstCtrl as c">
<input type="text" ng-model="c.Data.FirstName" data-ng-change="c.changeM()">
<br>Input is : <strong>{{c.Data.FirstName}}</strong>
<div ng-controller="SecondCtrl as c1">
Input should also be here: {{c1.Data.FirstName}}
<input type="text" ng-model="c1.Data.FirstName" data-ng-change="c1.changeM()">
</div>
</div>
<hr>
</div>
The only way I know to solve the problem is using watch, unfortunately. (I am new to angular.)
From the ngChange document (https://docs.angularjs.org/api/ng/directive/ngChange):
The ngChange expression is only evaluated when a change in the input value causes a new value to be committed to the model.
It will not be evaluated:
if the value returned from the $parsers transformation pipeline has not changed
if the input has continued to be invalid since the model will stay null
**if the model is changed programmatically and not by a change to the input value**

How to display one record from firebase in html?

I am trying to display one single record in HTML from firebase query, what am I doing wrong? This is the controller:
function getUrlVars()
{
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
function (m, key, value) { vars[key] = value; });
return vars;
}
var first = getUrlVars()["id"];
console.log("The id is: " + first);
$scope.username = CommonProp.getUser();
if (!$scope.username) {
$location.path('/home');
}
var firebaseObj = new Firebase("https://crackling-inferno-2072.firebaseio.com/Articles/" + first);
var sync = $firebase(firebaseObj.startAt($scope.username).endAt($scope.username));
$scope.title = sync.$asArray();
$scope.post = sync.$asArray();
console.log($scope.title);
console.log($scope.post);
console.log(sync);
console.log(firebaseObj);
I capture the id form the URL http://localhost:8000/app/#/show?id=-KHNW-LTLsOejTd-cjcO
This is the HTML
<div ng-repeat="article in articles">
<h1>{{title}}</h1>
<p>{{post}}</p>
</div>
<h1 ng-model="article.title">{{article.title}}</h1>
<p>{{post}}</p>
The issue is that nothing is running, and I need to show the title and the post from that ID. Can somebody help me out?
Thanks in advance

Getting value from JSON object with Angular

I've been trying to learn AngularJS recently, and hit a bump in the road with Localstorage i spend so many hours trying to make it save locally, I think that it's working as it should now, but now i would like to print out the data saved local from the JSON array, how can i go about that?
EDIT:
A bit of clarification, What im trying to achieve is getting the information i save in the localstorage out onto the website as a string, so it's readable. hope i'ts more understandable. Thanks in advance
My view.
<ion-list>
<div >
<ion-item ng-controller='ModalEditCtrl' ng-click="openModal()">
<div class="thumbnail" style="border:1px black solid">
</div>
<div ng-controller="createPerson" class="contactinfo" >
<li ng-repeat="contact in contactdetail.contactinfo"> {{contact.name}} </li>
</div>
</ion-item>
</div>
<div ng-controller="ModalAddCtrl">
<button type="button" ng-click="openModal()">+++</button>
</div>
</ion-list>
My controller
app.controller('createPerson', function ($scope) {
var id = id_counter = 1;
$scope.editorEnabled = false;
$scope.disableEditor = function() {
$scope.editorEnabled = false;
};
$scope.enableEditor = function() {
$scope.editorEnabled = true;
};
$scope.contactinfo = [
{name: 'test', phone: 1231, email: 'asd#asd.com'}
];
$scope.saveData = function () {
id_counter += 1;
$scope.editorEnabled = false;
$scope.contactinfo.push({
name: $scope.contactName,
phone: $scope.contactPhone,
email: $scope.contactEmail,
sort_id: id_counter
});
//$scope.todoText = ''; //clear the input after adding
localStorage.setItem('contactinfo', JSON.stringify($scope.contactinfo));
// localStorage.setItem("contacts", JSON.stringify(contacts));
}
$scope.loadData = function () {
var contacts = localStorage.getItem("contactinfo");
var contactdetail = JSON.parse(contacts); //
console.log(contactdetail);
}
$scope.clearData = function () {
window.localStorage.clear();
}
});
Your question is not very clear, I dont think you will be able to get much help unless you clean it up a little.
To print out the data (for debugging, usually) you could just add {{contactinfo|json}} somewhere in your html.
To actually display the data for use on the webpage the following should work for you.
<div ng-repeat="contact in contactinfo track by $index">
<div>Name: {{contact.name}}</div>
<div>Phone: {{contact.phone}}</div>
<div>Email: {{contact.email}}</div>
</div>
I think that some of that logic might be better split into a factory, too. Something like this maybe...?
var contactFactory = angular.module('contactFactory', []);
contactFactory.factory('contactInfo', ['$window', function ($window) {
var id = id_counter = 1;
var contacts = [];
function addContact(name, phone, email) {
id_counter += 1;
contacts.push({
name: name,
phone: phone,
email: email,
sort_id: id_counter
});
saveData();
}
function saveData(contactInfo) {
$window.localStorage.setItem('contactinfo', angular.fromJson(contacts));
}
function loadData() {
contacts = angular.toJson($window.localStorage.getItem('contactinfo'));
return contacts;
}
function clearData() {
$window.localStorage.removeItem('contactinfo');
}
return {
addContact: addContact,
saveData: saveData,
loadData: loadData,
clearData: clearData
};
}]);
var app = angular.module('yourAppName', ['contactFactory']);
app.controller('createPerson', ['$scope', 'contactInfo', function ($scope, contactInfo) {
$scope.editorEnabled = false;
$scope.disableEditor = function() {
$scope.editorEnabled = false;
};
$scope.enableEditor = function() {
$scope.editorEnabled = true;
};
$scope.contactinfo = [
{name: 'test', phone: 1231, email: 'asd#asd.com'}
];
$scope.saveData = function () {
contactInfo.addContact($scope.contactName, $scope.contactPhone, $scope.contactEmail);
$scope.editorEnabled = false;
}
$scope.loadData = contactInfo.loadData;
$scope.clearData = contactInfo.clearData;
}]);
Angular has wrapper for window, which should be used inside your code. There is also ngStorage module or many available solutions which are dealing with browser storage in Angular way. Moreover Angular has functions like angular.toJson() and angular.fromJson(). If e.g. jsonObj is JSON array then var obj = angular.fromJson(jsonObj) gives you JavaScript array. If jsonObj has array property inside then you should go with: var jsArray = angular.fromJson(jsonObj).array.

Binding a div row to a single item in an observableArray

I'm developing a 3 part upload form, where users can upload 3 sets of files
So far, I've got the following viewModel
var FileGroupViewModel = function (id) {
var self = this;
self.id = ko.observable(id);
self.files = ko.observableArray();
self.removeFile = function (item) {
self.files.remove(item);
}
self.fileUpload = function (data, e) {
var file = e.target.files[0];
self.files.push(file);
};
}
var ViewModel = function () {
var self = this;
self.fileGroups = ko.observableArray();
self.getFileGroupById = function (id) {
ko.utils.arrayFilter(self.fileGroups(), function (item) {
return item.id == id;
});
};
self.uploadFiles = function () {
alert('Uploading');
}
}
var viewModel = new ViewModel();
viewModel.fileGroups.push(new FileGroupViewModel(1));
viewModel.fileGroups.push(new FileGroupViewModel(2));
viewModel.fileGroups.push(new FileGroupViewModel(3));
ko.applyBindings(viewModel);
I have 3 'groups' of files a user can upload to.
(I will do the actual upload functionality later)
I'm struggling with how to bind my row to a specific item of the array?
Maybe I shouldn't use an observable array?
<div class="row files" id="files1" data-bind="???">
<h2>Files 1</h2>
<span class="btn btn-default btn-file">
Browse <input data-bind="event: {change: fileUpload}" type="file" />
</span>
<br />
<div class="fileList" data-bind="foreach: files"> <span data-bind="text: name"></span>
Remove
</div>
</div>
The idea is when a user selects files, they appear in a list under the button:
..with a link to remove the file from the upload queue.
I've set up a fiddle here - https://jsfiddle.net/alexjamesbrown/c9fvzjte/
There are few important modifications required to make your code work independently across files 0,1,2
KeyNote
event: { change: function(){fileUpload($data,$element.files[0])}}
here we are passing our selected file i.e filedata using $element in
change event not in usual click event . Filedata will have complete file information .
view:
<div class="row files" id="files1" data-bind="foreach:fileGroups">
<h2>Files 0</h2>
<span class="btn btn-default btn-file">
Browse <input data-bind="event: { change: function() { fileUpload($data,$element.files[0]) } }" type="file" />
</span>
<div class="fileList" data-bind="foreach: files"> <span data-bind="text: name"></span>
Remove
</div>
viewModel:
var SubFunction = function (data) {
var self = this;
self.name = data.name;
self.removeFile = function (item1) {
item1.files.remove(this); //current reference data & item1 has parent reference data
}
}
var FileGroupViewModel = function (id) {
var self = this;
self.id = ko.observable(id);
self.files = ko.observableArray([new SubFunction({
'name': 'Test'
})]);
self.fileUpload = function (item1, item2) {
self.files.push(new SubFunction(item2));
};
}
var ViewModel = function () {
var self = this;
self.fileGroups = ko.observableArray();
self.getFileGroupById = function (id) {
ko.utils.arrayFilter(self.fileGroups(), function (item) {
return item.id == id;
});
};
self.uploadFiles = function () {
alert('Uploading');
}
}
var viewModel = new ViewModel();
viewModel.fileGroups.push(new FileGroupViewModel(1));
ko.applyBindings(viewModel);
working sample up for grabs here
Working sample if you are planning to reuse your Html

Categories

Resources