I am implementing the tutorial on the mean stack https://www.youtube.com/watch?v=AEE7DY2AYvI
I am adding a delete feature to remove items from the database on a button click
My client side controller has the following 2 functions to add to db and remove
$scope.createMeetup = function() {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
$scope.deleteMeetup = function() {
item = $scope.meetups[0];
console.log("deleting meetup: " + item["name"]);
Meetup.delete(item);
scope.meetups.shift();
}
My server side has the following code
module.exports.create = function (req, res) {
var meetup = new Meetup(req.body);
meetup.save(function (err, result) {
res.json(result);
});
}
module.exports.remove = function(req, res) {
console.log("GOING TO REMOVE!!!");
console.log(req.query);
item = req.query;
Meetup.remove(item, function (err, results) {
console.log("done");
console.log(err);
console.log(results);
});
}
When I run my code and if I delete an already loaded item in the list, it is removed from Mongodb just fine. But if I add an item to the list and I do not refresh the page, it results in an error at my server that appears as
GOING TO REMOVE!!!
{ '$resolved': 'true',
__v: '0',
_id: '54ec04e70398fab504085178',
name: 'j' }
done
{ [MongoError: unknown top level operator: $resolved]
name: 'MongoError',
code: 2,
err: 'unknown top level operator: $resolved' }
null
I if I refresh the page, the it gets deleted fine. But if I added the entry, angular seems to be adding a new variable $resolved. Why is that happening?
Also another question, What is the proper way to call delete? I call it now but I am not able to put a callback. I want a callback which returns and then I shift the list of items. I tried adding a callback but the code never reaches it.
ie I tried the following
/*
Meetup.delete(item, function () {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
});
*/
/*Meetup.delete(item,
function (returnValue, responseHeaders) {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
},
function (httpResponse){
// error handling here
console.log("Need to handle errors");
});
*/
I am very new to node and am confused. Any help is very, very appreciated
Looks like it possible to call item.delete instead of Meetup.delete(item). You can call same methods on model instance. It prevent sending angular properties to server.
But better to make a rest API with delete method
DELETE /meetups/:id
and send just a _id
Meetup.remove({id: item._id});
Related
I'm trying to implement soft delete on a model in a sails.js project by I override the delete action in the respective controller to just update a boolean attribute called isDeleted.
The problem I'm facing is that, I need to override the find action for the respective controller so that it'll ignore the "deleted" records but I need to keep the rest of the original functionality. To do this I'm simply copying the code of the original find action into the override, but it depends on the actionUtil module, and, when doing the require for that module, no matter how I change the route it never manages to find the module.
So, this is what my controller looks like:
var actionUtil = require('/sails/lib/hooks/blueprints/actionUtil'),
_ = require('lodash');
module.exports = {
find: function(req, res){
// Look up the model
var Model = actionUtil.parseModel(req);
if ( actionUtil.parsePk(req) ) {
return require('./findOne')(req,res);
}
// Lookup for records that match the specified criteria
var query = Model.find()
.where( actionUtil.parseCriteria(req) )
.limit( actionUtil.parseLimit(req) )
.skip( actionUtil.parseSkip(req) )
.sort( actionUtil.parseSort(req) );
// TODO: .populateEach(req.options);
query = actionUtil.populateEach(query, req);
query.exec(function found(err, matchingRecords) {
if (err) return res.serverError(err);
// Only `.watch()` for new instances of the model if
// `autoWatch` is enabled.
if (req._sails.hooks.pubsub && req.isSocket) {
Model.subscribe(req, matchingRecords);
if (req.options.autoWatch)
{ Model.watch(req); }
// Also subscribe to instances of all associated models
_.each(matchingRecords, function (record) {
actionUtil.subscribeDeep(req, record);
});
}
res.ok(matchingRecords);
});
},//End .find
destroy: function(req,res){
console.log("Parametro: " + req.param('id') );
Vendedor.update({ id_vendedor: req.param('id') }, { isDeleted: true })
.exec(function (err, goal)
{
if (err)
return res.status(400).json(err);
return res.json(goal[0]);
});
}
};
But, when starting the server I get an error, saying that the module actionUtil couldn't be found. Does anyone know how I could do this?
I have a MySQL table with a url column and I want to get a list of every url value in the table. Structure:
In PHP using Laravel I could have done something like this to get an array of every url column value:
$boards = Board::all()->lists('url');
However, I cannot figure out how to do this using Sails JS. I've noticed that find() without any argument gets every row in the database but I can't find anything in the documentation that would allow me to either get a list of the values for the url column or a way to iterate over the returned collection.
I've tried this:
var boards = Board.find().exec(function(error, _boards) {
if(error)
{
return response.negotiate(error);
}
return _boards;
});
However, I can't actually seem to iterate over the returned data.
Any thoughts?
EDIT:
Full HomepageController.js:
module.exports = {
index: function (request, response) {
var data = {
currentDate: (new Date()).toString(),
boards: Board.query('SELECT url FROM board', function (error, results) {
if (error) {
return response.negotiate(error);
}
return results;
})
};
return response.view('homepage', data);
}
};
EDIT: Working Code:
module.exports = {
index: function (request, response) {
Board.query('SELECT url FROM board', function(error, results) {
if(error)
{
return response.negotiate(error);
}
return response.view('homepage', { currentDate: (new Date()).toString(), boards: results });
});
}
};
You can use a raw .query() to select individual columns:
Board.query('SELECT url FROM board', function (err, results) { ... });
However, keep in mind that your data will still look like this:
[{url: 'row 1 value'}, {url: 'row 2 value'}, ...]
I have a sample code that goes like this:
Client Helper:
getUsername: function (userId) {
Meteor.call("getUsername", userId, function (err, result) {
if(!err) {
Session.set("setUsername", result);
else {
console.log(err);
}
});
return Session.get("setUsername");
}
Server
Meteor.methods({
"getUsername": function (userId) {
var x = Meteor.users.find({_id: userId}, {fields: {username:1}}).fetch()[0];
return x.username;
}
});
The result of this code is an infinite loop of username passing to the client. Is there a way to stop the loop and pass only the data that is needed on the client? I believe the reactivity is causing the data to loop infinitely and I am not sure how to stop it. I tried using "reactive":false on my query in the server but it does not work.
If you want to access username everywhere in client templates (so thats why you put it into session), I would not set it in template helper. I would set it on startup and get username from session in template helpers (without calling server method)
If you need username just in one template, so you want to return its value from your template helper, do not put it into session, just return it in your server method callback.
Based on your sample code, I assume, you have a set of posts and you are retrieving user name based on user id for each post. Then instead of doing it this way, you should use publish composite package to publish related users as well.
Meteor.publishComposite('getPosts', function (postIds) {
return [{
find: function() {
return Posts.find({ _id: { $in: postIds }});
// you can also do -> return Posts.find();
// or -> return Posts.find({ /* or what ever your selector is to get the posts you need*/ });
},
children: [{
find: function(post) {
return Meteor.users.find({
id: post.userId //or the correct field in your post document to get user id
}, {
fields: {
"profile": 1
}
});
}
}}
}]
});
This way your publication will take care of publishing related users along with posts. You don't need to use methods and call them each time.
I have this helper:
agreed: function (){
if (Meteor.users.findOne({_id: Meteor.userId(), profile: {agreedTermsOfUse: 'true'}}))
return true;
}
On the page where I check it I have this:
{{#unless agreed}}
agree form
{{else}}
Create item form.
{{list of item}}
{{/unless}}
So far, all goes well. The user signs up then he can create an item and it renders on the list of items..
Now, I've added another Meteor.call, which when getting the success call back on the client, for the creating item, it adds the item id to the users' profile.hasItems.
Then after getting succes for that method, "unless" returns false, and I have to submit the agree to form again.
What am I missing? Thanks.
"submit .create_restaurant": function (event) {
event.preventDefault();
var text = event.target.create_restaurant.value;
Meteor.call('CreateRest', Meteor.userId(), text, function(error, result){
if(error){
}else{
console.log(result, Meteor.userId());
Meteor.call('userRestaurants', result, Meteor.userId(), function (error, result) {
if (error) {
alert(123);
} else {
console.log(result);
}
})
}
}
);
event.target.create_restaurant.value = "";
}
methods:
'CreateRest': function(user_id, title) {
check(title, String);
check(user_id, String);
return callback = Restaurants.insert({
createdBy: user_id,
createdAt: new Date(),
title: title
});
},
'userRestaurants': function(rest_id, createdBy) {
var restId = checkHelper(rest_id, createdBy);
if(restId)
console.log(rest_id, createdBy);
{
var callback = Meteor.users.update(
createdBy,
{$addToSet: {'profile.hasRestaurants': restId}}
);
return callback;
}
}
I don't know why you're seeing the behaviour that you are, but I do know that you have other problems to sort out first :)
You have a huge security hole - you're passing the user id through to the method from the client. That means that anyone can simply open the browser console and create a restaurant with any user id they like as the owner. Instead, use this.userId in the method to get the id of the caller.
Why the round trip to the server? Just have the first method update the client.
So, something like this (untested, written by hand here):
"submit .create_restaurant": function (event) {
event.preventDefault();
var text = event.target.create_restaurant.value;
Meteor.call('CreateRest',text, function(error, result){
if(error){
alert(123);
}else{
console.log(result);
}
});
event.target.create_restaurant.value = "";
}
and:
'CreateRest': function(user_id, title) {
check(title, String);
check(this.userId, String);
userId = this.userId;
Restaurants.insert({
createdBy: userId,
createdAt: new Date(),
title: title
}, function(err, restId) {
if (err) throw new Meteor.Error(err);
Meteor.users.update(
userId,
{$addToSet: {'profile.hasRestaurants': restId}},
function (err, res) {
if (err) throw new Meteor.Error(err);
return restId;
}
);
});
Once that's implemented properly it might start working. If it doesn't then the issue isn't related to the code you're posting.
Finally note that from a schema perspective it's really odd that that you have profile.hasRestaurants. To find the restaurants that a user has you should just do a find on the Restaurants collection.
Scenario
I have these two Cloud Functions that I want to use in my application. They check for the online status of the user and I want to set a boolean key "isOnline" for each user to YES if the user is online and to NO if they are not.
var moment = require("moment");
Parse.Cloud.define("registerActivity", function(request, response) {
var user = request.user;
user.set("lastActive", new Date());
user.save().then(function (user) {
response.success();
}, function (error) {
console.log(error);
response.error(error);
});
});
Parse.Cloud.define("getOnlineUsers", function(request, response) {
var userQuery = new Parse.Query(Parse.User);
var activeSince = moment().subtract("minutes", 2).toDate();
userQuery.greaterThan("lastActive", activeSince);
userQuery.find().then(function (users) {
response.success(users);
}, function (error) {
response.error(error);
});
});
Problem
I am not the best with Javascript, and because of that I need some help getting my head around what is happening/what I'm supposed to do.
Questions
1) When do I call "registerActivity" and "getOnlineUsers" inside my Xcode project?
2) Is "response.success(users)" just an array of PFUser Objects?
3) If "2)" is true, then how do I set the bool key "isOnline" for all of the users in the "response.success(users)" to YES if they are in the array?
You would call these functions when you want to get the online users. The code for calling these would be:
[PFCloud callFunctionInBackground:#"registerActivity" withParameters:#{#"user": Put objectId for user here}
block:^(NSString *response, NSError *error) {
if (!error) {
}
}];
[PFCloud callFunctionInBackground:#"getOnlineUsers" withParameters:#{}
block:^(NSArray *users, NSError *error) {
if (!error)
{
} }];
Yes, I believe it would just be an array of PFUser objects, I would run this just to make sure, though.
Once you get the response from "getOnlineUsers" you should probably send it back up to another cloud code function that uses the master key (Parse.Cloud.useMasterKey();) to access/change user objects, and change the "isOnline" field to YES.