How To Use Meteor.js Routing with Disqus
Published on 29 July 2013On most sites, using Disqus as the commenting system is as simple as copying the Universal Code (also known as embed.js
) into a web page. In single-page JavaScript applications, however, much of the rendering is on the client-side. This means that embed.js
might lead to stale Disqus threads or function incorrectly as pages are re-rendered.
This article explains how to integrate Disqus with Meteor.js (version 0.6.4.1 at the time of writing). If you want one Disqus thread for each route, copying the Universal Code won’t ensure that Disqus loads the correct thread for each page. Instead, the comments will either fail to load or retrieve a stale thread.
When embed.js
is loaded multiple times (when pages rerender and run the script multiple times), the following error will appear in the console:
DISQUS assertion failed: Unsafe attempt to redefine existing module <name>
Note: I’m using Meteor Router to create URL paths in my application, although this method should work with any routing system.
Disqus Single Sign-on
As a bonus, I’ve added the optional code snippet in Deps.autorun()
for using Disqus Single Sign-on with Meteor. If you want to see the server-side code in JavaScript, take a look at the examples that I added to the Disqus API Recipes.
Annotated Code
The code is written in CoffeeScript. If you want to take a look at the JavaScript version, you can use the CoffeeScript translator. Meteor automatically compiles .coffee
files to .js
.
With the code below, all you have to do is add the following to your Meteor Handlebars template to include Disqus comments:
{{> disqus}}
Easy, right?
Template.disqus.rendered = -> ### # We don’t want to load Disqus until the first time the template is # rendered, since it requires the #disqus_thread div # Triggers Deps.autorun (below) ### Session.set(“loadDisqus”, true)
### # OPTIONAL: Only include the part below if you’re using # Disqus single-sign on # Generate the disqusSignon variable appropriately from your server ### disqusSignon = Session.get(“disqusSignon”) if Meteor.user() and disqusSignon window.disqus_config = -> this.page.remote_auth_s3 = “#{disqusSignon.auth}” this.page.api_key = “#{disqusSignon.pubKey}” # … other Disqus configs
###
# Whenever the template is rendered, trigger a Disqus reset.
# This will find the correct thread for the current page URL.
# See http://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites
###
DISQUS?.reset(
reload: true
config: ->
)
Deps.autorun(->
# Load the Disqus embed.js the first time the disqus
template is rendered
# but never more than once
if Session.get(“loadDisqus”) && !window.DISQUS
# Below is the Disqus Universal Code
# (in Coffeescript, backticks escape Javascript code)
`
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = ‘YOUR_SHORTNAME’; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
` )
Disqus in Other Single-page JavaScript Frameworks
If you’re using another single-page JavaScript framework like Ember.js, Angular.js, etc., here’s a general strategy for using Disqus:
- Wait until the first time a Disqus thread needs to be loaded.
Whendiv #disqus_thread
has been rendered, loadembed.js
into the page. - Set a global flag to ensure that
embed.js
is not loaded again. - Each time a new Disqus thread is needed, trigger a
DISQUS.reset()
, including the first timeembed.js
is loaded. Again, make sure thatdiv #disqus_thread
is rendered in the DOM, or there may be an error about appending an element tonull
.