Detecting logout event of {{> loginButtons}} in Meteor - meteor

I am working on project using meteor 0.8.2 and i have added "accounts-ui" and "accounts-password" for login functionality in the project. The login module works perfect. I am curious to know that, How to detect the logout event? Is there any function like,
Template.loginButtons.events({
'click .logout'=function(e)
{
console.log("I logged out!");
}
});

There is no official callback like Meteor.onLogout, but the standard way to handle this is as follow :
In templates :
{{#if currentUser}}
<p>logged in</p>
{{else}}
<p>logged out</p>
{{/if}}
currentUser is a standard Spacebars helper that simply returns the current user, if there is none, it returns a falsy value.
http://docs.meteor.com/#template_currentuser
In javascript :
Deps.autorun(function(computation){
var currentUser=Meteor.user();
if(currentUser){
console.log("logged in");
}
else if(!computation.firstRun){
console.log("logged out");
}
});
We can mirror the tempate code by registering a new Deps.Computation that references Meteor.user() which happens to be a reactive data-source returning the current user.
Whenever this variable change (ie on login/logout) the computation will rerun and we can inject our own custom code to handle login/logout in our webapp.
EDIT : as Neil said, the computation is run immediately following the declaration, in a state where the login resuming process maybe uncomplete resulting in a useless systematic logout detection on app startup, which might be an inconvenience.
We can detect the first run of the computation using the built in firstRun property and execute the logout logic only when it's NOT the first run.

You want watch the reactive function Meteor.userId for changes using Deps.autorun.
var started = false;
Deps.autorun(function () {
if (started && !Meteor.userId())
console.log('I logged out!');
started = true;
});
The function runs once immediately so started prevents that from being interpreted as a logout.

Related

How to clear Meteor's user even offline

I don't know why, the logout button in my Meteor App often fails to callback. the code is simple:
$scope.logout = function () {
Accounts.logout(function () {
// the code often fails to come here
$state.go('login');
});
}
maybe the network's problem? so I added some code to ensure my logout button won't look like frozen:
$scope.logout = function () {
Accounts.logout(function () {
// the code often fails to come here
$state.go('login');
});
$timeout(function () {
$state.go('login');
}, 2000);
}
The redirection to login page succeeded, but because Meteor.userId() still have value, the login page still shows the App user someone is logged on.
I want to know if there is a way to delete Meteor.userId / Meteor.user family even when failed connecting to the server.
I know it is not a complete solution, the App user will probably failed to do the next login at that state, but at least they won't complain the App even cannot logout.
The function you're looking for is Meteor.logout() not Accounts.logout()

MeteorJS - List item Not updating after implementing publish / subscribe and methods / calls

Ok so this is a little weird...
I got these methods on server side ...
Meteor.publish('todos', function () {
return Todos.find({userId: this.userId},{sort:{createdAt:-1}});
});
Meteor.methods({
editTodo: function(todoId) {
Todos.update(todoId, {$set: {checked: !this.checked}});
}
});
And here is the invocation on client side ....
Template.list.helpers({
todos: function(){
Meteor.subscribe('todos');
return Todos.find({});
}
});
Template.list.events({
"click .toggle-check": function(){
Meteor.call('editTodo',this._id);
}});
The problem is that when the click on ".toggle-check" occurs ... the 'checked' boolean is triggered on but never comes off .... is this.checked (in {checked: !this.checked}) not referring to field immediately read from the collection?
Or maybe I am implementing something wrong when subscribing to the data?
Please help!
I believe the issue relates to the registration of the subscription as you suggested - more specifically that your Meteor.subscribe() is being called from within a Template.helpers function.
Try moving your subscription to an earlier page or template event such as Template.body.onCreated() or Template.list.onCreated() (depending on your requirements).
There is a good example in the Meteor documentation: https://www.meteor.com/tutorials/blaze/publish-and-subscribe (see section 10.3).

Meteor JS & Blaze - Show Only Once on Load

I have a partial that show's a notification modal to agree to the site's terms and service that I would only like to show once (once they click I agree it goes away).
Is there anyway to do that with Meteor?
Assuming you want to store a boolean in the DB indicating that the user has accepted the terms (so they never get asked again), you could add a field called hasAcceptedTerms somewhere on the user object (e.g. in the user's profile). Once you do that you could write your template like this:
<template name="myTemplate">
{{#if areTermsVisible}}
(put terms partial here)
{{/if}}
</template>
Where areTermsVisible looks like:
Template.myTemplate.helpers({
areTermsVisible: function() {
var user = Meteor.user();
return user && user.profile && !user.profile.hasAcceptedTerms;
}
});
And the code to record the acceptance looks like:
Template.myTemplate.events({
'click .accept-terms': function() {
var userId = Meteor.userId();
var modifier = {$set: {'profile.hasAcceptedTerms': true}};
Meteor.users.update(userId, modifier);
}
});
Maybe not surprisingly, the best way to deal with cookies policy notification is by using cookies. The problem is not meteor-specific, but there are at least two good atmosphere packages that can help you to deal with the problem:
https://atmospherejs.com/mrt/cookies
https://atmospherejs.com/chuangbo/cookie
What you need to do is basically, set cookie
Cookie.set('userHasAcceptedPolicy', true, { year: 1 });
with whatever arguments you like, and as soon as the user clicks the "accept" button. Then, before you decide if you need to show the policy notification you can use:
Cookies.get('userHasAcceptedPolicy');
to see if there's a need to do so. So it's pretty much the same solution as #DavidWeldon suggested but it does not require referencing the Meteor.user() object, so the user does not need to have an account to accept the policy.
Please note, that - at least in case of mrt:cookies - Cookies.get is a reactive data source, which is quite helpful when it comes to rendering templates.
There's plenty of ways...
This isn't a Meteor specific question.
Template.notifications.events({
'click #close-modal': function(e, t) {
$('#modal').hide();
}
})

Iron Router onBeforeAction isn't being called

I have a /user route set up, which is supposed to render the login template if the current user isn't logged in. The entire router has a waitOn that waits for the currentUser subscription to finish. The problem is that when I go to /user it simply renders the dataNotFound template instead.
Here's the snippets of code that are relevant to this situation. I've been careful to show you them in the order they're defined in my lib/router.js file.
Router.plugin('dataNotFound', {notFoundTemplate: 'notFound'});
Router.onBeforeAction(function () {
console.log(Meteor.userId())
if (!Meteor.userId()) this.render('login');
else this.next();
}, { only: ['user'] });
Router.configure({
waitOn: function () { return Meteor.subscribe('currentUser'); }
});
Router.route('/user', {
name: 'user',
template: 'userView',
data: function () { return Meteor.user(); }
});
That console.log above doesn't even ever fire. It seems to me that since it should be a reactive function that even if initially the dataNotFound is rendered, then soon after that the onBeforeAction should be fired and render the login template, right?
It's very bizarre that your console log doesn't even fire. I have a few ideas, but first want to address the last piece of your question.
The dataNotFound plugin is triggered when the data function fires on your rout. This means it is bypassing your onBeforeAction hook altogether, and not that it isn't getting there.
One thing I can think of that might be worth trying would be wrapping the 'user' route action in a if ( this.ready() ) statement:
edit:
Router.route('user', {
// Your other stuff
action: function() {
if this.ready() {
this.render();
},
The reason I suggest this is just that you are using a waitOn statement, but I'm not 100% sure how that works if you don't have a this.ready() somewhere in your route, because that's what (again, from my reading of the documentation, have not fiddled around with it) tells the router what to wait before executing. Possibly it's not waiting at all right now.
I had a problem with onBeforeAction hook after upgrading from meteor 0.9.1 to 1.
It didnt get fired when it should. Like after I log out, I enter address manually and instead of login page I can see the actual site waiting for data that never comes. onRun hook solved it, but as docs says it gets fired only once.
Router.onRun(function () {
if (!Meteor.userId()) {
this.render('login');
} else {
this.next();
}
}, { only: ['user'] });
Try swapping out Meteor.userId() with Meteor.user() in your if statement. See this link for reference on how to handle checking for the user in a before filter: http://www.manuel-schoebel.com/blog/meteorjs-iron-router-filters-before-and-after-hooks.
I found the issue here.
According to this post, thanks to Steeve Cannon. The problem is on waitOn function.
Probably when you logginOut the subscribe to currentUser will fail, and this will make your app in infinite waiting. onBeforeAction runs after waitOn
You will need to check all variables in you Publish to insure waitOn complete successfully.
Put an if statement inside the waitOn function.
waitOn: function () {
if(Meteor.userId())
return Meteor.subscribe('currentUser');
}
Refer this comment to know why this is happening: https://github.com/iron-meteor/iron-router/issues/1010#issuecomment-72210587

Client-side-only reactivity with Meteor?

I have a collection published on the server and auto-subscribed on the client. I'd like to set the 'selected' item on the session and have the template update to display only the selected item, but it seems this can only be done with a roundtrip to the server (which is totally unnecessary).
Common:
var Missions = new Meteor.Collection('missions');
Client:
Template.missionList.missions = function() {
var currMission = Session.get('selectedMission');
var searchMission = {};
if(currMission)
{
searchMission['_id'] = currMission;
}
return Missions.find(searchMission);
};
Template.missionList.events({
'click div.mission': function (e, t) {
Session.set('selectedMission',
this._id == Session.get('selectedMission') ? null : this._id
);
}
});
Template.mission.isSelected = function() {
return this._id == Session.get('selectedMission');
};
Meteor.autosubscribe(function () {
Meteor.subscribe("missions");
});
Server:
Meteor.publish('missions', function() {
// there are really some filters here, but removed for simplicity
return Missions.find();
});
Template:
<template name="missionList">
<div class="missionList">
{{#each missions}}
{{> mission}}
{{/each}}
</div>
</template>
<template name="mission">
<div class="mission{{#if isSelected}} selected{{/if}}">details</div>
</template>
My requirement is for the Missions.find() in Template.missionList.missions to filter the client-side cached results, rather than to re-request from the server, but I can't seem to find a flag or settings to allow me to tell minimongo to only use the currently available data.
I'm also not entirely sure if this is what I should be doing, I started out just using jQuery to hide the non-selected missions but getting my head round Meteor and it seems a natural fit to use the data and reactivity to drive selection/local-filtering.
Is there any way the roundtrip can be avoided or am I just using it wrong?
By setting up a publish / subscribe relationship, you are creating a simplified form of database replication. Minimongo will have a copy of the data locally and execute the find() locally without a server roundtrip. If you are seeing network activity or calls to the server code, it is because meteor is regularly working behind the scenes to keep the subscription in sync with the server, not for your specific find.
This also means you have to wary of sending too much data to the client, so your server side publish function may want to filter by the specific fields needed by client, in addition to existing your selection criteria.

Resources