我想将信号存储器"附加"到我的一个组件.我打算在组件级别而不是在根,因为状态是特定于该组件的.

然而,我喜欢使用路由解析器来防止导航到损坏的页面—在这种情况下,如果检索数据出现问题,我不会加载我的组件.

在根目录中不提供信号存储的情况下,是否有任何模式可以帮助我在解析器、组件和信号存储之间共享数据,以便我可以同时获得解析器和信号存储的好处?

推荐答案

您可以使用providers路.这样,服务将在路由级别被实例化.

看起来像这样:

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'a',
        component: AComponent,
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
      {
        path: 'b',
        component: BComponent,
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
    ]),
  ],
});

为了展示一个组件,它看起来像这样:

@Component({
  selector: 'app-a',
  standalone: true,
  template: `
    <h1>Component A</h1>
    <div>Store instance number: {{ store.instanceNumber }}</div><br />
    <div>Route data: <pre>{{ routeData | async | json }}</pre></div>
  `,
  imports: [CommonModule],
})
export class AComponent {
  public readonly store = inject(Store);
  public readonly routeData = inject(ActivatedRoute).data;
}

这只是为了证明您可以在解析器和组件中注入存储.

给你一百块.

请注意,这样做时,在路由级别提供的Store只在每条路由创建once个,而不是每个组件实例创建一个.根据您想要的,这可能是一个功能或一个问题:离开一条路由并返回它,您仍然拥有所有可用的数据.

无论你想要什么,在两种情况下都可以实现.下面是一个示例,每次我们返回到路由a时都会给出一个新的实例,并为路由b保留相同的Store实例:

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'a',
        component: AComponent,
        resolve: {
          store: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
            // small hack to create a new Store instance every time we open that route
            Injector.create({
              providers: [Store],
              parent: inject(Injector),
            }).get(Store),
        },
      },
      {
        path: 'b',
        component: BComponent,
        // here we'll get the same Store instance if we leave and come back
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
    ]),
  ],
});

对于组分B,您不需要更改任何内容,您可以像往常一样注入Store.

对于组件A,我们需要稍微调整代码,因为我们现在在路由数据中接收Store实例:

// this component receives a new Store instance every time it's been created
@Component({
  selector: 'app-a',
  standalone: true,
  template: `
    <h1>Component A</h1>
    <div>Store instance number: {{ store.instanceNumber }}</div><br />
  `,
  imports: [CommonModule],
})
export class AComponent {
  public readonly store:Store = inject(ActivatedRoute).snapshot.data['store']
}

给你another Stackblitz for this solution块如果你交替地转到a,然后几次转到b,你会在视图中看到a上的计数器增加,但在b中它保持不变.

Angular相关问答推荐

MAT表的内联文本编辑-未刷新编辑图标

使用Angular 13的NgxPrinterService打印时,第二页上的空白区域

ANGLE DI useFactory将参数传递给工厂函数

如何处理后端删除元素后元素列表的刷新

在switchMap操作符中使用条件语句以进行第一次或随后的执行

Angular 16:信号更新未能更新视图

Angular ngSubmit 不起作用(内部按钮和导入模块)

从具有特定 node 值的现有数组创建新数组

如何处理Angular 延迟订阅

如何从表单组中禁用的表单控件中获取值?

CORS 策略和 .NET Core 3.1 的问题

Angular2 Material Dialog css,对话框大小

取消订阅服务中的http observable

Angular 2:无法绑定到 x,因为它不是已知的本机属性

读取文件并解析其内容

unexpected token < 错误

Angular2延迟加载模块错误'找不到模块'

如何防止角material垫菜单关闭?

提交后在Angular 2中重置表单

Angular 4 material表突出显示一行