Error
email not defined.
I've been trying to debug this and it appears the error is being caused by the code below but I'm not sure why:
var html = Blaze.toHTMLWithData(Template.sample-email,data);
I'm trying to change my text email to a html template email in Meteor with very little luck. The end goal here is to be able to render the email with the users first name. My emails worked when they where basic text so I assume the problem is with how I'm implementing the templates.
Packages
email
meteorhacks:ssr
Path: server/email.js
Meteor.methods({
sendEmail: function (to, from, subject, text) {
check([to, from, subject, text], [String]);
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
html: html
});
}
});
Path: private/sample-email.html
<template name="sample-email">
<h1>Hey { { name } },</h1>
<h2>This is a simple email rendered with Blaze</h2>
</template>
Path: client/welcomePage.js
Template.welcomePage.events({
'click .send-email-button': function () {
var data = {
name: "Valentin"
};
var html = Blaze.toHTMLWithData(Template.sample-email,data);
Meteor.call('sendEmail',"test#gmail.com", "test#gmail.com","Test",html);
}
});
Related
I created a simple login with Polymer & Firebase (google authentication). I came across a problem which got me thinking that my chosen approach might not be the cleanest. So this question is more about the general pattern.
In my code below I combined the basic login from the latest Polycast video and some code I found in the Firebase Guide.
The Problem
Basically I am unable to call a function inside the login that would then store the values, neither can I store the returned user value's inside the login method directly.
My solution
To work around that problem I created a listener which fires if a user exists and then calls the modification method to store the user details inside my localstorgae userDetails object.
So I am wondering if my approach is okey and what I could improve to skip the observer and store the user details inside the login method. In addition I found in the Firebase guidelines a special observer but was not sure how to implement it.
<dom-module id="my-app">
<template>
<style>
:host {
display: block;
}
</style>
<firebase-app auth-domain="...firebaseapp.com"
database-url="...firebaseio.com"
api-key="..."></firebase-app>
<iron-localstorage id="localstorage" name="my-app-storage"
value="{{userDetails}}"></iron-localstorage>
<section class="wrapper">
<paper-material id="loginContainer" elevation="1">
<firebase-auth id="auth"
user="{{user}}"
status-known="{{statusKnown}}"
provider="{{provider}}"
on-error="handleError"></firebase-auth>
<template is="dom-if" if="[[user]]">
<h1>Welcome [[user.displayName]]</h1>
</template>
<paper-button raised on-tap="login" hidden$="[[user]]">Sign in</paper-button>
<paper-button raised on-tap="logout" hidden$="[[!user]]">Sign out</paper-button>
</paper-material>
</section>
</template>
<script>
Polymer({
is: 'my-app',
properties: {
userDetails: {
type: Object,
},
user: {
type: Object,
observer: '_changed'
},
statusKnown: {
type: Object
},
provider: {
type: String,
value: 'google'
}
},
login: function() {
this.$.auth.signInWithPopup(this.provider).then(function(result) {
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
//UNABLE TO CALL A METHOD OR TO STORE VALUES DIRECTLY IN MY OBJECT
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
var email = error.email;
var credential = error.credential;
});
},
//OBSERVER THAT CALLS THE MODIFICATION FOR THE LOCALSTORAGE
_changed: function() {
if (this.user != null) {
var user = firebase.auth().currentUser;
this.makeModifications(user);
}
},
// set localstorage
makeModifications: function(user) {
this.set('userDetails.name', user.displayName);
this.set('userDetails.email', user.email);
this.set('userDetails.photoUrl', user.photoURL);
console.log(this.userDetails.name + ' is singed in');
},
logout: function() {
this.$.localstorage.reload();
this.set('userDetails.name', null);
this.set('userDetails.email', null);
this.set('userDetails.photoUrl', null);
return this.$.auth.signOut();
},
});
</script>
</dom-module>
You have a problem with scope?. When inside this.$.auth.signInWithPopup().then(function you cant use Polymers this.set because your within a new scope. Theres also nothing wrong with what you've done, asuming its works for you.
this.$.auth.signInWithPopup().then(function(user) {
// notice bind(this), binds your polymer element to the scope of the
// function, this allows you to use its API, thus enabling
// the use of set within the Promise
this.set('userDetails.name', user.displayName);
}.bind(this));
this can also be done via
login: function() {
// create a local reference to the Polymer element
// assuming its within a closure like this login function it will be
// available to any function called from it.
var that = this;
this.$.auth.signInWithPopup().then(function(result) {
var user = result.user
that.set('userDetails.name', user.displayName);
});
}
I havent tested this code while writing so copy with caution.
Closures Example
The way I've been doing it recently is
login: function() {
this.$.auth.signInWithPopup()
.then(this._setUserDetails.bind(this))
.then(this._anotherFunctionCall.bind(this));
},
_setUserDetails: function(user) {
this.set('userDetails.name', user.displayName);
return Promise.resolve();
}
Its not doing anything extra just feels cleaner
I’m making an app, where users can leave their comments. All reviews are going to Mongo collection. Every week cron-job takes records from collection and sent them by e-mail.
I used the code below and I got not what was expecting. Email text was just: [Object, object].
Can anyone can explain me how should I properly write this line:
var myMessages = FeedbacksList.find({}).toString();
to get my app work corectly?
ALL CODE:
// Methods
Meteor.methods({
sendEmail: function (to, from, subject, text) {
Email.send({
to: to,
from: from,
subject: subject,
html: text
});
}
});
Meteor.methods({
'feedbacks.insert'(emoji, feed, timeSet) {
FeedbacksList.insert({
feedback: emoji,
knowFrom: feed,
createdAt: timeSet
});
}
});
var myMessages = FeedbacksList.find({}).toString();
// Cron Job for weekly email sending
SyncedCron.add({
name: 'Jura Ataskaitos',
schedule: function(parser) {
// parser is a later.parse object
return parser.text('at 9:00 am on Mon');
},
job: function() {
const sendM = Meteor.call('sendEmail', 'karolis.arbaciauskas#gmail.com', 'karolis#pretendentas.lt', 'test', myMessages);
return sendM;
}
});
// Start Cron
SyncedCron.start();
Note that the following returns a cursor
FeedbacksList.find({})
If you want to get all the records returns by this, then you need to fetch them:
var messages = FeedbacksList.find({}).fetch()
Or you can iterate over them:
FeedbacksList.find({}).fetch().foreach(function(message) {
console.log(message);
});
In my application I want to seed the database with users and send them an enrollment link to activate their account (and choose a password). I also want them to verify/change some profile data.
On the server I seed the database like this:
Meteor.startup(function () {
if(Meteor.users.find().count() === 0) {
var user_id = Accounts.createUser({ email: 'some#email.com', profile: { some: 'profile' } });
Accounts.sendEnrollmentEmail(user_id);
}
})
The enrollment link is sent as expected, but I want to create a custom template for when the url in the email is clicked. Preferably handled by iron-router. (Not using the accounts-ui package).
I tried things like redirecting the user to a custom route like this:
var doneCallback, token;
Accounts.onEnrollmentLink(function (token, done) {
doneCallback = done;
token = token;
Router.go('MemberEnroll')
});
which is not working (it changes the url but not rendering my template)
I also tried to change the enroll URL on the server like this:
Accounts.urls.enrollAccount = function (token) {
return Meteor.absoluteUrl('members/enroll/' + token);
};
But when I do this, the Accounts.onEnrollmentLink callback does not fire.
Also, changing the URL is not documented so I'm not sure its a good practice at all.
Any help is appreciated.
In my application I'm doing like this
this.route('enroll', {
path: '/enroll-account/:token',
template: 'enroll_page',
onBeforeAction: function() {
Meteor.logout();
Session.set('_resetPasswordToken', this.params.token);
this.subscribe('enrolledUser', this.params.token).wait();
},
data: function() {
if(this.ready()){
return {
enrolledUser: Meteor.users.findOne()
}
}
}
})
As enrollment url is like this
http://www.yoursite.com/enroll-account/hkhk32434kh42hjkhk43
when users click on the link they will redirect to this template and you can render your template
In my publication
Meteor.publish('enrolledUser', function(token) {
return Meteor.users.find({"services.password.reset.token": token});
});
After taking the password from the user
Accounts.resetPassword(token, creds.password,function(e,r){
if(e){
alert("Sorry we could not reset your password. Please try again.");
}else{
alert("Logged In");
Router.go('/');
}
})
enroll link
Accounts.urls.enrollAccount = function (token) {
return Meteor.absoluteUrl('enroll-account/' + token);
};
Im afraid now isnt possible, what i did is changing the html and css using "rendered" function but it has some probs with delay
Meteor.startup(function(){
Template["_enrollAccountDialog"].rendered = function(){
document.getElementById('enroll-account-password-label').innerHTML = 'Escolha sua senha';
$('.accounts-dialog').css('background-color','#f4f5f5');
$('.accounts-dialog').css('text-align','center');
$('.accounts-dialog').removeAttr('width');
document.getElementById('login-buttons-enroll-account-button').className = ' create-account-button';
document.getElementById('login-buttons-enroll-account-button').innerHTML = 'Criar conta';
}
});
I have a 'profile' template where I will display user related stuffs. So I wanna make a route for the template, but in the 'path' I want to dynamically insert the current user's username. Just the way we dynamically change the url with regard to post's id and everything.
Here's the router code block as of now.
Router.map(function() {
this.route('profile', {
path: '/profile', //here instead of 'profile' I wanna dynamically insert the current user's username.
});
});
By the way, I was able to load the user related data's to the said template.
I tried loading the username(/username) to the route path in a trial and error way, but in vain. :(
I guess I'm not very good with Iron Router after all. Please help.
I too was struggling with this one for a while... then I came across this SO answer. In my case, I was doing everything right except for failing to pass the username along with the template pathFor link helper.
For some reason, when using :_id in iron router routes, there's no need to reference it in the pathFor helper. This was the source of my confusion, perhaps others' as well.
Here is sample code of using the username in a path for iron router:
router.js
this.route('/:username', {
name: "dashboard",
waitOn: function() {
return Meteor.subscribe("allUserData");
},
data: function() {
return Meteor.users.findOne();
}
});
publications.js
Meteor.publish("allUserData", function() {
if (this.userId) {
return Meteor.users.find(this.userId)
} else {
this.ready()
}
})
page.html
<a href="{{pathFor 'dashboard' username=username}}">
User Dashboard
</a>
Again, at least in my particular case, I was missing the above username=username.
Have you tried this?
this.route('profile', {
path: '/:username',
data: function() { return Meteor.user().username; }
});
Use router parameters:
Router.map(function() {
this.route('profile', {
path: '/:_username', //dynamic parameter username
data: function() {
//here you will get the username parameter
var username = this.params.username;
return {
user: Meteor.users.find({ username: username }) //you can use user object in template
};
}
});
});
Don't forget the waitOn property on routes. Most of the time it's just the timing that's off, creating a publication for this is the best way to get rid of that issue..
Server side, publications.js:
Meteor.publish('me', function() {
if(!this.userId) return false;
else return Meteor.users.find({_id: this.userId});
});
In one of your Router.map() routes:
this.route('me', {
template: 'profile',
notFoundTemplate: 'profile_not_found',
path: '/profile',
waitOn: function() {
return Meteor.subscribe("me");
},
data: function() {
return Meteor.user();
}
});
Don't forget these configuration bits as well:
// Router config.. pretty self explanatory
Router.configure({
layoutTemplate: 'main',
notFoundTemplate: 'not_found',
loadingTemplate: 'loading'
});
// handle the loading screen
Router.onBeforeAction('loading');
// make sure you define routes here that rely on data to throw back
// 404/not found equivalent pages. e.g. no search results found,
// or in this case profile not found
Router.onBeforeAction('dataNotFound', {only: ['profile']});
and you can use the profile template:
<template name="profile">
Current user Id: {{_id}}
</template>
<template name="profile_not_found">
Profile not found. Are you logged in?
</template>
Using meteor 0.5.7 - following the Parties example - made client, server folders, and placed respective client.js and server.js files in them. I have autopublish, insecure removed, and added email package. I can't get the Meteor.call to fire off, debugging shows that it gets bypassed, I'm loosely following this - http://goo.gl/MV26m - and I still don't understand.
// server.js
Meteor.startup(function () {
process.env.MAIL_URL = '...'; // using mailgun URL
});
Meteor.methods({
call_me: function (options) {
var options = options || {};
Email.send({
from: options.from,
to: options.to,
replyTo: options.from || undefined,
subject: options.subj,
text: options.msg,
});
},
});
// client.js
Template.form.events({
'click .submit' : function (event, template) {
var from = template.find("#from").value;
var to = template.find("#to").value;
var subj = template.find("#subj").value;
var msg = template.find("#msg").value;
var options = { from: from, to: to, subj: subj, msg:msg };
Meteor.call('call_me', options, function(err, data) {
if (err)
console.log(err);
});
}
});
// client.html - the gist of it
<body>
{{> page }}
</body>
<template name="page">
{{> form }}
</template>
<template name="form">
<form ....
</template>
Lastly, I actually had the Meteor.methods({...}); sitting in a model.js file outside the client/server folders - and it still didn't fire off emails, or invoke the Meteor.call method. I'm kinda trying to wrap my head around the notion of a stub in the aforementioned attached link, wrapped the call within a function and called it, and I still didn't get any activity. Thanks for any advice.
Tried your gist. Removing the <form> tag and commenting out Process.env.MAIL_URL did it. The <form> tag is blocking the event trigger to button click.