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

Commit

Permalink
v7.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
formly-bot committed Sep 7, 2015
2 parents b245620 + 9e4ba87 commit 1603f62
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 561 deletions.
222 changes: 69 additions & 153 deletions dist/formly.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/formly.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/formly.min.js.map

Large diffs are not rendered by default.

47 changes: 0 additions & 47 deletions other/ERRORS_AND_WARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,53 +127,6 @@ 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)

# Validators returning promises should use asyncValidators

Due to some issues with treating all function validators as async validators, the functionality has been split into
simply `validators` and `asyncValidators`. The ability to return a promise from a validator has been deprecated and you
should use `asyncValidators` for those now. For more info, see
[#369](https://github.com/formly-js/angular-formly/issues/369).

# apiCheck as an object deprecated

As a performance optimization, the `apiCheck` property has been changed to a function. This is good because when
apiCheck is disabled (either globally or the specified `apiCheckInstance`), the function is not even called which means
the apiCheck checkers are never even created. Not much we can do about the couple of extra bytes, but that's not really
a big issue. For more info, see [#334](https://github.com/formly-js/angular-formly/issues/334). Note, this will be
removed in a major release.

# validateOptions deprecated

Because angular-formly already has a dependency on `api-check` and this is just a better way to validate your options,
you should use this method instead. In an effort to simplify things. This has been deprecated in favor of the `apiCheck`
property.

# skipNgModelAttrsManipulator moved

This property has been moved from the `data` property to the `extras` property.

Before:

```javascript
{
template: '<hr />',
data: {
skipNgModelAttrsManipulator: true
}
}
```

After:

```javascript
{
template: '<hr />',
extras: {
skipNgModelAttrsManipulator: true
}
}
```

# Notes

It is recommended to disable warnings in production using `formlyConfigProvider.disableWarnings = true`. Note: This will
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angular-formly",
"version": "6.26.9",
"version": "7.0.0",
"author": "Astrism <astrisms@gmail.com>",
"contributors": [
"Astrism <astrisms@gmail.com>",
Expand Down
54 changes: 4 additions & 50 deletions src/directives/formly-custom-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import angular from 'angular-fix';
export default formlyCustomValidation;

// @ngInject
function formlyCustomValidation(formlyConfig, formlyUtil, $q, formlyWarn) {
function formlyCustomValidation(formlyUtil) {
return {
restrict: 'A',
require: 'ngModel',
link: function formlyCustomValidationLink(scope, el, attrs, ctrl) {
const opts = scope.options;
const warnedValidators = [];
opts.validation.messages = opts.validation.messages || {};
angular.forEach(opts.validation.messages, (message, key) => {
opts.validation.messages[key] = () => {
Expand Down Expand Up @@ -41,45 +40,18 @@ function formlyCustomValidation(formlyConfig, formlyUtil, $q, formlyWarn) {
}

function setupWithValidators(validator, name, isAsync) {
const isPossiblyAsync = !angular.isString(validator);
let validatorCollection = (isPossiblyAsync || isAsync) ? '$asyncValidators' : '$validators';

// UPDATE IN 7.0.0
// this is temporary until we can have a breaking change. Allow people to get the wins of the explicitAsync api
if (formlyConfig.extras.explicitAsync && !isAsync) {
validatorCollection = '$validators';
}
const validatorCollection = isAsync ? '$asyncValidators' : '$validators';

ctrl[validatorCollection][name] = function evalValidity(modelValue, viewValue) {
const value = formlyUtil.formlyEval(scope, validator, modelValue, viewValue);
// UPDATE IN 7.0.0
// In the next breaking change, this code should simply return the value
if (isAsync) {
return value;
} else if (isPossiblyAsync && !formlyConfig.extras.explicitAsync) {
if (isPromiseLike(value)) {
logAsyncValidatorsDeprecationNotice(validator, opts);
return value;
} else {
return value ? $q.when(value) : $q.reject(value);
}
} else {
return value;
}
return formlyUtil.formlyEval(scope, validator, modelValue, viewValue);
};
}

function setupWithParsers(validator, name, isAsync) {
let inFlightValidator;
ctrl.$parsers.unshift(function evalValidityOfParser(viewValue) {
const isValid = formlyUtil.formlyEval(scope, validator, ctrl.$modelValue, viewValue);
// UPDATE IN 7.0.0
// In the next breaking change, rather than checking for isPromiseLike, it should just check for isAsync.

if (isAsync || isPromiseLike(isValid)) {
if (!isAsync) {
logAsyncValidatorsDeprecationNotice(validator, opts);
}
if (isAsync) {
ctrl.$pending = ctrl.$pending || {};
ctrl.$pending[name] = true;
inFlightValidator = isValid;
Expand All @@ -105,24 +77,6 @@ function formlyCustomValidation(formlyConfig, formlyUtil, $q, formlyWarn) {
return viewValue;
});
}

function logAsyncValidatorsDeprecationNotice(validator, options) {
if (warnedValidators.indexOf(validator) !== -1) {
// we've warned about this one before. No spam necessary...
return;
}
warnedValidators.push(validator);
formlyWarn(
'validators-returning-promises-should-use-asyncvalidators',
'Validators returning promises should use asyncValidators instead of validators.',
options
);
}
}
};


function isPromiseLike(obj) {
return obj && angular.isFunction(obj.then);
}
}
43 changes: 0 additions & 43 deletions src/directives/formly-custom-validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,6 @@ describe(`formly-custom-validation`, function() {
checkApi(formTemplate.replace(
`TEMPLATE`, `<input ng-model="input" name="field" formly-custom-validation />`
));

describe(`validators that are functions placement`, () => {
it(`should be placed in $asyncValidators because it can return a promise`, () => {
scope.options.validators.isHello = viewValue => viewValue === 'hello';
$compile(
`<form name="myForm"><input ng-model="input" name="field" formly-custom-validation /></form>`
)(scope);
scope.$digest();
const field = scope.myForm.field;
expect(field.$validators.isHello).to.not.exist;
expect(field.$asyncValidators.isHello).to.exist;
});

it(`should be placed in $validators if formlyConfig.extras.explicitAsync`, () => {
formlyConfig.extras.explicitAsync = true;
scope.options.validators.isHello = viewValue => viewValue === 'hello';
$compile(
`<form name="myForm"><input ng-model="input" name="field" formly-custom-validation /></form>`
)(scope);
scope.$digest();
const field = scope.myForm.field;
expect(field.$validators.isHello).to.exist;
expect(field.$asyncValidators.isHello).to.not.exist;
});

it(`should validate properly when explicitAsync is true`, () => {
formlyConfig.extras.explicitAsync = true;
const template = `<form name="myForm"><input ng-model="input" name="field" formly-custom-validation /></form>`;
doValidation(template, 'hello', false, viewValue => viewValue !== 'hello', false);
});
});
});

describe(`options.validation.messages`, () => {
Expand Down Expand Up @@ -100,18 +69,6 @@ describe(`formly-custom-validation`, function() {
it(`should fail if it's a function that fails`, () => {
validate(viewValue => viewValue !== value, false);
});

it(`should warn if it's a function that returns a promise for a regular validator (should use asyncValidators instead)`, () => {
const logArgs = [
'Formly Warning:',
'Validators returning promises should use asyncValidators instead of validators.',
scope.options,
/validators-returning-promises-should-use-asyncvalidators/
];
shouldWarnWithLog($log, logArgs, () => {
validate(() => $q.when(), true);
});
});
});

describe(`asyncValidators`, () => {
Expand Down
32 changes: 9 additions & 23 deletions src/directives/formly-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo

wrapper.forEach((aWrapper) => {
formlyUsability.checkWrapper(aWrapper, options);
aWrapper.validateOptions && aWrapper.validateOptions(options);
runApiCheck(aWrapper, options);
});
const promises = wrapper.map(w => getTemplate(w.template || w.templateUrl, !w.template));
Expand Down Expand Up @@ -639,9 +638,6 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
// validate with the type
const type = options.type && formlyConfig.getType(options.type);
if (type) {
if (type.validateOptions) {
type.validateOptions(options);
}
runApiCheck(type, options, true);
}
if (options.expressionProperties && options.expressionProperties.hide) {
Expand Down Expand Up @@ -679,26 +675,16 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
return;
}
const fn = apiCheckFunction || 'warn';
if (angular.isFunction(apiCheck)) {
// this is the new API
const checkerObjects = apiCheck(instance);
angular.forEach(checkerObjects, (shape, name) => {
const checker = instance.shape(shape);
const checkOptions = angular.extend({
prefix: `formly-field type ${options.type} for property ${name}`,
url: formlyApiCheck.config.output.docsBaseUrl + 'formly-field-type-apicheck-failed'
}, apiCheckOptions);
instance[fn](checker, options[name], checkOptions);
});
} else {
// TODO this is the deprecated API. Remove this in a breaking change.
const checker = instance.shape(apiCheck);
const checkOptions = apiCheckOptions || {
prefix: `formly-field type ${options.type}`,
// this is the new API
const checkerObjects = apiCheck(instance);
angular.forEach(checkerObjects, (shape, name) => {
const checker = instance.shape(shape);
const checkOptions = angular.extend({
prefix: `formly-field type ${options.type} for property ${name}`,
url: formlyApiCheck.config.output.docsBaseUrl + 'formly-field-type-apicheck-failed'
};
instance[fn](checker, options, checkOptions);
}
}, apiCheckOptions);
instance[fn](checker, options[name], checkOptions);
});
}


Expand Down
36 changes: 2 additions & 34 deletions src/directives/formly-field.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,12 @@ describe('formly-field', function() {


describe('api check', () => {
let validateOptions;
beforeEach(() => {
/* eslint no-console:0 */
const originalWarn = console.warn;
console.warn = () => {};
validateOptions = sinon.spy();
formlyConfig.setType({
name: 'text', template: `<input name="{{id}}" ng-model="model[options.key]" />`,
validateOptions
name: 'text', template: `<input name="{{id}}" ng-model="model[options.key]" />`
});
scope.model = {};
console.warn = originalWarn;
Expand All @@ -127,13 +124,6 @@ describe('formly-field', function() {

expect(() => compileAndDigest()).to.throw(/extra.*properties.*extraProp/);
});

it(`should invoke the validateOptions property of the type`, () => {
const field = {type: 'text'};
scope.fields = [field];
compileAndDigest();
expect(validateOptions).to.have.been.calledWith(field);
});
});

describe('default type options', () => {
Expand Down Expand Up @@ -184,7 +174,7 @@ describe('formly-field', function() {
attribute: 'required'
},
myChange: {
expression: 'ng-change'
statement: 'ng-change'
}
},
templateOptions: {
Expand Down Expand Up @@ -632,28 +622,6 @@ describe('formly-field', function() {
expect(type.apiCheck).to.have.been.calledWith(formlyApiCheck);
}));

it(`should work with the old api`, () => {
shouldWarn(
/deprecated/,
() => {
formlyConfig.setType({
name: 'someOtherType',
template: '<label>{{to.label}}</label>',
apiCheck: {
templateOptions: apiCheck.shape({
label: apiCheck.string
})
}
});
}
);
scope.fields = [{type: 'someOtherType'}];
shouldWarn(
/angular-formly: formly-field type someOtherType apiCheck failed.*?Required `label`.*?templateOptions.*?`String`/,
compileAndDigest
);
});

it(`should not warn if everything's fine`, () => {
scope.fields = [
{type, templateOptions: {label: 'string', className: 'string'}}
Expand Down
12 changes: 11 additions & 1 deletion src/other/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import angular from 'angular-fix';

export default {formlyEval, getFieldId, reverseDeepMerge, findByNodeName, arrayify, extendFunction, extendArray, startsWith};
export default {
formlyEval, getFieldId, reverseDeepMerge, findByNodeName, arrayify, extendFunction, extendArray, startsWith, contains
};

function formlyEval(scope, expression, $modelValue, $viewValue, extraLocals) {
if (angular.isFunction(expression)) {
Expand Down Expand Up @@ -109,3 +111,11 @@ function startsWith(str, search) {
return false;
}
}

function contains(str, search) {
if (angular.isString(str) && angular.isString(search)) {
return str.length >= search.length && str.indexOf(search) !== -1;
} else {
return false;
}
}
Loading

0 comments on commit 1603f62

Please sign in to comment.