Meteor subscribe on event/render - javascript

is there a way to subscribe in meteor when an event triggers or a template is rendered? Im trying to get a message popup and subscribe to all usernames when this happens.
Tried:
Template.newMessage.rendered = function(){
Meteor.subscribe("allUsernames");
}
And:
Template.layout.events({
"click #new-message": function(e, t){
$("#styledModal").modal();
Meteor.subscribe("allUsernames");
}
});
Neither work though, any way to do this or do I have to use a different route? Im using iron router

Im trying to understand why you would wanna do subscribe is such a late state of the process?
I would recommand that u subscribe in the waitOn property in IronRouter.
If you use the waitOn property to subscribe to all users, within that route, you can just display them in the popup =)
1 of the 7 Meteor principles is:
Latency Compensation. On the client, use prefetching and model simulation to make it look like you have a zero-latency connection to the database.
source:
http://docs.meteor.com/#sevenprinciples
Hope this helps,
Alex

You could try to do it using Deps and Session (although your code should work too, maybe you have a problem with publications?).
In your main template rendered function put this:
Template.layout.rendered = function() {
Session.set('getAllUsers',false);
Deps.autorun(function () {
if(Session.get('getAllUsers' == true)
Meteor.subscribe('allUsernames');
})
}
Then in the template that opens the user list:
Template.newMessage.rendered = function(){
Session.set('getAllUsers',true); //this should trigger Deps.autorun and subscribe.
}

Related

Reactively call a js function/event with meteor.js

I'm new to meteor.js. Still getting used to it.
I get how templates update reactively according to the cursor updates on the server, like this:
{{#if waitingforsomething.length}} Something Happened! {{/if}}
This is good to display elements on the page, updating lists and content. Now, my question is: what if I want to call some javascript or fire some event when something gets updated reactively? What would be the right way to do it with meteor.js?
Anything inside Tracker.autorun or template instance this.autorun runs with changes in reactive data sources inside these autoruns.
Reactive data sources are ReactiveVar instances, db queries, Session variables, etc.
Template.myTemplate.onCreated(function() {
// Let's define some reactive data source
this.reactive = new ReactiveVar(0);
// And put it inside this.autorun
this.autorun(() => console.log(this.reactive.get()));
});
Template.myTemplate.events({
// Now whenever you click we assign new value
// to our reactive var and this fires
// our console.log
'click'(event, template) {
let inc = template.reactive.get() + 1;
template.reactive.set(inc);
}
});
It is a little bit outdated, but Sacha Greif's Reactivity Basics is a very quick and concise introduction to meteor's reactivity model.
Basically, you have what's called reactive computations, code that observes special data objects (sessions, subscriptions, cursors, etc.) and gets executed whenever any of these reactive sources changes.
This is exposed via the Tracker API
Computation works pretty well for me:
Template.myTemplate.onRendered(function() {
this.computation = Deps.autorun(function () {
if (something) {
$(".reactive").html("Something Happened!");
}
});
});
Template.myTemplate.destroyed = function(){
if (this.computation){
this.computation.stop()
}
};
I Hope this helps.

Meteor: How to detect if users authenticated

In my app I use accounts-github. Works perfect, but I have one problem.
In one of my templates I do
Template.bar.rendered = function () {
if (Meteor.user()) {
// setup stuff
}
}
The problem is that if the user initially is not logged in this code is not executed (thats ok). But when the user authenticates this code is not executed again. So the question is how can I listen for this change inside a template (doesn't have to be in inside the rendered function!)?
You could use Deps.autorun. (http://docs.meteor.com/#deps_autorun)
Usually Deps.autorun would run for your whole Meteor app. If you want to make it so that it only runs per template you would need to create and stop it in the rendered and destroyed template callbacks
e.g
var loginRun;
Template.bar.rendered = function() {
loginRun = Deps.autorun(function() {
if(Meteor.user()) {
//Stuff to run when logged in
}
});
}
Template.bar.destroyed = function() {
loginRun.stop();
}
If you don't need it to run per template (need it to run just once for you app on any template, then you can use the Deps.autorun on its own, anywhere in your client side code.
Meteor.user() is reactive, it would ensure that the Deps.autorun callback runs again when it changes, so you could theoretically use it to do things when the user logs in or out.
Other alternatives is there is a package on atmosphere that provides login and logout hooks, though they basically would use the Deps.autorun like above to work anyway. See https://github.com/BenjaminRH/meteor-event-hooks
My solution for similar problem was to
Attach an event to template where the login happens
Re-render template if login is succesful so the Template.bar.rendered is called
E.g.
Template.bar.events({
'click .loginButton' : function() {
if( Meteor.call.Login( username, pw ) )
{
$('#bar').html( Meteor.render( Template.bar ));
//jQuery is optional
}
});

Angular simple routing without templates

I am looking for simple solution with Angular how to handle routes.
I have page generated by server with simple google map and little logic which is in 3 separated controllers.
Now i want to hook routing inside of this. Just simple routing. When I move with map and get new coordinas i want to push them into current url as param "?position=10.11,50.23". I want to use history push state with hashbang backup.
In other part of application i want to listen on change of this parameter (some $watch maybe?). And i want to use same code for detecting change to be used when page is loaded first.
I used CanJS in previous project, where this was absolutely simple, but in Angular i cant event make baby step to correct result :)
PS: this is just cut of minimal usecase.
Thanks
You do not really need angular routing to do that. Routing in angular is usually used to replace ng-view with different templates though it can be used for other things as well.
Your requirements can be met by using the $location service and setting up a $watch:
$scope.$watch(function () { return $location.search().position; }, function (newVal) {
$scope.params = newVal || 'No params';
});
$scope.setParams = function (val) {
$location.search('position', val);
};
Working demo
Launch the live-preview in a separate window to see the parameters change in the window address bar.
Update: The Demo doesn't work on plnkr.co anymore. Possibly because they have changed how they use the embedded mode.
Do not know CanJS, but in angular it is pretty easy as well.
First use: $location.search({parameter1:'someValue', parameter2: 'someOtherValue'}) to set you url -- the history will be updated automatically.
Then the most elegant way to detect any changes in url is to use (one of) two built-in events:
$locationChangeStart and $locationChangeSuccess, like that:
$scope.$on("$locationChangeStart", function (event, next, current) {
// your staff goes here
});
$scope.$on("$locationChangeSuccess", function (event, next, current) {
// or here (or both if needed)
});
To get the search parameters just use $location.search() in one of the above methods.

Updating view from service in angular?

Maybe I am designing this incorrectly ( new to angular ). Currently I have something like this:
[TVController] depends on [TVService]
[TVService] depends on [GameShowChannel] #could possibly have more channels
In code its something like so:
html
<div class='tv' ng-controller='TVController' ng-include='currentChannel()> </div>
TVController.js
var TVController = function($scope,TVService){
$scope.currentChannel = function(){ TVService.currentChannel(); }
}
TVService.js
angular.module('app.service').factory('TVService',function(GameShowChannel){
return { currentChannel: function(){ GameShowChannel.getView(); }
});
GameShowChannelService.js
angular.module('app.serivce').factory('GameShowChannel',function(){
return { getView: function(){ './partial/game_show_intro.html'} };
});
In GameShowChannelService.js I want to be able to update the scope in game_show_intro.html. I have a GameShowIntroController object in a file, but I am not able to import that into the GameShowChannelService.js. Is there a better solution to this problem? Again the problem is that I want to be able to update the view in the GameShowChannelService. I want the GameShowChannelService to be more than just a static html, but be dynamic so that I can actually 'play' something in that channel. Hope its clear enough.
Hmm..Maybe GameShowChannel should be a directive instead?
Another thought would be to broadcast event from service that some state has changed and the GameShowIntroController which controls the game_show_intr.html view, would listen and update to that state accordingly. Would this be a angular approach?

How should I update user.profile on subsequent login (something similar to Accounts.onCreateUser)?

I've been poking around in the Accounts packages, using a modified version of the ever-fabulous EventedMind Customizing Login screencast.
I modified it to use facebook instead of github, and I noticed something when trying to update user.profile information. Specifically, I'm looking for the right way/place to handle changes to user.profile.
Let's say, for example, that I authenticate as a FB user for the first time. When I do this, the CreateUser event will fire.
Using Accounts.onCreateUser(...), I can populate additional information from the FB graph into the profile, like so:
Accounts.onCreateUser(function(options,user){
var accessToken = user.services.facebook.accessToken,
result;
result = Meteor.http.get("https://graph.facebook.com/"+user.services.facebook.username, {
params: {
access_token:accessToken,
fields: ['picture', 'name','first_name','last_name','username','link','location','bio','relationship_status','email','timezone','locale']
}
});
if (result.error){
throw result.error;
}
user.profile = result.data; //lazily adding everything
return user;
});
This works just fine when the user is created. It's nice and clean.
But now let's say that some of the information changes. For example, let's say that the profile picture changes. If I log out and then back in to the meteor application, Accounts.onCreateUser(...) doesn't fire, because the user already exists. It's not being created again, it's being modified.
I need to update the user.profile on subsequent logins, or at least check for changes and then modify as needed. I'd ideally like to do this in similar fashion to .onCreateUser. Maybe with a .onModifyUser or something...
I can figure a couple of ways to do this using some checking and/or client-side code, but I'm wondering if there is an already-existing server hook that would be cleaner.
Any recommendations on the cleanest way to handle this situation?
Thanks in advance.
If you're manually calling the login functions you can pass a callback as the last parameter which will get called on the client after the login completes. See: http://docs.meteor.com/#meteor_loginwithpassword.
Meteor.loginWithFacebook({}, function (err) { /* make a Meteor method call here */ });
There are no documented server side callbacks at the moment.

Categories