Skip to content

Add global resolve for all routes #3060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jmanuelrosa opened this issue Oct 4, 2016 · 8 comments
Closed

Add global resolve for all routes #3060

jmanuelrosa opened this issue Oct 4, 2016 · 8 comments

Comments

@jmanuelrosa
Copy link

I try to add new resolve for all routes with 1.0.0-beta.3. I read in docs, that we need to use addResolvable in $transitions hook, but, how I can use Resolvable? because addResolvable need new Resolvable object.

Thanks!

@christopherthielen
Copy link
Contributor

Hi @jmanuelrosa can you explain why you want to add new Resolvable to each transition? It's pretty rare you need to do so. Usually you only need to add a normal Transition Hook.

I will add an overload to addResolvable in beta.4 allowing a ResolveLiteral.

If you're using javascript modules, the Resolvable class is exported, i.e., import { Resolvable } from "angular-ui-router";

@jmanuelrosa
Copy link
Author

Hi @christopherthielen, I need to get data from user, if he accesses from a route from my app, and I think that adding a new generic resolve would be the best solution. I try to use $transitions.onEnter or $transitions.onBefore, but request is asynchronous, and user can access to the route.

@christopherthielen
Copy link
Contributor

christopherthielen commented Oct 5, 2016

Regular transition hooks fully support asynchronous operations.

$transitions.onStart({}, function(transition) {
  // Return a promise; transition waits.
  return $http.get('/api').then(function(resp) {
    if (resp.data.role !== 'ADMIN') {
      // You can redirect ($state.target()) or cancel (return false)
      // or you can return another promise to do more async stuff
      return $state.target('home');
    }
  });
});

What are you doing with the data being fetched? If you don't need to display the data in a state's view then you probably don't want to use a resolve.

The dynamic resolve is also only available to the states being newly entered (the states being retained are not re-entered)

In ui-router legacy versions 0.x, you had no other choice for asynchronous handling than a resolve. But in 1.0 the transition hooks should almost always be the first choice for adding asynchronous handling to a state.

@jmanuelrosa
Copy link
Author

Wow! Thanks you very much! @christopherthielen ! and, i need to say you taht I love ui-router 😄

@TombolaShepless
Copy link

TombolaShepless commented Oct 6, 2016

@christopherthielen If data that is being fetched asynchronously and is not required as part of the component displayed for a given state, you say to put this in a transition. This makes complete sense and makes for a much neater implementation. However, a few questions:

  • What is "order of execution" between resolve and transitions? In my head it seems logical that it would be: resolve block --> transition
  • How do the transition hooks tie into the new resolve policies?
  • Is there a built-in way of handling a transition hook once? E.g. I want to check against all roots (**) but only on the very first load.
  • Is it possible to have a dynamic component in the state config? I tried using a function but had no joy.
  • Inside of a transition hook, if the you just specify a wildcard to ({ to: '**' }) how do you determine which state the transition is trying to go to? I have had a dig around the transition object passed into the callback function but can't see anything that specifies this. Am I missing something?

EDIT: I have found an answer to the last question:

transition.targetState().name();

Feels strange having to use these as methods - would be nice if they were getters. Any scope for this change?

Many thanks for all your hard work on this project!

@christopherthielen
Copy link
Contributor

@TombolaShepless

you say to put this in a transition

To be pedantic, put it in a transition hook. A transition itself is "the process of activating a state".

What is "order of execution" between resolve and transitions? In my head it seems logical that it would be: resolve block --> transition
How do the transition hooks tie into the new resolve policies?

  • $state.go()
  • new Transition()
  • .run()
  • .onBefore hooks invoked
  • .onStart hooks invoked
  • .onExit state hooks invoked
  • .onRetain state hooks invoked
  • .onEnter state hooks invoked
  • .onFinish hooks invoked
  • Transition is complete
  • .onSuccess hooks invoked

Is there a built-in way of handling a transition hook once? E.g. I want to check against all roots (**) but only on the very first load.

let deregister = $transitions.onStart({}, trans => {
  deregister();
  // do stuff with trans
});

Is it possible to have a dynamic component in the state config? I tried using a function but had no joy.

Not yet. Follow #2995

how do you determine which state the transition is trying to go to?

Use Transition.to()

$transitions.onStart({}, trans => {
  let toStateName = trans.to().name;
});

@TombolaShepless
Copy link

Thanks for the through answers and thanks again for your great efforts.

@landru29
Copy link

landru29 commented Sep 28, 2017

Still not resolved !

How to inject a resolve function from a decorator ?

.config(($stateProvider, $httpProvider) => {
        "use strict";

        /* Do not crash if translation was not found */
        $httpProvider.interceptors.push("translateInterceptor");

        $stateProvider.decorator("translations", (state) => {

            state.resolve = state.resolve || {};

            const translationsList = ["common"].concat(_.get(state, "self.translations", []));

            state.resolve.translations = ["$translate", "$translatePartialLoader", function ($translate, $translatePartialLoader) {
            // load translation parts
                _.forEach(_.uniq(translationsList), (part) => {
                    $translatePartialLoader.addPart(part);
                });

                return $translate.refresh();
            }];

            return translationsList;

        });
    })

then I have this:

angular.module("cmdbApp")
    .config(($stateProvider) => {
        "use strict";
        $stateProvider
            .state("app", {
                "abstract": true,
                translations: ["main"],
                views: {
                    MainView: {
                        templateUrl: "app/app.html",
                        controller: "AppCtrl",
                        controllerAs: "AppCtrl"
                    }
                },
                resolve: {
                    $title (translations, $translate) {
                        return $translate("atelier_network");
                    }
                }
            });
    });

But an error occurs due to "translations" that cannot be resolved :-(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants