TurboLinks with Angular

448 views Asked by At

I'm running Angular 1.6 along with TurboLinks 5. For the most part, things are working well. I disabled TurboLinks cache and am manually bootstrapping Angular per some of the suggestions on this post: Using angularjs with turbolinks

I have run into one issue though where I have an $interval running within a service. When changing pages via TurboLinks, Angular bootstraps again and the service creates a new interval, but the old one continues to run! Every time a page change event occurs, a new interval is created and they keep piling on top of each other.

I tried destroying the angular app when a TurboLinks link is clicked (using the code below), but that seems to cause the whole Angular app to quit working. I also can't seem to get a reference to the older interval after a page reload.

var app = angular.module('app', []);

// Bootstrap Angular on TurboLinks Page Loads
document.addEventListener('turbolinks:load', function() {
    console.log('Bootstrap Angular');
    angular.bootstrap(document.body, ['app']);
});

// Destroy the app before leaving -- Breaks angular on subsequent pages
document.addEventListener('turbolinks:click', function() {
    console.log('Destroy Angular');
    var $rootScope = app.run(['$rootScope', function($rootScope) {
        $rootScope.$destroy();
    }]);
});

Without the $rootScope.$destroy() on the turbolinks:click event, everything else appears to be working as expected.

I know I could fire off an event here and kill the interval in the service, but ideally I'd like some way where this is automatically handled and ensured nothing is accidentally carried over between TurboLinks requests. Any ideas?

1

There are 1 answers

0
Ryan On

After a lot of trial and error, this does the job, but is not exactly what I'm looking for. Would like to hear if anyone else has any suggestions. It would be ideal if this could happen automatically without a service having to remember to cancel it's own intervals. Also accessing $rootScope in this manner just feels so dirty...

// Broadcast Event when TurboLinks is leaving
document.addEventListener('turbolinks:before-visit', function(event) {
    console.log('TurboLinks Leaving', event);
    var $body = angular.element(document.body);
    var $rootScope = $body.injector().get('$rootScope');
    $rootScope.$apply(function () {
        $rootScope.$broadcast('page.leaving');
    });
});

I'm then injecting $rootScope into my service as well as keeping a reference to the interval. Once it hears the page.leaving event, it cancels the interval:

var self = this;
self.interval = $interval(myFunction, intervalPoll);

....

$rootScope.$on('page.leaving', function() {
    $interval.cancel(self.interval);
});

So this gets the job done... but would love to find a better way. Credit for accessing $rootScope this way came from here: How to access/update $rootScope from outside Angular