Angular子路由器出口中的组件的条件渲染

时间:2018-08-17 11:32:32

标签: angular angular-router angular-route-guards

我正在尝试找到一种方法,根据用户的角色来有条件地渲染子路线的router-outlet中的组件。

例如,我有一个DashboardComponent,它包含一个router-outlet。我希望子router-outlet中呈现的组件取决于令牌传递的用户角色而有所不同,而不必指定其他路由。

我希望尝试将我的路线写在靠近此的地方:

{ 
    path: 'dashboard', 
    component: DashboardComponent,
    children: [
        { path: '', component: DataViewsComponent }, // For standard user role
        { path: '', component: AdminViewsComponent } // For the admin user role
    ]
}

这种确切的模式当然行不通,因为路由器只能看到两条相同的路由路径。

我设法编写了一个使用canActivate属性的服务来检查用户的角色,并转发到依赖于该角色的其他路由:

@Injectable()
export class RoleRouteRedirectService implements CanActivate {

    roleRoutingPermissions: any = {
        // Will contain redirects for every route in the app
        // For this example, only contains reroutes for the dashboard route
        ['dashboard']: [
            { roles: [ 'user' ], redirect: '/dashboard/admin' },
            { roles: [ 'admin' ], redirect: '/dashboard/admin' }

        ]
    };

    constructor(private router: Router) {}

    canActivate(route: ActivatedRouteSnapshot): boolean {
        // In the larger app, the roles are taken out of the token
        // Here I've mocked them from localStorage for ease
        const userRoles: string[] = localStorage.getItem('user-role').split(',');
        const url: string = route.data.url;

        // Find the object property matching the desired origin URL
        if (url in this.roleRoutingPermissions) {
            // Iterate over the array of route permissions in this property
            for (const item of roleRoutingPermissions[url]) {
                // If we find the entry for the role, apply the redirect
                if (item.roles.some(role => userRoles.includes(role))) {
                    this.router.navigate([ item.redirect ]);

                    return false;
                }
            }
        }

        // Otherwise, fail
        console.log('Could not find matching route permissions');
        return false;

    }

}

这将使用不同的Routes模式:

{ 
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [ RoleRouteRedirectService ],
    data: {
        url: 'dashboard'
    },
    // Conditional Routes
    children: [
        {
            path: 'user',
            component: DataViewsComponent,
        },
        {
            path: 'admin',
            component: AdminHomeComponent,
        }
    ]
}

现在,这真的很好。但是,这种模式存在以下问题:

  1. 我想避免使用其他路线-即,我不希望dashboard/user,而只希望dashboard可以为不同的用户呈现不同的孩子
  2. 我看到这将迅速导致我的路线,并且RoleRouteRedirectService会随着应用程序的增长而变得令人费解。
  3. 这不是使用路由防护的正确方法(如果我错了,请纠正我!)
  4. 我觉得必须有一种方法可以从我缺少的路由器中处理此问题

如果有人有任何想法,我很想听听他们的想法。我赞赏这是一个相对复杂的问题-如果我错过了任何有用的信息,请发表评论,然后我会看到可以添加的内容。

2 个答案:

答案 0 :(得分:0)

一种替代方法是创建一个同时包含DataViewsComponentAdminHomeComponent的父组件。根据用户的角色,可以通过ngIf选择相关组件。然后,您可以将RoleRouteRedirectService中的逻辑移到该父组件中:

<DataViewsComponent *ngIf="user.hasRole('user')"></DataViewsComponent>
<AdminHomeComponent *ngIf="user.hasRole('admin')"></DataViewsComponent>

答案 1 :(得分:0)

角度路由器将first-match-wins策略用于定义的路由,与canActivate结合使用是IMO在您的用例中可行的策略。我认为这种方法没有任何问题。 这是我实现路由的方法:

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'logout', component: HomeComponent  },
  { path: '', component: AuthorizedComponent, canActivate: [AuthGuard], children: [
    { path: 'onboard', component: OnboardComponent, canActivate: [AuthGuard]  },
    { path: 'onboard_requests', component: OnboardRequestsComponent, canActivate: [AuthGuard]  },
    { path: 'employee_list', component: EmployeeListComponent, canActivate: [AuthGuard]  },
    { path: 'employee_detail', component: EmployeeDetailComponent, canActivate: [AuthGuard]  }
  ]
}]

虽然您的用例似乎与我的用例略有不同,但是您可以看到我使用了基于HomeComponent的两个组件AuthorizedComponentcanActivate作为根路径