rxMethod 必须注入构造函数上下文中

问题描述 投票:0回答:1

嗨@all,我有一个 Angular Ionic 应用程序,在这个应用程序中我的信号存储确实遇到了很多问题:

import {
  patchState,
  signalStore,
  signalStoreFeature,
  type,
  withComputed,
  withHooks,
  withMethods,
  withState,
} from '@ngrx/signals';
import { HttpShoppingListService } from '../service/http-shopping-list.service';
import { computed, inject } from '@angular/core';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { debounceTime, distinctUntilChanged, pipe, switchMap, tap } from 'rxjs';
import { tapResponse } from '@ngrx/operators';
import { ShoppingList } from '../domain/ShoppingList';
import { ShoppingListToCreate } from '../domain/ShoppingListToCreate';
import { Product } from '../domain/Product';
import { ShoppingListToUpdate } from '../domain/ShoppingListToUpdate';

export type Filter = {
  shoppingListId: string;
  order: 'asc' | 'desc';
};

export type ShoppingListState = {
  shoppingLists: ShoppingList[];
  isLoading: boolean;
  filter: Filter;
};

export const initialState: ShoppingListState = {
  shoppingLists: [],
  isLoading: false,
  filter: { shoppingListId: '', order: 'asc' },
};

export const ShoppingListStore = signalStore(
  { providedIn: 'root' },
  withState(initialState),
  // withComputed((store) => ({
  //   shoppingListCount: computed(() => store.shoppingLists().length),
  //   sortedShoppingLists: computed(() => store.shoppingLists().sort((a, b) => a.name.localeCompare( b.name ))),
  //   isLoading: computed(() => store.isLoading()),
  // })),

  withMethods(
    (store, httpShoppingListService = inject(HttpShoppingListService)) => ({
      loadShoppingListsByGroupId: rxMethod<string>(
        pipe(
          debounceTime(1000),
          distinctUntilChanged(),
          tap(() => patchState(store, { isLoading: true })),
          switchMap((groupId: string) =>
            httpShoppingListService.getAllShoppingLists(groupId).pipe(
              tapResponse({
                next: (shoppingLists: ShoppingList[]) =>
                  patchState(store, { shoppingLists }),
                error: (err) => {
                  console.error(err);
                },
                finalize: () => patchState(store, { isLoading: false }),
              })
            )
          )
        )
      ),

      addShoppingList: rxMethod<ShoppingListToCreate>(
        pipe(
          debounceTime(300),
          tap(() => patchState(store, { isLoading: true })),
          switchMap(shoppingListToCreate  =>
            httpShoppingListService.addShoppingList(shoppingListToCreate).pipe(
              tapResponse({
                next: (createdShoppingList: ShoppingList) => {
                  const test:ShoppingList[] = store.shoppingLists();
                  const updatedShoppingLists: ShoppingList[] = [
                      ...test,
                    createdShoppingList,
                  ]
                  patchState(store, { shoppingLists: updatedShoppingLists });
                },
                error: (err) => console.error(err),
                finalize: () => patchState(store, { isLoading: false }),
              })
            )
          )
        )
      ),

      addProductsToShoppingList: rxMethod<{
        shoppingListId: string;
        products: Product[];
      }>(
        pipe(
          distinctUntilChanged(),
          tap(() => patchState(store, { isLoading: true })),
          switchMap(({ shoppingListId, products }) =>
            httpShoppingListService
              .addProductsToShoppingList(shoppingListId, products)
              .pipe(
                tapResponse({
                  next: (updatedShoppingList: ShoppingList) => {
                    patchState(store, ({ shoppingLists }) => ({
                      shoppingLists: shoppingLists.map((list) =>
                        list.id === shoppingListId ? updatedShoppingList : list
                      ),
                    }));
                  },
                  error: (err) => console.error(err),
                  finalize: () => patchState(store, { isLoading: false }),
                })
              )
          )
        )
      ),

      updateShoppingList: rxMethod<{
        shoppingListToUpdate: ShoppingListToUpdate;
      }>(
        pipe(
          distinctUntilChanged(),
          tap(() => patchState(store, { isLoading: true })),
          switchMap(({ shoppingListToUpdate }) =>
            httpShoppingListService
              .updateShoppingList(shoppingListToUpdate)
              .pipe(
                tapResponse({
                  next: (updatedShoppingList: ShoppingList) => {
                    patchState(store, ({ shoppingLists }) => ({
                      shoppingLists: shoppingLists.map((list) =>
                        list.id === shoppingListToUpdate.id
                        ? updatedShoppingList
                        : list
                      ),
                    }));
                  },
                  error: (err) => {
                    console.error(err);
                  },
                  finalize: () => patchState(store, { isLoading: false }),
                })
              )
          )
        )
      ),
    })
  ),
);

它无法注入到我的组件中:

import { Component, inject, OnInit, signal, Signal } from '@angular/core';
import { IonicModule, NavController } from '@ionic/angular';
import { ShoppingListStore } from '../../store/shoppingListStore';

@Component({
  selector: 'app-group',
  templateUrl: './group.component.html',
  styleUrls: [ './group.component.scss' ],
  imports: [
    IonicModule
  ],
  standalone: true,
})
export class GroupComponent {

  readonly shoppingListStore = inject(ShoppingListStore);

  // activeIndex = 0;

  protected readonly groupId: Signal<string> = signal('1');

  // protected readonly shoppingLists: Signal<ShoppingList[]>;
  // protected readonly isLoading: Signal<boolean> = this.shoppingListStore.isLoading
  // protected readonly count: Signal<number> = this.shoppingListStore.shoppingListCount

  constructor() {
    this.shoppingListStore.loadShoppingListsByGroupId('1')
    // this.shoppingListStore.loadShoppingListsByGroupId('1');
    // this.shoppingLists = this.shoppingListStore.sortedShoppingLists;
    // @ts-ignore
    // this.a = at;
    // @ts-ignore

  }
}

在正常的角度应用程序中,这个商店可以工作,但我不知道为什么它会抛出错误。也许是因为模块导入?:

    import { Component, inject, OnInit, signal } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    import { IonButtons, IonContent, IonHeader, IonMenuButton, IonTitle, IonToolbar } from '@ionic/angular/standalone';
    import { NgComponentOutlet, NgIf } from '@angular/common';
    import { ComponentMapping } from '../domain/component-mapping';
    import { SideBarContentService } from '../service/side-bar-content.service';
    import { Folder } from '../domain/Folder';
    import { ShoppingListStore } from '../store/shoppingListStore';
    
    @Component({
      selector: 'app-folder',
      templateUrl: './folder.page.html',
      styleUrls: [ './folder.page.scss' ],
      standalone: true,
      providers: [ShoppingListStore],
      imports: [ IonHeader, IonToolbar, IonButtons, IonMenuButton, IonTitle, IonContent, NgComponentOutlet, NgIf ],
    })
    export class FolderPage implements OnInit {
    
      private activatedRoute = inject(ActivatedRoute);
      private sideBareContentService = inject(SideBarContentService);
    
      private allFolders = this.sideBareContentService.folders;
      currentFolderPage = signal<Folder | null>(null);
      component = signal<any | null>(null);
    
      private componentMapping: ComponentMapping = this.sideBareContentService.componentMapping;
    
      ngOnInit() {
        const folderId = this.activatedRoute.snapshot.paramMap.get('id');
        if (folderId) {
          const currentFolder = this.allFolders.find(folder => folder.id === folderId);
          if (currentFolder) {
            this.setFolder(currentFolder);
          }
        }
      }
      private setFolder(folder: Folder) {
        this.currentFolderPage.set(folder);
        this.loadComponent(folder);
      }
    
      private loadComponent(folder: Folder | null) {
        if( folder && this.componentMapping[ folder.id ] ) {
          this.componentMapping[ folder.id ]().then((component: any) => {
            this.component.set(component);
          });
        } else {
          this.component.set(null);
        }
      }
    }

import { AppPage } from '../domain/AppPage';
import { Observable, of } from 'rxjs';
import { ComponentMapping } from '../domain/component-mapping';
import { Folder } from '../domain/Folder';
import { DashboardComponent } from '../components/dashboard/dashboard.component';
import { GroupComponent } from '../components/group/group.component';

export class SideBarContentService {

  constructor() { }

  private _appPages: AppPage[] = [
    { sideBarName: 'Dashboard', url: '/folder/dashboard', icon: 'home-outline', isVisibleForUser: true },
    { sideBarName: 'Group Shopping Lists', url: '/folder/group', icon: 'cart-outline', isVisibleForUser: true },
    { sideBarName: 'PasswordManager', url: '/folder/password-manager', icon: 'key-outline', isVisibleForUser: true },
  ];

  private _componentMapping: ComponentMapping = {
    'dashboard': () => import('src/app/components/dashboard/dashboard.component').then(m => m.DashboardComponent),
    'group': () => import('src/app/components/group/group.component').then(m => m.GroupComponent),
  };

  private _folders: Folder[] = [
    {
      id: 'dashboard',
      title: 'Home',
      component: DashboardComponent,
    },
    {
      id: 'group',
      title: 'Shopping Lists for Group',
      component: GroupComponent,
    }
  ];

  get appPages(): Observable<AppPage[]> {
    return of(this._appPages);
  }

  get folders(): Folder[] {
    return this._folders;
  }

  get componentMapping() : ComponentMapping {
    return this._componentMapping;
  }
}

出现以下错误消息:

ERROR RuntimeError: NG0203: rxMethod() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203
    at assertInInjectionContext (core.mjs:3324:11)
    at rxMethod (ngrx-signals-rxjs-interop.mjs:5:5)
    at shoppingListStore.ts:50:35
    at ngrx-signals.mjs:211:21
    at ngrx-signals.mjs:87:62
    at Array.reduce (<anonymous>)
    at new _SignalStore (ngrx-signals.mjs:87:35)
    at Object.SignalStore_Factory [as factory] (ngrx-signals.mjs:116:14)
    at core.mjs:3136:35
    at runInInjectorProfilerContext (core.mjs:867:5)
handleError @ core.mjs:7195
next @ core.mjs:33183
ConsumerObserver2.next @ Subscriber.js:90
Subscriber2._next @ Subscriber.js:59
Subscriber2.next @ Subscriber.js:32
(anonym) @ Subject.js:41
errorContext @ errorContext.js:23
Subject2.next @ Subject.js:31
emit @ core.mjs:6590
(anonym) @ core.mjs:7082
invoke @ zone.js:339
run @ zone.js:110
runOutsideAngular @ core.mjs:6944
onHandleError @ core.mjs:7082
handleError @ zone.js:342
runGuarded @ zone.js:124
api.microtaskDrainDone @ zone.js:2235
drainMicroTaskQueue @ zone.js:541
invokeTask @ zone.js:444
invokeTask @ zone.js:1086
globalCallback @ zone.js:1116
globalZoneAwareCallback @ zone.js:1147
22 weitere Frames anzeigen
Weniger anzeigen

我认为 rxMethod 正在正确实施......有人有什么想法吗?

angular ionic-framework ngrx-signal-store
1个回答
0
投票

在您的组件中提供 ShoppingListStore

providers: [ShoppingListStore],
© www.soinside.com 2019 - 2024. All rights reserved.