Vuex-module-decorators: Reusable getters

Created on 19 Nov 2019  路  11Comments  路  Source: championswimmer/vuex-module-decorators

Is it possible to create dynamic modules extended from some parent module?
I tried it that way:

My parent-module.ts:

import {Action, getModule, Module, Mutation, VuexModule} from 'vuex-module-decorators';

export class ParentStore extends VuexModule {
    public get getterForInherit(): any {
        return someData
    }
}

Child modules:
child-one.ts:

import {Action, getModule, Module, Mutation, VuexModule} from 'vuex-module-decorators'
import {ParentModule} from './parent-module';

@Module({dynamic: true, store: Store, name: 'childOne', namespaced: true})
class FirstChildModule extends ParentModule {
    public get SecondChildGetter(): number {
        return 1;
    }
}

export const FirstChildStore: ParentModule = getModule(FirstChildModule)

child-two.ts:

import {Action, getModule, Module, Mutation, VuexModule} from 'vuex-module-decorators'
import {ParentModule} from './parent-module';

@Module({dynamic: true, store: Store, name: 'childTwo', namespaced: true})
class SecondChildModule extends ParentModule {
    public get FirstChildGetter(): number {
        return 2;
    }
}

export const SecondChildStore: ParentModule = getModule(SecondChildModule)

But when I import those modules to components getterForInherit is not available. Is it possible to do it this way?

Most helpful comment

@dan-an @rendrom This workaround may interest you.

import { getModule, VuexModule, Module } from "vuex-module-decorators";

class CollectionBase<T> extends VuexModule {
    items: T[] = [];
    get last() {
        return this.items[this.items.length - 1];
    }
}

@Module({ name: "numbers", namespaced: true })
class NumberCollection extends CollectionBase<number> {
    items = [0, 5, 2];
}

// Get wrapped parent module to access getters
const base: any = Module({})(CollectionBase);
// Copy parent getters to child
Object.assign(NumberCollection.getters, base.getters);
// Manually register module
store.registerModule("numbers", NumberCollection);

const numbers = getModule(NumberCollection, store);
console.log(numbers.last); // 2

All 11 comments

I created classes for inheritance in the project https://github.com/nextgis/nextgisweb_frontend/blob/master/packages/vuex-ngw/src/store/ResourceStore/ResourceStore.ts#L11

and then

@Module({ dynamic: true, store, name: 'annex' })
export class AnnexStore extends ResourceStore<AnnexProperties, MultiPolygon> {
  keynames: { [key in KeyName]: string } = {};
}

But to work, need to use tricks:

  • should write this.context.dispatch('getResources'); instead this.getResources();
  • need to simulate an Action with empty commit to access the class method from other method
@Action({ commit: '' })
async prepareFeatureToNgw() {}

(This stop working in new version 0.11.x)

@dan-an @rendrom This workaround may interest you.

import { getModule, VuexModule, Module } from "vuex-module-decorators";

class CollectionBase<T> extends VuexModule {
    items: T[] = [];
    get last() {
        return this.items[this.items.length - 1];
    }
}

@Module({ name: "numbers", namespaced: true })
class NumberCollection extends CollectionBase<number> {
    items = [0, 5, 2];
}

// Get wrapped parent module to access getters
const base: any = Module({})(CollectionBase);
// Copy parent getters to child
Object.assign(NumberCollection.getters, base.getters);
// Manually register module
store.registerModule("numbers", NumberCollection);

const numbers = getModule(NumberCollection, store);
console.log(numbers.last); // 2

@Exeteres

I did something similar, but assigned the base getters before exporting my child class.
Did you attempt something like this? And if so, did you run into any problems?
It looks like maybe the constructor is just not instantiating the getters?

I'd be willing to help on a fleshed out solution.

@FullPint

Did you attempt something like this?

Actually no. The solution I presented earlier is the last thing I tried to do in my old vue project.

It looks like maybe the constructor is just not instantiating the getters?

According to this line, the constructor does not initialize anything. The @Module decorator collects getters. If we don't apply the decorator to the base class, it will not extract getters. But it doesn鈥檛 matter, because they will still be overridden by the child class decorator. So in my solution i use Object.assign to mix base and child getters after child decorator execution.

P. S.
Now I managed to create a fixed version of the decorator that copies getters.

import { ModuleOptions } from "vuex-module-decorators/dist/types/moduleoptions";

function FixedModule(options: ModuleOptions) {
    return (target: any) => {
        const mod = Module(options)(target) as typeof VuexModule;
        const base = Module({})(Object.getPrototypeOf(mod));
        Object.assign(mod.getters, base.getters);
        return mod as any;
    };
}


class CollectionBase<T> extends VuexModule {
    items: T[] = [];
    get last() {
        return this.items[this.items.length - 1];
    }
}

@FixedModule({ name: "numbers", namespaced: true })
class NumberCollection extends CollectionBase<number> {
    items = [0, 5, 2];
}

store.registerModule("numbers", NumberCollection);

const numbers = getModule(NumberCollection, store);
console.log(numbers.last); // 2

But I still think this is a terrible workaround, and at the moment I'm looking for an alternative to this module.

@Exeteres did you end up having an issue with modules colliding?

@FullPint I had no such issues. By the way, I have not worked with Vue since my last answer.

@Exeteres thanks for the quick reply -- I might just have an odd typo somewhere.

What is the status on this?

@seflue my team ended up using a different package because of the amount of generics we use.

@FullPint can you tell which package you are now using instead?

@fen89 we use this: https://github.com/gertqin/vuex-class-modules

But it looks like they may have merged a fix with this package. Haven鈥檛 tested it yet.

Was this page helpful?
0 / 5 - 0 ratings