I'm pretty new with programming. I'm learning how to use CollectionFS with Angular, but cant get the files back from DB. Here is my code:
Html:
<body>
<div class="container" ng-app="upload">
<div ng-controller="uploadCtrl">
<form id="uploadForm" >
<input type="file" id="file">
<button ng-click="uploadPhoto()">Pobierz</button>
</form>
<ul>
<li ng-repeat="zdjecie in zdjecia">
<img ng-src="{{ zdjecie.url }}" />
</li>
</ul>
</div>
</div>
</body>
angular:
angular.module('upload', ['angular-meteor']);
angular.module('upload').controller('uploadCtrl', ['$scope', '$meteor',
function ($scope, $meteor) {
$scope.zdjecia = $meteor.collectionFS(Zdjecia, false, Zdjecia);
var fileInput = document.getElementById('file');
$scope.uploadPhoto = function () {
var file = fileInput.files[0];
$scope.zdjecia.save(file);
};
}]);
backend:
Zdjecia = new FS.Collection("zdjecia", {
stores: [
new FS.Store.FileSystem("zdjecia"), { path : '~/zdjecia'}
]
});
if (Meteor.isServer) {
Zdjecia.allow({
insert: function () {
return true;
}
});
}
I really can't get, how to grab a file back from the database, they also ain’t appear in the path folder.
Related
I am not able to post files using dropzone.js to controller. I have a parameter IEnumerable files. All data can be posted except dropzone files.
My code:
//Html
<div class="jumbotron">
<div class="dropzone" id="dropzoneForm">
<div class="fallback">
<input name="files" type="file" multiple/>
</div>
</div>
</div>
//Javascript:
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("div#dropzoneForm", {
url:'/TravelPlaces/Create',
paramName: 'files',
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 25,
maxFiles: 5
});
//Called by submit
function uploadClicked() {
myDropzone.processQueue();
}
//Here is my Controller Code:
// I have two other file uploader in the same form as well.
public ActionResult Create([Bind(Include = "TravelPlaceID,Title,PlaceDescription,Logo,CountryID,State,ProvinceID,DistrictID,Address,Location,OtherMap,ServicesID")] TravelPlace travelPlace,HttpPostedFileBase Logo,HttpPostedFileBase OtherMap,IEnumerable<HttpPostedFileBase> files)
{
foreach (var p in files)
{
var z = p.FileName;
}
}
I am currently working on a small angularjs app which is basically a user profile management app.
The problem i am having is with adding users dynamically. When i enter the user data, it successfully POST's to my local server i have setup, BUT i have to refresh the page to see the new user in the users list
I obviously dont want to have to refresh.
-Yes i've tried $scope.apply() after running the POST function
Something i am noticing with Angular Batarang (Debugging tool), is that the scope is updating fine, but there is a blank spot or 'null' value where the new user should be.
Here are the Controllers:
UsersApp.controller('UserListController', [ '$scope', 'userService', function($scope, userService) {
$scope.usersList = userService.usersList;
$scope.users = userService.users;
$scope.user = userService.user;
}]);
UsersApp.controller('AddUserController', function($scope, $window, dataResources, userService) {
$scope.addNew = function addNew(newUser) {
$scope.usersList = userService.usersList;
var firstName = newUser.firstName;
var lastName = newUser.lastName;
var phone = newUser.phone;
var email = newUser.email;
$scope.newUserData = {
firstName , lastName, phone , email
}
new dataResources.create($scope.newUserData);
$scope.usersList.push(dataResources);
$scope.$apply();
};
And Here are my views:
Add User:
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="js/minimize.js"></script>
<div ng-controller="AddUserController">
<div class="userInfo" id="usernameDiv">
<h2 id="username">User<img id="showhide" src="images/plus.png" style="position:absolute; padding-left:15px; width:31px; color:white;"></h2>
</div>
<div class="userInfo">
<div id="listInfo">
<form ng-controller="AddUserController">
<input type="text" placeholder= "First Name" ng-model="newUser.firstName"></input>
<input type="text" placeholder= "Last Name" ng-model="newUser.lastName"></input>
<input type="text" placeholder= "Phone Number" ng-model="newUser.phone"></input>
<input type="text" placeholder= "Email" ng-model="newUser.email"></input>
<button type="submit" ng-click="addNew(newUser)">Add User</button>
</form>
</div>
</div>
Users List:
<!DOCTYPE html>
<html>
<head></head>
<body id="">
<div ng-controller="UserListController">
<div class="userInfo">
<h2>List of Users</h2>
<div id="listInfo">
<ul style="list-style-type: none;">
<li ng-repeat="user in usersList">
<!--<p class="userData">ID: {{ user }}</p> -->
<p class="userData"><a style="cursor:pointer;" ui-sref="UserProfile">{{ user.firstName }}</a></p>
</li>
</ul>
</div>
</div>
Factory and Service:
UsersApp.factory('dataResources', [ '$resource', function($resource) {
return $resource('http://localhost:24149/users/:id', {}, {
query: {method:'GET', params:{idnum: '#id'}, isArray:true},
create: {method:'POST', headers: { 'Content-Type': 'application/json' }},
update: {method:'PUT', params:{idnum: '#id'}},
remove: {method:'DELETE', params:{idnum:'#id'}, isArray:true}
});
}]);
UsersApp.service('userService', function(dataResources) {
return {
usersList: dataResources.query()
}
});
I'm not sure if I follow exactly, but I believe you need to deal with a promise from your POST and then push the result. e.g.,
dataResources.create($scope.newUserData).$promise.then(function(data) {
$scope.usersList.push(data);
});
Your service will return a promise and then when the POST is complete your service should return the new user and you just add it to your current list.
See $resource documentation:
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
According to the doc your code should look like this:
dataResources.create($scope.newUserData,
function(data) {
$scope.usersList.push(data);
}
);
controller: you don't need to make a new userdata object, you can just use newUser
UsersApp.controller('AddUserController', function($scope, $window, dataResources, userService) {
$scope.usersList = userService.usersList;
$scope.addNew = function addNew(newUser) {
dataResources.create($scope.newUser,
function(data) {
$scope.usersList.push(data);
}
);
};
};
Same idea for angular2 using observables.
public posts: any;
onPost(input) {
this.dataService.jsonserverPost(input)
.subscribe(
(data: any) => {
this.posts.push(data);
}
);
}
Using one of the comments/answers I fixed the photo viewing, however it does not load sometimes if the image is too big. It would be great to see an example of code to turn an image into a thumbnail.
<template name="photos">
<form>
<input id="file" type="file">
<input id="addFile" type="submit">
</form>
{{#each images}}
<div>
<img src="{{this.url store='images' uploading='/images/uploading.jpg' storing='/images/storing.jpg'}}" alt="" class="thumbnail" />
</div>
{{/each}}
</template>
Javascript:
if (Meteor.isServer) {
// Create server database for listings
var Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images", {path: "~/uploads"})]
});
Template.photos.events({
'click #addFile' : function(e, t){
var file = t.find('#file').files[0];
var ticket = this._id;
var newFile = new FS.File(file);
newFile.metadata = {
ticketId: ticket
};
Images.insert(newFile, function (err, fileObj) {
if (!err) {
console.log(fileObj);
}
});
}
});
Template.photos.helpers({
images: function () {
return Images.find(); // Where Images is an FS.Collection instance
}
});
}
Ive built a rest-API to add todos in a mongodb. I can successfully save instances by using the following setup in postman:
http://localhost:3000/api/addtodo x-www-form-urlencoded with values text="Test", completed: "false".
Now when I try to replicate this with Angular, it doesnt work, the todo is saved but without the text and completed attributes, I cant seem to access the text or completed values from body. What am I doing wrong? Code below:
Angular-HTML:
<div id="todo-form" class="row">
<div class="col-sm-8 col-sm-offset-2 text-center">
<form>
<div class="form-group">
<!-- BIND THIS VALUE TO formData.text IN ANGULAR -->
<input type="text" class="form-control input-lg text-center" placeholder="I want to buy a puppy that will love me forever" ng-model="formData.text">
</div>
<!-- createToDo() WILL CREATE NEW TODOS -->
<button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">Add</button>
</form>
</div>
</div>
Angular-js:
$scope.createTodo = function() {
$http.post('/api//addtodo', $scope.formData)
.success(function(data) {
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
REST-API:
router.post('/addtodo', function(req,res) {
var Todo = require('../models/Todo.js');
var todo = new Todo();
todo.text = req.body.text;
todo.completed = req.body.completed;
todo.save(function (err) {
if(!err) {
return console.log("created");
} else {
return console.log(err);
}
});
return res.send(todo);
});
$http.post sends it's data using application/json and not application/x-www-form-urlencoded. Source.
If you're using body-parser, make sure you've included the JSON middleware.
app.use(bodyParser.json());
Either that or change your default headers for angular.
module.run(function($http) {
$http.defaults.headers.post = 'application/x-www-form-urlencoded';
});
I'm a beginner to angular.js but I have a good grasp of the basics.
What I am looking to do is upload a file and some form data as multipart form data. I read that this isn't a feature of angular, however 3rd party libraries can get this done. I've cloned angular-file-upload via git, however I am still unable to post a simple form and a file.
Can someone please provide an example, html and js of how to do this?
First of all
You don't need any special changes in the structure. I mean: html input tags.
<input accept="image/*" name="file" ng-value="fileToUpload"
value="{{fileToUpload}}" file-model="fileToUpload"
set-file-data="fileToUpload = value;"
type="file" id="my_file" />
1.2 create own directive,
.directive("fileModel",function() {
return {
restrict: 'EA',
scope: {
setFileData: "&"
},
link: function(scope, ele, attrs) {
ele.on('change', function() {
scope.$apply(function() {
var val = ele[0].files[0];
scope.setFileData({ value: val });
});
});
}
}
})
In module with $httpProvider add dependency like ( Accept, Content-Type etc) with multipart/form-data. (Suggestion would be, accept response in json format)
For e.g:
$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.post['Content-Type'] = 'multipart/form-data; charset=utf-8';
Then create separate function in controller to handle form submit call.
like for e.g below code:
In service function handle "responseType" param purposely so that server should not throw "byteerror".
transformRequest, to modify request format with attached identity.
withCredentials : false, for HTTP authentication information.
in controller:
// code this accordingly, so that your file object
// will be picked up in service call below.
fileUpload.uploadFileToUrl(file);
in service:
.service('fileUpload', ['$http', 'ajaxService',
function($http, ajaxService) {
this.uploadFileToUrl = function(data) {
var data = {}; //file object
var fd = new FormData();
fd.append('file', data.file);
$http.post("endpoint server path to whom sending file", fd, {
withCredentials: false,
headers: {
'Content-Type': undefined
},
transformRequest: angular.identity,
params: {
fd
},
responseType: "arraybuffer"
})
.then(function(response) {
var data = response.data;
var status = response.status;
console.log(data);
if (status == 200 || status == 202) //do whatever in success
else // handle error in else if needed
})
.catch(function(error) {
console.log(error.status);
// handle else calls
});
}
}
}])
<script src="//unpkg.com/angular/angular.js"></script>
This is pretty must just a copy of that projects demo page and shows uploading a single file on form submit with upload progress.
(function (angular) {
'use strict';
angular.module('uploadModule', [])
.controller('uploadCtrl', [
'$scope',
'$upload',
function ($scope, $upload) {
$scope.model = {};
$scope.selectedFile = [];
$scope.uploadProgress = 0;
$scope.uploadFile = function () {
var file = $scope.selectedFile[0];
$scope.upload = $upload.upload({
url: 'api/upload',
method: 'POST',
data: angular.toJson($scope.model),
file: file
}).progress(function (evt) {
$scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);
}).success(function (data) {
//do something
});
};
$scope.onFileSelect = function ($files) {
$scope.uploadProgress = 0;
$scope.selectedFile = $files;
};
}
])
.directive('progressBar', [
function () {
return {
link: function ($scope, el, attrs) {
$scope.$watch(attrs.progressBar, function (newValue) {
el.css('width', newValue.toString() + '%');
});
}
};
}
]);
}(angular));
HTML
<form ng-submit="uploadFile()">
<div class="row">
<div class="col-md-12">
<input type="text" ng-model="model.fileDescription" />
<input type="number" ng-model="model.rating" />
<input type="checkbox" ng-model="model.isAGoodFile" />
<input type="file" ng-file-select="onFileSelect($files)">
<div class="progress" style="margin-top: 20px;">
<div class="progress-bar" progress-bar="uploadProgress" role="progressbar">
<span ng-bind="uploadProgress"></span>
<span>%</span>
</div>
</div>
<button button type="submit" class="btn btn-default btn-lg">
<i class="fa fa-cloud-upload"></i>
<span>Upload File</span>
</button>
</div>
</div>
</form>
EDIT: Added passing a model up to the server in the file post.
The form data in the input elements would be sent in the data property of the post and be available as normal form values.
It is more efficient to send the files directly.
The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. If the server supports it, it is more efficient to send the files directly:
Doing Multiple $http.post Requests Directly from a FileList
$scope.upload = function(url, fileList) {
var config = {
headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
var promises = fileList.map(function(file) {
return $http.post(url, file, config);
});
return $q.all(promises);
};
When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.
Working Demo of "select-ng-files" Directive that Works with ng-model1
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
angular.module("app",[]);
angular.module("app").directive("selectNgFiles", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileList" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileList">
{{file.name}}
</div>
</body>
You can check out this method for sending image and form data altogether
<div class="form-group ml-5 mt-4" ng-app="myApp" ng-controller="myCtrl">
<label for="image_name">Image Name:</label>
<input type="text" placeholder="Image name" ng-model="fileName" class="form-control" required>
<br>
<br>
<input id="file_src" type="file" accept="image/jpeg" file-input="files" >
<br>
{{file_name}}
<img class="rounded mt-2 mb-2 " id="prvw_img" width="150" height="100" >
<hr>
<button class="btn btn-info" ng-click="uploadFile()">Upload</button>
<br>
<div ng-show = "IsVisible" class="alert alert-info w-100 shadow mt-2" role="alert">
<strong> {{response_msg}} </strong>
</div>
<div class="alert alert-danger " id="filealert"> <strong> File Size should be less than 4 MB </strong></div>
</div>
Angular JS Code
var app = angular.module("myApp", []);
app.directive("fileInput", function($parse){
return{
link: function($scope, element, attrs){
element.on("change", function(event){
var files = event.target.files;
$parse(attrs.fileInput).assign($scope, element[0].files);
$scope.$apply();
});
}
}
});
app.controller("myCtrl", function($scope, $http){
$scope.IsVisible = false;
$scope.uploadFile = function(){
var form_data = new FormData();
angular.forEach($scope.files, function(file){
form_data.append('file', file); //form file
form_data.append('file_Name',$scope.fileName); //form text data
});
$http.post('upload.php', form_data,
{
//'file_Name':$scope.file_name;
transformRequest: angular.identity,
headers: {'Content-Type': undefined,'Process-Data': false}
}).success(function(response){
$scope.IsVisible = $scope.IsVisible = true;
$scope.response_msg=response;
// alert(response);
// $scope.select();
});
}
});