How to call vue method inside vuex module?

1.2k Views Asked by At

Assume that we need the single modal dialog with dynamic content. To access to this modal's API from any component, we can use below Vuex store. Below solution has been checked in real project and working fine:

import store from "@Store/store";
import { Action, Mutation, VuexModule, Module, getModule } from "vuex-module-decorators";

type UnifiedModalDialogOptions = {
  targetContentID: string;
  mainTitle?: string;
};


@Module({
  name: "VUEX_MODULE/COMPONENTS/UNIFIED_MODAL",
  store,
  dynamic: true,
  namespaced: true
})
export default class UnifiedModalDialogService extends VuexModule {

  private _displayFlag: boolean = false;
  private _activeContent: string | null = null;
  private _mainTitle: string | null = null;

  @Action
  public displayDialog({
    targetContentID,
    mainTitle
  }: UnifiedModalDialogOptions): void {

    this.setActiveContentID(targetContentID);
    this.setSizingMode(sizingMode);

    if (!isUndefined(mainTitle)) {
      this.setMainTitle(mainTitle);
    }

    if (!isUndefined(sizingCustomCSS_Class)) {
      this.setCustomSizingCSS_Class(sizingCustomCSS_Class);
    }

    this.setDisplayFlag(true);
  }

  @Mutation
  public dismiss(): void {
    this._displayFlag = false;
    this._activeContent = null;
    this._mainTitle = null;
  }

  public get displayFlag(): boolean { return this._displayFlag; }
  public get mainTitle(): string | null { return this._mainTitle; }
  public get activeContentID(): string | null { return this._activeContent; }


  @Mutation
  private setDisplayFlag(newFlagValue: boolean): void {
    this._displayFlag = newFlagValue;
  }

  @Mutation
  private setActiveContentID(targetContentID: string): void {
    this._activeContent = targetContentID;
  }

  @Mutation
  private setMainTitle(newMainTitle: string): void {
    this._mainTitle = newMainTitle;
  }
}

Now what if we need to call some additional function when closing modal? For instance, in below example, when we click "close" button of modal or click the dim underlay under modal, we need to utilize the account editing by finishAccountEditing method:

import { Vue, Component } from "vue-property-decorator";
import { getModule } from "vuex-module-decorators";
import UnifiedModalDialogService
    from "@Components:SharedSingletons/UnifiedModalDialog/UnifiedModalDialogService.vuex";

@Component
export default class AccountsManagementPage extends Vue {

  private onClickEditAccountButton(targetAccount: Account): void {

    private inputtedAccountName: string = "";
    private inputtedEmail: string = "";

    this.inputtedAccountName = targetAccount.name;
    this.inputtedEmail = targetAccount.email;

    getModule(UnifiedModalDialogService).displayDialog({
      targetContentID: this.ACCOUNT_ADDING_AND_EDITING_MODAL_DIALOG_ID,
      mainTitle: StaticStrings.modalDialogsTitles.accountEditing,
      sizingMode: UnifiedModalDialogService.SizingModes.fixedMaximalWidth,
    });
  }

  private finishAccountEditing() void {
    this.inputtedAccountName = "";
    this.inputtedEmail = "";
  }
}

Please note that the modal dialog component is not the child component, so we cant's access to it by reference.

Attempts and experiments

The logically right solution is to pass the function to vuex module and remember it:

@Component
export default class AccountsManagementPage extends Vue {

  private onClickEditAccountButton(targetAccount: Account): void {

    private inputtedAccountName: string = "";
    private inputtedEmail: string = "";

    this.inputtedAccountName = targetAccount.name;
    this.inputtedEmail = targetAccount.email;

    getModule(UnifiedModalDialogService).displayDialog({
      targetContentID: this.ACCOUNT_ADDING_AND_EDITING_MODAL_DIALOG_ID,
      mainTitle: StaticStrings.modalDialogsTitles.accountEditing,
      sizingMode: UnifiedModalDialogService.SizingModes.fixedMaximalWidth,
      // added ↓
      onClose: this.finishAccountEditing.bind(this)
    });
  }

  private finishAccountEditing() void {
    this.inputtedAccountName = "";
    this.inputtedEmail = "";
  }
}

Now I'll try to call it inside UnifiedModalDialogService module (just for experiment - inside displayDialog):

@Action
public displayDialog({
  targetContentID,
  sizingMode,
  sizingCustomCSS_Class,
  mainTitle,
  onClose
}: UnifiedModalDialogOptions): void {

  onClose();

  // ...
}

The result is unexpected:

index.js?0da5:363 Uncaught (in promise) Error: ERR_ACTION_ACCESS_UNDEFINED: 
Are you trying to access this.someMutation() or this.someGetter inside an @Action? 
That works only in dynamic modules. 
If not dynamic use this.context.commit("mutationName", payload) and this.context.getters["getterName"]
Error: Could not perform action displayDialog

At least two strange moments:

Are you trying to access this.someMutation() or this.someGetter inside an @Action?

No.

That works only in dynamic modules.

My module is dynamic:

@Module({
  name: "VUEX_MODULE/COMPONENTS/UNIFIED_MODAL",
  store,
  dynamic: true,
  namespaced: true
})
export default class UnifiedModalDialogService extends VuexModule {
  //...
}

The next experiment is delegating onClose calling to static method.

export default class UnifiedModalDialogService extends VuexModule {

  @Action
  public displayDialog({
    targetContentID,
    sizingMode,
    sizingCustomCSS_Class,
    mainTitle,
    onClose
  }: UnifiedModalDialogOptions): void {

    UnifiedModalDialogService._onClose(onClose);

    this.setActiveContentID(targetContentID);
    this.setSizingMode(sizingMode);

    if (!isUndefined(mainTitle)) {
      this.setMainTitle(mainTitle);
    }

    if (!isUndefined(sizingCustomCSS_Class)) {
      this.setCustomSizingCSS_Class(sizingCustomCSS_Class);
    }

    this.setDisplayFlag(true);
  }
  
  private static _onClose(implementation: () => unknown): void {
    implementation();
  }
}

The result is identical:

index.js?0da5:363 Uncaught (in promise) Error: ERR_ACTION_ACCESS_UNDEFINED

Herewith, generally the calling of static methods is possible:

@Module({
  name: "VUEX_MODULE/COMPONENTS/UNIFIED_MODAL",
  store,
  dynamic: true,
  namespaced: true
})
export default class UnifiedModalDialogService extends VuexModule {

  @Action
  public displayDialog({
    targetContentID,
    sizingMode,
    sizingCustomCSS_Class,
    mainTitle,
    onClose
  }: UnifiedModalDialogOptions): void {

    UnifiedModalDialogService.staticMethodExample();

    // ...
  }


  private static staticMethodExample(): void {
    console.log("Im am vuex module static method!");
  }
}

enter image description here

0

There are 0 best solutions below