I'm starting out my little quest into the world of the Meteor framework and I thought it'd be fun to do something a little bit facebooky with it.
step one was to follow the create an app tutorial in meteor then add the FB code to the template as found here: https://developers.facebook.com/docs/opengraph/tutorial/#authenticate
Sadly it doesn't seem to work on the page at all. In fact, I've just realized that if I add something like alert('foo');
to my meteor page it doesn't execute. Interesting.
So Metor, despite being completely amazing doesn't work like I expect it to... (shock, horror!).
How do I execute client side JS in this framework? (specifcially with the hope of creating a facebook JS object on the page?)
Thanks!
UPDATE (Jan 2013): Meteor released 0.5.0 which has built in authentication and facebook login support.
Documentation is here: http://docs.meteor.com/#accountsui
Essentially you run some commands in the shell
meteor add accounts-password
meteor add accounts-ui
meteor add accounts-facebook
then in your code you add the login button.
{{loginButtons}}
then you're in.
It's probably a very bad idea to do any sort of authentication to an external API, while passing around App IDs, secrets, etc, from the browser (client in the meteor stack).
I've implemented full facebook authentication on the server successfully.
Add the accounts-facebook
smart package by running meteor add accounts-facebook
from your application's working directory. This will allow you to be able to configure support for both the OAuth single user as well as the OAuth multi-user facebook authentication workflows. Please see Meteor Accounts System docs for more info.
After adding the accounts-facebook
smart package, you may do something along these lines...
Under your application's working directory, in server/server.js
(or similar file under the server
directory), implement something like this:
Meteor.startup(function () {
Accounts.loginServiceConfiguration.remove({
service: "facebook"
});
Accounts.loginServiceConfiguration.insert({
service: "facebook",
appId: process.env.FACEBOOK_APP_ID,
secret: process.env.FACEBOOK_APP_SECRET
});
});
Take note of these lines:
appId: process.env.FACEBOOK_APP_ID,
secret: process.env.FACEBOOK_APP_SECRET
You will need to set the environment variables FACEBOOK_APP_ID
and FACEBOOK_APP_SECRET
properly for the above code to use the correct values.
In client/client.js
(or similar file under the client
directory), implement something like this:
Meteor.startup(function() {
Meteor.loginWithFacebook({
requestPermissions: ['publish_actions']
}, function (err) {
if (err) {
Session.set('errorMessage', err.reason || 'Unknown error');
}
});
});
As per Meteor.loginWithExternalService([options], [callback]), the callback function for Meteor.loginWithFacebook
allows you to easily distinguish between error states, and non-error states:
Optional callback. Called with no arguments on success, or with a single Error argument on failure.
It appears that running client side code is done by placing it inside the "myapp.js" file
Template.hello.greeting = function () {
// ADD YOUR CODE HERE
alert('foo');
return "Welcome to matchmakeur.";
};
So in order to connect your code to Facebook authentication you've got to do something like
Template.fbconnect.connect = function () {
window.fbAsyncInit = function() {
FB.init({
appId : '[YOUR_APP_ID]', // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
return true;
};
and have a template
<template name="fbconnect">
<div id="fb-root"></div>
{{connect}}
<fb:login-button show-faces="true" width="200" max-rows="1" scope="publish_actions">
</fb:login-button>
<template>
It is not a bad idea to use Facebook JavaScript SDK if you want to build a full client-side app with Meteor...
Alex C answer works at first glance, but I had some problems with FB.logout()
after "navigating" and going back to the "page" where <div id="fb-root"></div>
was defined, because when fb-root
is re-rendered, FB.logout() stops working.
So I think the best way to load Facebook JavaScript SDK is to use a Template created callback:
Template.fbLogin.created = function () {
if (!Session.get("is Facebook JDK loaded?")) {
Session.set("is Facebook JDK loaded?", true);
// https://developers.facebook.com/docs/reference/javascript/
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : '[YOUR_APP_ID]', // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code such as adding Event Listeners goes here
};
// Load the SDK's source Asynchronously
// Note that the debug version is being actively developed and might
// contain some type checks that are overly strict.
// Please report such bugs using the bugs tool.
(function(d, debug){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all" + (debug ? "/debug" : "") + ".js";
ref.parentNode.insertBefore(js, ref);
}(document, /*debug*/ false));
}
};
Also, other thing that needs to be done for FB.logout()
to work correctly is using a constant template helper around <div id="fb-root"></div>
. So your code should be like this:
<body>
{{#constant}}
<div id="fb-root"></div>
{{/constant}}
<!-- rest of body... -->
I also found that it is necessary to put fb-root
immediately after body.
There is a live app running code like this at http://evee.meteor.com
And you can find its source-code here: https://github.com/fjsj/evee/
(check fbLogin.js for created
and app.html for constant
and fb-root
)
As of January 2013, Meteor does not support server-side routes to serve static HTML. So how to make a channel.html with Meteor? Putting it in /public won't work, since .html files are processed by Meteor as templates.
By using Meteor internals, it is possible! As suggested by this answer, we need to use a middleware-like approach (powered by Connect). Just put this on your /server (note it will be served at yourapp.meteor.com/fb/channel.html):
// serve channel.html file
var connect = __meteor_bootstrap__.require("connect");
__meteor_bootstrap__.app
.use(connect.query())
.use(function(req, res, next) {
// Need to create a Fiber since we're using synchronous http
// calls and nothing else is wrapping this in a fiber
// automatically
Fiber(function () {
if (req.url === "/fb/channel.html") {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<script src="//connect.facebook.net/en_US/all.js"></script>');
} else {
// not an channel.html request. pass to next middleware.
next();
return;
}
}).run();
});
Also this is working in production and the code is available at GitHub (includes cache headers).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With