Up and Downvote button - javascript

I try to achieve an up or downvote button where a user is able to vote just 1 time up and 1 time down. If you already have upvoted something it should be possible to remove that with another click on the upvote button, but i dont know what is missing for this. My code looks like the following. I guess i have to implement something with a true of false statement but i tried some things and nothing worked. I would appreciate your help!
Template.postArgument.events({
'click':function() {
Session.set('selected_argument', this._id);
},
'click .yes':function() {
if(Meteor.user()) {
var postId = Arguments.findOne({_id:this._id})
console.log(postId);
if($.inArray(Meteor.userId(), postId.votedUp) !==-1) {
return "Voted";
} else {
var argumentId = Session.get('selected_argument');
Arguments.update(argumentId, {$inc: {'score': 1 }});
Arguments.update(argumentId, {$addToSet: {votedUp: Meteor.userId()}});
}
}
}});

Your general approach is correct however you don't need the Session variable at all or even the first click handler. And you don't need to return anything at all from the function.
Template.postArgument.events({
'click .yes': function(){
if ( Meteor.user() ) {
var post = Arguments.findOne({_id:this._id});
if ( $.inArray(Meteor.userId(), post.votedUp) === -1 ) {
Arguments.update(this._id, {
$inc: { score: 1 },
$addToSet: { votedUp: Meteor.userId() }
});
} else {
Arguments.update(this._id, {
$inc: { score: -1 },
$pull: { votedUp: Meteor.userId() }
});
}
}
}
});

You can start simple by checking for the existence of the user in the upvotes and downvotes and increment/decrement accordingly then add the user to the sets.
Meteor.methods({
'downvote post': function (postId) {
check(postId, String);
let post = Posts.findOne(postId);
Posts.update(postId, post.downvoters.indexOf(this.userId !== -1) ? {
$inc: { downvotes: -1 }, // remove this user's downvote.
$pull: { downvoters: this.userId } // remove this user from downvoters
} : {
$inc: { downvotes: 1 }, // add this user's downvote
$addToSet: { downvoters: this.userId } // add this user to downvoters.
});
}
});

Related

Subscribe to Meteor.users() both listing all users and this.userId

PAGE CUSTOMERS: Lists all users in the users collection.
PAGE PROFILE: List only logged in user profile information.
userProfiles.js:
if (Meteor.isServer) {
Meteor.publish("userData", function () {
return Meteor.users.find({}, {
fields: {
// VISIBLE
'profile.mobile': 1,
'profile.zipcode': 1,
'profile.first_name': 1,
'profile.work_title': 1,
'emails[0].address': 1,
}});
});
}
profile.js
Template.profileDetails.helpers({
user: function() {
return Meteor.users.find({_id: this.userId});
},
userEmail: function() {
return this.emails[0].address;
},
userFirstName: function() {
return this.profile.first_name;
},
userTitle: function() {
return this.profile.work_title;
},
userMobile: function() {
return this.profile.mobile;
},
userZip: function() {
return this.profile.zipcode;
},
});
customers.js
Template.customerDetails.helpers({
user: function() {
return Meteor.users.find();
},
userEmail: function() {
return this.emails[0].address;
},
userFirstName: function() {
return this.profile.first_name;
},
userTitle: function() {
return this.profile.work_title;
},
userMobile: function() {
return this.profile.mobile;
},
userZip: function() {
return this.profile.zipcode;
},
});
The profile page is not showing any information at all. How can i get it to only display the logged in user information? Thank you!
the "this" in the helpers isn't the user. since you're looking for the current user in your profile template, you can do it in Blaze, without a helper:
{{currentUser.profile.first_name}}
for the customers, you can loop over the users returned by your helper. i would rename the helper:
Template.customerDetails.helpers({
customers(){
return Meteor.users.find({});
}
});
then you can loop over them, in Blaze, like this:
{{#each customer in customers}}
{{customer.profile.first_name}}
{{else}}
No customers found.
{{/each}}
note that you don't need any other helpers to make that work.
c.f. http://blazejs.org/guide/spacebars.html#Each-in
To get the currently logged-in user, you could use: Meteor.user():
//...
user: function() {
return Meteor.user();
},
//...

Meteor: publish dynamically requested range of items

I have huge collection of over 5000+ records. I want to be able to view records 10 at a time. How can I dynamically publish the data that way?
I've tried this so far:
My server.js file :
Meteor.methods({
publishSongs : function (first, last) {
Meteor.publish('adminSongs', function() {
return Songs.find({}, {
skip : first,
limit : last,
sort : {
date : -1
}
});
});
}
});
My client.jsfile :
Template.admin.events({
'click #previous' : function() {
updateSession(-10);
publishSong();
},
'click #next' : function() {
updateSession(10);
publishSong();
}
});
Template.admin.onCreated(function() {
Session.setDefault('limit', {
first : 0,
last : 10
});
publishSong()
})
function publishSong() {
Meteor.call(
'publishSong',
Session.get('limit').first,
Session.get('limit').last
);
}
function updateSession(value) {
Session.set('limit', {
first: Session.get('limit').first + value,
last: Session.get('limit').last + value,
});
}
The server is printing this error message:
Ignoring duplicate publish named 'adminSongs'
It seems like I'm using publications wrong and could use some guidance.
It doesn't look like you're never updating your Session.get('limit'). You'll need to update then you press next/previous otherwise you're always going to get the same records. You'll also need to change the way you're doing publications:
Template.admin.events({
'click #previous' : function() {
updateSession(-10);
},
'click #next' : function() {
updateSession(10);
}
});
Template.admin.onCreated(function() {
Session.setDefault('limit', {
first : 0,
last : 10
});
Template.instance().autorun( function() {
Template.instance().subscribe('adminSongs', Session.get('limit').first, Session.get('limit').last);
});
});
function updateSession(value) {
Session.set('limit', {
first: Session.get('limit').first + value,
last: Session.get('limit').last + value,
});
}
I'm assuming based on your code that you already have a helper defined to return the available songs. The code above makes it so that you have one subscription, and that subscription will update any time your session variable changes.
Your server code will also need to be updated:
Meteor.publish('adminSongs', function(first, last) {
return Songs.find({}, {
skip : first,
limit : last,
sort : {
date : -1
}
});
});
Can be outside of a Meteor.method.

Subscribing the collection (Meteor)

I have some specific problem.
I use MeteorJS and installed yogiben:admin. I tried to build some schema, but I have an error after updating something.
I want to add that I have subpages in page, maybe that's the problem?
That's what I get after adding items to my invoice:
http://s7.postimg.org/l0q52l27v/error.png
As I can see in the picture, the problem is with some modifier and with "After.Update.sum". I use function that use "sum".
In my "server/collections/invoices_item.js"
I have:
InvoicesItem.after.update(function(userId, doc, fieldNames, modifier, options) {
var sum = 0; InvoicesItem.find({ invoiceId: doc.invoiceId }).map(function(item) { sum += item.amount; }); Invoices.update({ _id: doc.invoiceId }, { $set: { totalAmount: sum }});
});
Than I saw that problem could be with "totalAmount:sum". I use Chrome, so I tried "console.log()" to see if the page takes my collection.
And it doesn't.
I use Chrome, so I tried to see what the console will give me. I have something like this: http://s4.postimg.org/rusm4wx9p/fakturka.png
I did sth like that in my code on server side:
Meteor.publish("fakturka", function(invoiceId) {
return Invoices.find({_id:invoiceId,ownerId:this.userId}, {});
});
And did that on client side:
this.InvoicesNewInsertController = RouteController.extend({
template: "InvoicesNew",
yieldTemplates: {
'InvoicesNewInsert': { to: 'InvoicesNewSubcontent'}
},
onBeforeAction: function() {
/*BEFORE_FUNCTION*/
this.next();
},
action: function() {
if(this.isReady()) { this.render(); } else { this.render("InvoicesNew"); this.render("loading", { to: "InvoicesNewSubcontent" });}
/*ACTION_FUNCTION*/
},
isReady: function() {
var subs = [
Meteor.subscribe("invoices_item"),
Meteor.subscribe("invoiceeeee"),
Meteor.subscribe("customers"),
Meteor.subscribe("fakturka", this.params.invoiceId),
Meteor.subscribe("invoices_item_empty_faktura"),
Meteor.subscribe("invoices_itemss_faktura", this.params.invoiceId)
];
var ready = true;
_.each(subs, function(sub) {
if(!sub.ready())
ready = false;
});
return ready;
},
data: function() {
return {
params: this.params || {},
invoices_item: InvoicesItem.find({}, {}),
invoiceeeee: Invoices.find({}, {}),
customers: Customers.find({}, {}),
fakturka: Invoices.findOne({_id:this.params.invoiceId}, {}),
invoices_item_empty_faktura: InvoicesItem.findOne({_id:null}, {}),
invoices_itemss_faktura: InvoicesItem.find({invoiceId:this.params.invoiceId}, {})
};
/*DATA_FUNCTION*/
},
onAfterAction: function() {
}
});
I'm sorry for so much code, but I really want to solve that problem and I want to give so much info as I could. Please, help me to solve my problem.
After removing that code from: both/collections/invoices.js
Schemas={};
Schemas.Invoicess = new SimpleSchema({
invoiceNumber:{
type:Number
},
date_issued:{
type:Date
},
date_due:{
type:Date
},
customerId:{
type:String
},
totalAmount:{
type:String
}
});
Invoices.attachSchema(Schemas.Invoicess);
"fakturka" is visible. After adding that code - "fakturka" in undefined.

Upload images associated to a meteor collection

I'm having a hard time understanding the whole process of uploading images to a certain Meteor collection eg.(the belongs_to and has_one association with rails).
I have a portfolioitem collection, this is the file:
PortfolioItems = new Mongo.Collection('portfolioItems');
ownsDocument = function(userId, doc) {
return doc && doc.userId === userId;
}
PortfolioItems.allow({
update: function(userId, portfolioItem) { return ownsDocument(userId, portfolioItem); },
remove: function(userId, portfolioItem) { return ownsDocument(userId, portfolioItem); },
});
Meteor.methods({
portfolioItemInsert: function(portfolioItemAttributes) {
check(Meteor.userId(), String);
check(portfolioItemAttributes, {
title: String
});
var portfolioItemWithSameTitle = PortfolioItems.findOne({ title: portfolioItemAttributes.title});
if (portfolioItemWithSameTitle) {
return {
portfolioItemExists: true,
_id: portfolioItemWithSameTitle._id
}
}
var user = Meteor.user();
var portfolioItem = _.extend(portfolioItemAttributes, {
userId: user._id,
submitted: new Date()
});
var portfolioItemId = PortfolioItems.insert(portfolioItem);
return {
_id: portfolioItemId
};
}
});
This is the submit.js template for submitting portfolio items:
Template.submit.events({
'submit #submit-form': function(e) {
e.preventDefault();
var portfolioItem = {
title: $(e.target).find('#submit-title').val()
};
Meteor.call('portfolioItemInsert', portfolioItem, function(error, result) {
if (error) {
return alert(error.reason);
}
if(result.portfolioItemExists) {
alert('Title already taken!');
pause();
}
Router.go('portfolioItemPage', {_id: result._id});
});
}
});
Did you give a try to FSCollection? if not i think its a good option to accomplish this.
You can just declare the collection.
I Suggest you to use GridFS.
just run this 2 commands
meteor add cfs:standard-packages
meteor add cfs:gridfs
Declare the collections like any others.
Images = new FS.Collection("Images", {
stores: [new FS.Store.GridFS("Images")]
});
And you can associate the Simple collection with the FSCollection using metadata.
Template.exampe.events({
'click #addImage':function(){
var file = $('#inputPng').get(0).files[0],
fsFile = new FS.File(file);
fsFile.metadata = {
ownerId:Meteor.userId(),
title:$(e.target).find('#submit-title').val()
}
Images.insert(fsFile,function(err,result){
if(!err){
console.log(result)
}
})
}
})
At this moment the README on the fsCollection its empty so I made a little DEMO about this.

How to get Email.send to send emails in the future (7 days, 14 days from now, etc)

I need to send email reminders to people in the future. I have implemented MomentJS and I can get dates I'd need my email to send, I just couldn't find anything in meteor docs for Email.send(options) to have anything there. Is there a different package you can recommend?
Here is some of my code as per #richsilv 's advice
createTransfer.js (client)
Template.createTransfer.events({
'submit form': function (event, template) {
event.preventDefault();
Transfers.insert(transfer, function (error, id) {
if (error) {
showError(error);
} else {
Session.set('files');
showAlert('Transfers sent!');
transfer._id = id;
Meteor.call('sendEmail', transfer);
scheduleEmail(transfer); // send reminder email
Router.go('viewTransfer', {_id: id});
}
});
// scheduleEmail(transfer);
console.log(transfer);
function scheduleEmail(transfer) {
if (transfer.invoice.due == "7 Days"){
console.log('its due in 7 days');
if (moment(transfer.date).add(7, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "14 Days") {
if (moment(transfer.date).add(14, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "30 Days") {
if (moment(transfer.date).add(30, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "90 Days") {
if (moment(transfer.date).add(90, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else {
console.log('need to initiate cron!');
var thisId = FutureEmails.insert(transfer);
console.log('inserted into db');
Meteor.call('addCronMail',thisId, transfer);
}
}
methods.js (lib)
Meteor.methods({
sendMail: function(transfer) {
check([transfer.senderEmail,
transfer.recipientEmail,
transfer.message,
// transfer.invoice.total
], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
transfer.url = Meteor.absoluteUrl() +'transfer/' + transfer._id;
var template = 'invoice-due';
Email.send({
to: transfer.recipientEmail,
bcc: transfer.senderEmail,
from: transfer.senderEmail,
subject: transfer.senderEmail + ' sent you files!',
html: Handlebars.templates[template](transfer)
});
},
addCronMail: function(id, transfer) {
SyncedCron.add({
name: id,
schedule: function(parser) {
return parser.recur().on(transfer.date).fullDate();
},
job: function() {
sendMail(transfer);
FutureEmails.remove(id);
SyncedCron.remove(id);
return id;
}
});
}
});
cron.js (server)
Meteor.startup(function() {
FutureEmails.find().forEach(function(mail) {
if (moment(mail.date).format("MMM Do YY") == moment(new Date()).format("MMM Do YY")) {
sendMail(mail)
} else {
addCronMail(mail._id, mail);
}
});
SyncedCron.start();
});
As requested, although note that this is not tested, so you might have to play around with it.
$ meteor add percolatestudio:synced-cron
Then something like this on the server:
FutureEmails = new Meteor.Collection('future_emails'); // server-side only
// "details" should be an object containing a date, plus required e-mail details (recipient, content, etc.)
function sendMail(details) {
Email.send({
from: details.from,
to: details.to,
etc....
});
}
function addCronMail(id, details) {
SyncedCron.add({
name: id,
schedule: function(parser) {
return parser.recur().on(details.date).fullDate();
},
job: function() {
sendMail(details);
FutureEmails.remove(id);
SyncedCron.remove(id);
return id;
}
});
}
function scheduleEmail(details) {
if (details.date < new Date()) {
sendMail(details);
} else {
var thisId = FutureEmails.insert(details);
addCronMail(thisId, details);
}
}
Meteor.startup(function() {
FutureEmails.find().forEach(function(mail) {
if (mail.date < new Date()) {
sendMail(mail)
} else {
addCronMail(mail._id, mail);
}
});
SyncedCron.start();
});
Then just call scheduleEmail(details) whenever you want to schedule a new mail.
Hope that's helpful!

Categories

Resources