Skip to content

Commit 1bc7342

Browse files
authored
Merge pull request #30 from formly-js/nested-fields
adding method for setting nested field values
2 parents 618f314 + 2f84211 commit 1bc7342

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

src/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Components from './components/index';
22
import Filters from './filters/index';
3-
import Util,{getTypes, addType, addValidationMessage} from './util';
3+
import Util,{getTypes, addType, addValidationMessage, set} from './util';
44
import Directives from './directives/index';
55

66

@@ -16,6 +16,7 @@ let Formly = {
1616
Filters(Vue);
1717

1818
Vue.$formly = {getTypes, addType, addValidationMessage};
19+
Vue.prototype.$formlySet = set
1920
}
2021
};
2122

src/util.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,50 @@ export function getTypes(){
1919
return exports.formlyFields;
2020
}
2121

22+
/**
23+
* Allows deep nesting or not, depending on compatability
24+
* Should first check for the deeply nested field. If it doesn't exist then we treat the key as target[key]
25+
* If it does exist, then we set it
26+
* @param {Object} target
27+
* @param {String} key
28+
* @param {Mixed} val
29+
*/
30+
export function set(target, key, val){
31+
if ( hasNestedProperty( target, key ) ){
32+
const parts = key.split('.');
33+
const finalKey = parts.pop();
34+
const newTarget = parts.reduce( (acc, cur) => acc[cur], target);
35+
this.$set(newTarget, finalKey, val);
36+
} else {
37+
this.$set(target, key, val);
38+
}
39+
}
40+
41+
/**
42+
* Checks to see whether an object has a deeply nested path
43+
* @param {Object} target
44+
* @param {String} propertyPath
45+
* @returns {Boolean}
46+
*/
47+
function hasNestedProperty(obj, propertyPath){
48+
if(!propertyPath)
49+
return false;
50+
51+
const properties = propertyPath.split('.');
52+
53+
for (var i = 0; i < properties.length; i++) {
54+
var prop = properties[i];
55+
56+
if(!obj || !obj.hasOwnProperty(prop)){
57+
return false;
58+
} else {
59+
obj = obj[prop];
60+
}
61+
}
62+
63+
return true;
64+
}
65+
2266
/**
2367
* Allows a field to add/remove errors to the form
2468
* @param {Object} form

test/unit/specs/index.spec.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {expect} from 'chai';
22
import Vue from 'vue';
33
import VueFormly from 'src/index';
4-
import Util, {addType, getTypes, setError, addValidationMessage, parseValidationString} from 'src/util';
4+
import Util, {addType, getTypes, setError, addValidationMessage, parseValidationString, set} from 'src/util';
55

66

77
describe('module', () => {
@@ -70,6 +70,44 @@ describe('module', () => {
7070
expect(output).to.be.false;
7171
});
7272

73+
describe('set()', () => {
74+
75+
it('should be present on the Vue instance', () => {
76+
const test = new Vue();
77+
expect(test.$formlySet).to.be.a('function');
78+
});
79+
80+
it('should take a nested field', () => {
81+
const test = new Vue({
82+
data: {
83+
deeply: {
84+
nested: {
85+
child: 'foo'
86+
}
87+
}
88+
}
89+
});
90+
91+
expect(test.deeply.nested.child).to.equal('foo');
92+
test.$formlySet(test.deeply, 'nested.child', 'bar');
93+
expect(test.deeply.nested.child).to.equal('bar');
94+
});
95+
96+
it('should set dotted properties', () => {
97+
const test = new Vue({
98+
data: {
99+
deeply: {
100+
'nested.child': 'foo'
101+
}
102+
}
103+
});
104+
105+
test.$formlySet(test.deeply, 'nested.child', 'bar');
106+
expect(test.deeply['nested.child']).to.equal('bar');
107+
});
108+
109+
});
110+
73111
describe("Directives", () => {
74112

75113
it('formly-atts', () => {

0 commit comments

Comments
 (0)