What is the best approach to use Disqus in a single page application? I see that the angular js docs has implemented it successfully.
Currently our approach looks like is this in our AngularJS app, but it seems unstable, is hard to test, and loads wrong thread ids (the same thread gets loaded almost everywhere).
'use strict';
angular.module('studentportalenApp.components')
.directive('disqusComponent',['$log', '$rootScope', function($log, $rootScope) {
var _initDisqus = function _initDisqus(attrs)
{
if(window.DISQUS) {
DISQUS.reset({
reload: true,
config: function () {
this.page.identifier = attrs.threadId;
this.disqus_container_id = 'disqus_thread';
this.page.url = attrs.permalinkUrl;
}
});
}
else
{
$log.error('window.DISQUS did not exist before directive was loaded.');
}
}
//Destroy DISQUS bindings just before route change, to properly dispose of listeners and frame (postMessage nullpointer exception)
$rootScope.$on('$routeChangeStart', function() {
if(window.DISQUS) {
DISQUS.reset();
}
});
var _linkFn = function link(scope, element, attrs) {
_initDisqus(attrs);
}
return {
replace: true,
template: '<div id="disqus_thread"></div>',
link: _linkFn
};
}]);
I also wanted to include Disqus on my AngularJS-powered blog. I found the existing solutions a bit unwieldy so I wrote my own directive:
.directive('dirDisqus', function($window) {
return {
restrict: 'E',
scope: {
disqus_shortname: '@disqusShortname',
disqus_identifier: '@disqusIdentifier',
disqus_title: '@disqusTitle',
disqus_url: '@disqusUrl',
disqus_category_id: '@disqusCategoryId',
disqus_disable_mobile: '@disqusDisableMobile',
readyToBind: "@"
},
template: '<div id="disqus_thread"></div><a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>',
link: function(scope) {
scope.$watch("readyToBind", function(isReady) {
// If the directive has been called without the 'ready-to-bind' attribute, we
// set the default to "true" so that Disqus will be loaded straight away.
if ( !angular.isDefined( isReady ) ) {
isReady = "true";
}
if (scope.$eval(isReady)) {
// put the config variables into separate global vars so that the Disqus script can see them
$window.disqus_shortname = scope.disqus_shortname;
$window.disqus_identifier = scope.disqus_identifier;
$window.disqus_title = scope.disqus_title;
$window.disqus_url = scope.disqus_url;
$window.disqus_category_id = scope.disqus_category_id;
$window.disqus_disable_mobile = scope.disqus_disable_mobile;
// get the remote Disqus script and insert it into the DOM
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + scope.disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}
});
}
};
});
The main advantage of this approach, I think, is that it keeps things simple. Once you have registered the directive with your app, you don't need to write any JavaScript or set any config values in your JavaScript. All configuration is handled by passing attributes in the directive tag like so:
<dir-disqus disqus-shortname="YOUR_DISQUS_SHORTNAME"
disqus-identifier="{{ article.id }}"
disqus-title="{{ article.title }}"
...>
</dir-disqus>
Also, you don't need to alter your index.html file to include the Disqus .js file - the directive will dynamically load it when it is ready. This means that all that extra .js will only get loaded on those pages that actually use the Disqus directive.
The above will only work properly when your site is in HTML5Mode, i.e. not using the "#" in your URLs. I am updating the code on GitHub so the directive will work when not using HTML5Mode, but be warned that you must set a hashPrefix of "!" to make "hashbang" URLs - e.g. www.mysite.com/#!/page/123
. This is a limitation imposed by Disqus - see http://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites
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