Skip to content

Commit f966cef

Browse files
committed
adding to retrieve deeply nested values
1 parent cab88d5 commit f966cef

File tree

2 files changed

+78
-96
lines changed

2 files changed

+78
-96
lines changed

src/util.js

Lines changed: 26 additions & 36 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,11 +27,11 @@ 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);
@@ -40,48 +40,39 @@ export function set(target, key, val){
4040

4141
/**
4242
* returns an object value by string
43-
* https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
4443
* @param {Object} target
4544
* @param {String} key
4645
*/
47-
export function get(target, key){
48-
key = key.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
49-
key = key.replace(/^\./, ''); // strip a leading dot
50-
var a = key.split('.');
51-
for (var i = 0, n = a.length; i < n; ++i) {
52-
var k = a[i];
53-
if (k in target) {
54-
target = target[k];
55-
} else {
56-
return;
57-
}
58-
}
59-
return target;
46+
export function get(target, key) {
47+
const hasNested = hasNestedProperty(target, key, true);
48+
return hasNested === null ? target[key] : hasNested;
6049
}
6150

6251
/**
6352
* Checks to see whether an object has a deeply nested path
6453
* @param {Object} target
6554
* @param {String} propertyPath
66-
* @returns {Boolean}
55+
* @param {Boolean} returnVal
56+
* @returns {Boolean || Any} will return either true/false for existance or the actual value
6757
*/
68-
function hasNestedProperty(obj, propertyPath){
69-
if(!propertyPath)
70-
return false;
58+
function hasNestedProperty(obj, propertyPath, returnVal = false) {
59+
if (!propertyPath) return false;
7160

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

7465
for (var i = 0; i < properties.length; i++) {
7566
var prop = properties[i];
7667

77-
if(!obj || !obj.hasOwnProperty(prop)){
78-
return false;
68+
if (!obj || !obj.hasOwnProperty(prop)) {
69+
return returnVal ? null : false;
7970
} else {
8071
obj = obj[prop];
8172
}
8273
}
8374

84-
return true;
75+
return returnVal ? obj : true;
8576
}
8677

8778
/**
@@ -91,8 +82,8 @@ function hasNestedProperty(obj, propertyPath){
9182
* @param {String} err
9283
* @param {Bool} isError
9384
*/
94-
export function setError(form, key, err, isError, message = false){
95-
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] = {};
9687
form.$errors[key][err] = isError ? message || isError : false;
9788
}
9889

@@ -101,8 +92,8 @@ export function setError(form, key, err, isError, message = false){
10192
* @param {string} key
10293
* @param {string} message
10394
*/
104-
export function addValidationMessage(key, message){
105-
exports.validationMessages[ key ] = message;
95+
export function addValidationMessage(key, message) {
96+
exports.validationMessages[key] = message;
10697
}
10798

10899
/**
@@ -112,13 +103,12 @@ export function addValidationMessage(key, message){
112103
* @param {string} label
113104
* @param {string} value
114105
*/
115-
export function parseValidationString(key, message, label, value){
116-
106+
export function parseValidationString(key, message, label, value) {
117107
// if a key has been passed and there's no validation message and no message has been passed then return
118-
if ( key && !(key in exports.validationMessages ) && !message ) return false;
119-
108+
if (key && !(key in exports.validationMessages) && !message) return false;
109+
120110
// first check if a validation message with this key exists
121-
if ( key in exports.validationMessages ){
111+
if (key in exports.validationMessages) {
122112
message = exports.validationMessages[key];
123113
}
124114

test/unit/specs/index.spec.js

Lines changed: 52 additions & 60 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,7 +67,7 @@ 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

@@ -71,52 +76,45 @@ describe('module', () => {
7176
});
7277

7378
describe('get()', () => {
74-
7579
it('should be present on the Vue instance', () => {
7680
const test = new Vue();
7781
expect(test.$formlyGet).to.be.a('function');
7882
});
7983

80-
it('should return nested fields', () => {
84+
it('should get a nested field, and one with dot notation', () => {
8185
const test = new Vue({
82-
data: {
83-
deeply: {
84-
nested: {
85-
child: 'foo',
86-
},
87-
arr: [
88-
{
89-
foo: 'bar'
90-
},
91-
{
92-
bar: 'foo'
93-
}
94-
]
95-
}
96-
}
86+
data: {
87+
deeply: {
88+
nested: {
89+
child: 'foo'
90+
},
91+
'child.nested': 'bar'
92+
}
93+
}
9794
});
95+
96+
expect(test.deeply.nested.child).to.equal('foo');
97+
expect(test.deeply['child.nested']).to.equal('bar');
9898
expect(test.$formlyGet(test.deeply, 'nested.child')).to.equal('foo');
99-
expect(test.$formlyGet(test.deeply, 'arr[1].bar')).to.equal('foo');
99+
expect(test.$formlyGet(test.deeply, 'child.nested')).to.equal('bar');
100100
});
101-
102101
});
103102

104103
describe('set()', () => {
105-
106104
it('should be present on the Vue instance', () => {
107105
const test = new Vue();
108106
expect(test.$formlySet).to.be.a('function');
109107
});
110108

111109
it('should take a nested field', () => {
112110
const test = new Vue({
113-
data: {
114-
deeply: {
115-
nested: {
116-
child: 'foo'
117-
}
118-
}
119-
}
111+
data: {
112+
deeply: {
113+
nested: {
114+
child: 'foo'
115+
}
116+
}
117+
}
120118
});
121119

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

127125
it('should set dotted properties', () => {
128126
const test = new Vue({
129-
data: {
130-
deeply: {
131-
'nested.child': 'foo'
132-
}
133-
}
127+
data: {
128+
deeply: {
129+
'nested.child': 'foo'
130+
}
131+
}
134132
});
135-
133+
136134
test.$formlySet(test.deeply, 'nested.child', 'bar');
137135
expect(test.deeply['nested.child']).to.equal('bar');
138136
});
139-
140137
});
141138

142-
describe("Directives", () => {
143-
139+
describe('Directives', () => {
144140
it('formly-atts', () => {
145141
let atts = {
146-
placeholder: 'testing',
147-
foo: 'bar'
142+
placeholder: 'testing',
143+
foo: 'bar'
148144
};
149145

150146
let el = document.createElement('div');
151-
147+
152148
let vm = new Vue({
153-
data: {
154-
atts: atts
155-
},
156-
template: '<div v-formly-atts="atts"></div>'
149+
data: {
150+
atts: atts
151+
},
152+
template: '<div v-formly-atts="atts"></div>'
157153
}).$mount(el);
158154

159155
expect(vm.$el.getAttribute('placeholder')).to.equal(atts.placeholder);
160156
expect(vm.$el.getAttribute('foo')).to.equal(atts.foo);
161157
});
162158

163159
it('formly-input-type', () => {
164-
165160
let el = document.createElement('div');
166-
161+
167162
let vm = new Vue({
168-
data: {
169-
type: 'email'
170-
},
171-
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">'
172167
}).$mount(el);
173168

174169
expect(vm.$el.getAttribute('type')).to.equal('email');
175-
176170
});
177-
178171
});
179-
180172
});

0 commit comments

Comments
 (0)