Setting up the same route for both client and server using iron-router in meteor - meteor

I want to set up a route for POST requests, where the server does some logic and then the client loads a view for the same route. So, for example, my route /myRoute would have:
if (Meteor.isClient) {
Router.route('/myRoute');
}
if (Meteor.isServer) {
Router.route('/myRoute', {where: 'server'})
.post(function() {
console.log('This is the server side');
this.next();
});
}
However, the server-side is not called at all, and I only get the template rendered with no console logs on the server.
How can I make this work?

Related

Meteor - initiate client login automatically

i have a meteor app where i'm using nginx with an internal SSO service to authenticate. I'm able to do this successfully and retrieve user details in the nginx set http headers on the server Meteor.onConnection method.
At this point, i'm not sure what the best approach is to get access to the user details on the client side. I feel like i should use the built in Meteor Accounts but i'm not sure how to initiate the login process from the client since the user will not actually be logging in through the Meteor client but through a redirect that happens through nginx. I feel like i need a way to automatically initiate the login process on the meteor side to set up the meteor.users collection appropriately, but i can't figure out a way to do that.
Checkout the answers here. You can pass the userId (or in whatever you want to pass the user) through nginx to the server then onto the client to login. You can generate and insert the token in a Webapp.connectHandler.
import { Inject } from 'meteor/meteorhacks:inject-initial';
// server/main.js
Meteor.startup(() => {
WebApp.connectHandlers.use("/login",function(req, res, next) {
Fiber(function() {
var userId = req.headers["user-id"]
if (userId){
var stampedLoginToken = Accounts._generateStampedLoginToken();
//check if user exists
Accounts._insertLoginToken(userId, stampedLoginToken);
Inject.obj('auth', {
'loginToken':stampedLoginToken
},res);
return next()
}
}).run()
})
}
Now you can login on the client side with the help of the meteor-inject-initial package
import { Inject } from 'meteor/meteorhacks:inject-initial';
// iron router
Router.route('/login', {
action: function() {
if (!Meteor.userId()){
Meteor.loginWithToken(Inject.getObj('auth').loginToken.token,
function(err,res){
if (err){
console.log(err)
}
}
)
} else {
Router.go('/home')
}
},
});

Meteor server-side redirection when new user is created

I want to redirect when a new user account has been created.
Accounts.onCreateUser(function(options, user) {
// what to do?
})
I am using iron:router but Router.go() doesn't work because it's only for the client. Iron Router is said to support server-side redirection but in this case, I am not sure how to apply it.
You can use your own method in client code that calls a server method which will call Accounts.createUser. If the method succeeds you can then perform a redirect. e.g
//client method
Meteor.call('createUser', userObj, function(err,data) {
if (err) {
//account creation failed
} else {
//success, redirect
Router.go('routeName');
}
});
//server code
Meteor.methods({
createUser: function(user) {
//account creation
Accounts.createUser(user);
}
});

Server send command to all clients in Meteor

I have a public client side function:
test = function(){
alert("HELLO")!;
}
What I need is a function that works like this - so on the admin client script, they hit a button which calls a server method:
Meteor.call("callFunctions");
The server side function:
Meteor.methods({
callFunctions: function() {
//call clientside function test() for all clients
}
});
How can I do this without depending on a database?
My client-call package does that. It depends on database internally, but you don't have to worry about that dependence.
To call the methods on all clients you'll need to manually register and loop through their ids.
Set up method:
Meteor.ClientCall.methods({
'alert': function() {
...
},
});
Call it:
Meteor.ClientCall.apply(clientId, 'alert', []);

Backbone router and Meteor user authentication

I'm new to Meteor, and I would like to use a Backbone router in my project:
AppRouter = Backbone.Router.extend
({
"routes":
{
"": "home",
// ...
},
"home": function()
{
if (Meteor.user())
{
// ...
}
else
{
// ...
}
}
});
The problem I have is that, when a user is already logged in and goes to the "home" page, Meteor.user() returns null and Meteor.loggingIn() returns true...So I guess I need to wait for the end of the authentication, but how can I do that (Meteor.loginWithPassword seems to be called automatically when loading the page)?
assuming meteor calls some kind of callback when login finishes, delay calling Backbone.history.start() until then.

Invoke a client js function in Meteor after getting results from the server

I'm trying to see how can I invoke a js function after the client gets a result from a Meteor method call. The only thing I was able to get is to invoke the function myFunc only on the client that made the actual method call.
Any thoughts how i can invoke the function on all the currently subscribed clients?
here is the code:
function myFunc(error, result) {
alert(result);
}
if (Meteor.is_client) {
Template.container.events = {
'click input' : function () {
Meteor.call('someMethod',myFunc);
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
};
}
if (Meteor.is_server) {
Meteor.startup(function () {
// code to run on server at startup
});
}
Meteor.methods({
someMethod: function() {
//console.log(!this.is_simulation);
return "something";
}
})
Thanks
Currently you can't broadcast a method call to all clients directly. At least as far as I can tell. But a work around would be to create a collection called Alerts and monitor it for changes. Then when you want to send a message to all your users you can change the document in Alerts:
Client:
Alerts = new Meteor.Collection("alerts")
Meteor.autosubscribe(function() {
Alerts.find().observe({
added: function(item){
alert(item.message);
}
});
});
Server:
Alerts = new Meteor.Collection("alerts")
Meteor.publish("alerts", function(){
Alerts.find();
});
Alerts.remove({}); // remove all
Alerts.insert({message: "Some message to show on every client."});
Another option is using Meteor Stream package which purpose is to avoid using a mongodb collection on the server side. It does supports client to clients, server to clients, client to server AND server to servers messaging, including a support for Meteor Cluster
If you want to stay with meteor only using collections, the following code allows you to either broadcast a message from the client to all the clients or a message from the server to all the subscribed clients. Just use this mechanism to then fire a function on the client side once the right message is received. The code is made in such a way that you will never have useless items remaining into the collection.
Messages = new Meteor.Collection("messages");
if (Meteor.isClient) {
Meteor.subscribe("messages");
var query = Messages.find({});
var handle = query.observe({
added: function(document)
{
console.log(document.message);
}
});
// Test the mechanism from the client side
Meteor.call("client talked");
}
if (Meteor.isServer) {
Meteor.startup(function() {
Messages.remove({});
});
Meteor.publish("messages", function()
{
// you might add an optional filter in order to broadcast only the messages you want to the client
return Messages.find();
});
function talk(message)
{
var id = Messages.insert({"message":message});
Messages.remove(id);
}
Meteor.methods(
{
talk: function(message)
{
// you might filter here if the clients can talk using this.userId
talk(message);
}
});
// test the mechanism from the server side
talk("server talked");
}
I like what Zeke said, but for people who uses Meteor 0.5.0+, use Deps.autorun instead of autosubscribe... details at:
https://groups.google.com/forum/#!topic/meteor-core/mTa81RLvhbY
and
http://www.meteor.com/blog/2013/02/14/meteor-055-devshop-code-and-community-contributions
I simple approach to call a JavaScript client-side function would be to add a script tag in your html template that is bound by your collection. Anytime a new item is inserted, this tag would be inserted into the client would run your function. I have a collection call uploads with some properties such as name. The following template triggers drawpoints() client-side function upon receipt of a new item in Uploads collection:
{{#each uploads}}
<tr>
<td>{{name}}</td>
<td>
<div class="alert alert-success">Download Here</div>
</td>
</tr>
<script>drawpoints();</script>
{{/each}}

Resources