Skip to content

Nodeps: Support deep nested structures for mapMultiRowFields #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ module.exports = {
env: {
test: {
presets: [
`@babel/preset-env`,
[
`@babel/preset-env`,
{
targets: {
node: `current`,
},
},
],
],
},
},
Expand Down
36 changes: 19 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vuex-map-fields",
"version": "1.3.6",
"version": "1.4.1",
"description": "Enable two-way data binding for form fields saved in a Vuex store",
"keywords": [
"vue",
Expand Down Expand Up @@ -29,23 +29,23 @@
},
"devDependencies": {
"@avalanche/eslint-config": "^4.0.0",
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@vue/test-utils": "1.0.0-beta.29",
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@vue/test-utils": "1.1.0",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^24.9.0",
"coveralls": "^3.0.7",
"eslint": "^6.5.1",
"eslint-plugin-compat": "^3.3.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-markdown": "^1.0.1",
"jest": "^24.9.0",
"rollup": "^1.25.2",
"rollup-plugin-babel": "^4.3.3",
"babel-jest": "^26.3.0",
"coveralls": "^3.1.0",
"eslint": "^7.10.0",
"eslint-plugin-compat": "^3.8.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-markdown": "^1.0.2",
"jest": "^26.4.2",
"rollup": "^2.28.2",
"rollup-plugin-babel": "^4.4.0",
"uglify-es": "^3.3.9",
"vue": "^2.6.10",
"vue-template-compiler": "^2.6.10",
"vuex": "^3.1.1"
"vue": "^2.6.12",
"vue-template-compiler": "^2.6.12",
"vuex": "^3.5.1"
},
"main": "dist/index.js",
"module": "dist/index.esm.js",
Expand All @@ -57,7 +57,9 @@
"url": "https://github.com/maoberlehner/vuex-map-fields/issues"
},
"browserslist": [
"last 2 versions"
"> 0.5%",
"not ie <= 10",
"not op_mini all"
],
"jest": {
"coveragePathIgnorePatterns": [
Expand Down
16 changes: 12 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import arrayToObject from './lib/array-to-object';


function normalizeNamespace(fn) {
return (...params) => {
// eslint-disable-next-line prefer-const
Expand Down Expand Up @@ -71,19 +72,26 @@ export const mapMultiRowFields = normalizeNamespace((
const store = this.$store;
const rows = store.getters[getterType](path);

return rows
.map((fieldsObject, index) => Object.keys(fieldsObject).reduce((prev, fieldKey) => {
const fieldPath = `${path}[${index}].${fieldKey}`;
const defineProperties = function (fieldsObject, index, nestedPath) {
return Object.keys(fieldsObject).reduce((prev, fieldKey) => {
const fieldPath = index !== false ? `${nestedPath}[${index}].${fieldKey}` : `${nestedPath}.${fieldKey}`;

return Object.defineProperty(prev, fieldKey, {
get() {
if (typeof fieldsObject[fieldKey] === `object` && fieldsObject[fieldKey] !== null) {
return defineProperties(fieldsObject[fieldKey], false, fieldPath);
}
return store.getters[getterType](fieldPath);
},
set(value) {
store.commit(mutationType, { path: fieldPath, value });
},
});
}, {}));
}, {});
};

return rows
.map((fieldsObject, index) => defineProperties(fieldsObject, index, path));
},
};

Expand Down
18 changes: 10 additions & 8 deletions src/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ describe(`index`, () => {
bar: `Bar`,
},
{
foo: `Foo`,
bar: `Bar`,
foo: {
bar: `Bar`,
},
},
];
const mockGetField = jest.fn().mockReturnValue(mockFieldRows);
Expand All @@ -166,8 +167,8 @@ describe(`index`, () => {
expect(mockGetField).lastCalledWith(`fieldRows[0].bar`);

// eslint-disable-next-line no-unused-vars
const y = getterSetters[1].foo; // Trigger getter function.
expect(mockGetField).lastCalledWith(`fieldRows[1].foo`);
const y = getterSetters[1].foo.bar; // Trigger nested getter function.
expect(mockGetField).lastCalledWith(`fieldRows[1].foo.bar`);
});

test(`It should commit new values to the store.`, () => {
Expand All @@ -177,8 +178,9 @@ describe(`index`, () => {
bar: `Bar`,
},
{
foo: `Foo`,
bar: `Bar`,
foo: {
bar: `Bar`,
},
},
];
const mockCommit = jest.fn();
Expand All @@ -194,8 +196,8 @@ describe(`index`, () => {
getterSetters[0].bar = `New Bar`; // Trigger setter function.
expect(mockCommit).toBeCalledWith(`updateField`, { path: `fieldRows[0].bar`, value: `New Bar` });

getterSetters[1].foo = `New Foo`; // Trigger setter function.
expect(mockCommit).toBeCalledWith(`updateField`, { path: `fieldRows[1].foo`, value: `New Foo` });
getterSetters[1].foo.bar = `New Bar`; // Trigger nested setter function.
expect(mockCommit).toBeCalledWith(`updateField`, { path: `fieldRows[1].foo.bar`, value: `New Bar` });
});
});

Expand Down
4 changes: 3 additions & 1 deletion test/module-namespaced-double.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ describe(`Component initialized with namespaced Vuex module.`, () => {
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.fooModule.foo = `foo`;

await wrapper.vm.$nextTick();

expect(wrapper.element.value).toBe(`foo`);
});

Expand Down
8 changes: 6 additions & 2 deletions test/module-namespaced-inline.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,20 @@ describe(`Component initialized with namespaced Vuex module.`, () => {
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.fooModule.foo = `foo`;

await wrapper.vm.$nextTick();

expect(wrapper.element.value).toBe(`foo`);
});

test(`It should update the store when the field values are updated.`, () => {
test(`It should update the store when the field values are updated.`, async () => {
wrapper.element.value = `foo`;
wrapper.trigger(`input`);

await wrapper.vm.$nextTick();

expect(store.state.fooModule.foo).toBe(`foo`);
});
});
3 changes: 2 additions & 1 deletion test/module-namespaced.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ describe(`Component initialized with namespaced Vuex module.`, () => {
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.fooModule.foo = `foo`;
await wrapper.vm.$nextTick();

expect(wrapper.element.value).toBe(`foo`);
});
Expand Down
6 changes: 4 additions & 2 deletions test/module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ describe(`Component initialized with Vuex module.`, () => {
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.fooModule.foo = `foo`;

await wrapper.vm.$nextTick();

expect(wrapper.element.value).toBe(`foo`);
});

test(`It should update the store when the field values are updated.`, () => {
test(`It should update the store when the field values are updated.`, async () => {
wrapper.element.value = `foo`;
wrapper.trigger(`input`);

Expand Down
24 changes: 23 additions & 1 deletion test/multi-row.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe(`Component initialized with multi row setup.`, () => {
<div v-for="user in users">
<input v-model="user.name">
<input v-model="user.email">
<input v-model="user.address.city">
</div>
</div>
`,
Expand All @@ -33,10 +34,23 @@ describe(`Component initialized with multi row setup.`, () => {
{
name: `Foo`,
email: `foo@foo.com`,
address: {
city: `Foo Bar`,
},
},
{
name: `Bar`,
email: `bar@bar.com`,
address: {
city: `Foo Bar`,
},
},
{
name: `Foo`,
email: `foo@foo.com`,
address: {
city: `Foo Bar`,
},
},
],
},
Expand All @@ -55,12 +69,16 @@ describe(`Component initialized with multi row setup.`, () => {
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.users[0].name = `New Name`;
store.state.users[1].email = `new@email.com`;
store.state.users[2].address.city = `New City Name`;

await wrapper.vm.$nextTick();

expect(wrapper.find(`input`).element.value).toBe(`New Name`);
expect(wrapper.find(`div:nth-child(2) input:nth-child(2)`).element.value).toBe(`new@email.com`);
expect(wrapper.find(`div:nth-child(3) input:nth-child(3)`).element.value).toBe(`New City Name`);
});

test(`It should update the store when the field values are updated.`, () => {
Expand All @@ -75,7 +93,11 @@ describe(`Component initialized with multi row setup.`, () => {
wrapper.find(`div:nth-child(2) input:nth-child(2)`).element.value = `new@email.com`;
wrapper.find(`div:nth-child(2) input:nth-child(2)`).trigger(`input`);

wrapper.find(`div:nth-child(2) input:nth-child(3)`).element.value = `New City Name`;
wrapper.find(`div:nth-child(2) input:nth-child(3)`).trigger(`input`);

expect(store.state.users[0].name).toBe(`New Name`);
expect(store.state.users[1].email).toBe(`new@email.com`);
expect(store.state.users[1].address.city).toBe(`New City Name`);
});
});
4 changes: 3 additions & 1 deletion test/nested-store.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ describe(`Component initialized with customized getter and mutation functions.`,
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.form.foo.foo = `foo`;

await wrapper.vm.$nextTick();

expect(wrapper.element.value).toBe(`foo`);
});

Expand Down
4 changes: 3 additions & 1 deletion test/packaged.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ localVue.use(Vuex);
expect(wrapper.exists()).toBe(true);
});

test(`It should update field values when the store is updated.`, () => {
test(`It should update field values when the store is updated.`, async () => {
store.state.foo = `foo`;
store.state.bar.bar = `bar`;
store.state.baz[0].foo.baz = `baz`;

await wrapper.vm.$nextTick();

expect(wrapper.find(`#foo`).element.value).toBe(`foo`);
expect(wrapper.find(`#bar`).element.value).toBe(`bar`);
expect(wrapper.find(`#baz`).element.value).toBe(`baz`);
Expand Down
Loading