Skip to content

Commit f2bfe9b

Browse files
authored
Merge pull request #31 from formly-js/nested-fields
Retrieving nested fields
2 parents 1b0aa61 + f966cef commit f2bfe9b

File tree

3 files changed

+100
-65
lines changed

3 files changed

+100
-65
lines changed

src/index.js

Lines changed: 3 additions & 2 deletions
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, set} from './util';
3+
import Util,{getTypes, addType, addValidationMessage, set, get} from './util';
44
import Directives from './directives/index';
55

66

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

1818
Vue.$formly = {getTypes, addType, addValidationMessage};
19-
Vue.prototype.$formlySet = set
19+
Vue.prototype.$formlySet = set;
20+
Vue.prototype.$formlyGet = get;
2021
}
2122
};
2223

src/util.js

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ export default exports;
1111
* @param {String} id
1212
* @param {Object} options
1313
*/
14-
export function addType(id, options){
15-
exports.formlyFields['formly_'+id] = options;
14+
export function addType(id, options) {
15+
exports.formlyFields['formly_' + id] = options;
1616
}
1717

18-
export function getTypes(){
18+
export function getTypes() {
1919
return exports.formlyFields;
2020
}
2121

@@ -27,40 +27,52 @@ export function getTypes(){
2727
* @param {String} key
2828
* @param {Mixed} val
2929
*/
30-
export function set(target, key, val){
31-
if ( hasNestedProperty( target, key ) ){
30+
export function set(target, key, val) {
31+
if (hasNestedProperty(target, key)) {
3232
const parts = key.split('.');
3333
const finalKey = parts.pop();
34-
const newTarget = parts.reduce( (acc, cur) => acc[cur], target);
34+
const newTarget = parts.reduce((acc, cur) => acc[cur], target);
3535
this.$set(newTarget, finalKey, val);
3636
} else {
3737
this.$set(target, key, val);
3838
}
3939
}
4040

41+
/**
42+
* returns an object value by string
43+
* @param {Object} target
44+
* @param {String} key
45+
*/
46+
export function get(target, key) {
47+
const hasNested = hasNestedProperty(target, key, true);
48+
return hasNested === null ? target[key] : hasNested;
49+
}
50+
4151
/**
4252
* Checks to see whether an object has a deeply nested path
4353
* @param {Object} target
4454
* @param {String} propertyPath
45-
* @returns {Boolean}
55+
* @param {Boolean} returnVal
56+
* @returns {Boolean || Any} will return either true/false for existance or the actual value
4657
*/
47-
function hasNestedProperty(obj, propertyPath){
48-
if(!propertyPath)
49-
return false;
58+
function hasNestedProperty(obj, propertyPath, returnVal = false) {
59+
if (!propertyPath) return false;
5060

61+
// strip the leading dot
62+
propertyPath = propertyPath.replace(/^\./, '');
5163
const properties = propertyPath.split('.');
5264

5365
for (var i = 0; i < properties.length; i++) {
5466
var prop = properties[i];
5567

56-
if(!obj || !obj.hasOwnProperty(prop)){
57-
return false;
68+
if (!obj || !obj.hasOwnProperty(prop)) {
69+
return returnVal ? null : false;
5870
} else {
5971
obj = obj[prop];
6072
}
6173
}
6274

63-
return true;
75+
return returnVal ? obj : true;
6476
}
6577

6678
/**
@@ -70,8 +82,8 @@ function hasNestedProperty(obj, propertyPath){
7082
* @param {String} err
7183
* @param {Bool} isError
7284
*/
73-
export function setError(form, key, err, isError, message = false){
74-
if ( !form.$errors[key] ) form.$errors[key] = {};
85+
export function setError(form, key, err, isError, message = false) {
86+
if (!form.$errors[key]) form.$errors[key] = {};
7587
form.$errors[key][err] = isError ? message || isError : false;
7688
}
7789

@@ -80,8 +92,8 @@ export function setError(form, key, err, isError, message = false){
8092
* @param {string} key
8193
* @param {string} message
8294
*/
83-
export function addValidationMessage(key, message){
84-
exports.validationMessages[ key ] = message;
95+
export function addValidationMessage(key, message) {
96+
exports.validationMessages[key] = message;
8597
}
8698

8799
/**
@@ -91,13 +103,12 @@ export function addValidationMessage(key, message){
91103
* @param {string} label
92104
* @param {string} value
93105
*/
94-
export function parseValidationString(key, message, label, value){
95-
106+
export function parseValidationString(key, message, label, value) {
96107
// if a key has been passed and there's no validation message and no message has been passed then return
97-
if ( key && !(key in exports.validationMessages ) && !message ) return false;
98-
108+
if (key && !(key in exports.validationMessages) && !message) return false;
109+
99110
// first check if a validation message with this key exists
100-
if ( key in exports.validationMessages ){
111+
if (key in exports.validationMessages) {
101112
message = exports.validationMessages[key];
102113
}
103114

test/unit/specs/index.spec.js

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import {expect} from 'chai';
22
import Vue from 'vue';
33
import VueFormly from 'src/index';
4-
import Util, {addType, getTypes, setError, addValidationMessage, parseValidationString, set} from 'src/util';
5-
4+
import Util, {
5+
addType,
6+
getTypes,
7+
setError,
8+
addValidationMessage,
9+
parseValidationString,
10+
set,
11+
get
12+
} from 'src/util';
613

714
describe('module', () => {
8-
915
it('module props', () => {
1016
expect(VueFormly).to.exist;
1117
expect(VueFormly.install).to.be.a('function');
@@ -19,11 +25,10 @@ describe('module', () => {
1925
});
2026

2127
it('addType()', () => {
22-
2328
//mock vue
2429
window.Vue = {
25-
component(){},
26-
filter(){}
30+
component() {},
31+
filter() {}
2732
};
2833
VueFormly.install(Vue);
2934

@@ -34,7 +39,7 @@ describe('module', () => {
3439
expect(getTypes().formly_test).to.deep.equal(newField);
3540
});
3641

37-
it('setError()',()=>{
42+
it('setError()', () => {
3843
let form = {
3944
$errors: {}
4045
};
@@ -62,30 +67,54 @@ describe('module', () => {
6267
let expected = 'label just value testing';
6368
let output = parseValidationString('parseTest', false, 'label', 'value');
6469
expect(output).to.equal(expected);
65-
70+
6671
output = parseValidationString(false, message, 'label', 'value');
6772
expect(output).to.equal(expected);
6873

6974
output = parseValidationString('blahblahblah', false, '', '');
7075
expect(output).to.be.false;
7176
});
7277

73-
describe('set()', () => {
78+
describe('get()', () => {
79+
it('should be present on the Vue instance', () => {
80+
const test = new Vue();
81+
expect(test.$formlyGet).to.be.a('function');
82+
});
83+
84+
it('should get a nested field, and one with dot notation', () => {
85+
const test = new Vue({
86+
data: {
87+
deeply: {
88+
nested: {
89+
child: 'foo'
90+
},
91+
'child.nested': 'bar'
92+
}
93+
}
94+
});
7495

96+
expect(test.deeply.nested.child).to.equal('foo');
97+
expect(test.deeply['child.nested']).to.equal('bar');
98+
expect(test.$formlyGet(test.deeply, 'nested.child')).to.equal('foo');
99+
expect(test.$formlyGet(test.deeply, 'child.nested')).to.equal('bar');
100+
});
101+
});
102+
103+
describe('set()', () => {
75104
it('should be present on the Vue instance', () => {
76105
const test = new Vue();
77106
expect(test.$formlySet).to.be.a('function');
78107
});
79108

80109
it('should take a nested field', () => {
81110
const test = new Vue({
82-
data: {
83-
deeply: {
84-
nested: {
85-
child: 'foo'
86-
}
87-
}
88-
}
111+
data: {
112+
deeply: {
113+
nested: {
114+
child: 'foo'
115+
}
116+
}
117+
}
89118
});
90119

91120
expect(test.deeply.nested.child).to.equal('foo');
@@ -95,55 +124,49 @@ describe('module', () => {
95124

96125
it('should set dotted properties', () => {
97126
const test = new Vue({
98-
data: {
99-
deeply: {
100-
'nested.child': 'foo'
101-
}
102-
}
127+
data: {
128+
deeply: {
129+
'nested.child': 'foo'
130+
}
131+
}
103132
});
104-
133+
105134
test.$formlySet(test.deeply, 'nested.child', 'bar');
106135
expect(test.deeply['nested.child']).to.equal('bar');
107136
});
108-
109137
});
110138

111-
describe("Directives", () => {
112-
139+
describe('Directives', () => {
113140
it('formly-atts', () => {
114141
let atts = {
115-
placeholder: 'testing',
116-
foo: 'bar'
142+
placeholder: 'testing',
143+
foo: 'bar'
117144
};
118145

119146
let el = document.createElement('div');
120-
147+
121148
let vm = new Vue({
122-
data: {
123-
atts: atts
124-
},
125-
template: '<div v-formly-atts="atts"></div>'
149+
data: {
150+
atts: atts
151+
},
152+
template: '<div v-formly-atts="atts"></div>'
126153
}).$mount(el);
127154

128155
expect(vm.$el.getAttribute('placeholder')).to.equal(atts.placeholder);
129156
expect(vm.$el.getAttribute('foo')).to.equal(atts.foo);
130157
});
131158

132159
it('formly-input-type', () => {
133-
134160
let el = document.createElement('div');
135-
161+
136162
let vm = new Vue({
137-
data: {
138-
type: 'email'
139-
},
140-
template: '<input type="text" v-formly-input-type="type">'
163+
data: {
164+
type: 'email'
165+
},
166+
template: '<input type="text" v-formly-input-type="type">'
141167
}).$mount(el);
142168

143169
expect(vm.$el.getAttribute('type')).to.equal('email');
144-
145170
});
146-
147171
});
148-
149172
});

0 commit comments

Comments
 (0)