How To Use Meteor.js Routing with Disqus

Published on 29 July 2013

On 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:

  1. Wait until the first time a Disqus thread needs to be loaded.
    When div #disqus_thread has been rendered, load embed.js into the page.
  2. Set a global flag to ensure that embed.js is not loaded again.
  3. Each time a new Disqus thread is needed, trigger a DISQUS.reset(), including the first time embed.js is loaded. Again, make sure that div #disqus_thread is rendered in the DOM, or there may be an error about appending an element to null.

Comments