Skip to content

Commit 998e6fc

Browse files
authored
Merge pull request #25 from sascha245/feature/dynamic_modules
Feature/dynamic modules
2 parents bc91f3e + 5671e31 commit 998e6fc

File tree

17 files changed

+466
-245
lines changed

17 files changed

+466
-245
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,17 @@ You can use the `useStore(store)` function to get the bound module class instanc
144144

145145
import { useStore } from 'vuex-simple';
146146
import { MyStore } from '@/store/store';
147+
import { FooModule } from '@/store/modules/foo';
147148

148149
@Component
149150
export default class MyComponent extends Vue {
150151

151152
// get the module instance from the created store
152153
public store: MyStore = useStore(this.$store);
153154

155+
// get the module instance with the given namespace
156+
public foo1?: FooModule = useModule(this.$store, ['bar', 'foo1']);
157+
154158
public get readState() {
155159
// access state like a property
156160
return this.store.version;
@@ -177,6 +181,28 @@ export default class MyComponent extends Vue {
177181
}
178182
```
179183

184+
## Dynamic modules
185+
186+
To add a dynamic module to your store, you can use the `registerModule` function from this package:
187+
188+
```ts
189+
registerModule($store, ['dynamic_foo'], new FooModule(6));
190+
```
191+
192+
You can then use `useModule`, to get the bound class instance of the given namespace:
193+
194+
```ts
195+
const foo = useModule<FooModule>($store, ['dynamic_foo']);
196+
```
197+
198+
To remove the dynamic module from the store, you can use the `unregisterModule` function from this package:
199+
200+
```ts
201+
unregisterModule($store, ['dynamic_foo']);
202+
```
203+
204+
**Note**: You can also those functions on a standard Vuex store.
205+
180206
## Example with dependency injections
181207

182208
This section shows how to use dependency injection with this library.

samples/views/Home.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Component, Vue } from 'vue-property-decorator';
22
import { Inject } from 'vue-typedi';
33

4-
import { useStore } from '../../src';
4+
import { registerModule, unregisterModule, useModule, useStore } from '../../src';
5+
import { MyModule } from '../store/modules/my';
56
import { TestModule } from '../store/modules/test';
67
import { MyStore } from '../store/store';
78
import tokens from '../store/tokens';
@@ -13,10 +14,26 @@ export default class Home extends Vue {
1314
@Inject(tokens.TEST)
1415
public testModule!: TestModule;
1516

17+
public my1?: MyModule = useModule(this.$store, ['test', 'my1']);
18+
1619
// public get testModule() {
1720
// return this.store.test;
1821
// }
1922

23+
public mounted() {
24+
const test = useModule<TestModule>(this.$store, ['test']);
25+
26+
registerModule(this.$store, ['dynamic'], new TestModule());
27+
28+
const dynamicModule = useModule<TestModule>(this.$store, ['dynamic']);
29+
if (dynamicModule) {
30+
dynamicModule.increment();
31+
}
32+
}
33+
public destroyed() {
34+
unregisterModule(this.$store, ['dynamic']);
35+
}
36+
2037
public get counter() {
2138
return this.testModule.counter;
2239
}

samples/views/Home.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<button @click="increment">Increment</button>
1313
</div>
1414
<div>
15-
<p>My1 Counter: {{ testModule.my1.counter }}</p>
16-
<button @click="testModule.my1.increment">Increment</button>
15+
<p>My1 Counter: {{ my1.counter }}</p>
16+
<button @click="my1.increment">Increment</button>
1717
</div>
1818
<div>
1919
<p>My2 Counter: {{ testModule.my2.counter }}</p>
@@ -29,5 +29,4 @@
2929
</div>
3030
</template>
3131

32-
<style>
33-
</style>
32+
<style></style>

src/decorators.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/decorators/action.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Action as VuexAction } from 'vuex';
2+
3+
import { StoreBuilder } from '../types';
4+
import { createDecorator } from '../utils';
5+
6+
function getAction(pModule: any, propertyName: string): VuexAction<any, any> {
7+
const action: Function = pModule[propertyName];
8+
const boundAction = action.bind(pModule);
9+
return (state, payload) => boundAction(payload);
10+
}
11+
12+
function bindAction(pBuilder: StoreBuilder, pModule: any, propertyName: string) {
13+
const options = pBuilder.options;
14+
const provider = pBuilder.provider;
15+
options.actions![propertyName] = getAction(pModule, propertyName);
16+
const nsPath = pBuilder.namespaces.join('/');
17+
const actionName = (nsPath ? nsPath + '/' : '') + propertyName;
18+
19+
pModule[propertyName] = (payload: any) => {
20+
return provider.store!.dispatch(actionName, payload);
21+
};
22+
}
23+
24+
export const Action = createDecorator(bindAction);

src/decorators/getter.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Getter as VuexGetter } from 'vuex';
2+
3+
import { getterNotFoundError } from '../errors';
4+
import { StoreBuilder } from '../types';
5+
import { createDecorator } from '../utils';
6+
7+
function getGetter(pModule: any, propertyName: string): VuexGetter<any, any> {
8+
const getter = pModule.__lookupGetter__(propertyName);
9+
if (!getter) {
10+
const className = pModule.constructor.name;
11+
throw getterNotFoundError(propertyName, className);
12+
}
13+
const boundGetter = getter.bind(pModule);
14+
return state => boundGetter();
15+
}
16+
17+
function bindGetter(pBuilder: StoreBuilder, pModule: any, propertyName: string) {
18+
const options = pBuilder.options;
19+
const provider = pBuilder.provider;
20+
options.getters![propertyName] = getGetter(pModule, propertyName);
21+
const nsPath = pBuilder.namespaces.join('/');
22+
const getterName = (nsPath ? nsPath + '/' : '') + propertyName;
23+
24+
Object.defineProperty(pModule, propertyName, {
25+
get() {
26+
return provider.store!.getters[getterName];
27+
}
28+
});
29+
}
30+
31+
export const Getter = createDecorator(bindGetter);

src/decorators/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './state';
2+
export * from './getter';
3+
export * from './mutation';
4+
export * from './action';
5+
export * from './module';

src/decorators/module.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { transformRecursive } from '../transform';
2+
import { StoreBuilder } from '../types';
3+
import { createDecorator } from '../utils';
4+
5+
function bindModule(pBuilder: StoreBuilder, pModule: any, propertyName: string) {
6+
const subModule = pModule[propertyName];
7+
if (!subModule) {
8+
return;
9+
}
10+
try {
11+
const moduleOptions = transformRecursive(
12+
pBuilder.provider,
13+
subModule,
14+
pBuilder.namespaces.concat(propertyName),
15+
pBuilder.dynamic
16+
);
17+
const options = pBuilder.options;
18+
options.modules![propertyName] = moduleOptions;
19+
} catch (err) {
20+
console.error(err);
21+
}
22+
Object.defineProperty(pModule, propertyName, {
23+
get() {
24+
return subModule;
25+
}
26+
});
27+
}
28+
29+
export const Module = createDecorator(bindModule);

src/decorators/mutation.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Mutation as VuexMutation } from 'vuex';
2+
3+
import { StoreBuilder } from '../types';
4+
import { createDecorator } from '../utils';
5+
6+
function getMutation(pModule: any, propertyName: string): VuexMutation<any> {
7+
const mutation: Function = pModule[propertyName];
8+
const boundMutation = mutation.bind(pModule);
9+
return (state, payload) => boundMutation(payload);
10+
}
11+
12+
function bindMutation(pBuilder: StoreBuilder, pModule: any, propertyName: string) {
13+
const options = pBuilder.options;
14+
const provider = pBuilder.provider;
15+
options.mutations![propertyName] = getMutation(pModule, propertyName);
16+
const nsPath = pBuilder.namespaces.join('/');
17+
const mutationName = (nsPath ? nsPath + '/' : '') + propertyName;
18+
19+
pModule[propertyName] = (payload: any) => {
20+
provider.store!.commit(mutationName, payload);
21+
};
22+
}
23+
24+
export const Mutation = createDecorator(bindMutation);

src/decorators/state.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { StoreBuilder } from '../types';
2+
import { createDecorator } from '../utils';
3+
4+
function getState(pState: any, pNamespace: string[]) {
5+
let state = pState;
6+
for (const namespace of pNamespace) {
7+
state = state[namespace];
8+
}
9+
return state;
10+
}
11+
12+
function bindState(pBuilder: StoreBuilder, pModule: any, propertyName: string) {
13+
const value = pModule[propertyName];
14+
const provider = pBuilder.provider;
15+
const options = pBuilder.options;
16+
Object.defineProperty(pModule, propertyName, {
17+
get() {
18+
const state = provider.store
19+
? getState(provider.store.state, pBuilder.namespaces)
20+
: options.state;
21+
return state[propertyName];
22+
},
23+
set(val: any) {
24+
const state = provider.store
25+
? getState(provider.store.state, pBuilder.namespaces)
26+
: options.state;
27+
state[propertyName] = val;
28+
}
29+
});
30+
pModule[propertyName] = value;
31+
}
32+
33+
export const State = createDecorator(bindState);

0 commit comments

Comments
 (0)