MEAN Stack: How to bind uploads to a mongoose model? - angularjs

I´m playing around with upload forms in my MEAN Application (its a project control panel). I used this tutorial for implementing a working upload: http://markdawson.tumblr.com/post/18359176420/asynchronous-file-uploading-using-express-and
With this I can upload files - they appear in my upload folder.
Now I want to achieve, that the upload is linked to the project the user made. E.g.: Jon Doe is logged in, he uploads a picture. Now I want to render his profile page. I query my project model for Jon Doe --> now I want to media files uploaded by him.
So how do I post my media, to the projectSchema of Jon Doe? Afterwards, whats the best way to display all the media in Angular?
------Edit------
I´ve been trying aroud with the extension multer, and I nearly managed to make GET and POST of uploads working. Problem is, I cant fetch any data from the database. My Console gives me a GET /uploads/media/[object%20Object] 304.
The target is: Writing the project_id, with the files to the mediaSchema. So when I´m opening a project, I get all media matching the project_id of this Project. I updated my code for you:
HTML Form
<form id="uploadForm"
enctype="multipart/form-data"
action="/uploads/"
method="post">
<label for="project_id">Ihre Projekt ID</label>
<input type="text" name="project_id" value="{{projects._id}}" readonly>
<input type="file" name="userPhoto"/>
<button type="submit">Hochladen</button>
</form>
<hr>
<img ng-src="{{media.img}}"/>
Angular Controller
var app = angular.module('myApp', []);
var projectId =
app.controller('projectCtrl', function($scope, $http) {
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar
};
$http.get('/profile/project/').then(function (res){
$scope.projects = res.data;
var projectId = $scope.projects._id;
});
//GET Media
$http.get('/uploads/media/'+projectId).then(function(data){
console.log('Medien-Daten erhalten');
$scope.media = data;
});
});
Routing:
//FILE HANDLING FOR PROJECTMEDIA
var Media = require('./models/media.js');
//GET all the media
app.get('/uploads/', function(req, res, next){
Media.find(function (err, media){
if (err) return next (err);
res.json(media);
});
});
//GET one item
app.get('/uploads/media/:projectId', function(req, res, next){
Media.findOne(req.params , function (err, media){
if (err) return next (err);
res.json(media);
});
});
mediaSchema
var mongoose = require ('mongoose');
var mediaSchema = mongoose.Schema({
img : {data: Buffer, contentType: String},
project_id : String,
updated_at : {type: Date, default: Date.now }
});
projectSchema
var projectSchema = mongoose.Schema({
author : String,
name : String,
description : String,
tags : String,
updated_at : {type: Date, default: Date.now },
active : {type: Boolean, default: false}
});

To answer your questions.
how do I post my media, to the projectSchema of Jon Doe?
In Angular you want to use the $http service. It's very simple, an example for you would be.
HTML
<input id="filebutton" name="filebutton" file-model="myFile" class="input-file" type="file">
<br>
<button ng-click="postForm()" id="singlebutton" name="singlebutton" class="btn btn-primary">Upload</button>
APP
var app = angular.module('jsbin', []);
//we need to use this directive to update the scope when the input file element is changed.
app.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
//use a service to handle the FormData upload.
app.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('userPhoto', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
//all done!
})
.error(function(){
});
};
}]);
app.controller('DemoCtrl', function($scope, $http, fileUpload) {
$scope.postForm = function(){
console.log($scope.myFile);
// Run our multiparty function.
fileUpload.uploadFileToUrl($scope.myFile, '/upload/');
};
});
Afterwards, whats the best way to display all the media in Angular?
Assuming you have your endpoint working correctly. You can do a $http only this time do a get.
JS
// make the request
$http.get('/your/media').then(function(response){
//add to scope
$scope.myMedia = response.data;
});
HTML
<div ng-repeat="photo in myMedia">{{photo}}</div>

Related

How to bind data in 'value' attribute of <input tag> to NET core MVC model using angular

I’ve been playing around with Upload file - Streaming method. The original code, here:
https://github.com/aspnet/Docs/tree/master/aspnetcore/mvc/models/file-uploads/sample/FileUploadSample
However, I’m trying to get the data in the value attribute of <input value=” ”> using Angular, the idea is that I can POST the value into my MVC model instead of whatever is typed by the user (as in the original code). So, I have done this change to the input value property.
Streaming/Index.cshtml:
<div ng-app="myApp">
<div ng-controller="myCtrl">
..
<input value="#Model.name” type="text" name="Name" ng-model="name"/>
..
<button ng-click="createUser()">Create User</button>
..
</div>
</div>
#section scripts{
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="~/js/app.js"></script>
}
However, with Angular code running under app.js, the following piece of code actually fails with status code 400. This is because the passed value is “” and not the data under of value attribute of the HTML input tag.
App.js:
var User = (function () {
function User(name) {
this.name = name;
}
return User;
}());
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('userService', ['$http', function ($http) {
this.createUser = function(user) {
var fd = new FormData();
fd.append('name', user.name);
return $http.post('/streaming/upload', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
};
}]);
myApp.controller('myCtrl', ['$scope', 'userService', function ($scope, userService) {
$scope.createUser = function () {
$scope.showUploadStatus = false;
$scope.showUploadedData = false;
var user = new User($scope.name);
userService.createUser(user).then(function (response) { // success
if (response.status == 200) {
$scope.uploadStatus = "User created sucessfully.";
$scope.uploadedData = response.data;
$scope.showUploadStatus = true;
$scope.showUploadedData = true;
$scope.errors = [];
}
},
function (response) { // failure
$scope.uploadStatus = "User creation failed with status code: " + response.status;
$scope.showUploadStatus = true;
$scope.showUploadedData = false;
$scope.errors = [];
$scope.errors = parseErrors(response);
});
};
}]);
function parseErrors(response) {
var errors = [];
for (var key in response.data) {
for (var i = 0; i < response.data[key].length; i++) {
errors.push(key + ': ' + response.data[key][i]);
}
}
return errors;
}
The solution must be a simple one, but after much research, I haven’t been able to find out how to modify it to make the data in the value=’’” attribute being passed across. This might be a stupid question but a headache for me however since I’m a total newbie regarding Angular. Please have some mercy, help.
Thanks
Use the ng-init directive to initialize the model:
<input ng-init="name= #Model.name" type="text" name="Name" ng-model="name"/>

Uploading file as part of the form in Django Rest Framework return 415

I am trying to submit a form that has an attachment from angularJS to Django backend.
I am trying to work my way through the documentation, but I still cannot get pass the 415 error.
This is my backend code so far:
class TGBuildDetail(generics.RetrieveUpdateAPIView):
queryset = TGBuild.objects.all()
serializer_class = TGBuildSerializer
permission_classes = (permissions.IsAuthenticated,)
parser_classes = (FormParser, MultiPartParser,)
def perform_update(self, serializer):
print "Hello"
Thank you in advance.
I got this working. I do not even use the FormParser, MultiPartParser, nor FileParser on the serializer.
This is how I do it. I mostly follow the file upload angularjs tutorial:
https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
At the template html:
<div class="col-sm-9"><input class="form-control" type="file" file-model="tgbuild.upload"></div>
Then I created directive file:
angular.module('ctdgroup').directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind("change", function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Then, finally in my create method in service.js:
function create(tgbuild) {
tgbuild.status = OPEN;
tgbuild.deployment_date = moment(tgbuild.deployment_date).format('YYYY/MM/DD');
var fd = new FormData();
for (var key in tgbuild){
fd.append(key, tgbuild[key]);
}
return $http.post('/tgbuilds/', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
});
}

Why isn't the form sending the text value from my form?

I'm following a tutorial to create a simple todo app using the MEAN stack. Everything was working fine until I moved the controllers and services into separate files. Now I can create a new todo but it doesn't get the text value. I can see in my mongoDB database that a new entry has been created but it doesn't have a text value. I've been looking all over my code but I can't find anything nor do I get any error or warnings in the developer tools of the browser.
Here is the code for the form:
<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="Add a todo" ng-model="formData.text">
</div>
<button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">Add</button>
</form>
</div>
</div>
Here is my service:
//todos.js service
//the service is meant to interact with our api
angular.module('todoService', [])
//simple service
//each function returns a promise object
.factory('Todos', function($http){
return {
get : function() {
return $http.get('/api/todos');
},
create : function(todoData){
return $http.post('/api/todos', todoData);
},
delete : function(id){
return $http.delete('/api/todos/' + id);
}
}
});
Here is my main controller which uses the service:
//main.js
var myApp = angular.module('todoController', []);
myApp.controller('mainController', ['$scope', '$http', 'Todos', function($scope, $http, Todos){
$scope.formData = {};
//GET
//get all the todos by using the service we created
Todos.get()
.success(function(data){
$scope.todos = data;
});
//CREATE
$scope.createTodo = function(){
Todos.create($scope.formData)
.success(function(data){
$scope.formData = {};
$scope.todos = data;
});
}
//DELETE
$scope.deleteTodo = function(id){
Todos.delete(id)
.success(function(data){
$scope.todos = data;
});
};
}]);
Lastly, here is the route for creating a todo:
var Todo = require('./models/todos');
//expose our routes to our app with module exports
module.exports = function(app){
//api
//get all todos
app.get('/api/todos', function(req, res){
Todo.find(function(err, todos){
if(err)
res.send(err);
res.json(todos);
});
});
//create to do
app.post('/api/todos', function(req, res){
Todo.create({
text: req.body.text,
done: false
}, function(err, todo){
if(err)
res.send(err);
//get and return all todos after creating the new one
Todo.find(function(err, todos){
if(err)
res.send(err);
res.json(todos);
});
});
});
To recap, for some reason the formData.text value doesn't get stored somewhere and I don't know why.
I can't say for sure with angular but normal HTML forms inputs need a name attribute to submit

How to post file and data with AngularJS with MEAN stack

I went through hundreds of pages for several days without success and here is my problem.
I use the MEAN stack and at this point I have a simple form that works very well to save a "name" field to a MongoDB collection. Now, I would like, client-side, add an image upload and, on form submit, store the image on my server and finally save the "name" field and the image path to the MongoDB collection.
AngularJS side, I tried using ng-file-upload with multer server-side. I have done well to operate for the upload of the file but only that. But after hundreds of tests, I despair. Here is an extract of my original code without file upload.
Server side
sections.server.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var SectionSchema = new Schema({
name: {
type: String,
default: '',
trim: true,
required: true,
unique: true
},
image: {
type: String,
default: ''
}
});
mongoose.model('Section', SectionSchema);
sections.server.controller
exports.create = function (req, res) {
var section = new Section(req.body);
section.save(function (err) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
res.json(section);
}
});
};
sections.server.routes
var sections = require('../../app/controllers/sections.server.controller');
module.exports = function (app) {
app.route('/api/sections')
.post(sections.create);
};
Client side
sections.client.module
'use strict';
var sections = angular.module('sections', []);
sections.client.controller
'use strict';
angular.module('sections')
.controller('SectionsController',
['$scope', '$routeParams', '$location', 'Sections'
function ($scope, $routeParams, $location, Sections) {
$scope.create = function () {
var section = new Sections({
name: this.name
});
section.$save(function (response) {
$location.path('sections/' + response._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
}]);
sections.client.routes
angular.module('sections').config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/sections', {
controller: 'SectionsController',
templateUrl: 'sections/views/list-sections.client.view.html'
})
.when('/sections/create', {
controller: 'SectionsController',
templateUrl: 'sections/views/create-section.client.view.html'
})
.otherwise({
redirectTo: '/'
});
}]);
sections.client.service
'use strict';
angular.module('sections').factory('Sections', ['$resource', function ($resource) {
return $resource('api/sections/:sectionId', {
sectionId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
create-section.client.view
<section>
<h1>New Article</h1>
<form data-ng-submit="create()" novalidate>
<div>
<label for="name">Nom du rayon</label>
<div>
<input type="text" data-ng-model="name" id="name" placeholder="Name" required>
</div>
</div>
<div>
<input type="submit">
</div>
<div data-ng-show="error"><strong data-ng-bind="error"></strong></div>
</form>
</section>
Now, from this can anyone help me to add the image upload in the form and then save the field name and the image path in MongoDB.
Note that I want to reuse the upload mecanism in other forms of my app.
I had the idea of switching a generic middleware function in the road-side server wich call multer and return the image path to my sections.create function for MongoDB storing, something like that :
module.exports = function (app) {
app.route('/api/sections')
.post(uploads.upload, sections.create);
But I've never managed to pass the file in the POST from AngularJS request.
Thank you so much for all your ideas, your help and possibly an example of code that works.

AngularJS Display Blob in embed tag - Document not loaded

I already did some research about this issue, but I don't find any problems in the code. If I save the file to disk it looks fine.
The document could not be loaded...
The javascript blob object has bytes.
Response code is 200.
Maybe somebody finds a coding issue?
The html:
<div data-ng-show="vouchercontent">
<embed ng-src="{{vouchercontent}}" style="width:400px;height:700px;"></embed>
</div>
Angular Controller:
$scope.vouchercontent = undefined;
$scope.generateVoucher = function() {
var self = this;
generateVoucherService.generateVoucher($scope.voucherdata).then(function(result) {
var file = new Blob([result], {type: 'application/pdf' });
var fileURL = window.URL.createObjectURL(file);
$scope.vouchercontent = $sce.trustAsResourceUrl(fileURL);
}, function(error) {
alert(error);
});};
Angular Service:
generateVoucher : function(data){
return $http.post('rest/generatevoucher/generate', data, {responseType: 'arraybuffer'})
.then(function(response){
return response.data;
}, function (response) {
return $q.reject(response.data);
});
}
Response in the service:
Response in the controller:

Resources