我正在使用Ngrx和Angular材料开发新的Angular 6应用程序。 我正在创建将由公司中的许多开发人员使用的基本应用程序。我的问题出在我要创建的对话框redux系统上。
我将首先分享我的实际代码,并说明问题和尝试的方法。
我的目标:在我的应用程序中的任何地方,我只想简单地调用一个操作即可打开自定义对话框(特定于每个功能)。该应用程序应打开多个全屏对话框。
这是我的简化架构:
AppModule
CoreModule
DialogsModule (StoreModule.forFeature('dialog', dialogReducer) / Effects.forFeature([DialogEffects]))
FeatureAModule (contains specific dialogs component)
FeatureBModule (contains specific dialogs component)
我想要的应用程序中的任何地方:
// Random Feature
openDialog(): void {
const payload: {
componentOrTemplateRef: MyDialogComponent, // The dialog, create by dev, in a specific feature
config: {
id: 'my-custom-id',
data: {
... // MAT_DIALOG_DATA
}
}
};
this.store.dispatch(new OpenDialogAction(payload));
}
我的实际对话框Redux:
dialog.action.ts
export enum DialogActionTypes {
OPEN = '[DIALOG] OPEN',
SAVE_REF = '[DIALOG] SAVE_REF' // use to store dialog reference in the ngrx store
CLOSE = '[DIALOG] CLOSE'
}
export type DialogAction = OpenDialogAction | SaveRefDialogAction | CloseDialogAction;
export interface OpenDialogPayload {
componentOrTemplateRef: ComponentType<any>;
config: MatDialogConfig;
}
export interface CloseDialogPayload {
dialogId: string;
responseData?: any;
}
export class OpenDialogAction implements Action {
readonly type = DialogActionTypes.OPEN;
constructor(public payload: OpenDialogPayload) {}
}
export class SaveRefDialogAction implements Action {
readonly type = DialogActionTypes.SAVE_REF;
constructor(public payload: MatDialogRef<any>) {}
}
export class CloseDialogAction implements Action {
readonly type = DialogActionTypes.CLOSE;
constructor(public payload: CloseDialogPayload) {}
}
dialog.reducer.ts
export interface DialogState {
refs: Array<{ id: string, ref: MatDialogRef<any> }>;
}
const initialState: DialogState = {
refs: []
};
export function dialogReducer(state: DialogState = initialState, action: DialogAction): DialogState {
switch (action.type) {
case DialogActionTypes.SAVE_REF:
return { ...state, refs: [...state.refs, { id: action.payload.id, ref: action.payload }] };
case DialogActionTypes.CLOSE:
return { ...state, refs: state.refs.filter(ref => ref.id !== action.payload.dialogId) };
default:
return state;
}
}
// DialogState Selector
export const getDialogState = createFeatureSelector('dialog');
// DialogState property selectors
export const getDialogRefById = (id: string) => createSelector(getDialogState, (state: DialogState) => state.refs.find(ref => ref.id === id).ref);
dialog.effects.ts
@Injectable()
export class DialogEffects {
@Effect()
openDialog$: Observable<SaveRefDialogAction> = this.actions$.pipe(
ofType(DialogActionTypes.OPEN),
map((action: OpenDialogAction) => action.payload),
switchMap((payload: OpenDialogPayload) => of(this.dialog.open(payload.componentOrTemplateRef, payload.config))),
map((dialogRef: MatDialogRef<any>) => new SaveRefDialogAction(dialogRef))
);
@Effect({ dispatch: false })
closeDialog$: Observable<{}> = this.actions$.pipe(
ofType(DialogActionTypes.CLOSE),
map((action: CloseDialogAction) => action.payload),
tap((payload: CloseDialogPayload) => this.dialog.getDialogById(payload.dialogId).close(payload.responseData)),
mapTo(of())
);
constructor(private actions$: Actions, private dialog: MatDialog) {}
我对功能的自定义对话框组件有疑问。它们未被DialogsModule识别(它们必须在entryComponents上)。因此,我创建了一个静态方法withComponents
,该方法返回ModuleWithProviders并使用注入令牌ANALYZE_FOR_ENTRY_COMPONENTS
@NgModule({
imports: [
MatDialogModule,
StoreModule.forFeature('dialog', dialogReducer),
EffectsModule.forFeature([DialogEffects])
]
})
export class DialogsModule {
static withComponents(components: any) ModuleWithProviders {
return {
ngModule: DialogsModule,
providers: [{ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true }]
};
}
}
问题
我所有带有自定义对话框的功能都需要导入DialogsModule ...但是,每次都会对DialogEffects进行实例化(如果我有3个必须导入DialogsModule的模块,那么DialogEffects将被实例化3次)。
如何在没有这个问题和entryComponents问题的情况下拥有正确的物料对话框管理器?我愿意接受任何建议。
先谢谢您!
答案 0 :(得分:0)
您可以为模块使用forRoot和forFeature。 Link here
对于根模块,将服务添加为单例(如效果)。对于功能模块,您可以添加其他模块。
您可以将单例服务与providedIn: 'root'
一起使用,但实际上我不知道它是否可以与NgRx效果一起使用。
P.S。另一方面,如果您使用HMR恢复状态,则模态将不会保持打开状态。