Skip to content
This repository was archived by the owner on Apr 30, 2018. It is now read-only.

Commit fc45fb3

Browse files
Phil JollyKent C. Dodds
authored andcommitted
feat(formly-field): Adds parser for keys that contain arrays (#709)
angular. does not (and will not angular/angular.js#9850) properly handle arrays in keys unless they have already been created in the model. This fix/feature adds a separate parser for these circumstances and a formlyConfig.extras flag to control its use. The flag is in place to minimize impact on current functionality of the setter. This is in support of #706
1 parent 2073a91 commit fc45fb3

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed

src/directives/formly-field.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
3535

3636
// @ngInject
3737
function FormlyFieldController($scope, $timeout, $parse, $controller, formlyValidationMessages) {
38-
/* eslint max-statements:[2, 34] */
38+
/* eslint max-statements:[2, 37] */
3939
if ($scope.options.fieldGroup) {
4040
setupFieldGroup()
4141
return
@@ -109,6 +109,24 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
109109
return angular.isNumber(key) || !formlyUtil.containsSelector(key)
110110
}
111111

112+
function keyContainsArrays(key) {
113+
return /\[\d{1,}\]/.test(key)
114+
}
115+
116+
function deepAssign(obj, prop, value) {
117+
if (angular.isString(prop)) {
118+
prop = prop.replace(/\[(\w+)\]/g, '.$1').split('.')
119+
}
120+
121+
if (prop.length > 1) {
122+
const e = prop.shift()
123+
obj[e] = obj[e] || (isNaN(prop[0])) ? {} : []
124+
deepAssign(obj[e], prop, value)
125+
} else {
126+
obj[prop[0]] = value
127+
}
128+
}
129+
112130
function parseSet(key, model, newVal) {
113131
// If either of these are null/undefined then just return undefined
114132
if ((!key && key !== 0) || !model) {
@@ -118,6 +136,8 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
118136
if (shouldNotUseParseKey(key)) {
119137
// TODO: Fix this so we can get several levels instead of just one with properties that are numeric
120138
model[key] = newVal
139+
} else if (formlyConfig.extras.parseKeyArrays && keyContainsArrays(key)) {
140+
deepAssign($scope.model, key, newVal)
121141
} else {
122142
const setter = $parse($scope.options.key).assign
123143
if (setter) {

src/directives/formly-field.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,20 @@ describe('formly-field', function() {
566566
expect(scope.model[key]).to.eq(defaultValue)
567567
})
568568

569+
it('should handle arrays properly when formlyConfig.extras.parseKeyArrays is set', () => {
570+
const key = 'foo[0]'
571+
const defaultValue = 'bar'
572+
573+
formlyConfig.extras.parseKeyArrays = true
574+
scope.fields = [
575+
{template: input, key, defaultValue},
576+
]
577+
scope.model = {}
578+
579+
compileAndDigest()
580+
expect(scope.model.foo).to.be.instanceof(Array)
581+
})
582+
569583
it('should get and set values when key is alpha numeric with alpha first', () => {
570584
const key = 'A1'
571585
const defaultValue = 'bar'

src/providers/formlyApiCheck.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ const formOptionsApi = apiCheck.shape({
166166
resetModel: apiCheck.func.optional,
167167
updateInitialValue: apiCheck.func.optional,
168168
removeChromeAutoComplete: apiCheck.bool.optional,
169+
parseKeyArrays: apiCheck.bool.optional,
169170
templateManipulators: templateManipulators.optional,
170171
manualModelWatcher: apiCheck.oneOfType([apiCheck.bool, apiCheck.func]).optional,
171172
watchAllExpressions: apiCheck.bool.optional,

src/providers/formlyConfig.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ function formlyConfig(formlyUsabilityProvider, formlyErrorAndWarningsUrlPrefix,
2828
fieldTransform: [],
2929
ngModelAttrsManipulatorPreferUnbound: false,
3030
removeChromeAutoComplete: false,
31+
parseKeyArrays: false,
3132
defaultHideDirective: 'ng-if',
3233
getFieldId: null,
3334
},

0 commit comments

Comments
 (0)