ui-router onEnter hook fired multiple times

I’m migrating my app to ui-router 1.0.0 and I have this issue with nested states, when onEnter $transitions hook fires as many times, as many parents the state has (i.e. how deep it is nested), regardless of whether I filter states in my hook or not. Is this expected or a bug?

$stateProvider
  .state("root", {
    url: "/"
  })
  .state("root.child", {
    url: "/child"
  })
  .state("root.child.child", {
    url: "/child",
      data: {
      foo: "bar"
    }
  });


$transitions.onEnter(
  {to: state => state.data && state.data.foo === "bar"},
  transition =>
    console.log(`on enter triggered`, transition.from(),   transition.to())
);

$state.go("root.child.child");

In this example the hook is fired 3 times.

Here’s the fiddle.

Answer

I created an issue on github with same question, and christopherthielen, the top contributor of the ui-router gave me a comprehensive answer to this question, which I’m obliged to post here in case someone comes across the same problem.


This is expected based on how you coded your hook. The onEnter hook is a state based. The pseudocode for processing onEnter is as follows:

When initially going to root.child.child there are three states being entered: root, root.child, root.child.child.

Your criteria is { to: state => state.data && state.data.foo === "bar" } which matches for each of the three states being entered. This is because although three states are being entered, there is only one “to state”, which is root.child.child. That state’s data has the foo: 'bar' data, so it matches.

You should change your criteria to use entering instead of to.

{ entering: state => state.data && state.data.foo === 'bar' }

Here’s an updated fiddle: https://jsfiddle.net/2m63pvqb/1/

Some other approaches that might work:

Put onEnter on the state itself

  .state("root.child.child", {
    url: "/child",
      data: {
      foo: "bar"
    },
   onEnter: ($transition$, $state$) => do something specific when entering root.child.child 
  });

do something ONCE per transition if any states being entered have data.foo === ‘bar’

   $transitions.onStart({ entering: state => state.data && state.data.foo === 'bar' }, trans => 
      // do something 

Leave a Reply

Your email address will not be published. Required fields are marked *