webark/ember-component-css

Namespaces not applying during ember `loading` states

Closed this issue · 12 comments

Having a strange issue where the styles don't seem to apply to the route templates when they are in a loading state as described here:

https://guides.emberjs.com/v2.15.0/routing/loading-and-error-substates/

Not sure if I am doing something wrong but code looks roughly like:

<div class="{{styleNamespace}}__content">
...
</div>

Any components have their css namespace classes applied so it seems like whatever is hooking in to generate the namespace is not triggered until loading is complete.

this is probably getting the specific “loading” route styles, and wouldn’t be getting the related routes styles. If you wanted to grab those, you’d have to either inject the controller and grab it there, or import the “pod-styles” and pull it from there.

The primary issue here is that didTransition does not fire when the substates are entered. This definitely happens in the error substate, have not confirmed the loading substate.

I'll report back if I ever do find a solution to this.

the problem we're seeing is this: when we access route foo.bar and bar has a loading template then even the class for the foo route will only be applied once bar has loaded (aka. the transition has finished)

this seems like a major caveat to using this addon with per-route style files and should at least be mentioned in the README if we can't find a solution.


after writing the above lines I experimented a bit and I think I might have found a solution. instead of using the regular route style assignment code I'm using this:

Route.reopen({
  activate() {
    this._super(...arguments);

    let applicationController = getOwner(this).lookup('controller:application');

    let activeRoutes = applicationController.activeRoutes.slice();
    activeRoutes.push(this.routeName);

    applicationController.set('activeRoutes', activeRoutes);
  },

  deactivate() {
    this._super(...arguments);

    let applicationController = getOwner(this).lookup('controller:application');

    let activeRoutes = applicationController.activeRoutes.slice();
    let index = activeRoutes.indexOf(this.routeName);
    activeRoutes.splice(index, 1);

    applicationController.set('activeRoutes', activeRoutes);
  },
});

and the application controller looks like this:

import Controller from '@ember/controller';
import { computed } from '@ember/object';
import podNames from 'ember-component-css/pod-names';

export default Controller.extend({
  routeStyleNamespaceClassSet: computed('activeRoutes', function() {
    return this.activeRoutes
      .map(routeName => podNames[routeName.replace(/\./g, '/')])
      .filter(Boolean)
      .join(' ');
  }),

  init() {
    this._super(...arguments);
    this.set('activeRoutes', []);
  },
});

caveat: this workaround does not assign the styleNamespace to controllers yet. we don't use that feature so I didn't care much about it. it should be possible to implement that part too though.

Hmm. For the few times I'm used route styles, I generally only use the styleNamespace property. And expecting individuals to add that to their application controller seems a bit verbose, and we're trying to move away from reopening classes also when possible (though this isn't a hard and fast rule, just a preference). I'll try to poke around and see if there is a viable option for this.

@Turbo87 what do you feel about using the willChange and testing to see if it's a loading route? (I couldn't find a better was to see if it's going into a loading route, and was wondering if it's due to the later mentioned transition state issue)

  router.on('routeWillChange', function(transition) {
    if (/loading$/.test(transition.to.name) && transition.isActive) {
      addRouteStyleNamespace(appInstance, transition.to.name.split('.'));
    }
  });
  // this is from the "registry-way" rewrite, but the principle is still the same

(I also noticed in a "will transition to loading", the sequence is always -1 which is what it looks like the default is
https://github.com/tildeio/router.js/blob/604f7dfa246148a7737e1bb052b563c679b6d91a/lib/router/transition.ts#L87
and the routeInfos is an empty array and the state is the default object, so perhaps a side issue to this is that the state isn't getting properly set for loading routes?)

@webark are loading routes considered in routeWillChange?

there are several issues with routeStyleNamespaceClassSet:

  1. it always applies the route namespacing at the top level, so even styles from a subroute would get applied to the parent route, which makes the whole concept of routeStyleNamespaceClassSet pretty much pointless

  2. while the subroute is still in its loading state the parent route namespace is still not applied yet (this is solved by the workaround above)

  3. I haven't found a way to disable route namespacing without also having to disable the component namespacing. the main reason why we use the addon is to have the styles next to the controller, route and template files in Pods layout, not necessarily for scoping, except for components. did I miss that option or does it indeed not exist yet?

@Turbo87 apparently loading routes are considered in “willChange” (even though they look to be set up wrong).

“routeStyleNamespaceClassSet” is optional to use. It gets applied to an element of one’s choosing in the application template. There is no way to automatically create the same kind of namespacing without adding arbitrary wrapping elements into the code. (Any time i’ve used route styles, i have always just used the local styleNamespace and added that in where i needed).

However, if you do not want your styles to be namespaced, having them all namespaced at the same level leaves you in roughly the same place. using a keyword like @at-root and nesting all styles in that would remove the namespacing of the individual file.

Having the ability to manage namespacing independently between routes and components is a nice feature. It has not been requested before, and no one has ever opened a PR with that functionality.

using a keyword like @at-root and nesting all styles in that would remove the namespacing of the individual file.

is that built-in already? must have missed that 🤔

Having the ability to manage namespacing independently between routes and components is a nice feature. It has not been requested before, and no one has ever opened a PR with that functionality.

yeah, might be something worth looking into. I'll have to take a closer look at our styles though to figure out if it would work properly.

thanks for the quick responses :)

I assumed you where using scss and @at-root is a scss thing.

this should be fixed with #319

I just tried this out with the v0.7.3 release and it does not seem to do it's thing. When I look at the DOM inspector I don't see any loading styles/classes being applied. 🤔

@Turbo87 I just released a 0.7.4 and I am using it with error and loading states. do you have any more info into how you are setting up the loading state, and how you are getting there?