Embedding data into Mongoose schema with angularJS. MEAN stack - angularjs

I am using the CRUD module in mean.js to add data to my webapp.
I am having no issues adding in strings etc, however I am having issues with embeded data.
My desired data format is below.
{
"_id":"5559abc02ef1bcdc2e6e6137",
"messages": [
"title":"title of msg",
"msg":"msg content"
],
"created":"2015-05-19T09:30:25.117Z",
"department":"finance",
"name":"accounts receivable"
}
From this snippet I want to be able to push data into the messages field. I have seen ideas on how to do this in posts such as this pushing object into array schema in Mongoose.
However I am not sure how I can implement this soloution with angular.
So far I have the below, which works for all fields except the messages field.
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Team Schema
*/
var TeamSchema = new Schema({
name: {
type: String, //eg accounts receivable
default: '',
required: 'Please fill Team name',
trim: true
},
department: {
type: String, //eg finance
default: '',
required: 'Please fill department',
trim: true
},
messages: [
{
title: {type: String},
msg: {type: String}
}
],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
/**
* Create a Team
*/
var mongoose = require('mongoose'),
errorHandler = require('./errors.server.controller'),
Team = mongoose.model('Team'),
_ = require('lodash');
exports.create = function(req, res) {
var team = new Team(req.body);
team.user = req.user;
team.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(team);
}
});
};
/**
* Angular controller
*/
$scope.create = function() {
// Create new Team object
var team = new Teams ({
name: this.name,
department: this.department,
messages: this.messages.title
//this.messages[0].title
});
// Redirect after save
team.$save(function(response) {
$location.path('teams/' + response._id);
// Clear form fields
$scope.name = '';
$scope.department = '';
$scope.messages.title = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
Angular View
<form class="form-horizontal" data-ng-submit="create()" novalidate>
<fieldset>
<div class="form-group">
<label class="control-label" for="name">Name</label>
<div class="controls">
<input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required>
</div>
</div>
<div class="form-group">
<label class="control-label" for="department">Department</label>
<div class="controls">
<input type="text" data-ng-model="department" id="department" class="form-control" placeholder="Department" required>
</div>
</div>
<div class="form-group">
<label class="control-label" for="messages">messages</label>
<div class="controls">
<input type="text" data-ng-model="messages.title" id="messages" class="form-control" placeholder="messages">
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default">
</div>
<div data-ng-show="error" class="text-danger">
<strong data-ng-bind="error"></strong>
</div>
</fieldset>
</form>
How can I save the messages title and msg like I am saving the other items?
I would also potentially want to give users the ability to add their own fields to this messages field so they could add their own customization to the model, so it would be good if the solution rather than explicitly mentioned title and message, instead referenced each item.

You need to create an array of messages in the $scope.create function, something like this when creating the new team object:
// Create new Team object
var team = new Teams ({
name: this.name,
department: this.department,
messages: [
{ title: this.messages.title, msg: "" }
]
});
In order to add multiple messages with different titles etc, I'd create a scope variable to hold the messages (e.g. $scope.messages = [{title:"",msg:""}]) then use ng-repeat to iterate over it in your template to create multiple inputs:
<input type="text" data-ng-repeat="message in messages" data-ng-model="message.title" id="messages" class="form-control" placeholder="messages">
You could then have a button for "add message", wire up it's click to push another {title:"",msg:""} onto the $scope.messages array. Lastly, you'd then update your $scope.create function again to add that array as the value for the messages field:
// Create new Team object
var team = new Teams ({
name: this.name,
department: this.department,
messages: this.messages
});
On clearing the form, just set $scope.messages back to its initial single-item array value.

Related

Why will my data not save my updated scope data from my form?

I have created a form in a modal which allows someone to enter in plan details. I have then created the scope form in ng-model attribute as you can see below...
<form>
<div class="form-group">
<label>{{plans.title}}</label>
<input type="text" name="title" ng-model="plans.title" class="form-control" placeholder="Enter Title" required />
</div>
<div class="form-group">
<label>{{plans.overview}}</label>
<textarea name="overview" ng-model="plans.overview" class="form-control" placeholder="Overview/Purpose" required />
</div>
<div class="form-group">
<label>{{plans.notes}}</label>
<textarea name="notes" ng-model="plans.notes" class="form-control" placeholder="Plan Notes" required />
</div>
<div class="form-group">
<label>{{plans.visualplan}}</label>
<div class="button" ngf-select ng-model="plans.visualplan" name="visualplan" ngf-pattern="'image/*'" ngf-accept="'image/*'" ngf-max-size="20MB" ngf-min-height="100" >Upload Visual Plan</div>
</div>
<div class="form-group">
<button type="submit" ng-click="submit()" Value="Post">Post</button>
</div>
</form>
In my code I am then trying to pull the data from the form into my scope object for plans under title, overview, notes and visualplan. Then i have coded this to upload the data from the form into my firebase json. However upon submitting the details, the upload to json process works correctly, but it is uploading the default values for title, overview, notes and visualplan which i have initiatlly set in my dailyplans.js file. What i want to upload is the details which I have attached through ng-model instead of the initial set values. Can anyone spot what I am doing wrong?
Below is my js file.
$scope.submit = function() {
$scope.plans = {
title: 'title',
overview: 'overview',
notes: 'notes',
visualplan: 'visual plan'
}
if (authData) {
ref.child('teaching-plans').child('teaching-plans' + authData.uid).set($scope.plans).then(function(authdata) {
console.log('successful');
}).catch(function(error) {
console.log(error);
});
}
}
You are resetting the plans object when user clicks on submit. Ideally it should be outside of submit method.
This is how you should do it
$scope.plans = {
title: 'title',
overview: 'overview',
notes: 'notes',
visualplan: 'visual plan'
}
$scope.submit = function(plans) {
if (authData) {
ref.child('teaching-plans').child('teaching-plans' + authData.uid).set(plans).then(function(authdata) {
console.log('successful');
}).catch(function(error) {
console.log(error);
});
}
}
And also update the html as
<div class="form-group">
<button type="submit" ng-click="submit(plans)" Value="Post">Post</button>
</div>
Hope this helps.
Just don't overwrite your plans object:
$scope.submit = function() {
$scope.plans.title = 'title';
$scope.plans.overview = 'overview';
$scope.plans.notes = 'notes';
$scope.plans.visualplan = 'visual plan;
if (authData) {
ref.child('teaching-plans').child('teaching-plans' + authData.uid).set($scope.plans).then(function(authdata) {
console.log('successful');
}).catch(function(error) {
console.log(error);
});
}
}
This way angular can fire the listeners correctly.

Building array in controller AngularJS

So I have a client controller like so (with only relevant code):
angular.module('employees').controller('EmployeesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Employees',
function($scope, $stateParams, $location, Authentication, Employees) {
$scope.authentication = Authentication;
// Create new Employee
$scope.create = function() {
// Create new Employee object
var employee = new Employees ({
name: this.name,
eid: this.eid,
availibility: [monday: this.monday, tuesday: this.tuesday]
});
With a client view (again, only code relevant to the availability array)
<div class="form-group form-inline">
<label class="control-label" for="monday">Monday</label>
<label class="control-label" for="start">Start</label>
<label class="control-label" for="finish">Finish</label>
<div class="controls">
<input type="checkbox" id="monday" class="form-control" required>
<input type="time" id="start" class="form-control" required> <input type="time" id="finish" class="form-control" required>
</div>
</div>
<div class="form-group form-inline">
<label class="control-label" for="tuesday">Tuesday</label>
<label class="control-label" for="start">Start</label>
<label class="control-label" for="finish">Finish</label>
<div class="controls">
<input type="checkbox" id="tuesday" class="form-control" required>
<input type="time" id="start" class="form-control" required>
<input type="time" id="finish" class="form-control" required>
</div>
</div>
And a server controller like so:
exports.create = function(req, res) {
var employee = new Employee(req.body);
employee.user = req.user;
console.log(req.body);
employee.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(employee);
}
});
};
How can I make it so that the user can update an "availability" schedule? For some reason, when I POST the form, all I am getting is the eid and name (in the req.body). What am I doing wrong here? Can anyone point me in the direction of a resource that I could use?
Also, another question that kinda has something to do with this: Can I use ngTable to style these forms? As in, can I put forms inside of a table?
Thanks everybody for the help!
P.S. I realize the code is pretty dirty (particular the HTML code + the fact that none of my controllers are actually trying to pull data from the forms yet). Again, I don't have any real reason to continue on to that part until I know why when I POST the form, the data is not included in the post.
Things to try:
Verify spelling of availability you have availibility in your create function and it could be an issue with your setup.
It looks like you are probably using a mean.js-like setup. I would first confirm that you have added the availability field to your Employee object. In this case you would have to make the file app/model/employee.server.model.js (or where ever your model definition is to have the array)
_
new Employee({
name: {type: String},
eid: {type: String},
availibility: {type: Array,
default: []
}
}
Finally your create function looks a little funky to me. I would use a more standard definition for the array
// Create new Employee
$scope.create = function() {
// Create new Employee object
var employee = new Employees ({
name: this.name,
eid: this.eid,
availibility: [this.monday, this.tuesday]
});

Repeating a Form in Angular

I've got a form that allows users to create a service. Currently you can only add one provider to that service.
I'd like to allow users to add up to 10 providers, using the "Add Another Provider" button.
Here's my code at the moment:
add-service.html
<form role="form" name="createServiceForm">
<input type="text" ng-model="title">
<h2>Attach Provider</h2>
<input type="text" ng-model="provider.title">
<textarea rows="3" ng-model="provider.description"></textarea>
<button type="submit">Add Another Provider</button>
<button type="submit" ng-click="createService()">Submit</button>
</form>
main.js
$scope.createService = function() {
var newService = {
title: $scope.title,
providers: {
provider: {
title: $scope.provider.title,
description: $scope.provider.description
}
},
};
var promise = ServiceService.add(newService);
};
I could duplicate parts of the code like so:
<input type="text"ng-model="provider1.title">
<input type="text"ng-model="provider2.title">
<input type="text"ng-model="provider3.title">
...
providers: {
provider1: {
title: $scope.provider1.title,
},
provider2: {
title: $scope.provider2.title,
},
provider3: {
title: $scope.provider3.title,
}
...
}
But that seems like a messy solution...
What's the best way to duplicate the provider portion of the form, when you click "Add Another Provider" without repeating it 10 times in my HTML and in my newService object?
You can accomplish what you want by using ng-repeat. I've made providers into an array, which you can then iterate over. You could use ng-repeat with an object if the key is important to you.
Also added a function which will push a new provider onto the array, which will then show in the form.
main.js
$scope.providers = [];
$scope.addProvider = function() {
$scope.providers.push({
title: '',
description: ''
});
};
// Start with one provider
$scope.addProvider();
$scope.createService = function() {
var newService = {
title: $scope.title,
providers: $scope.providers,
};
var promise = ServiceService.add(newService);
};
addService.html
<form role="form" name="createServiceForm">
<input type="text" ng-model="title">
<h2>Attach Provider</h2>
<div ng-repeat="provider in providers">
<input type="text" ng-model="provider.title">
<textarea rows="3" ng-model="provider.description"></textarea>
</div>
<button ng-click="addProvider()">Add Another Provider</button>
<button type="submit" ng-click="createService()">Submit</button>
</form>

how to show/hide div according to user permission/role using angularjs in sharepoint 2010

i have to create a form using content editor web part in SharePoint 2010. I have to hide some item or div based on group permission (example: admin,user) using angularjs.
There have two ways to solve your problem:
You receive all the data and you display it or not based on the current role, helped by a display function. jsFiddle1
Javascript code:
var demoApp = angular.module('demoApp', []);
demoApp.controller('PermissionsForm', function ($scope) {
// Mock data. You must receive it from your server
$scope.mockData = {
field1: {
value: 'field1 value',
roles: ['admin','user']
},
field2: {
value: 'field2 value',
roles: ['admin']
},
field3: {
value: 'field3 value',
roles: ['admin','user']
},
role: 'user'
};
$scope.displayField = function(fieldName){
var foundRole = false;
angular.forEach($scope.mockData[fieldName].roles, function(value, key) {
if (value == $scope.mockData.role){
foundRole = true;
}
});
return foundRole;
};
});
HTML code:
<div data-ng-app="demoApp" data-ng-controller="PermissionsForm" class="main">
<form>
<div ng-if="displayField('field1')">
<label for="field1">Field 1</label>
<input id="field1" value="{{mockData.field1.value}}">
</div>
<div ng-if="displayField('field2')">
<label for="field2">Field 2</label>
<input id="field2"value="{{mockData.field2.value}}">
</div>
<div ng-if="displayField('field3')">
<label for="field3">Field 3</label>
<input id="field3" value="{{mockData.field3.value}}">
</div>
</form>
</div>
You receive only the data related to each roles/permission and you build your interface with the list of fields. This is the more secure way to hide info. jsFiddle2
Javascript code:
var demoApp = angular.module('demoApp', []);
demoApp.controller('PermissionsForm', function ($scope) {
// Mock data. You must receive it from your server
$scope.mockData = {
field1: {
value: 'field1 value'
},
field3: {
value: 'field3 value'
},
field4: {
value: 'field4 value'
}
};
$scope.displayField = function(fieldName){
if ( $scope.mockData[fieldName] == undefined )
return false;
return true;
};
});
HTML code:
<div data-ng-app="demoApp" data-ng-controller="PermissionsForm" class="main">
<form>
<div ng-if="displayField('field1')">
<label for="field1">Field 1</label>
<input id="field1" value="{{mockData.field1.value}}">
</div>
<div ng-if="displayField('field2')">
<label for="field2">Field 2</label>
<input id="field2"value="{{mockData.field2.value}}">
</div>
<div ng-if="displayField('field3')">
<label for="field3">Field 3</label>
<input id="field3" value="{{mockData.field3.value}}">
</div>
<div ng-if="displayField('field4')">
<label for="field4">Field 4</label>
<input id="field4" value="{{mockData.field4.value}}">
</div>
</form>
</div>
From a secure point of view, the second solution is the best, because your are not exposing the data in the client side (browser)

Backbone - How to this.model.save() an attribute with array?

I have this model:
var Contact = Backbone.Model.extend({
defaults: function () {
return {
idc: ""
name: ""
email: "",
phones: new Array()
}
},
urlRoot: 'admin/contact'
});
This form (underscore template):
<form>
<input type="hidden" value="{{ idc }}" />
<p>
<label>Name:</label>
<input type="text" name="name" value="{{ name}}" />
</p>
<p>
<label>Email:</label>
<input type="text" name="email" value="{{ email }}" />
</p>
<p>
<label>Phones:</label>
<input type="text" name="phones[]" value="" />
<input type="text" name="phones[]" value="" />
<input type="text" name="phones[]" value="" />
</p>
<button class="cancel">Cancel</button><button class="save">Save</button>
</form>
And when I click in save, this function into Contact View:
e.preventDefault();
var formData = {},
prev = this.model.previousAttributes();
$(e.target).closest("form").find(":input").each(function () {
var el = $(this);
formData[el.attr("name")] = el.val();
});
this.model.set(formData);
this.model.save();
this.render();
I expect that when the function is called, it creates an array to send for the PHP file with the phones, so I can store it in the database. But looking at the browser console the attribute array is with the value: []
Is there something I´m missing to pass it to the PHP file?
PS: The array is in the formData array, but when I call this.model.save() looks like it lost the array.
Anyway, Thankyou!
Your problem is basically that you're using jQuery's serializeArray. serializeArray is great if you want to create a model for every form element, because it produces JSON like this (example JSON taken from the jQuery documentation):
[
{name: 'firstname', value: 'Hello'},
{name: 'lastname', value: 'World'},
{name: 'alias'}, // this one was empty
]
However, you don't want that, you want to create a single model from the combined elements; in other words you want:
{
firstname: 'Hello',
lastname: 'World',
alias: undefined
}
There are jQuery plug-ins that produce output like that if you want, but personally I'd recommend just writing your own. If you have a form view with an onSubmit handler, you could do something like:
this.model.set('name', this.$('[name="name"]').val());
this.model.set('email', this.$('[name="email"]').val());
// etc.
that's tailored specifically for your app and serializes the data the exact way you want.

Resources