Track and count clicks with AngularJS and post to MongoDB - javascript

I want to be able to track the click from a user on an item and have it update the JSON object associate with it and display the number of all the clicks. I know how to create and delete an object, but how do I add a new name and value and update the object when the user clicks and appropriate vote button? Any help will be greatly appreciated and I thank you in advance.
The HTML
<body ng-controller="mainController">
<div class="table-responsive">
<table class="table">
<tr>
<td>Vote</td>
<td>Song</td>
<td>Edit</td>
</tr>
<tr ng-repeat="todo in todos">
<td><button class="btn btn-success icon-thumbs-up" alt="Up vote this song if you like it.">Vote</button></td>
<td>{{ todo.text }}</td>
<td><button class="btn btn-danger fa fa-times" ng-click="deleteTodo(todo._id)" alt="Remove the song if you need to make an edit and then add it back."></button></td>
</tr>
</table>
</div>
</body>
The Model
var mongoose = require('mongoose');
module.exports = mongoose.model('Todo', {
text : String,
done : Boolean
});
The Service
angular.module('todoService', [])
// super 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);
}
}
});
Server side Angular
var Todo = require('./models/todo');
module.exports = function(app) {
// api ---------------------------------------------------------------------
// get all todos
app.get('/api/todos', function(req, res) {
// use mongoose to get all todos in the database
Todo.find(function(err, todos) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
res.json(todos); // return all todos in JSON format
});
});
// create todo and send back all todos after creation
app.post('/api/todos', function(req, res) {
// create a todo, information comes from AJAX request from Angular
Todo.create({
text : req.body.text,
done : false
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// delete a todo
app.delete('/api/todos/:todo_id', function(req, res) {
Todo.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// application -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
};
Client side Angular
angular.module('todoController', [])
// inject the Todo service factory into our controller
.controller('mainController', function($scope, $http, Todos) {
$scope.formData = {};
$scope.loading = true;
// GET =====================================================================
// when landing on the page, get all todos and show them
// use the service to get all the todos
Todos.get()
.success(function(data) {
$scope.todos = data;
$scope.loading = false;
});
// CREATE ==================================================================
// when submitting the add form, send the text to the node API
$scope.createTodo = function() {
$scope.loading = true;
if ($scope.formData.text != undefined) {
// call the create function from our service (returns a promise object)
Todos.create($scope.formData)
// if successful creation, call our get function to get all the new todos
.success(function(data) {
$scope.loading = false;
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.todos.unshift(data); // assign our new list of todos
});
}
};
// DELETE ==================================================================
// delete a todo after checking it
$scope.deleteTodo = function(id) {
$scope.loading = true;
Todos.delete(id)
// if successful creation, call our get function to get all the new todos
.success(function(data) {
$scope.loading = false;
$scope.todos = data; // assign our new list of todos
});
};
});

Here is what you would do.
Add a new field to schema to store the votes:
votes: {type: Number, default: 0}
Add a new handler on the server side to increment vote when it gets a request:
app.get('/api/todos/:todo_id/vote', function(req, res) {
Todo.update({_id: req.params.todo_id}, { $inc: {votes: 1} } ), function(err,doc){
...
}
}
Add a new function to AngularJS service to call this new API handler:
vote: function(id) {
return $http.get('/api/todos/' + id + '/vote');
}
Wire up ngClick on ngRepeated elements to call the new Svc function. NOTE: You would need Todos svc in your scope to do this as below, otherwise create a wrapper function in the scope as you have done.
<td>
<button data-ng-click="Todos.vote(todo._id)"
class="btn.." alt="Up vote this....">Vote
</button>
</td>
then display in your view somehow the new "votes" field of the ToDo Models coming back.
Check this out: http://meanjs.org/ You can get a lot of good examples working with Angular, node and Mongo, look at the "articles" module that comes with it.
I didn't try any of this but it should give you the basic idea what to do. Also, realize there is nothing here to stop a user from upvoting more than once. Hope it helps!

Related

Saving data for only one user with using Firebase

I'm developing electron app and using Firebase Database. I created database user by user but saving data for everyone. I want to save data also separate for the user ID.
I can create a user under their user IDs but cannot write their data under their user IDs.
app.controller('loginCtrl', function($scope,$location){
$scope.signup = function(){
auth.createUserWithEmailAndPassword($scope.mail,$scope.parola).then(sonuc=>{
console.log(sonuc.user);
return db.collection('users').doc(sonuc.user.uid).set({
inputQ: $scope.inputQ
}).then( ()=> {
console.log('deneme basarili');
}).catch(err => {
console.log(err.message);
})
})
}
$scope.login = function(){
auth.signInWithEmailAndPassword($scope.mail,$scope.parola).then(sonuc=> {
$location.path('/dashboard')
})
}
});
This part successfully creates a user under its user ID.
app.controller('dashboardCtrl', function($scope){
$scope.add = function() {
db.collection('users').doc(user.uid).add({
baslik: $scope.baslik,
icerik: $scope.icerik
}).then( ()=> {
console.log('ekleme basarili');
}).catch(err=>{
console.log(err.message);
})
}
This part cannot create data under its user ID.
The error is user is not defined.
app.controller('dashboardCtrl', function($scope){
$scope.add = function() {
db.collection('users').doc(user.uid).set({
baslik: $scope.baslik,
icerik: $scope.icerik
}).then( ()=> {
console.log('ekleme basarili');
}).catch(err=>{
console.log(err.message);
})
}
Trying using "set" rather than "add", "add" is usually reserved for adding to a collection where it creates the records identifier for you, without you having to provide it.
You should change .add to .set but also make sure to include merge: true to prevent an override to the document (e.x. if there is a current document it will update it and if there is no document it will create one).
app.controller('dashboardCtrl', function($scope){
$scope.add = function() {
db.collection('users').doc(user.uid).set(
{
.
.
.
},
{ merge: true }
).then( ()=> {
}).catch(err=>{
})
}

Angularjs form not submitting data

I'm creating a MEAN stack app and I've been using the book 'Mean Web Development' by Amos Q. Haviv to help me along. I've run into a problem where I have a form that is suppose to submit a recipe, but when I check the database the entry is there with an id, date and author but no title, mainImage, content, category or tags. I've been trying to figure it out on my own for the past couple of days and going over the book again to see if I made any mistakes, but no luck.
Here is my model:
// Load the module dependencies
var mongoose = require('mongoose'),
paginator = require('mongoose-paginator'),
Schema = mongoose.Schema;
var CommentsSchema = new Schema({
commentor: String,
data: {
type: Date,
default: Date.now()
},
content: {
type: String,
default: ' ',
trim: true,
required: "Enter a comment into the comment box"
},
agree: Number,
disagree: Number
});
function toLower(lowerText) {
return lowerText.toLowerCase();
}
var TagsSchema = new Schema({
tags: {
type: String,
set: toLower
}
});
var RecipeSchema = new Schema({
created: {
type: Date,
default: Date.now()
},
author: {
type: Schema.ObjectId,
ref: 'User'
},
title: {
type: String,
default: ' ',
trim: true,
required: 'Title cannot be blank'
},
mainImage: {
type: String,
default: ' ',
trim: true
},
content: {
type: String,
default: ' ',
trim: true,
required: "Please enter recipe"
},
likes: Number,
faves: Number,
category: {
type: String,
set: toLower
},
tags: [TagsSchema],
comments: [CommentsSchema]
});
// Use paginator
RecipeSchema.plugin(paginator, {
limit: 20,
defaultKey: '_id',
direction: 1
});
mongoose.model('Recipe', RecipeSchema);
Here is my controller
// Load the module dependencies
var mongoose = require('mongoose'),
Recipe = mongoose.model('Recipe');
// Create a new error handling controller
var getErrorMessage = function(err) {
if (err.errors) {
for (var errName in err.errors) {
if (err.errors[errName].message) return err.errors[errName].message;
}
} else {
return 'Unknown server error';
}
};
// Create a new controller method that creates a new recipe
exports.create = function(req, res) {
// Create a new recipe object
var recipe = new Recipe(req.body);
// Set the recipe's 'author' property
recipe.author = req.user;
// Try saving the recipe
recipe.save(function(err) {
if (err) {
// If an error occurs send the error message
return res.status(400).send({
message: getErrorMessage(err)
});
}else {
// Send a JSON representation of the recipe
res.json(recipe);
}
});
};
// Create a new controller method that retrieves a list of recipes
exports.list = function(req, res) {
// User the model 'find' method to get a list of recipes
Recipe.find().sort('-created').populate('author', 'username userName').exec(function(err, recipes) {
if (err) {
// If an error occurs send the error message
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
// Send a JSON representation of the article
res.json(recipes);
}
});
};
// Create a new controller method that returns an existing recipe
exports.read = function(req, res) {
res.json(req.recipe);
}
// Create a new controller method that updates an existing recipe
exports.update = function(req, res) {
// Get the recipe from the 'request' object
var recipe = req.recipe;
// Update the recipe fields
recipe.title = req.body.title;
recipe.mainImage = req.body.mainImage;
recipe.content = req.body.content;
recipe.category = req.body.category;
recipe.tags = req.body.tags;
// Try saving the updated recipe
recipe.save(function(err) {
if (err) {
// If an error occurs send the error message
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
// Send a JSON representation of the recipe
res.json(recipe);
}
});
};
// Create a new controller method that deletes an existing recipe
exports.delete = function(req, res) {
// Get the recipe from the 'request' object
var recipe = req.recipe;
// Use the model 'remove' method to delete the recipe
recipe.remove(function(err) {
if (err) {
// If an error occurs send the error message
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
// Send a JSON representation of the recipe
res.json(recipe);
}
});
};
// Create a new controller middleware that retrieves a single existing recipe
exports.recipeByID = function(req, res, next, id) {
// Use the model 'findById' method to find a single recipe
Recipe.findById(id).populate('author', 'username userName').exec(function(err, recipe) {
if (err) return next(err);
if (!recipe) return next(new Error('Failed to load recipe ' + id));
// If an recipe is found use the 'request' object to pass it to the next middleware
req.recipe = recipe;
// Call the next middleware
next();
});
};
// Create a new controller middleware that is used to authorize an recipe operation
exports.hasAuthorization = function(req, res, next) {
// If the current user is not the author of the recipe send the appropriate error message
if (req.recipe.author.id !== req.user.id) {
return res.status(403).send({
message: 'User is not authorized'
});
}
// Call the next middleware
next();
};
Here is express.js
// Load the module dependencies
var config = require('./config'),
http = require('http'),
express = require('express'),
morgan = require('morgan'),
compress = require('compression'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
session = require('express-session'),
MongoStore = require('connect-mongo')(session),
flash = require('connect-flash'),
passport = require('passport');
// Define the Express configuration method
module.exports = function(db) {
// Create a new Express appllication instance
var app = express();
// Create a new HTTP server
var server = http.createServer(app);
// Use the 'NDOE_ENV' variable to activate the 'morgan' logger or 'compress' middleware
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
} else if (process.env.NODE_ENV === 'production') {
app.use(compress());
}
// Use the 'body-parser' and 'method-override' middleware functions
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json({ type: 'application/*+json' }));
app.use(methodOverride('X-HTTP-Method-Override'));
// Configure the MongoDB session storage
var mongoStore = new MongoStore({
db: db.connection.db
});
// Configure the 'session' middleware
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret
}));
// Set the application view engine and 'views' folder
app.set('views', './app/views');
app.set('view engine', 'ejs');
// Configure the flash messages middleware
app.use(flash());
// Configure the Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Load the routing files
require('../app/routes/index.server.routes.js')(app);
require('../app/routes/users.server.routes.js')(app);
require('../app/routes/recipes.server.routes.js')(app);
// Configure static file serving
app.use(express.static('./public'));
// Return the Server instance
return server;
};
AngularJS recipes controller
// Invoke 'strict' JavaScript mode
'use strict';
// Create the 'recipes' controller
angular.module('recipes').controller('RecipesController', ['$scope', '$routeParams', '$location', 'Authentication', 'Recipe',
function($scope, $routeParams, $location, Authentication, Recipe) {
// Expose the Authentication service
$scope.authentication = Authentication;
// Create a new controller method for creating new recipes
$scope.create = function() {
// Use the form fields to create a new recipe $resource object
var recipe = new Recipe({
title: this.title,
mainImage: this.mainImage,
content: this.content,
category: this.category,
tags: this.tags
});
// Use the recipe '$save' method to send an appropriate POST request
recipe.$save(function(response) {
// If an recipe was created successfully, redirect the user to the recipe's page
$location.path('recipes/' + response._id);
}, function(errorResponse) {
// Otherwise, present the user with the error message
$scope.error = errorResponse.data.message;
});
};
// Create a new controller method for retrieving a list of recipes
$scope.find = function() {
// Use the recipe 'query' method to send an appropriate GET request
$scope.recipes = Recipe.query();
};
// Create a new controller method for retrieving a single recipe
$scope.findOne = function() {
// Use the recipe 'get' method to send an appropriate GET request
$scope.recipe = Recipe.get({
recipeId: $routeParams.recipeId
});
};
// Create a new controller method for updating a single recipe
$scope.update = function() {
// Use the recipe '$update' method to send an appropriate PUT request
$scope.recipe.$update(function() {
// If an recipe was updated successfully, redirect the user to the recipe's page
$location.path('recipes/' + $scope.recipe._id);
}, function(errorResponse) {
// Otherwise, present the user with the error message
$scope.error = errorResponse.data.message;
});
};
// Create a new controller method for deleting a single recipe
$scope.delete = function(recipe) {
// If an recipe was sent to the method, delete it
if (recipe) {
// Use the recipe '$remove' method to delete the recipe
recipe.$remove(function() {
// Remove the recipe from the recipes list
for (var i in $scope.recipes) {
if ($scope.recipes[i] === recipe) {
$scope.recipes.splice(i, 1);
}
}
});
} else {
// Otherwise, use the recipe '$remove' method to delete the recipe
$scope.recipe.$remove(function() {
$location.path('recipes');
});
}
};
}
]);
And here is the form
<section data-ng-controller="RecipesController">
<div class="full-width-container">
<div class="create-recipe">
<div class="content">
<form data-ng-submit="create()" novalidate>
<h1>Create A New Recipe</h1>
<label>Title</label>
<div>
<input type="text" data-ng-model="title" placeholder="Title" id="title" required />
</div>
<label>Main Image</label>
<div>
<input type="text" data-ng-model="mainImage" placeholder="Enter image url" id="mainImage" />
</div>
<label>Recipe</label>
<div>
<textarea data-ng-model="content" placeholder="Enter Recipe" id="content"></textarea>
</div>
<label>Category</label>
<div>
<input type="text" data-ng-model="category" placeholder="Available categories (Breakfast, Brunch, Lunch, Dinner)" id="category"/>
</div>
<label>Tags</label>
<div>
<input type="text" data-ng-model="tags" placeholder="Seperate tags by a comma" id="tags"/>
</div>
<div>
<input type="submit" value="Create" class="form-submit" />
</div>
<div data-ng-show="error">
<strong data-ng-bind="error"></strong>
</div>
</form>
</div>
</div>
</div>
</section>
Thanks for the suggestions, mcpDESIGNS. I tried of your suggestions, but still no luck. When I submit it goes through successfully like before, but still when I look at the database it's still empty with the exception of id, author and date. I don't know I'm implementing your suggestion correctly or not.
The first suggestion -
<section ng-controller="RecipesController">
<div class="full-width-container">
<div class="create-recipe">
<div class="content">
<form ng-submit="create(recipe)" novalidate>
<h1>Create A New Recipe</h1>
<label>Title</label>
<div>
<input type="text" ng-model"recipe.title" placeholder="Title" id="title" required />
</div>
<label>Main Image</label>
<div>
<input type="text" ng-model"recipe.mainImage" placeholder="Enter image url" id="mainImage" />
</div>
<label>Recipe</label>
<div>
<textarea ng-model"recipe.content" placeholder="Enter Recipe" id="content"></textarea>
</div>
<label>Category</label>
<div>
<input type="text" ng-model"recipe.category" placeholder="Available categories (Breakfast, Brunch, Lunch, Dinner)" id="category"/>
</div>
<label>Tags</label>
<div>
<input type="text" ng-model"recipe.tags" placeholder="Seperate tags by a comma" id="tags"/>
</div>
<div>
<input type="submit" value="Create" class="form-submit" />
</div>
<div ng-show="error">
<strong ng-bind="error"></strong>
</div>
</form>
</div>
</div>
</div>
</section>
The second suggestion -
// Invoke 'strict' JavaScript mode
'use strict';
// Create the 'recipes' controller
angular.module('recipes').controller('RecipesController', ['$scope', '$routeParams', '$location', 'Authentication', 'Recipe',
function($scope, $routeParams, $location, Authentication, Recipe) {
// Expose the Authentication service
$scope.authentication = Authentication;
// Create a new controller method for creating new recipes
$scope.create = function() {
// Use the form fields to create a new recipe $resource object
var recipe = new Recipe({
title: $scope.title,
mainImage: $scope.mainImage,
content: $scope.content,
category: $scope.category,
tags: $scope.tags
});
// Use the recipe '$save' method to send an appropriate POST request
recipe.$save(function(response) {
// If an recipe was created successfully, redirect the user to the recipe's page
$location.path('recipes/' + response._id);
}, function(errorResponse) {
// Otherwise, present the user with the error message
$scope.error = errorResponse.data.message;
});
};
// Create a new controller method for retrieving a list of recipes
$scope.find = function() {
// Use the recipe 'query' method to send an appropriate GET request
$scope.recipes = Recipe.query();
};
// Create a new controller method for retrieving a single recipe
$scope.findOne = function() {
// Use the recipe 'get' method to send an appropriate GET request
$scope.recipe = Recipe.get({
recipeId: $routeParams.recipeId
});
};
// Create a new controller method for updating a single recipe
$scope.update = function() {
// Use the recipe '$update' method to send an appropriate PUT request
$scope.recipe.$update(function() {
// If an recipe was updated successfully, redirect the user to the recipe's page
$location.path('recipes/' + $scope.recipe._id);
}, function(errorResponse) {
// Otherwise, present the user with the error message
$scope.error = errorResponse.data.message;
});
};
// Create a new controller method for deleting a single recipe
$scope.delete = function(recipe) {
// If an recipe was sent to the method, delete it
if (recipe) {
// Use the recipe '$remove' method to delete the recipe
recipe.$remove(function() {
// Remove the recipe from the recipes list
for (var i in $scope.recipes) {
if ($scope.recipes[i] === recipe) {
$scope.recipes.splice(i, 1);
}
}
});
} else {
// Otherwise, use the recipe '$remove' method to delete the recipe
$scope.recipe.$remove(function() {
$location.path('recipes');
});
}
};
}
]);
Here is my recipes.server.routes.js
var users = require('../../app/controllers/users.server.controller'),
recipes = require('../../app/controllers/recipes.server.controller');
var needsRole = function(role) {
return function(req, res, next) {
if (req.user && req.user.role === role)
next();
else
res.status(401, 'Unauthorized');
};
};
// Deine the routes 'module' method
module.exports = function(app) {
// Setting the 'recipes' base routes
app.route('/api/recipes')
.get(recipes.list)
.post(users.requiresLogin, needsRole("admin"), recipes.create);
// Set up the 'recipes' parameterized routes
app.route('/api/recipes/:recipeId')
.get(recipes.read)
.put(users.requiresLogin, recipes.hasAuthorization, recipes.update)
.delete(users.requiresLogin, recipes.hasAuthorization, recipes.delete);
// Set up the 'recipeId' parameter middleware
app.param('recipeId', recipes.recipeByID);
};
So from what I can see, the problem is in your $scope.create function.
In your function, you're creating your object that you want to send to the database, but the big problem is: this. Since you're creating a resource there, the this might be referring to something totally different, not your $scope.
You have 2 options, either change them all to:
title : $scope.title,
mainImage : $scope.mainImage,
// etc
Or:
Try simply creating an object in your View of that entire form. For example:
<input ng-model="recipe.title" />
<input ng-model="reciple.mainImage" />
// etc
This way you can just pass the entire object to your ng-submit create(recipe).
When you're in the controller you can then access each property of that object with recipe., much easier. You could even pass that entire thing to your resource and let it map itself. new Recipe(recipe); for example.

Grab attribute of current record for Meteor Method Call

I am working on a project to pull in twitter timeline's for selected teams/players. When I am on the team/_id page, how can I grab an attribute to path through a method?
Below is my client side javascript, as well as the relevant route from iron router. When I type in something like "patriots" to the "????" section, I get a result. I would like to do this dynamically, I currently have the twitter handles stored under the twitter attribute.
Template.tweets.helpers({
teams: function() {
return Teams.find();
},
});
Template.tweets.onRendered(function () {
var twitterHandle = "???";
Meteor.call('getTimeline', twitterHandle, function(err,results){
if (err) {
console.log("error", error);
};
console.log(results);
Session.set("twitter", JSON.parse(results.content));
})
return Session.get("twitter");
});
Router.route('/teams/:_id', {
name: 'teamView',
template: 'teamView',
data: function(){
var currentTeam = this.params._id;
return Teams.findOne({ _id: currentTeam });
var twitterHandle = this.params.twitter;
return Teams.findOne({twitter: twitterHandle});
}
});
<template name="tweets">
<h3>Tweets</h3>
<div class="container">
{{twitter}}
</div>
</template>
You should be able to access all information from the current route using the Router.current() object. In your case you can use Router.current().params._id to get the _id param:
var twitterHandle = Router.current().params._id;
Edits based on your comments below
I did not notice that you were calling the Teams.findOne function twice in your route's data function. Form the looks of it you're already storing the twitter handle in the Teams collection, so you merely need to access the data that's returned by the route.
Template.tweets.helpers({
twitterData: function() {
//return the data stored in the callback function of the Meteor method call in the onRendered event
return Session.get('twitter');
}
});
Template.tweets.onRendered(function () {
//clear any previously stored data making the call
Session.set('twitter', null);
//property of the team document returned by the data function in the route.
var twitterHandle = this.data.twitter;
Meteor.call('getTimeline', twitterHandle, function(err,results){
if (err) {
console.log("error", error);
} else {
Session.set("twitter", JSON.parse(results.content));
}
});
});
Router.route('/teams/:_id', {
name: 'teamView',
template: 'teamView',
data: function(){
var currentTeam = this.params._id;
return Teams.findOne({ _id: currentTeam });
}
});
<template name="tweets">
<h3>Tweets</h3>
<div class="container">
<!-- twitterData will be an object, so you'll need to figure out what properties to display and use dot notation//-->
{{twitterData}}
</div>
</template>

Specifying Mongo Query Parameters From Client Controller (MEAN.JS)

I am building an application using MongoDB, Angular, Express, and Node (MEAN stack).
I used the MEAN.JS generator to scaffold my application.
I will use the articles module as a reference.
Suppose I have 7000 records in my articles collection, and each record has a date associated with it. It is inefficient to load all 7000 records into memory every time I load the page to view the records in a table and I am seeing terrible performance losses because of it. For this reason, I would only like to load records with a date in the range of (1 Month Ago) to (1 Year From Now) and display them in the table. I can currently do this with the following:
In my articles.client.controller.js:
$scope.find = function() {
$articles = Articles.query();
};
...and in my articles.server.controller.js:
var now = new Date();
var aYearFromNow = new Date(now.getTime() + 86400000*365); //add a year
var aMonthAgo = new Date(now.getTime() - 86400000*30); //subtract roughly a month
exports.list = function(req, res) { Article.find().where('date').lt(aYearFromNow).gt(aMonthAgo).sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
};
The problem is that this is not a dynamic way of doing things. In other words, I want the user to be able to specify how far back and how far forward they want to see.
How can I bind to variables (e.g. 'aYearFromNow' and 'aMonthAgo') in my client view that will change the query parameters in my server controller?
Another way is to just pass the search parameters in the query method, like this:
$scope.searchart = function() {
Articles.query({start:$scope.startDate, end:$scope.endDate}, function(articles) {
$scope.articles = articles;
});
};
and then at the server side controller, read your query string parameters like this:
exports.searcharticle = function(req, res) {
Article.find().where('date').gt(req.query['start']).lt(req.query['end']).exec(function(err, articles) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(articles);
}
});
};
This way doesn't require more routes or services.
It's probably not the cleanest way, but you can create a new service (or edit the current one to work with several parameters):
.factory('ArticlesService2', ['$resource',
function($resource) {
return $resource('articles/:param1/:param2', {
param1: '',
param2: ''
}, {
update: {
method: 'PUT'
}
});
}
]);
Then call it in your controller :
$scope.findWithParams = function() {
$scope.article = ArticlesService2.query({
param1: $scope.aYearFromNow,
param2: $scope.aMonthAgo
});
};
On the back-end, you'll need to prepare a route :
app.route('/articles/:param1/:param2')
.get(articles.listWithParams)
Add a function to your back-end controller :
exports.listWithParams = function(req, res) {
Article.find()
.where('date')
.lt(req.params.param1)
.gt(req.params.param2)
.sort('-created').populate('user', 'displayName')
.exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
};
Should work, haven't tested it though.

AngularJS redirection after ng-click

I have a REST API that read/save data from a MongoDB database.
The application I use retrieves a form and create an object (a job) from it, then save it to the DB. After the form, I have a button which click event triggers the saving function of my controller, then redirects to another url.
Once I click on the button, I am said that the job has well been added to the DB but the application is jammed and the redirection is never called. However, if I reload my application, I can see that the new "job" has well been added to the DB. What's wrong with this ??? Thanks !
Here is my code:
Sample html(jade) code:
button.btn.btn-large.btn-primary(type='submit', ng:click="save()") Create
Controller of the angular module:
function myJobOfferListCtrl($scope, $location, myJobs) {
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(err) {
if(err)
console.log('Impossible to create new job');
else {
console.log('Ready to redirect');
$location.path('/offers');
}
});
};
}
Configuration of the angular module:
var myApp = angular.module('appProfile', ['ngResource']);
myApp.factory('myJobs',['$resource', function($resource) {
return $resource('/api/allMyPostedJobs',
{},
{
save: {
method: 'POST'
}
});
}]);
The routing in my nodejs application :
app.post('/job', pass.ensureAuthenticated, jobOffers_routes.create);
And finally the controller of my REST API:
exports.create = function(req, res) {
var user = req.user;
var job = new Job({ user: user,
title: req.body.title,
description: req.body.description,
salary: req.body.salary,
dueDate: new Date(req.body.dueDate),
category: req.body.category});
job.save(function(err) {
if(err) {
console.log(err);
res.redirect('/home');
}
else {
console.log('New job for user: ' + user.username + " has been posted."); //<--- Message displayed in the log
//res.redirect('/offers'); //<---- triggered but never render
res.send(JSON.stringify(job));
}
});
};
I finally found the solution ! The issue was somewhere 18inches behind the screen....
I modified the angular application controller like this :
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(job) {
if(!job) {
$log.log('Impossible to create new job');
}
else {
$window.location.href = '/offers';
}
});
};
The trick is that my REST api returned the created job as a json object, and I was dealing with it like it were an error ! So, each time I created a job object, I was returned a json object, and as it was non null, the log message was triggered and I was never redirected.
Furthermore, I now use the $window.location.href property to fully reload the page.

Categories

Resources