diff --git a/other/ERRORS_AND_WARNINGS.md b/other/ERRORS_AND_WARNINGS.md index 32d03c2e..1f085e54 100644 --- a/other/ERRORS_AND_WARNINGS.md +++ b/other/ERRORS_AND_WARNINGS.md @@ -127,6 +127,12 @@ of the expression, the scope you're passed wont have all the properties you may See documentation [here](http://docs.angular-formly.com/docs/field-configuration-object#hideexpression-string--function) and an example [here](http://angular-formly.com/#/example/field-options/hide-fields) +# FieldTransform as a function deprecated + +To allow for plugin like functionality, `fieldTransform` functions on `formlyConfig.extras` and `formly-form.options` +are now deprecated. Moving forward fieldTransform will accept an array of `fieldTransform` functions. This makes it possible +to have multiple fieldTransforms. Note, `fieldTransform` functions will be removed in a major release. + # Notes It is recommended to disable warnings in production using `formlyConfigProvider.disableWarnings = true`. Note: This will diff --git a/src/directives/formly-form.js b/src/directives/formly-form.js index 5ccfe474..8660caf6 100644 --- a/src/directives/formly-form.js +++ b/src/directives/formly-form.js @@ -133,21 +133,47 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol function setupFields() { $scope.fields = $scope.fields || []; - const fieldTransform = $scope.options.fieldTransform || formlyConfig.extras.fieldTransform; - if (fieldTransform) { - $scope.fields = fieldTransform($scope.fields, $scope.model, $scope.options, $scope.form); - if (!$scope.fields) { - throw formlyUsability.getFormlyError('fieldTransform must return an array of fields'); - } + checkDeprecatedOptions($scope.options); + + let fieldTransforms = $scope.options.fieldTransform || formlyConfig.extras.fieldTransform; + + if (!angular.isArray(fieldTransforms)) { + fieldTransforms = [fieldTransforms]; } + angular.forEach(fieldTransforms, function transformFields(fieldTransform) { + if (fieldTransform) { + $scope.fields = fieldTransform($scope.fields, $scope.model, $scope.options, $scope.form); + if (!$scope.fields) { + throw formlyUsability.getFormlyError('fieldTransform must return an array of fields'); + } + } + }); + setupModels(); angular.forEach($scope.fields, attachKey); // attaches a key based on the index if a key isn't specified angular.forEach($scope.fields, setupWatchers); // setup watchers for all fields } + function checkDeprecatedOptions(options) { + if (formlyConfig.extras.fieldTransform && angular.isFunction(formlyConfig.extras.fieldTransform)) { + formlyWarn( + 'fieldtransform-as-a-function-deprecated', + 'fieldTransform as a function has been deprecated.', + `Attempted for formlyConfig.extras: ${formlyConfig.extras.fieldTransform.name}`, + formlyConfig.extras + ); + } else if (options.fieldTransform && angular.isFunction(options.fieldTransform)) { + formlyWarn( + 'fieldtransform-as-a-function-deprecated', + 'fieldTransform as a function has been deprecated.', + `Attempted for form`, + options + ); + } + } function setupOptions() { formlyApiCheck.throw( diff --git a/src/directives/formly-form.test.js b/src/directives/formly-form.test.js index 4455fbbf..ae66b46d 100644 --- a/src/directives/formly-form.test.js +++ b/src/directives/formly-form.test.js @@ -6,7 +6,7 @@ import testUtils from '../test.utils.js'; import angular from 'angular-fix'; import _ from 'lodash'; -const {getNewField, input, basicForm} = testUtils; +const {getNewField, input, basicForm, shouldWarnWithLog} = testUtils; describe('formly-form', () => { let $compile, formlyConfig, scope, el, $timeout; @@ -759,6 +759,33 @@ describe('formly-form', () => { formlyConfig.extras.fieldTransform = fieldTransform; }); + it(`should give a deprecation warning when formlyConfig.extras.fieldTransform is a function rather than an array`, inject(($log) => { + shouldWarnWithLog( + $log, + [ + 'Formly Warning:', + 'fieldTransform as a function has been deprecated.', + /Attempted for formlyConfig.extras/ + ], + compileAndDigest + ); + })); + + it(`should give a deprecation warning when options.fieldTransform function rather than an array`, inject(($log) => { + formlyConfig.extras.fieldTransform = undefined; + scope.fields = [getNewField()]; + scope.options.fieldTransform = fields => fields; + shouldWarnWithLog( + $log, + [ + 'Formly Warning:', + 'fieldTransform as a function has been deprecated.', + 'Attempted for form' + ], + compileAndDigest + ); + })); + it(`should throw an error if something is passed in and nothing is returned`, () => { scope.fields = [getNewField()]; scope.options.fieldTransform = function() { @@ -778,6 +805,20 @@ describe('formly-form', () => { doExpectations(spy); }); + it(`should allow you to use an array of transform functions`, () => { + scope.fields = [getNewField({ + customThing: 'foo', + otherCustomThing: { + whatever: '|-o-|' + }})]; + scope.options.fieldTransform = [fieldTransform]; + expect(() => compileAndDigest()).to.not.throw(); + + const field = scope.fields[0]; + expect(field).to.have.deep.property('data.customThing'); + expect(field).to.have.deep.property('data.otherCustomThing'); + }); + function doExpectations(spy) { const originalFields = [{ key: 'keyProp', diff --git a/src/providers/formlyApiCheck.js b/src/providers/formlyApiCheck.js index 7aa250d6..ecf5d98e 100644 --- a/src/providers/formlyApiCheck.js +++ b/src/providers/formlyApiCheck.js @@ -158,7 +158,6 @@ const fieldOptionsApiShape = { const formlyFieldOptions = apiCheck.shape(fieldOptionsApiShape).strict; - const formOptionsApi = apiCheck.shape({ formState: apiCheck.object.optional, resetModel: apiCheck.func.optional, @@ -166,7 +165,9 @@ const formOptionsApi = apiCheck.shape({ removeChromeAutoComplete: apiCheck.bool.optional, templateManipulators: templateManipulators.optional, wrapper: specifyWrapperType.optional, - fieldTransform: apiCheck.func.optional, + fieldTransform: apiCheck.oneOfType([ + apiCheck.func, apiCheck.array + ]).optional, data: apiCheck.object.optional }).strict;