I want to display users which are currently online and have a focus on a special page. Somewhere on this page I like to display the list of users and there status (on/offline focus/no focus)
I found this package: benjaminrh/event-hooks
The setup is clear, this is in the docs. But I do not understand how to use the Hooks. E.g.:
Hooks.onLoseFocus = function ([server: userId]) { ... }
( anywhere ) - Provide a callback to run when the window loses focus.
So the function takes a userId.
Having the above layout in mind, I will have somewhere an extra template and an each loop like:
{{#each userstatus}}
{{>users_stats}
{{/each}}
How would I create userstatus when the hook takes individual userIds?
Ok, here is a fully working solution which tracks users currently viewing a particular route path and displays this list of users via a helper. This works under the assumption you are using iron:router
:
Server:
Hooks.onCloseSession = function() {
Meteor.call('clearUserFocus', function(error, result) {
if(error)
console.log(error);
});
}
Meteor.methods({
'setUserFocus': function(_routePath) {
Meteor.users.update({_id: Meteor.userId()}, {$set: {focus: _routePath}});
},
'clearUserFocus': function() {
var userId = Meteor.userId();
Meteor.users.update({_id: userId}, {$unset: {focus: ''}});
}
});
onCloseSession
seems to only work reliably in the server, as you would expect.
Client:
Meteor.startup(function() {
// Start hooks, for user focus tracking
Hooks.init({
updateFocus: 500
});
});
Hooks.onGainFocus = function() {
// Router.current().route.getName(); // route name
var routePath = Iron.Location.get().pathname; // route path
Meteor.call('setUserFocus', routePath, function(error, result) {
if(error)
console.log(error);
});
}
Hooks.onLoseFocus = function() {
Meteor.call('clearUserFocus', function(error, result) {
if(error)
console.log(error);
});
}
Client Global Router:
Router.onBeforeAction(function() {
// Record user focus
var routePath = Iron.Location.get().pathname;
Meteor.call('setUserFocus', routePath, function(error, result) {
if(error)
console.log(error);
});
this.next();
});
Client Template Helper:
Template.yourTemplateName.helpers({
'focusedUsers': function() {
var routePath = Iron.Location.get().pathname;
return Meteor.users.find({focus: routePath});
}
});
Client Template:
<ul>
{{#each focusedUsers}}
<li>{{_id}}</li>
{{/each}}
</ul>
This is working pretty nicely for me, I need to test it thoroughly though as I've discovered at least one caveat. With multiple windows running it seems it can get a bit confused with focus.
Also note you'll need all your routes to have access to the users
publication (whatever yours is called) so that the helper has access to the collection and can get focus
. Which you can do like this:
// Global router settings
Router.configure({
layoutTemplate: 'defaultLayout',
loadingTemplate: 'loading',
waitOn: function() {
return Meteor.subscribe('users');
}
});
As requested: Note that this includes an optional example of default layout and loading templates. The loading template replaces the contents of the layoutTemplate {{> yield}} until the waitOn (both globally and route specific) subscriptions are ready.
I'm also getting a browser console error, which doesn't seem to hinder anything as far as I can tell, but I don't like it being there: 'Error invoking Method 'eventsOnHooksInit': Method not found [404]'