Skip to content

Replacement for Resolve & Guard #18247

Closed
Closed

Description

@Toub

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

The way Guard and Resolve have to be used is very restrictive.
There are many case it make it very complicated to do simple things.

Expected behavior

Introduce a new concept to solve all theses common problems.

For example:

resolve: [
   {
      use: UserGuardResolver,
      name: user1, // store the return of the function here
      parameters: {
          id: 1,
          role: 'guest'
     }
]

This UserGuardResolver has to be able to:

  • store the user1 in data
  • cancel the route activation and redirect

What is the motivation / use case for changing the behavior?

Problem 1: pass parameters to Resolve (or Guard) when using it multiple times (the following code does not work, just to show there is no way to pass theses parameters)

resolve: {
   user1: UserResolver(1),
   user2: UserResolver(2)
},
canActivate:[DenyAccessForRoleGuard('guest'), DenyAccessForRoleGuard('non-granted-user')]

In some case, we can pass parameters with data, but not when using the guard multiple times.

Problem 2: sometimes, you want to do Guard stuff in Resolve, or Resolve stuff in Guard.
For example, I make a http call in a guard to check some stuff, then I want to make it available in the component, so I store it in data.

Sometimes, I get a 401 during Resolve http call, so I want to cancel the route activation and redirect.

Not sure about what is the best solution, but we should make it easier to integrate both concepts.

Problem 3: there are no way to order or chain easily the guards and resolve
@see for example #18092 and #15032

Environment


Angular version: 4.3.0

Activity

  1. jasonaden commented on Jul 26, 2017

    @jasonaden
    Contributor

    @Toub Thanks for the issue. Do you have any suggestions of what you would like to see? Maybe a sample API that would be better than we have currently?

  2. Toub commented on Aug 8, 2017

    @Toub
    Author

    Currently, we have:

    resolve: {
       var1: Resolver1,
       var2: Resolver2
    },
    canActivate:[Guard1, Guard2]

    To keep simple cases easy, and for retro-compatibility, we could simply add an advanced configuration.

    To fix problem1 & 2 (passing parameters, and mixing Guard & Resolver):

    before: [{
          // PreRouteHttpFetch can be a "resolver", or a "resolver + guard"
          action: PreRouteHttpFetch,
          result: 'shoppingcart', // optional
          parameters: {
                url: '/api/shoppingcart',
                id: 'mine',
                cache: false,
                // ...
          }
    },
    {
          // reuse the same PreRoute with different parameters
          action: PreRouteHttpFetch,
          result: 'customer',
          // parameters can also accept a function to dynamically set the parameters from route state
          parameters: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
                return {
                   url: '/api/customers',
                   id: route.params['customer'],
                   cache: true,
                   // ...
                };
          }
    }]

    To cancel route activation, the PreRoute receive an extra parameter:

    // class PreRouteHttpFetch
    preroute(route: ActivatedRouteSnapshot, state: RouterStateSnapshot, parameters, routeControl){
       // ...
       const res = this.httpService.get(parameters.url);
       if (res.status === 404){
          routeControl.cancel();
       }
    }

    Note: we can also store the parameters directly in the route snapshot object

    Then, to fix problem 3, if we consider that all PreRoute configurations in the array are launched simultaneously, we can add an extra parameter to allow to chain them:

    before: { // before can accept an array or a single object for easier use if we have only one PreRoute.
          action: PreRouteHttpFetch,
          result: 'customer',
          parameters: (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
                return {
                   url: '/api/customers',
                   id: route.params['customerId'],
                   cache: true,
                   // ...
                };
          },
          then:[
                {
                  // if router activation has not be canceled, this PreRoute will be called after PreRouteHttpFetch and will transform the customer object, or maybe do a few extra-checks based on the customer properties 
                   action: PreRouteTransformCustomer,
                   result: 'smartCustomer',
                }
          ]
    }
  3. Toub commented on Sep 1, 2017

    @Toub
    Author

    @jasonaden any update about this one?

    My suggestion would be currently broken by AOT compilation: #18886

  4. Toub commented on Sep 21, 2017

    @Toub
    Author

    There are a bunch of issues about router, guards and resolvers.

    @jasonaden any plan to improve it in angular5 or later releases?

  5. jasonaden commented on Dec 7, 2017

    @jasonaden
    Contributor

    @Toub You probably noticed, there wasn't much update for Angular 5. But there is a plan to make some changes in an upcoming release. Hopefully this can be done by v6.

  6. Toub commented on Dec 8, 2017

    @Toub
    Author

    @jasonaden thanks for the update, waiting for a link to the tracking issue or discussion when the work starts publicly

  7. added this to the Backlog milestone on Jan 23, 2018
  8. Toub commented on May 30, 2018

    @Toub
    Author

    @jasonaden any plan to add a new resolve & guard mechanism in v7?

  9. self-assigned this
    on Jun 5, 2018
  10. jasonaden commented on Jun 5, 2018

    @jasonaden
    Contributor

    @Toub Not sure if this will be something for v7. We have a lot going on in other areas (Ivy), and most of the feature updates to the router are dependent on this work being complete.

  11. ggjersund commented on Jan 20, 2019

    @ggjersund

    Am I understanding this correctly: You want the resolve() to be able to fail the same way as canActivate() by triggering cancelNavigation? If so, I'm really hoping for this as well.

    In the following case:
    www.example.com/item/1 resolves fine e.g. the item exist in the database and returns data.
    www.example.com/item/2 can't resolve e.g. the item does not exist in the database and returns 404.
    Currently the last URL would force me to redirect to another URL, and return an empty observable like this

    catchError(error => {
        this.router.navigate(['404']);
        return EMPTY;
    })
    

    What I'd like:
    To force throwError() for observables to trigger navigationCancel in the routing process, thus making it possible for failed resolves to trigger the wildcard (404 page) path while persisting the URL like this:

    catchError(error => {
        return throwError("Some error");
    })
    

    What is currently happening:
    The application crashes if an throwError() is returned inside the resolve() function.

  12. angular-robot commented on Jun 4, 2021

    @angular-robot
    Contributor

    Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

    Find more details about Angular's feature request process in our documentation.

  13. rob3c commented on Jun 6, 2021

    @rob3c

    The bot links to a feature request process that says there are 60 days for voting. Two days ago, the bot labeled this issue as "votes required" and said there are 20 days until the voting process ends. What happened to 60?

  14. angular-robot commented on Jun 24, 2021

    @angular-robot
    Contributor

    Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

    We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

    You can find more details about the feature request process in our documentation.

  15. atscott commented on Sep 15, 2021

    @atscott
    Contributor

    Closing as duplicate of #42171 and #40577

    Problem 1 is a duplicate of #42171

    Problem 2 can be solved by storing data from the guard in a place that can be retrieved by the resolver. This data can be cleared on NavigationStart events.

    Problem 3 is understandable and is a duplicate of #40577. The way guards execute should generally be changeable, though not necessarily provided as a feature of the Router. @sod provided an example of how to configure chainable guards with the existing APIs: #40577 (comment).

  16. angular-automatic-lock-bot commented on Oct 16, 2021

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on Oct 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions