Edit: NEVERMIND - I made a small mistake in the Angular service. My bad.
I'm trying to teach myself more backend by building a simple CMS using angular, Node and Express, and PostgreSql. I figured out how to do achieve all the CRUD functionality except UPDATE. I thought I understood what to do but I can't figure out where I'm going wrong. I keep getting a 404. What am I misunderstanding or going about the wrong way? I know this is simple but I'm pretty new so any help in understanding where I'm getting confused is really appreciated. Here's the relevant code:
HTML
<form ng-submit="updateBlogEntry(specificBlog.id, specificBlog.title, specificBlog.author, specificBlog.imageurl, specificBlog.content)">
<h2>Title:</h2>
<input type="text" ng-model="specificBlog.title"></input>
<br>
<h3>Author:</h3>
<input type="text" ng-model="specificBlog.author"></input>
<br>
<h3>Photo:</h3>
<input type="text" ng-model="specificBlog.imageurl"></input>
<br>
<h3>Content:</h3>
<textarea type="text" rows="5" cols="50" ng-model="specificBlog.content">
</textarea>
<br>
<button type="submit">Save Changes</button>
</form>
Angular Controller
var id = $stateParams.id;
var title = $stateParams.title;
var author = $stateParams.author;
var imageurl = $stateParams.imageurl;
var content = $stateParams.content;
$scope.updateBlogEntry = function(id, title, author, imageurl, content) {
adminService.updateBlogEntry(id, title, author, imageurl, content);
}
Angular Service
this.updateBlogEntry = function(id, title, author, imageurl, content) {
return $http({
method: 'PUT',
url: 'updateBlogEntry/' + id,
data: {
id: id,
title: title,
author: author,
imageurl: imageurl,
content: content
}
})
.success(function(data) {
alert("Entry Updated");
})
.error(function(data) {
alert("Error Updating");
})
Server Index
// EXTERNAL MODULES //
var express = require('express');
var bodyParser = require('body-parser');
var session = require('express-session');
var massive = require('massive');
// CONFIG //
var config = require('./config');
// EXPRESS //
var app = module.exports = express();
app.use(express.static(__dirname + './../dist'));
app.use(bodyParser.json());
// MASSIVE //
var massiveUri = config.MASSIVE_URI;
var massiveServer = massive.connectSync({
connectionString: massiveUri
});
app.set('db', massiveServer);
var db = app.get('db');
var dbSetup = require('./services/dbSetup');
dbSetup.run();
// CONTROLLERS //
var userCtrl = require('./controllers/userCtrl');
var blogCtrl = require('./controllers/blogCtrl');
// Blog Endpoints //
app.post('/api/createBlogEntry', blogCtrl.createBlogEntry);
app.get('/api/getBlogEntries', blogCtrl.readBlogEntries);
app.get('/api/getBlogEntry/:id', blogCtrl.readBlogEntry);
// BUG Why isn't this working?
app.put('/api/updateBlogEntry/:id', blogCtrl.updateBlogEntry);
// CONNECTIONS //
var port = config.PORT;
app.listen(port, function() {
console.log('Listening on port ' + port);
});
Node Controller
updateBlogEntry: function(req, res, next){
db.blogs.blog_update([
req.params.id,
req.body.title,
req.body.author,
req.body.imageurl,
req.body.content
],
function(err, results){
if (err){
console.error(err);
res.send(err);
} else {
res.send(results[0]);
}
})
}
blog_update.sql
UPDATE blogs
set
title = COALESCE($2, title),
author = COALESCE($3, author),
imageurl = COALESCE($4, imageurl),
content = COALESCE($5, content)
WHERE id = $1
RETURNING * ;
The error in the console:
angular.js:11881 PUT http://localhost:3000/updateBlogEntry/1 404 (Not Found)
You have written your URL wrong.
It should be /api/updateBlogEntry as per your Node's express routes.
change this part
` url: 'updateBlogEntry/' + id,`
It should be
url: '/api/updateBlogEntry/' + id,
so Im currently making an application using MEAN stack. The problem i have at the moment is, when making a call to the API, I am able to successfully retrieve all objects and each object by ID from the database(using POSTMAN(Chrome)) I have set up using mongoose & express router. My question is, can I retrieve an object by it's name ? I have been searching the web and I am unsure how I could implement this. For example: This is the Api code i currently have.
var Dishes = require('../../app/models/dishes');
var Terms = require('../../app/models/terms');
var config = require('../../config');
module.exports = function(app,express){
// api ---------------------------------------------------------------------
var apiRouter = express.Router();
// middleware to use for all requests
apiRouter.use(function (req, res, next) {
// do logging
console.log('Somebody just came to our app!');
next();
});
// Test routes to make sure everything is working
//(accessed at GET http://localhost:3000/api)
apiRouter.get('/', function (req, res) {
res.json({message: 'Welcome to the API!'});
});
/** ================================= Dishes ==========================================**/
//on routes that end in /dishes , show all dishes in json
apiRouter.get('/dishes', function (req, res) {
Dishes.find(function (err, dishes) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err);
res.json(dishes); // return all dishes in JSON format
});
});
//on routes that end in /dishes/:_id , show all the this with the corresponding ID
// get the dish with that id
// (accessed at GET http://localhost:8080/api/dishes/:dish_id)
apiRouter.get('/dishes/:_id',function(req, res) {
Dishes.findById(req.params._id, function(err, dish) {
if (err) res.send(err);
// return that dish
res.json(dish);
});
});
return apiRouter;
};
The dish model I am access is as follows:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//with Mongoose everything is derived from a schema ! Lets get a reference and define our Dishes Schema
var DishSchema = mongoose.Schema({
dishName: {type: String, index: {unique: true}},
Desc : {type: String, index: { unique: true}},
Allergy: String,
HealthRisks: String
},{collection:'Dishes'});
module.exports = DishSchema;
//The Next step is to compile our schema into a model
var Dishes = mongoose.model('Dishes', DishSchema);//Dish Schema into model
// return the model
module.exports = mongoose.model('Dishes', DishSchema)
What I wish to do is make an api call to (/dishes/:dishName) and return the relevant dish. Any help would be greatly appreciated.
apiRouter.get('/dishes/getByName/:dishName',function(req, res) {
Dishes.findOne({dishName:req.params.dishName}, function(err, dish) {
if (err) res.send(err);
// return that dish
res.send(dish);
});
});
I know this has been asked many times before, and I have read almost all I could find about the subject, namely:
https://stackoverflow.com/a/25022437/1031184
Uploading images using Node.js, Express, and Mongoose
Those are the best I have found so far. My problem is tho that they still aren't very clear, there is very little documentation online at all about this and the discussion seems aimed at people who are much more advanced than I am.
So with that I would really love it if someone could please walk me though how to upload images using Mongoose, Express & AngularJS. I am actually using the MEAN fullstack. (this generator to be precise – https://github.com/DaftMonk/generator-angular-fullstack)
AddController:
'use strict';
angular.module('lumicaApp')
.controller('ProjectAddCtrl', ['$scope', '$location', '$log', 'projectsModel', 'users', 'types', function ($scope, $location, $log, projectsModel, users, types) {
$scope.dismiss = function () {
$scope.$dismiss();
};
$scope.users = users;
$scope.types = types;
$scope.project = {
name: null,
type: null,
images: {
thumbnail: null // I want to add the uploaded images _id here to reference with mongoose populate.
},
users: null
};
$scope.save = function () {
$log.info($scope.project);
projectsModel.post($scope.project).then(function (project) {
$scope.$dismiss();
});
}
}]);
I want to add the Images ID reference to project.images.thumbnail but I want to store all the information inside an Image Object using the following Schema:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ImageSchema = new Schema({
fileName: String,
url: String,
contentType: String,
size: String,
dimensions: String
});
module.exports = mongoose.model('Image', ImageSchema);
I have also added the following https://github.com/nervgh/angular-file-upload to my bower packages.
As I say I just can't figure out how to tie it all together. And I'm not even sure if what I am trying to do is the correct way either.
--------------------------------------------------------------------------\
UPDATE:
Here is what I now have, I have added some comments detailing how I would like it to work, unfortunately I still haven't managed to get this working, I can't even get the image to start uploading, never mind uploading to S3. Sorry to be a pain but I am just finding this particularly confusing, which surprises me.
client/app/people/add/add.controller.js
'use strict';
angular.module('lumicaApp')
.controller('AddPersonCtrl', ['$scope', '$http', '$location', '$window', '$log', 'Auth', 'FileUploader', 'projects', 'usersModel', function ($scope, $http, $location, $window, $log, Auth, FileUploader, projects, usersModel) {
$scope.dismiss = function () {
$scope.$dismiss();
};
$scope.newResource = {};
// Upload Profile Image
$scope.onUploadSelect = function($files) {
$scope.newResource.newUploadName = $files[0].name;
$http
.post('/api/uploads', {
uploadName: newResource.newUploadName,
upload: newResource.newUpload
})
.success(function(data) {
newResource.upload = data; // To be saved later
});
};
$log.info($scope.newResource);
//Get Projects List
$scope.projects = projects;
//Register New User
$scope.user = {};
$scope.errors = {};
$scope.register = function(form) {
$scope.submitted = true;
if(form.$valid) {
Auth.createUser({
firstName: $scope.user.firstName,
lastName: $scope.user.lastName,
username: $scope.user.username,
profileImage: $scope.user.profileImage, // I want to add the _id reference for the image here to I can populate it with 'ImageSchema' using mongoose to get the image details(Name, URL, FileSize, ContentType, ETC)
assigned: {
teams: null,
projects: $scope.user.assigned.projects
},
email: $scope.user.email,
password: $scope.user.password
})
.then( function() {
// Account created, redirect to home
//$location.path('/');
$scope.$dismiss();
})
.catch( function(err) {
err = err.data;
$scope.errors = {};
// Update validity of form fields that match the mongoose errors
angular.forEach(err.errors, function(error, field) {
form[field].$setValidity('mongoose', false);
$scope.errors[field] = error.message;
});
});
}
};
$scope.loginOauth = function(provider) {
$window.location.href = '/auth/' + provider;
};
}]);
server/api/image/image.model.js I would like to store all image information here and use this to populate profileImage in people controller.
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ImageSchema = new Schema({
fileName: String,
url: String, // Should store the URL of image on S3.
contentType: String,
size: String,
dimensions: String
});
module.exports = mongoose.model('Image', ImageSchema);
client/app/people/add/add.jade
.modal-header
h3.modal-title Add {{ title }}
.modal-body
form(id="add-user" name='form', ng-submit='register(form)', novalidate='')
.form-group(ng-class='{ "has-success": form.firstName.$valid && submitted,\
"has-error": form.firstName.$invalid && submitted }')
label First Name
input.form-control(type='text', name='firstName', ng-model='user.firstName', required='')
p.help-block(ng-show='form.firstName.$error.required && submitted')
| First name is required
.form-group(ng-class='{ "has-success": form.lastName.$valid && submitted,\
"has-error": form.lastName.$invalid && submitted }')
label Last Name
input.form-control(type='text', name='lastName', ng-model='user.lastName', required='')
p.help-block(ng-show='form.lastName.$error.required && submitted')
| Last name is required
.form-group(ng-class='{ "has-success": form.username.$valid && submitted,\
"has-error": form.username.$invalid && submitted }')
label Username
input.form-control(type='text', name='username', ng-model='user.username', required='')
p.help-block(ng-show='form.username.$error.required && submitted')
| Last name is required
// Upload Profile Picture Here
.form-group
label Profile Image
input(type="file" ng-file-select="onUploadSelect($files)" ng-model="newResource.newUpload")
.form-group(ng-class='{ "has-success": form.email.$valid && submitted,\
"has-error": form.email.$invalid && submitted }')
label Email
input.form-control(type='email', name='email', ng-model='user.email', required='', mongoose-error='')
p.help-block(ng-show='form.email.$error.email && submitted')
| Doesn't look like a valid email.
p.help-block(ng-show='form.email.$error.required && submitted')
| What's your email address?
p.help-block(ng-show='form.email.$error.mongoose')
| {{ errors.email }}
.form-group(ng-class='{ "has-success": form.password.$valid && submitted,\
"has-error": form.password.$invalid && submitted }')
label Password
input.form-control(type='password', name='password', ng-model='user.password', ng-minlength='3', required='', mongoose-error='')
p.help-block(ng-show='(form.password.$error.minlength || form.password.$error.required) && submitted')
| Password must be at least 3 characters.
p.help-block(ng-show='form.password.$error.mongoose')
| {{ errors.password }}
.form-group
label Assign Project(s)
br
select(multiple ng-options="project._id as project.name for project in projects" ng-model="user.assigned.projects")
button.btn.btn-primary(ng-submit='register(form)') Save
pre(ng-bind="user | json")
.modal-footer
button.btn.btn-primary(type="submit" form="add-user") Save
button.btn.btn-warning(ng-click='dismiss()') Cancel
server/api/upload/index.js
'use strict';
var express = require('express');
var controller = require('./upload.controller');
var router = express.Router();
//router.get('/', controller.index);
//router.get('/:id', controller.show);
router.post('/', controller.create);
//router.put('/:id', controller.update);
//router.patch('/:id', controller.update);
//router.delete('/:id', controller.destroy);
module.exports = router;
server/api/upload/upload.controller.js
'use strict';
var _ = require('lodash');
//var Upload = require('./upload.model');
var aws = require('aws-sdk');
var config = require('../../config/environment');
var randomString = require('../../components/randomString');
// Creates a new upload in the DB.
exports.create = function(req, res) {
var s3 = new aws.S3();
var folder = randomString.generate(20); // I guess I do this because when the user downloads the file it will have the original file name.
var matches = req.body.upload.match(/data:([A-Za-z-+\/].+);base64,(.+)/);
if (matches === null || matches.length !== 3) {
return handleError(res, 'Invalid input string');
}
var uploadBody = new Buffer(matches[2], 'base64');
var params = {
Bucket: config.aws.bucketName,
Key: folder + '/' + req.body.uploadName,
Body: uploadBody,
ACL:'public-read'
};
s3.putObject(params, function(err, data) {
if (err)
console.log(err)
else {
console.log("Successfully uploaded data to my-uploads/" + folder + '/' + req.body.uploadName);
return res.json({
name: req.body.uploadName,
bucket: config.aws.bucketName,
key: folder
});
}
});
};
function handleError(res, err) {
return res.send(500, err);
}
server/config/environment/development.js
aws: {
key: 'XXXXXXXXXXXX',
secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
region: 'sydney',
bucketName: 'my-uploads'
}
All of this code is straight out of a project that depends heavily on this for large file uploads and images. Definitely checkout https://github.com/nervgh/angular-file-upload
In my view somewhere:
<div class="form-group">
<label>File Upload</label>
<input type="file" ng-file-select="onUploadSelect($files)" ng-model="newResource.newUpload">
</div>
Using the module angularFileUpload I then have in my controller:
$scope.onUploadSelect = function($files) {
$scope.newResource.newUploadName = $files[0].name;
};
https://github.com/nervgh/angular-file-upload
When the user clicks upload this gets executed where I send the file to be uploaded:
$http
.post('/api/uploads', {
uploadName: newResource.newUploadName,
upload: newResource.newUpload
})
.success(function(data) {
newResource.upload = data; // To be saved later
});
This request is sent to a controller that looks something like this:
'use strict';
var _ = require('lodash');
var aws = require('aws-sdk');
var config = require('../../config/environment');
var randomString = require('../../components/randomString');
// Creates a new upload in the DB.
exports.create = function(req, res) {
var s3 = new aws.S3();
var folder = randomString.generate(20); // I guess I do this because when the user downloads the file it will have the original file name.
var matches = req.body.upload.match(/data:([A-Za-z-+\/].+);base64,(.+)/);
if (matches === null || matches.length !== 3) {
return handleError(res, 'Invalid input string');
}
var uploadBody = new Buffer(matches[2], 'base64');
var params = {
Bucket: config.aws.bucketName,
Key: folder + '/' + req.body.uploadName,
Body: uploadBody,
ACL:'public-read'
};
s3.putObject(params, function(err, data) {
if (err)
console.log(err)
else {
console.log("Successfully uploaded data to csk3-uploads/" + folder + '/' + req.body.uploadName);
return res.json({
name: req.body.uploadName,
bucket: config.aws.bucketName,
key: folder
});
}
});
};
function handleError(res, err) {
return res.send(500, err);
}
server/components/randomString/index.js
'use strict';
module.exports.generate = function(textLength) {
textLength = textLength || 10;
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for(var i = 0; i < textLength; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
server/config/environment/development.js
server/api/upload/upload.controller.js
This is the way i used MEAN.JS for file upload.
Model
var UserSchema = new mongoose.Schema({
name:{type:String,required:true},
photo:Buffer // Image
});
Server Controller
var userPicture = function(req,res){ // Stores Picture for a user matching the ID.
user.findById(req.param('id'), function (err, user) {
console.log(req.files) // File from Client
if(req.files.file){ // If the Image exists
var fs = require('node-fs');
fs.readFile(req.files.file.path, function (dataErr, data) {
if(data) {
user.photo ='';
user.photo = data; // Assigns the image to the path.
user.save(function (saveerr, saveuser) {
if (saveerr) {
throw saveerr;
}
res.json(HttpStatus.OK, saveuser);
});
}
});
return
}
res.json(HttpStatus.BAD_REQUEST,{error:"Error in file upload"});
});
};
Client Controller
$scope.saveuserImage = function(){
$scope.upload = $upload.upload({ // Using $upload
url: '/user/'+$stateParams.id+'/userImage', // Direct Server Call.
method:'put',
data:'', // Where the image is going to be set.
file: $scope.file
}).progress(function (evt) {})
.success(function () {
var logo = new FileReader(); // FileReader.
$scope.onAttachmentSelect = function(file){
logo.onload = function (e) {
$scope.image = e.target.result; // Assigns the image on the $scope variable.
$scope.logoName = file[0].name; // Assigns the file name.
$scope.$apply();
};
logo.readAsDataURL(file[0]);
$scope.file = file[0];
$scope.getFileData = file[0].name
};
location.reload();
$scope.file = "";
$scope.hideUpload = 'true'
});
$scope.getFileData = '';
// location.reload()
};
Html
The ng-file-select is used to get the file from the client.
This works fine for me. Hope this helps.
Note: I have used HTML tag instead of jade. Suitable changes applicable while using jade.
As far as I can guess, you are binding the FileReader.onload() method inside the saveUserImage function, then the onload method will be never called as the function is never binded instead a user calls saveUserImage method before editing the image. After that, no image will be selected as the onload() method will not execute.
Try coding Client Controller it this way
//This goes outside your method and will handle the file selection.This must be executed when your `input(type=file)` is created. Then we will use ng-init to bind it.
$scope.onAttachmentSelect = function(){
var logo = new FileReader(); // FileReader.
logo.onload = function (event) {
console.log("THE IMAGE HAS LOADED");
var file = event.currentTarget.files[0]
console.log("FILENAME:"+file.name);
$scope.image = file;
$scope.logoName = file.name; // Assigns the file name.
$scope.$apply();
//Call save from here
$scope.saveuserImage();
};
logo.readAsDataURL(file[0]);
$scope.file = file[0];
$scope.getFileData = file[0].name
reader.readAsDataURL(file);
};
//The save method is called from the onload function (when you add a new file)
$scope.saveuserImage = function(){
console.log("STARGING UPLOAD");
$scope.upload = $upload.upload({ // Using $upload
url: '/user/'+$stateParams.id+'/userImage',
method:'put'
data:, $scope.image
file: $scope.file
}).progress(function (evt) {})
.success(function () {
location.reload();
$scope.file = "";
$scope.hideUpload = 'true'
});
$scope.getFileData = '';
// location.reload()
};
The HTML.
//There is the ng-init call to binding function onAttachmentSelect
<div class="form-group">
<label>File Upload</label>
<input type="file" ng-init="onAttachmentSelect" ng-model="newResource.newUpload">
</div>
Hope this clue may help you
EDIT*
Will try to explain you the different Steps you must follow to check your code:
1.- Is your input[type=file] showing? If showing, please select an image
2.- Is your input calling the onload when the image selected has changed? (a console.log should be printed with my code version)
3.- If it has been called. Make the operations you need before sending, inside the onload method (if possible)
4.- When this method has finished doing desired changes. Inform with ng-model or however you want, a variable in the object you prepared to upload, with the base64 string generated in the onload method.
When arriving this point, remember checking that:
As very big images could be sent over json with base64, it´s very important to remember changing the minimum json size in Express.js for your app to prevent rejects. This is done, for example in your server/app.js as this:
var bodyParser = require('body-parser');
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb'}));
Remember also that the method reader.readAsDataURL(file) will give you a base64 string that could act as src of the image. You don´t need more than this. This base64 is what you can save in mongoose. Then, you can use ng-model to send a variable containing the base64 in the form with the "submit" button.
Then, in the Express.js endpoint that will handle your form, you will be able to decode the base64 string to a file, or to save the base64 directly on mongoose (storing images in the db is not much recommended if a lot of images is being to be loaded, or big ones desired, as the mongoDB query will be very slow).
Hope you can solve with those indications. If you still have some doubts, please comment and I´ll try to help
I'm also a noob using MEANJS, and this is how I made it work using ng-flow + FileReader:
HTML input:
<div flow-init
flow-files-added="processFiles($files)"
flow-files-submitted="$flow.upload()"
test-chunks="false">
<!-- flow-file-error="someHandlerMethod( $file, $message, $flow )" ! need to implement-->
<div class="drop" flow-drop ng-class="dropClass">
<span class="btn btn-default" flow-btn>Upload File</span>
<span class="btn btn-default" flow-btn flow-directory ng-show="$flow.supportDirectory">Upload Folder</span>
<b>OR</b>
Drag And Drop your file here
</div>
controller:
$scope.uploadedImage = 0;
// PREPARE FILE FOR UPLOAD
$scope.processFiles = function(flow){
var reader = new FileReader();
reader.onload = function(event) {
$scope.uploadedImage = event.target.result;
};
reader.onerror = function(event) {
console.error('File could not be read! Code ' + event.target.error.code);
};
reader.readAsDataURL(flow[0].file);
};
And on the server side the variable on the model receiving the value of uploadedImage is just of type string.
Fetching it back from the server didn't require any conversion:
<img src={{result.picture}} class="pic-image" alt="Pic"/>
Now just need to find out what to do with big files...
I am using ABP (ASP.NET Boilerplate) Web API and angularjs to build a SinglePageApplication. I already got it working to call the server side methods via angular and the abp framework. It is easy to just send JSON-data but I have no idea how to send files.
Here is an example of sending JSON-Data:
Server-Code
public class PostAppService : ApplicationService, IPostAppService
{
public LoginOutput Login(LoginInput input)
{
doSomeStuffHere();
}
}
[DependsOn(typeof(AbpWebApiModule))]
public class SimpleTaskSystemWebApiModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
}
}
Client-Code
(function() {
var app = angular.module('app');
var controllerId = 'sts.views.authentication.login';
app.controller(controllerId, [
'$scope', '$location', 'abp.services.tasksystem.authentication',
function ($scope, $location, authService) {
var vm = this;
vm.user = {
username: '',
password: ''
};
var localize = abp.localization.getSource('SimpleTaskSystem');
vm.login = function () {
abp.ui.setBusy(
null,
authService.login(
vm.user
).success(function(response) {
displayLoggedInMessage();
})
);
};
}
]);
})();
I would like to do something like this but instead of sending JSON-Data I would like to send an image selected via:
<input type="file"/>
Any ideas?
A good way of achieving upload file:
Create a controller named UploadController from the base
AbpController
Add a method to upload the file. Let's name it ProductPhoto
public JsonResult ProductPhoto(string comment, int productId)
{
try
{
if (!Request.Files.Any() || Request.Files[0] == null)
{
return null;
}
var fileName = Guid.NewGuid();
var uniqueFilePath = #"~\Upload\ProductPhotos\" + fileName;
Request.Files[0].SaveAs(uniqueFilePath);
//save your additional parameters such as comment, productId
return Json(new
{
Success = true,
FileName = fileName
});
}
catch (Exception ex)
{
Logger.Error(ex.ToString);
return Json(new
{
Success = false
});
}
}
On the client send send the file using jquery or angular
vm.showProductPhotoUploadFileDialog = function () {
var formData = = new FormData()
formData .append("productId", vm.form.product.id);
formData .append("formId", vm.form.id);
if (vm.newProductPhoto.comment) {
formData .append("comment", vm.newProductPhoto.comment);
}
$('#productPhotoFileInput').click();
};
After upload completes get the result using callback
vm.productPhotoUploaded = function (response) {
if (!response.success) {
return;
}
vm.productPhotoFileName = response.fileName;
};
At this step you have the unique filename generated on the server for this file. Now you can update your client side object. Or you can go on your cascade savings.
Note: One disadvantage of this approach is; when user uploads file and then cancels the master entity save, you have to manually handle to delete the temp file uploaded to server.
Should be a fairly easy one here for anyone who knows Angular. I am trying to update the data that is displayed after I make a PUT request to update the object. Here is some code:
Post service (services/post.js)
'use strict';
angular.module('hackaboxApp')
.factory('Post', function($resource) {
return $resource('/api/posts/:id', {id : '#id'}, {
'update': { method: 'PUT' }
})
});
Server side controller function that gets executed when trying to update data (lib/controllers/api.js)
exports.editsave = function(req, res, next) {
var posty = req.body;
console.log(posty._id.toString() + " this is posty");
function callback (err, numAffected) {
console.log(err + " " + numAffected);
if(!err) {
res.send(200);
//res.redirect('/forum');
}
}
Post.update(posty, { id: posty._id.toString() }, callback);
};
This is the console output for the above code:
53c54a0d4960ddc11495d7d7 this is posty
null 0
So as you can see, it isn't affecting any of the MongoDB documents, but it also isn't producing errors.
This is what happens on the client (Angular) side when a post is updated:
$scope.saveedit = function() {
console.log($scope.post._id + " post id");
// Now call update passing in the ID first then the object you are updating
Post.update({ id:$scope.post._id }, $scope.post, function() {$location.path('/forum')});
};
After the redirect, $location.path('/forum'), none of the data is displayed as being updated...when I look in the database...nothing has changed either...it is like I am missing the step to save the changes...but I thought that update (a PUT request) would do that for me.
I use ng-init="loadposts()" when the /forum route is loaded:
$scope.loadposts = function() {
$http.get('/api/posts').success(function (data) {$scope.posts = data});
};
Shouldn't all the new data be loaded after this? Any help would be appreciated. Thanks!
Your server side output indicate that the update query doesn't match any document in the database.
I'm guessing that you are using Mongoose in NodeJS server side code to connect to mongodb.
If that the case, your update statement seems incorrect.
Instead of { id: .. } it should be { _id: .. }
Also the conditions object and updated object are swapped.
The statement should be like this:
Post.update({ _id: posty._id.toString() }, posty, callback);
If you are not using Mongoose, please eloborate more on which library you are using or better than that, show the code where the Post variable is defined in your server side code.
Ok I got it.
the problem is that you are not using the Angular resource api correct.
This code need to be changed:
$scope.saveedit = function() {
console.log($scope.post._id + " post id");
Post.update({ id:$scope.post._id }, $scope.post, function() {$location.path('/forum')});
};
Into:
// Update existing Post
$scope.saveedit = function() {
var editedpost = new Post($scope.post); //New post object
editedpost.$update(function() {
$location.path('/forum');
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
And as for the server code (taken from my own working module):
exports.update = function (req, res) {
var post == req.post;
post = _.extend(post, req.body);
post.save(function (err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(post);
}
});
};