Permalink
Browse files

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
  • Loading branch information...
1 parent 2073a91 commit fc45fb3541c70d6499351fc158907c14f4632791 @pjlnmix pjlnmix committed with kentcdodds Sep 6, 2016
@@ -35,7 +35,7 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
// @ngInject
function FormlyFieldController($scope, $timeout, $parse, $controller, formlyValidationMessages) {
- /* eslint max-statements:[2, 34] */
+ /* eslint max-statements:[2, 37] */
if ($scope.options.fieldGroup) {
setupFieldGroup()
return
@@ -109,6 +109,24 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
return angular.isNumber(key) || !formlyUtil.containsSelector(key)
}
+ function keyContainsArrays(key) {
+ return /\[\d{1,}\]/.test(key)
+ }
+
+ function deepAssign(obj, prop, value) {
+ if (angular.isString(prop)) {
+ prop = prop.replace(/\[(\w+)\]/g, '.$1').split('.')
+ }
+
+ if (prop.length > 1) {
+ const e = prop.shift()
+ obj[e] = obj[e] || (isNaN(prop[0])) ? {} : []
+ deepAssign(obj[e], prop, value)
+ } else {
+ obj[prop[0]] = value
+ }
+ }
+
function parseSet(key, model, newVal) {
// If either of these are null/undefined then just return undefined
if ((!key && key !== 0) || !model) {
@@ -118,6 +136,8 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
if (shouldNotUseParseKey(key)) {
// TODO: Fix this so we can get several levels instead of just one with properties that are numeric
model[key] = newVal
+ } else if (formlyConfig.extras.parseKeyArrays && keyContainsArrays(key)) {
+ deepAssign($scope.model, key, newVal)
} else {
const setter = $parse($scope.options.key).assign
if (setter) {
@@ -566,6 +566,20 @@ describe('formly-field', function() {
expect(scope.model[key]).to.eq(defaultValue)
})
+ it('should handle arrays properly when formlyConfig.extras.parseKeyArrays is set', () => {
+ const key = 'foo[0]'
+ const defaultValue = 'bar'
+
+ formlyConfig.extras.parseKeyArrays = true
+ scope.fields = [
+ {template: input, key, defaultValue},
+ ]
+ scope.model = {}
+
+ compileAndDigest()
+ expect(scope.model.foo).to.be.instanceof(Array)
+ })
+
it('should get and set values when key is alpha numeric with alpha first', () => {
const key = 'A1'
const defaultValue = 'bar'
@@ -166,6 +166,7 @@ const formOptionsApi = apiCheck.shape({
resetModel: apiCheck.func.optional,
updateInitialValue: apiCheck.func.optional,
removeChromeAutoComplete: apiCheck.bool.optional,
+ parseKeyArrays: apiCheck.bool.optional,
templateManipulators: templateManipulators.optional,
manualModelWatcher: apiCheck.oneOfType([apiCheck.bool, apiCheck.func]).optional,
watchAllExpressions: apiCheck.bool.optional,
@@ -28,6 +28,7 @@ function formlyConfig(formlyUsabilityProvider, formlyErrorAndWarningsUrlPrefix,
fieldTransform: [],
ngModelAttrsManipulatorPreferUnbound: false,
removeChromeAutoComplete: false,
+ parseKeyArrays: false,
defaultHideDirective: 'ng-if',
getFieldId: null,
},

0 comments on commit fc45fb3

Please sign in to comment.