【问题标题】:Using Resolve In Angular2 Routes在 Angular2 路由中使用 Resolve
【发布时间】:2016-02-01 10:42:01
【问题描述】:

在 Angular 1 中,我的配置如下所示:

$routeProvider
  .when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        message: function(messageService){
            return messageService.getMessage();
    }
  }
})

如何在Angular2中使用resolve?

【问题讨论】:

标签: angular angular2-routing


【解决方案1】:

正如 alexpods 已经提到的,似乎没有这样的“解决方案”。这个想法似乎是您利用路由器提供的生命周期钩子。它们是:

  • 可以重复使用
  • 可以停用
  • onActivate
  • 重复使用
  • onDeactivate

然后是 @CanActivate。这是一个特殊的钩子,因为它在您的组件被实例化之前被调用。它的参数是(next, previous),分别是您要路由到的组件和您来自的组件(如果您没有历史记录,则为 null)。

import {Component} from '@angular/core';
import {ROUTER_DIRECTIVES, CanActivate, OnActivate} from '@angular/router';

@Component({
    selector: 'news',
    templateUrl: 'newsView.html',
    directives: [ROUTER_DIRECTIVES]
})

@CanActivate((next) => {
    return messageService.getMessage()
        .then((message) => {
            next.params.message = message;
            return true; //truthy lets route continue, false stops routing
        });
})

export class Accounts implements OnActivate {

    accounts:Object;

    onActivate(next) {
        this.message = next.params.message;
    }
}

我还没有弄清楚如何将承诺的结果放入您的 onActivate 中 - 除了将其存储在您的“下一个”组件中。这是因为 onActivate 也只被 nextprevious 调用,而不是 promise 的结果。 我对那个解决方案不满意,但这是我能想到的最好的解决方案。

【讨论】:

  • 仅供参考,钩子是 routerOnActivate(至少在 ES6/7 中)
  • 你是如何注入你的messageService的?我正在尝试使用Injector.resolveAndCreate()。它显然无法将bootstrap() 中指定的应用程序范围的依赖项提供给它正在创建的服务。例如,结果是“No provider for Http”,或者我的服务需要的其他东西。
  • 我也有兴趣,请问如何将服务依赖注入@CanActivate
  • @shannon 我在 @CanActivate 等装饰器中找到了 DI 的解决方案。使用来自bootstrap 的承诺保存对 appInjector 的引用并使用它进行注入。看到这个 plunker:plnkr.co/edit/SF8gsYN1SvmUbkosHjqQ?p=preview
  • 如何在 RC 中做到这一点? RC出来以后有没有更好的办法?
【解决方案2】:

https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html “resolve”已被带回 angular2 路由器,但文档很少。

例子:

class TeamResolver implements Resolve {
  constructor(private backend: Backend) {}
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<any> {
    return this.backend.fetchTeam(this.route.params.id);
  }
}
bootstrap(AppComponent, [
  TeamResolver,
  provideRouter([{
    path: 'team/:id',
    component: TeamCmp,
    resolve: {
      team: TeamResolver
    }
  }])
);

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
  • 谢谢@RichardTelford!仍然在这里学习最佳实践。想知道为什么十多年来我一直在只读模式下使用 stackoverflow...:)
  • 好的,这显示了如何在组件实例化之前进行查询,但是您如何/在哪里访问组件中的解析值?
  • 我在ActivatedRoute 中找到了解析值,您必须将其注入到您的组件中。解析的值存储在属性中:route.snapshot.data。我也暂时放弃了决心。在我的情况下,我希望在路由器保护的canActivate 方法之前发生解析,但保护总是首先被调用:(
  • @KishoreRelangi import {Resolve} from "@angular/router";
【解决方案3】:

基于@angular/router v3-beta,这些是必需的步骤。

实现一个返回 Observable 或普通值的解析器:

@Injectable()
export class HeroResolver implements Resolve {

    constructor(
        private service: HeroService
    ) {}

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Hero> {
        const id = +route.params['id'];
        return Observable.fromPromise(this.service.getHero(id));
    }

}

请注意,如果您返回一个 observable,解包后的值(第一个)将通过 route.snapshot.data 获得。 如果您希望 observable 本身可用,则需要将其包装在另一个 Observable 中:

return Observable.of(source$);

将解析器添加到您的路由中:

export const HeroesRoutes: RouterConfig = [
    { path: 'heroes',  component: HeroListComponent, resolve: { heroes: HeroesResolver } },
    { path: 'hero/:id', component: HeroDetailComponent, resolve: { hero: HeroResolver } }
];

最后,提供你的解析类和任何依赖于引导程序或你的主要组件providers

bootstrap(AppComponent, [
    HeroesResolver, HeroService
])

使用来自 ActivatedRoute 实例的解析数据:

ngOnInit() {
    this.hero = this.route.snapshot.data['hero'];
}

请记住,快照意味着在组件类和解析器类中的执行状态下的值。 使用此方法无法从参数更新中刷新数据。

Plunker:http://plnkr.co/edit/jpntLjrNOgs6eSFp1j1P?p=preview 源素材:https://github.com/angular/angular/commit/f2f1ec0#diff-a19f4d51bb98289ab777640d9e8e5006R436

【讨论】:

  • 您能否将服务import { HeroService } as heroSvc from './hero.service' 导入路由并执行resolve: { heroes: heroSvc.getHeroes() }
  • @Baruch 你不能。解决的任何问题都用作 DI 的标记。这通常是一个类,但也可以是一个字符串,甚至是一个函数引用。但是因为您需要先提供它,所以它不会按您的意图工作。
  • 是否可以将hero作为参数直接注入构造函数?
  • "使用这种方法无法从参数更新中刷新数据。"哪种方法用于参数更新?
  • 我在下面回答了我自己的问题!
【解决方案4】:

@AndréWerlang 的回答很好,但是如果你希望页面上解析的数据在路由参数改变时改变,你需要:

解析器:

@Injectable()
export class MessageResolver implements Resolve<Message> {

  constructor(private messageService: MessageService, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Message> {
    const id = +route.params['id'];
    return this.messageService.getById(id);
  }
}

您的组件:

ngOnInit() {
  this.route.data.subscribe((data: { message: Message }) => {
    this.message = data.message;
  });
}

【讨论】:

    【解决方案5】:

    您可以在 Angular2+ 中创建您的解析器并将其应用到路由器上很容易。看下面,这是在Angular中创建解析器的方法:

    @Injectable()
    export class AboutResolver implements Resolve<Message> {
    
      constructor(private aboutService: AboutService, private router: Router) {}
    
      resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
        const id = route.params['id'];
        return this.aboutService.getById(id);
      }
    }
    

    然后在路由器配置中:

    export const Routes: RouterConfig = [
      { path: 'about',  component: AboutComponent, resolve: { data: AboutResolver } }
    ]; 
    

    最后在你的组件中:

    ngOnInit() {
      this.route.data.subscribe((data: { about: About }) => {
        this.about = data.about;
      });
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-10
      • 2016-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 2017-07-10
      • 1970-01-01
      相关资源
      最近更新 更多