extend mean module findOne() to handle other attributes that strings - javascript

When start a new meanjs project (mongoose, angular etc.) using the generator and add a CRUD-module i get methods like this:
$scope.findOne = function() {
$scope.income = Incomes.get({
incomeId: $stateParams.incomeId
});
In my income server model is shown below, it has some different attributes and some different object types on these attributes, for example, number, date and string.
When i get data in my $scope.income after the promise "$scope.findOne" has succeded all my data are strings. Do i need to cast each and every one of them to their proper type?
In my front end i want to present the different types in the input elements of my "update" view. For example:
<label class="control-label" for="date">Date of transaction</label>
<div class="list-group-item">
<div class="controls">
<input type="date" data-ng-model="income.date" id="date" class="form-control" placeholder="Date" required>
</div>
This does not work since the object $scope.income.date consists of a string. Changing the input type to string makes it show up. But I want to use a date picker here.
Should I write something like:
$scope.findOne = function() {
Incomes.get({
incomeId: $stateParams.incomeId
}).then(function(data){
var dateVar=new Date(data.date);
var amountVar =Number(data.amount)
$scope.income ={date: dateVar, name: data.name, amount:amountVar}()
);
What is best practise here?
Model I am using:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Income Schema
*/
var IncomeSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Income name',
trim: true
},
amount: {
type: String,
default: '',
required: 'Please fill Income amount',
trim: true
},
date: {
type: Date,
default: '',
required: 'Please fill Income date',
trim: true
},
monthly: {
type: Boolean,
default: '',
required: 'Please fill whether income is recurring monthly',
trim: true
},
yearly: {
type: Boolean,
default: '',
required: 'Please fill whether income is recurring yearly',
trim: true
},
account: {
type: Schema.ObjectId,
ref: 'Account',
required: 'Please select account'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Income', IncomeSchema);

First I had to get a hold of the promise, than I easily could build more complex objects from the Incomes.get response. The data is sent over the network as JSON and there fore it is just text, so I needed to instantiate it to the proper types using f ex. Date and Number:
Incomes.get({
incomeId: $stateParams.incomeId
}).$promise.then(function(data){
var dateVar=new Date(data.date);
var amountVar =Number(data.amount)
$scope.income ={date: dateVar, name: data.name, amount:amountVar}()
);

To make the resources function for remove work properly "this" needed to be used, dont forget that the promise is in another namespace so "that=this" is needed.
var that=this;
Incomes.get({
incomeId: $stateParams.incomeId
}).$promise.then(function(income){
income.date= new Date(income.date);
var recurringVar;
if(income.monthly===true){
recurringVar = 'monthly';
} else if( income.yearly===true){
recurringVar = 'yearly';
}
income.recurring=recurringVar;
that.income=income;
});

Related

How to pass multiple user inputs and update the data in a single popup using Vue-SweetAlert2

I know how to ask a user for his or her user name by a popup with Vue-SweetAlert2.
<template>
<v-btn class="create-button" color="yellow" #click="alertDisplay">Create</v-btn>
<br/>
<p>Test result of createCustomer: {{ createdCustomer }}</p>
</div>
</template>
<script>
export default {
data() {
return {
createdCustomer: null
}
},
methods: {
alertDisplay() {
var customer = await this.$swal({
title: 'What is your Name?',
input: 'text',
inputPlaceholder: 'Enter your name here',
showCloseButton: true,
});
console.log(customer);
this.createdCustomer = customer;
}
}
}
</script>
With code like the one above, you can store whatever the user typed into createdCustomer, and it should be displayed on the screen after the user gives the input.
But what if I wanted to ask the user for multiple pieces of information?
For example, how do I ask for info like
"customerNumber" (also want to make sure that alphabets and numbers are combined)
"locale" (also want to make sure that the input is a collection of choices that the user chooses from, like drop down menu, rather than a text field where you can type in whatever you like)
"firstName" (also want to make sure that the name doesn't exceed 255 characters)
etc.
in a single popup?
I tried to set multiple input fields like below, but I got a warning "Unknown parameter", and this doesn't seem to be a valid way.
var customer = await this.$swal({
title: 'Fill in your personal data',
input1: 'text',
input2: 'text',
input3: 'text',
inputPlaceholder: 'Enter your name here',
showCloseButton: true,
});
And how do I check if the user has given a valid input (like the name is within 255 characters, both of alphabets and numbers are used etc)?
If I were using C or Java, I could imagine using if-statements like
if(length <= 255){
// proceed
} else {
// warn the user that the input is too long
}
somewhere in the code, but in this case I don't know how I can do a similar if-statement like thing within the popup...
[ADDITIONAL QUESTION]
Is it also possible to pass an object that consists of multiple smaller elements, like "address"?
"address": {
"street": "string",
"city": "string",
"country": "USA",
"region": "string",
"zipCode": "string"
}
As per the documentation :
Multiple inputs aren't supported, you can achieve them by using html
and preConfirm parameters. Inside the preConfirm() function you can
return (or, if async, resolve with) the custom result:
const {value: formValues} = await Swal.fire({
title: 'Multiple inputs',
html: '<input id="swal-input1" class="swal2-input">' +
'<input id="swal-input2" class="swal2-input">',
focusConfirm: false,
preConfirm: () => {
return [
document.getElementById('swal-input1').value,
document.getElementById('swal-input2').value
]
}
})
if (formValues) {
Swal.fire(JSON.stringify(formValues))
}
https://sweetalert2.github.io/
For validation you have to use the inputValidor prop like this :
const {value: ipAddress} = await Swal.fire({
title: 'Enter your IP address',
input: 'text',
inputValue: inputValue,
showCancelButton: true,
inputValidator: (value) => {
if (!value) {
return 'You need to write something!'
}
}
})
if (ipAddress) {
Swal.fire(`Your IP address is ${ipAddress}`)
}

Loop Through all users to send email Node JS

I tried finding the answer but couldn't. I'm new to Node Js and have a user schema that includes users emails. I want to have a form that has 'subject' and 'message' fields, and a submit button which would then send the contents of the form in an email. I'm currently using Mailgun, and a standard email looks like this:
var data = {
to: user.email,
from: '"Lighthouse Studios" <noreply#reception.lighthousespace.co.uk>',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
And my user schema looks like:
var UserSchema = new mongoose.Schema({
username: {type: String, unique: true, required: true},
name: {type: String, required: true},
email: {type: String, unique: true, required: true},
password: String,
studio: {type: String, required: true},
resetPasswordToken: String,
resetPasswordExpires: Date,
comments: [
{
quantity: String,
received: { type: Date, default: Date.now },
collected: { type: String, default: "At Reception" }
}
],
isAdmin: {type: Boolean, default: false}
});
Here's the form code:
<form action="/" method="POST">
<div class="form-group">
<input class="form-control" type="text" name="subject" placeholder="Subject">
</div>
<div class="form-group">
<textarea class="form-control" rows="5" id="comment" name="message" placeholder="Message"></textarea>
</div>
<div class="form-group">
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Send">
</div>
</form>
So to summarise, I want to use the form to send all users an email when the button 'submit' is clicked. Thanks for your time reading this.
UserModel.find({})
.select('email')
.lean()
.exec((err,users)=>{
if(users){
let userEmails = "";
let recp = users.reduce((a,u)=>{ a[u.email]={}; a[u.email].email = u.email; userEmails+=u.email; return a; },{})
let data = {
to: userEmails,
from: '"Lighthouse Studios" <noreply#reception.lighthousespace.co.uk>',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +'This is a confirmation that the password for your account ' + %recipient.email% + ' has just been changed.\n',
'recipient-variables': JSON.stringify(recp)
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
}
})
Hope this one will work

The correct way to display cards in lists, as in Trello

I'm trying to create project like Trello. I do not know how to do it properly.
I created function init in AngularJS Controller where i put http requests:
$scope.loadLists();
$scope.loadsCards();
Scripts:
$scope.loadLists = function () {
return ApiService.staff.list()
.then(function (resp) {
for (var i = 0; i < resp.length; i++) {
$scope.lists[i] = resp[i];
}
})
}
$scope.loadsCards = function () {
return ApiService.staff.cards()
.then(function (resp) {
for (var i = 0; i < resp.length; i++) {
$scope.cards = resp;
}
console.log($scope.cards)
})
}
I'm downloading tasks to $scope.cards
In console.log() we can see:
Array [ Object, Object, Object, Object, Object, Object, Object, Object ]
where the object consists of
var CardSchema = new Schema({
name: { type: String, maxlength: 20, required: true },
list: { type: Schema.Types.ObjectId, ref: 'List' },
updated: { type: Date, default: Date.now },
created: { type: Date, default: Date.now },
active: Boolean
});
And now I do not know what to do so that the cards are displayed only those in the given column that are assigned to the list. I mean : task.list == list._id
for the moment I did it
<div ng-repeat="list in lists track by $index">
<div style="float: left; margin-left: 5px;">
<div id="tasks">
<h3>{{list.name}}</h3>{{$index}}
<ul>
<li ng-repeat="task in cards">
<div ng-hide="task.list == list._id">
{{task.name}}
</div>
<i ng-click="removeTask(task)" class="fa fa-trash-o"></i></li>
</ul>
<form ng-submit="addTask(list._id, $index, newTask)">
<input type="text" ng-model="newTask" placeholder="add a new task" required />
</form>
</div>
</div>
</div>
But it does not work and so it probably can not be if I want to still create a database for the card field
Position (Later to enable drag & dropping)
Can anyone tell me how to properly display cards in lists?
EDIT;;;
thank you very much for the help.
Can you explain more to me because I still have a problem with the cards
I did directiv in angularJS:
App.directive('myList', function() {
return {
restrict: 'E',
replace: true,
template: '<div style="float: left; margin-left: 5px;"><div id="tasks">{{list.name}}<br>{{card.name}}</div></div>'
};
});
App.directive('myCard', function() {
return {
restrict: 'E',
replace: true,
template: '<div style="float: left; margin-left: 5px;"><div id="tasks">{{card.name}}</div></div>'
};
});
and in index.ejs
<my-list ng-repeat="list in lists" list-data="list"></my-list>
<my-card ng-repeat="card in listData.cards" card-data="card"></my-card>
I also did AJAX inquiry after all cards :
https://gist.github.com/anonymous/ed17c3fd675ea4361cb8fbd78e94cb37
name: its name card
list: its _id list
In $scope.cards I stores AJAX inquiry after all cards,
Its my card model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CardSchema = new Schema({
name: { type: String, maxlength: 20, required: true },
// description: { type: String, maxlength: 300 },
list: { type: Schema.Types.ObjectId, ref: 'List' },
updated: { type: Date, default: Date.now },
created: { type: Date, default: Date.now },
active: Boolean
});
module.exports = mongoose.model('Card', CardSchema);
And I have no idea how this loop looks, would you help me somehow?
It's not that easy to solve with two ng-repeat's. You may want to create your list and card directives because eventually they will be complex views:
<my-list ng-repeat="list in lists" list-data="list"></my-list>
And in my-list directive, you can create a loop to to render cards:
<my-card ng-repeat="card in listData.cards" card-data="card"></my-card>

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]
})

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