powerbuoy
powerbuoy

Reputation: 12838

Detect change to router.isNavigating

I'm trying to add a class to the html element when Aurelia is navigating to a new route so that I can style the page differently when it's loading.

My current solution is to add the class to the main element because that's part of my View and so it "just works", like this:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class App {
    constructor (router) {
        this.router = router;
    }
}

And then in my view I simply do:

<main class="${router.isNavigating ? 'loading' : ''}">
    <router-view></router-view>
</main>

But, like I mentioned, I would prefer to add the loading class to the html element instead (so that I can style every single decendant on the page). Since the html element is not part of my view I can't accomplish this the same way, but instead I need to document.documentElement.classList.add('loading') whenever router.isNavigating is true.

So my question is; how can I accomplish this? I know aurelia supports propertyChanged methods but I'm not sure how it works when it's a nested property like router.isNavigating, routerIsNavigatingChanged() does not work. I've also tried @computedFrom(router) and variants of that but can't get it to work.

Upvotes: 2

Views: 1068

Answers (2)

Fabio
Fabio

Reputation: 11990

Another solution could be using the BindingEngine, but I think that EventAggregator is a better solution. I'm posting this here just for your curiosity.

import {BindingEngine} from 'aurelia-binding';

export class App {

  static inject = [BindingEngine];

  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
  }

  configureRouter(config, router) {
      //...
      this.router = router;        
  }

  attached() {
    this.navigationSubs = this.bindingEngine
      .propertyObserver(this.router, 'isNavigating')
      .subscribe(this.isNavigationChanged);
  }

  detached() {
    this.navigationSubs.dispose();
  }

  isNavigationChanged(newValue, oldValue) {
    if (newValue) {
      document.documentElement.classList.add('loading');
    } else {
      document.documentElement.classList.remove('loading');
    }
  }

}

In addition, I'm not sure if setting class of the html is good idea.

Upvotes: 4

powerbuoy
powerbuoy

Reputation: 12838

Ok so I ended up solving this using the EventAggregator instead;

this.ea.subscribe('router:navigation:processing', event => {
    document.documentElement.classList.add('loading');
});

this.ea.subscribe('router:navigation:success', event => {
    document.documentElement.classList.remove('loading');
});

I'm not sure it's the best solution but it seems to work. Would still like to know whether it's possible to do @computedFrom('router.isNavigating') because trying that throws errors.

Upvotes: 2

Related Questions