嗨@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 正在正确实施......有人有什么想法吗?
在您的组件中提供 ShoppingListStore
providers: [ShoppingListStore],