How to add an array to a javascript server side model in MEAN.JS - javascript

I am using MEAN.JS and I have created a module for projects. I would like to add tasks to these projects and I would like to do it with a multi-dimensional array. I would like the array to include a task.description and a task.status which would both be strings. I think I understand the client-side part of my project and I know there are still other files. However, I believe this will make the question as simple as possible, as I am struggling to get my profile developed on this site. I will however include controller.js, so I can get this working and hopefully give credit for a correct answer.
project.server.model.js
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Project Schema
*/
var ProjectSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
description: {
type: String,
default: '',
trim: true
},
/* MODEL for TASK ARRAY*/
task: {
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Project', ProjectSchema);
projects.server.controller.js
'use strict';
/**
* Module dependencies.
*/
var path = require('path'),
mongoose = require('mongoose'),
Project = mongoose.model('Project'),
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
/**
* Create a project
*/
exports.create = function (req, res) {
var project = new Project(req.body);
project.user = req.user;
project.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(project);
}
});
};
/**
* Show the current project
*/
exports.read = function (req, res) {
res.json(req.project);
};
/**
* Update a project
*/
exports.update = function (req, res) {
var project = req.project;
project.title = req.body.title;
project.description = req.body.description;
project.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(project);
}
});
};
edit-project.client.view.html
<section ng-controller="ProjectsController" ng-init="findOne()">
<div class="page-header">
<h1>Edit Project</h1>
</div>
<div class="col-md-12">
<form name="projectForm" class="form-horizontal" ng-submit="update(projectForm.$valid)" novalidate>
<fieldset>
<div class="form-group" show-errors>
<label for="title">Title</label>
<input name="title" type="text" ng-model="project.title" id="title" class="form-control" placeholder="Title" required>
<div ng-messages="projectForm.title.$error" role="alert">
<p class="help-block error-text" ng-message="required">Project title is required.</p>
</div>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" ng-model="project.description" id="description" class="form-control" cols="30" rows="4" placeholder="Description"></textarea>
</div>
<div class="form-group">
Task Description
<textarea name="description" ng.model="project.task.description" class="form-control" cols="30" rows="3" placeholder="Description"></textarea>
<div>
Task Status
<input name="status" ng.model="project.task.status" class="form-control" placeholder="Status">
</div>
</div>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
</fieldset>
</form>
</div>
</section>

First, create a model for tasks (task.server.model.js), which references a Project
var TaskSchema = new mongoose.Schema({
description: String,
status: String,
// referencing Project model
project: { type: mongoose.Schema.Types.ObjectId, ref: 'Project' }
});
And then in Project model reference Task
// Add this to Project Schema definition
tasks: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Task' }]

It's should
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Task Schema
*/
var TaskSchema = new Schema({
description: String,
status: String,
project: {
type: Schema.ObjectId,
ref: 'Project'
}
});
Hope it's help you!

Related

MethodOverride PUT not working

I am using Node.js, Express and MethodOverride to try and have a form update only 1 part of a model (my user model).
User model:
var userSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true },
password: String,
profile: {
name: { type: String, default: 'Company Name' },
location: { type: String, default: 'Location' },
website: { type: String, default: 'Your Website' },
picture: { type: String, default: '' }
},
assetNumPre: { type: String, default: 'test' }, // this is the one I want to change
});
module.exports = mongoose.model('User', userSchema);
HTML form:
<form role="form-inline"action="/dashboard/settings/assetNumber?_method=PUT" method="POST">
<div class="col-md-3">
<div class="form-group">
<label for="prefix" class="control-label">Prefix for Asset Number</label>
<br>
<small>Any alphanumeric characters to a limit of 6</small>
<input type="text" class="form-control" id="prefix" name="prefix" placeholder="Prefix max 6 characters" maxlength="6" value="{{ prefix }}">
</div><!-- Prefix for Asset Number-->
<br>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
Then route:
app.put('/dashboard/settings/assetNumber',
setRender('dashboard/settings/assetNumbers'),
setRedirect({auth: '/login'}),
isAuthenticated,
dashboard.getDefault,
(req, res) => {
var prefix = req.body.prefix;
console.log(req.params);
User.findByIdAndUpdate({_id: req.params.user_id}, prefix, function(err, UpdatedUser) {
if (err) {
res.send(err);
}
console.log(UpdatedUser);
});
res.locals.prefix = req.user.assetNumPre;
});
One thing my route is missing is req.user.assetNumPre which is where I need to save it but I have no clue how to do this PUT request. Docs are not helping much either.
I got the route from a Stack Overflow example a few days ago and can't find the link to it. My app.js had method override working because I have done DELETE requests already. The model has the correct field and has a default test value that shows up in my show page.
You're calling this:
User.findByIdAndUpdate({_id: req.params.user_id}, prefix...
But prefix is only the value:
var prefix = req.body.prefix;
findByIdAndUpdate takes an Object, not a value, to update a specific field.
So try:
User.findByIdAndUpdate({_id: req.params.user_id}, { assetNumPre: prefix }...
Here is the fixed route:
app.put('/dashboard/settings/assetNumber',
setRedirect({auth: '/login', success: '/dashboard/settings/assetNumber', failure: '/dashboard/settings/assetNumber'}),
isAuthenticated,
(req, res) => {
User.findById(req.user.id, function(err, user) {
if (err) return (err);
user.assetNumPre = req.body.prefix || 'pre';
user.save(function(err) {
if (err) return (err);
req.flash('success', { msg: 'Asset Number Prefix updated.' });
res.redirect(req.redirect.success);
});
});
res.locals.prefix = req.user.assetNumPre;
});
So a few things changed that were not part of the issue. I figured out I need to just set the data inside the callback function. Then do a user.save.

Creating new array with variables coming back as undefined

I am creating a blog web application. I currently have the blogSchema set up as
var BlogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created:
{type: Date, default: Date.now},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
module.exports = mongoose.model("Blog", BlogSchema);
I have a post form of the following
<div class="ui main text container segment">
<div class="ui huge header">New Blog</div>
<form class="ui form" action="/blogs" method="POST">
<div class="field">
<label>Title</label>
<input type="text" name="blog[title]" placeholder="title">
</div>
<div class="field">
<label>Image</label>
<input type="text" name="blog[image]" placeholder="image">
</div>
<div class="field">
<label>Blog Content</label>
<textarea name="blog[body]"></textarea>
</div>
<input class="ui violet big basic button" type="submit">
</form>
</div>
On my blog routes page I have my create route as
router.post("/blogs", function(req, res){
// create blog
//req.body.blog.body = req.sanitize(req.body.blog.body);
var title = req.body.title;
var image = req.body.image;
var desc = req.body.body;
var author= {
id: req.user._id,
username: req.user.username
}
var newBlogpost = {title: title, image: image, body: desc, author: author}
Blog.create(newBlogpost, function(err, newBlog){
if(err){
res.render("blogs/new");
} else {
//then, redirect to the index
console.log(newBlogpost)
res.redirect("/blogs");
}
});
});
However when I sign in on the web application and complete the form and view my commmand line for the return of console.log(newBlogpost) after I submit, I get:
{ title: undefined,
image: undefined,
body: undefined,
author: { id: 5a0cbcc3d6c7070a7bb6c45e, username: 'cat' }
I am not sure why the new variable array I am creating has these three variable as undefinded and would appreciate help.

how do i store ng-repeat array form data in meanjs?

I am using MEANJS from meanjs.org.
trying to store ng-repeat array data for deal which has dealtype and dealprice as array under it, but unable to do so.
i have setup addFields for the ng-repeat input tag in the create form, but it does not store the data. here is my code.
food.server.model.js
var FoodSchema = new Schema({
created: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
required: 'Please fill Food name',
trim: true
},
deal: [{
dealtype: {
type: String,
default: '',
trim: true
},
dealprice: {
type: String,
default: '',
trim: true
}
}],
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
foods.client.controller.js
// initial array setup
var deal = [ { dealtype: '',dealprice: '' }, {dealtype: '',dealprice: '' } ];
$scope.food = {};
$scope.food.deal = deal;
$scope.addItem = function() {
$scope.food.deal.push({
dealtype: '',
dealprice: ''
});
};
// Create new Food
$scope.create = function (isValid) {
$scope.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'foodForm');
return false;
}
// Create new Food object
var food = new Foods({
name: this.name,
deal:[{
dealtype: this.dealtype,
dealprice: this.dealprice,
}],
});
// Redirect after save
food.$save(function (response) {
$location.path('foods/' + response._id);
// Clear form fields
$scope.name = '';
$scope.dealtype = '';
$scope.dealprice = '';
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
create-food.client.view.html
<form name="foodForm" class="form-horizontal" ng-submit="create(foodForm.$valid)" novalidate>
<fieldset>
<div class="col-md-12">
<md-input-container flex="">
<label >Food Name</label>
<input type="text" data-ng-model="name" id="name" required>
</md-input-container>
</div>
<div ng-repeat="de in food.deal">
<div class="col-md-6">
<md-input-container class="">
<label class="" for="dealtype">Dealtype</label>
<input type="text" data-ng-model="de.dealtype" id="dealtype" >
</md-input-container>
</div>
<div class="col-md-6">
<md-input-container class="">
<label class="" for="dealprice">Dealprice</label>
<input type="text" data-ng-model="de.dealprice" id="dealprice" >
</md-input-container>
</div>
</div>
<a href ng:click="addItem()" class="btn btn-small">add item</a>
<button class="md-primary md-raised width-100 md-whiteframe-5dp" type="submit">Create Food</button>
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
</fieldset>
</form>
Try to set your schema up without the embedded array and send without deal. If that works you may need to set up your schema with a subdocument.
If you are wanting to set your deal property up as a Subdocument you would need to follow this. You would define a schema for deal separately. Something like this:
var dealSchema = new Schema({ {
dealtype: {
type: String,
default: '',
trim: true
},
dealprice: {
type: String,
default: '',
trim: true
}
} });
var FoodSchema = new Schema({
...,
deal: [dealSchema]
})

How to add an array to MEAN.JS on the client side

I am trying to add an array of tasks to a project module on MEAN.js and I am using this question to follow up on how to add it to the server side (How to add an array to a javascript server side model in MEAN.JS, How to add an array to a javascript server side model in MEAN.JS) The answer given to me there only gets me to the point of inserting an empty array when entering data from the form on edit-project.client.view.html. So, I'll put the code here to check my client-side work, complete both these question and develop my profile. If there is any additional info required, besides the code I'll be adding, please leave suggestions to edit.
edit-project.client.view.html
<section ng-controller="ProjectsController" ng-init="findOne()">
<div class="page-header">
<h1>Edit Project</h1>
</div>
<div class="col-md-12">
<form name="projectForm" class="form-horizontal" ng-submit="update(projectForm.$valid)" novalidate>
<fieldset>
<div class="form-group" show-errors>
<label for="title">Title</label>
<input name="title" type="text" ng-model="project.title" id="title" class="form-control" placeholder="Title" required>
<div ng-messages="projectForm.title.$error" role="alert">
<p class="help-block error-text" ng-message="required">Project title is required.</p>
</div>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" ng-model="project.description" id="description" class="form-control" cols="30" rows="4" placeholder="Description"></textarea>
</div>
<div class="form-group">
Task Description
<textarea name="description" ng.model="project.task.description" class="form-control" cols="30" rows="3" placeholder="Description"></textarea>
<div>
Task Status
<input name="status" ng.model="project.task.status" class="form-control" placeholder="Status">
</div>
</div>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
</fieldset>
</form>
</div>
</section>
project.server.model.js
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Project Schema
*/
var ProjectSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
description: {
type: String,
default: '',
trim: true
},
/* MODEL for TASK ARRAY*/
tasks: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Task'
}],
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Project', ProjectSchema);
projects.server.controller.js (partial - seems incomplete on server side)
'use strict';
/**
* Module dependencies.
*/
var path = require('path'),
mongoose = require('mongoose'),
Project = mongoose.model('Project'),
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
/**
* Create a project
*/
exports.create = function (req, res) {
var project = new Project(req.body);
project.user = req.user;
project.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(project);
}
});
};
/**
* Show the current project
*/
exports.read = function (req, res) {
res.json(req.project);
};
/**
* Update a project
*/
exports.update = function (req, res) {
var project = req.project;
project.title = req.body.title;
project.description = req.body.description;
project.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(project);
}
});
};
...

Error copying req.body properties into Mongoose Model

First of all I have to say that I'm new in Angular and node technologies. So sorry for my ignorance.
I get this error when I try to save an Entity from edition view: 'Cast to ObjectId failed for value "[object Object]" at path "category"'.
Well, I've got these code:
HTML:
<form class="form-horizontal" data-ng-submit="update()" novalidate>
<fieldset>
<div class="form-group">
<label for="listaCat">Categoría:</label>
<select id="listaCat" class="form-control" data-ng-Fmodel="notification.category" data-ng-options="c.name for c in listaCategorias track by c._id">
</select>
</div>
<div class="form-group">
<label class="control-label" for="name">Descripción</label>
<div class="controls">
<input type="text" data-ng-model="notification.name" id="name" class="form-control" placeholder="Descripción" required>
</div>
</div>
<div class="form-group">
<input type="submit" value="Guardar" class="btn btn-default">
</div>
<div data-ng-show="error" class="text-danger">
<strong data-ng-bind="error"></strong>
</div>
</fieldset>
</form>`
Angular controller:
$scope.update = function() {
var notification = $scope.notification;
notification.$update(function() {
$location.path('notifications/' + notification._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
Server side controller:
var mongoose = require('mongoose'),
errorHandler = require('./errors.server.controller'),
Notification = mongoose.model('Notification'),
_ = require('lodash');
exports.update = function(req, res) {
var notification = req.notification;
notification = _.extend(notification , req.body);
notification.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(notification);
}
});
};
Mongoose Model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NotificationSchema = new Schema({
name: {
type: String,
default: '',
required: 'Rellena la notificación',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
category: {
type: Schema.ObjectId,
ref: 'Category'
}
});
mongoose.model('Notification', NotificationSchema);
var CategorySchema = new Schema({
name: {
type: String,
default: '',
required: 'Rellena la categoría',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Category', CategorySchema);
So, if I debug inside Server controller at update method with WebStorm, I can see that req.body comes with each attribute well formed, but after convert req.body into Notification Mongoose Model with:
notification = _.extend(notification , req.body);
the category attribute is not a Model but an ObjectId. It seems as lodash.extend is not working properly for complex attributes. I've tried many other ways of cloning the object but without success.
Finally I solved it, with this line inside the angular controller:
notification.category = $scope.notification.category._id;
notification.$update(function() {
Anyway, I think that this is not the right way. I guess there must be a way of copying the req.body properties into a mongoose model without doing it manually for the complex properties.
Thanks a lot in advance!
Since you are working on AngularJS and ExpressJS, i would suggest you to use $resource service which is exactly meant for interacting with the rest API.
**$resource** contains these default set of actions:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
There is nice documentation available in the link that i shared above.
In your case:
i assume, http://localhost:300/notifications/:id, this might be your rest url where you want to perform update action.
You can create your custom services like:
var module = angular.module('myapp.services',['ngResource']);
module.factory('MyAppUpdateService',function($resource){
return $resource('notifications/:id',
{
id: '#id'
},
{
'update': { method:'PUT' }
}
);
});
Now inside your angular app controller you can inject this service as dependency and hence it will be available to perform update in that REST url.
angular.module('myapp',['ngResource','myapp.services']);
angular.module('myapp').controller('MeetupsController',['$scope','$resource','$state','$location','MeetupUpdateService','socket',
function($scope,$resource,$state,$location, MyAppUpdateService){
$scope.updateMeetup = function(){
$scope.updateService = new MyAppUpdateService();
$scope.updateService.name = $scope.notification.name;
.
.
.
$scope.updateService.$update({id:$scope.notification.category._id},function(result){
$location.path("/meetup/")
});
}
})]);
So this was just an example, if you want more comprehensive implementation. Look here, i am creating a MEAN seed of my own, and i am doing the same.
Any doubt please do ask.

Categories

Resources