├── .coveralls.yml
├── .eslintignore
├── .eslintrc
├── .travis.yml
├── CHANGELOG.md
├── README.md
├── docs
├── auto-formly-parsers.md
└── auto-formly.md
├── lib
├── client
│ ├── auto-formly-component.js
│ ├── auto-formly-component.ng.html
│ ├── auto-formly-helpers.js
│ ├── auto-formly-parsers.js
│ ├── auto-formly.js
│ ├── formly-validator
│ │ └── unique.js
│ ├── main.js
│ └── parsers
│ │ ├── defaultvalue.js
│ │ ├── key.js
│ │ ├── template-options
│ │ ├── label.js
│ │ ├── max-date.js
│ │ ├── min-date.js
│ │ └── options.js
│ │ ├── type.js
│ │ ├── validation
│ │ └── messages.js
│ │ └── validators
│ │ ├── allowed.js
│ │ ├── maxlength.js
│ │ ├── maxnumber.js
│ │ ├── minlength.js
│ │ ├── minnumber.js
│ │ ├── pattern.js
│ │ ├── required.js
│ │ └── unique.js
└── schema.js
├── package.js
└── tests
└── client
├── auto-formly-parsers-spec.js
├── auto-formly-spec.js
├── collection.js
├── parsers
├── defaultvalue-spec.js
├── key-spec.js
├── template-options
│ ├── label-spec.js
│ ├── max-date-spec.js
│ └── min-date-spec.js
├── type-spec.js
├── validation
│ └── messages-spec.js
└── validators
│ ├── allowed-spec.js
│ ├── maxlength-spec.js
│ ├── maxnumber-spec.js
│ ├── minlength-spec.js
│ ├── minnumber-spec.js
│ ├── pattern-spec.js
│ ├── required-spec.js
│ └── unique-spec.js
└── schema.js
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | .meteor
2 | tests
3 | **/tests
4 |
5 | **/*.md
6 | **/*.html
7 | **/*.css
8 | **/*.json
9 | **/*.yaml
10 | **/*.yml
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "eslint:recommended",
4 | "env": {
5 | "browser": true,
6 | "node": true,
7 | "meteor": true,
8 | "mongo": true,
9 | "jasmine": true,
10 | "es6": true
11 | },
12 | "globals": {
13 | // app globals
14 | "autoFormlyHelpers": true,
15 | // thrid-party packages globals
16 | "SimpleSchema": false,
17 | "angular2now": false,
18 | "angular": false
19 | },
20 | "rules": {
21 | "no-unused-vars": [
22 | 1,
23 | {
24 | "vars": "all",
25 | "args": "after-used"
26 | }
27 | ],
28 | "curly": 2,
29 | // Require Following Curly Brace Conventions
30 | "eqeqeq": 2,
31 | // Require === and !==
32 | "no-alert": 2,
33 | // Disallow Use of Alert
34 | "no-caller": 2,
35 | // Disallow Use of caller/callee
36 | "no-else-return": 2,
37 | // Disallow return in else
38 | "no-eval": 2,
39 | // Disallow eval()
40 | "no-implied-eval": 2,
41 | // Disallow Implied eval()
42 | "no-labels": 2,
43 | // Disallow use of labeled statements
44 | "no-lone-blocks": 2,
45 | // Disallow Unnecessary Nested Blocks
46 | "no-loop-func": 2,
47 | // Disallow Functions in Loops
48 | "no-magic-numbers": 1,
49 | // Disallow Magic Numbers
50 | "no-multi-spaces": 2,
51 | // Disallow multiple spaces
52 | "no-native-reassign": 2,
53 | // Disallow Reassignment of Native Objects
54 | "no-new-func": 2,
55 | // Disallow Function Constructor
56 | "no-new-wrappers": 2,
57 | // Disallow Primitive Wrapper Instances
58 | "no-new": 2,
59 | // Disallow new For Side Effects
60 | "no-param-reassign": 2,
61 | // Disallow Reassignment of Function Parameters
62 | "no-proto": 2,
63 | // Disallow Use of __proto__
64 | "no-return-assign": 2,
65 | // Disallow Assignment in return Statement
66 | "no-script-url": 2,
67 | // Disallow use of javascript: urls
68 | "no-self-compare": 2,
69 | // Disallow comparisons where both sides are exactly the same
70 | "no-throw-literal": 2,
71 | // Restrict what can be thrown as an exception
72 | "no-unused-expressions": 2,
73 | // Disallow usage of expressions in statement position
74 | "no-useless-call": 2,
75 | // Disallow unnecessary .call() and .apply()
76 | "no-useless-concat": 2,
77 | // Disallow unnecessary concatenation of literals or template literals
78 | "no-void": 2,
79 | // Disallow use of the void operator
80 | "no-with": 2,
81 | // No with statements
82 | "vars-on-top": 2,
83 | // Require Variable Declarations to be at the top of their scope
84 | "wrap-iife": 2,
85 | // Require immediate function invocation to be wrapped in parentheses
86 | "array-bracket-spacing": [
87 | 2,
88 | "never"
89 | ],
90 | // Disallow or enforce spaces inside of brackets
91 | "block-spacing": [
92 | 2,
93 | "always"
94 | ],
95 | // Disallow or enforce spaces inside of single line blocks
96 | "camelcase": [
97 | 2,
98 | {
99 | "properties": "always"
100 | }
101 | ],
102 | // Require Camelcase
103 | "comma-spacing": [
104 | 2,
105 | {
106 | "before": false,
107 | "after": true
108 | }
109 | ],
110 | // Enforces spacing around commas
111 | "computed-property-spacing": [
112 | 2,
113 | "never"
114 | ],
115 | // Disallow or enforce spaces inside of computed properties
116 | "consistent-this": [
117 | 2,
118 | "self"
119 | ],
120 | // Require Consistent This
121 | "max-nested-callbacks": [
122 | 2,
123 | 3
124 | ],
125 | // Set Maximum Depth of Nested Callbacks
126 | "new-parens": 2,
127 | // Require Parens for Constructors
128 | "newline-after-var": 2,
129 | // Require or disallow an empty newline after variable declarations
130 | "no-array-constructor": 2,
131 | // Disallow creation of dense arrays using the Array constructor
132 | "no-inline-comments": 2,
133 | // Disallows comments after code. Comments must come on their own lines
134 | "no-multiple-empty-lines": [
135 | 2,
136 | {
137 | "max": 2
138 | }
139 | ],
140 | // Disallows multiple blank lines
141 | "no-nested-ternary": 2,
142 | // Disallow Nested Ternaries
143 | "no-new-object": 2,
144 | // Disallow the use of the Object constructor
145 | "no-unneeded-ternary": 2,
146 | // Disallow conditional expressions that can be expressed with simpler constructs
147 | "object-curly-spacing": [
148 | 2,
149 | "never"
150 | ],
151 | // Disallow or enforce spaces inside of curly braces in objects.
152 | "one-var": [
153 | 2,
154 | "never"
155 | ],
156 | // Require or Disallow One Variable Declaration per Scope
157 | "wrap-regex": 2,
158 | // Require Regex Literals to be Wrapped
159 | "arrow-parens": [
160 | 2,
161 | "always"
162 | ],
163 | // Require parens in arrow function arguments
164 | "constructor-super": 2,
165 | // Verify calls of super() in constructors
166 | "no-class-assign": 2,
167 | // Disallow modifying variables of class declarations
168 | "no-const-assign": 2,
169 | // Disallow modifying variables that are declared using const
170 | "no-dupe-class-members": 2,
171 | // Disallow duplicate name in class members
172 | "no-this-before-super": 2,
173 | // Disallow use of this/super before calling super() in constructors
174 | }
175 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.12"
4 | before_install:
5 | - "curl -L https://raw.githubusercontent.com/arunoda/travis-ci-meteor-packages/master/configure.sh | /bin/sh"
6 | - "npm install -g velocity-cli"
7 | before_script:
8 | - "export PATH=$HOME/.meteor:$PATH"
9 | script:
10 | - "velocity test-package ./ --ci"
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
5 |
6 | [0.8.0](https://github.com/wieldo/meteor-autoformly/compare/v0.7.0...v0.8.0) - 2016-01-18
7 |
8 | ### Changed
9 |
10 | - at least wieldo:angular-formly-validator@1.5.0
11 |
12 | [0.7.0](https://github.com/wieldo/meteor-autoformly/compare/v0.6.0...v0.7.0) - 2015-12-30
13 |
14 | ### Added
15 |
16 | - Support for **Date** fields with **min** and **max**
17 |
18 | [0.6.0](https://github.com/wieldo/meteor-autoformly/compare/v0.5.1...v0.6.0)
19 | ----------------------------------------------------------------------------
20 |
21 | ### Added
22 |
23 | - validation for `schema.allowedValues`
24 |
25 | ### Changed
26 |
27 | - BREAKING CHANGE: uses now **formly:angular-formly** instead of wieldo:angular-formly
28 |
29 | [0.5.1](https://github.com/wieldo/meteor-autoformly/compare/v0.5.0...v0.5.1) - 2015-11-25
30 | -----------------------------------------------------------------------------------------
31 |
32 | ### Added
33 |
34 | - add info about options to autoFormly component's documentation
35 |
36 | [0.5.0](https://github.com/wieldo/meteor-autoformly/compare/v0.4.0...v0.5.0) - 2015-11-25
37 | -----------------------------------------------------------------------------------------
38 |
39 | ### Added
40 |
41 | - `auto-formly` component to automate process of insertion or collection update
42 |
43 | [0.4.0](https://github.com/wieldo/meteor-autoformly/compare/v0.3.1...v0.4.0) - 2015-11-25
44 | -----------------------------------------------------------------------------------------
45 |
46 | ### Added
47 |
48 | - `autoFormly.errors()` method to handle validation errors while inserting or updating collection object
49 |
50 | [0.3.1](https://github.com/wieldo/meteor-autoformly/compare/v0.3.0...v0.3.1) - 2015-11-23
51 | -----------------------------------------------------------------------------------------
52 |
53 | ### Fixed
54 |
55 | - Missing support for **$meteor.collection()**
56 |
57 | [0.3.0](https://github.com/wieldo/meteor-autoformly/compare/v0.2.1...v0.3.0) - 2015-11-23
58 | -----------------------------------------------------------------------------------------
59 |
60 | ### Added
61 |
62 | - Support autoformly.validation.messages in SimpleSchema
63 | - Add optional manual formly configuration for each field in autoFormly service
64 | - Implement more advanced filtering
65 | - `schema.autoformly.templateOptions.rows` to be displayed as textarea
66 |
67 | ### Deprecated
68 |
69 | - Filtering using schema keys as array
70 |
71 | ### Fixed
72 |
73 | - Prevent templatesObject.label overwriting
74 |
75 | [0.2.1](https://github.com/wieldo/meteor-autoformly/compare/v0.2.0...v0.2.1) - 2015-11-18
76 | -----------------------------------------------------------------------------------------
77 |
78 | ### Changed
79 |
80 | - Refactor all files to use Strict Dependency Injection
81 |
82 | [0.2.0](https://github.com/wieldo/meteor-autoformly/compare/v0.1.0...v0.2.0) - 2015-11-18
83 | -----------------------------------------------------------------------------------------
84 |
85 | ### Added
86 |
87 | - Support for ***Boolean*** type (as checkbox)
88 | - Support for allowedValues with ***String*** type (as select)
89 |
90 | [0.1.0](https://github.com/wieldo/meteor-autoformly/compare/v0.0.1...v0.1.0) - 2015-11-15
91 | -----------------------------------------------------------------------------------------
92 |
93 | ### Added
94 |
95 | - Support for default values
96 | - Support for schema.autoformly.type
97 | - Support for schema.regEx
98 | - Tests for all parsers
99 |
100 | 0.0.1 - 2015-11-14
101 | ------------------
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | AutoFormly
2 | ==========
3 |
4 | [](https://badge.fury.io/gh/wieldo%2Fmeteor-autoformly)
5 |
6 | [](https://travis-ci.org/wieldo/meteor-autoformly)
7 |
8 | [](https://gitter.im/wieldo/meteor-autoformly?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
9 |
10 | [](https://coveralls.io/github/wieldo/meteor-autoformly?branch=master)
11 |
12 | [](https://www.codacy.com/app/mys-sterowiec/meteor-autoformly)
13 |
14 | Create [Angular-Formly](http://angular-formly.com) forms with automatic insert and update, and automatic reactive validation. Requires [SimpleSchema](http://github.com/aldeed/meteor-simple-schema) or [Collection2](http://github.com/aldeed/meteor-collection2).
15 |
16 | Installation
17 | ------------
18 |
19 | ```
20 | meteor add wieldo:autoformly
21 | ```
22 |
23 | How to use it
24 | -------------
25 |
26 | Add autoFormly and angular-formly templates to your angular module.
27 |
28 | ```javascript
29 | angular.module('app', [
30 | 'autoFormly',
31 | 'formlyMaterial' // or other angular-formly templates
32 | ]);
33 | ```
34 |
35 | ### Templates
36 |
37 | As you can see above, I'm using [angular-formly-templates-material](http://github.com/formly-js/angular-formly-templates-material) which I also maintain. You can add it using `meteor add formly:angular-formly-templates-material`.
38 |
39 | ### Be aware
40 |
41 | ```
42 | Be aware that not all angular-formly templates have same API
43 |
44 | It is not yet a stable version
45 |
46 | If you found some mismatch with other templates, post an issue
47 | ```
48 |
49 | ### auto-formly component
50 |
51 | To insert or update collection
52 | ```html
53 |
59 |
60 |
61 | ```
62 |
63 | - **collection** Mongo.Collection object
64 | - **doc** document from collection (optional)
65 | - **options** same object as in autoFormly.collection (to custom configuration and filtering) (optional)
66 | - **onSuccess** callback with result of action as argument (optional)
67 | - **onError** callback with error as argument (false if form contains errors on client-side) (optional)
68 |
69 | ### Convert all schema fields
70 |
71 | ```javascript
72 | const fields = autoFormly.collection(BooksCollection);
73 | // or
74 | const fields = autoFormly.collection($meteor.collection(BooksCollection);
75 | // or
76 | const fields = autoFormly.schema(BooksSchema);
77 | ```
78 |
79 | ### Save object to collection with validation error handling
80 |
81 | ```javascript
82 | const fields = autoFormly.collection(BooksCollection);
83 |
84 | function submit(book) {
85 | $meteor.collection(BooksCollection)
86 | .save(book)
87 | .then(() => {
88 | // success
89 | })
90 | .catch(() => autoFormly.errors(BooksCollection, fields);
91 | }
92 | ```
93 |
94 | ### Convert all schema fields excluding one
95 |
96 | ```javascript
97 | const fields = autoFormly.schema(BooksSchema, {
98 | fields: {
99 | published: false
100 | }
101 | });
102 | ```
103 |
104 | ### Convert selected collection fields
105 |
106 | ```javascript
107 | const fields = autoFormly.collection(BooksCollection, {
108 | all: false,
109 | fields: {
110 | published: true,
111 | author: true,
112 | title: true
113 | }
114 | });
115 | ```
116 |
117 | ### Extend formly configuration for selected field
118 |
119 | ```javascript
120 | const fields = autoFormly.schema(BooksSchema, {
121 | all: false,
122 | fields: {
123 | published: true,
124 | author: {
125 | templateOptions: {
126 | label: "Written by"
127 | }
128 | }
129 | }
130 | });
131 | ```
132 |
133 | #### Helpers
134 |
135 | We're currently working on three other packages that are very useful in autoFormly.
136 |
137 | - [formlyTransformer](http://github.com/wieldo/angular-formly-transformer) to simplify process of formly field transformation.
138 | - [formlyValidator](http://github.com/wieldo/angular-formly-validator) to make validation easier (with built-in validators)
139 | - [formlyMaterial](http://github.com/formly-js/angular-formly-templates-material) is a AngularJS module with Angular Material templates to use in angular-formly.
140 |
141 | What is ready?
142 | --------------
143 |
144 | See examples above.
145 |
146 | - creating formly fields with validators using collection or schema (autoFormly.collection(), autoFormly.schema())
147 | - handling validation errors (autoFormly.errors() sets validation on form fields)
148 |
149 | Take a look at this docs:
150 |
151 | - [autoFormly](docs/auto-formly.md)
152 | - [autoFormlyParsers](docs/auto-formly-parsers.md)
153 |
154 | Contributing
155 | ------------
156 |
157 | It is a new project, at the beginning of development process.
158 |
159 | Feel free to ask me anything.
160 |
161 | ### You can help
162 |
163 | If you would like to add functionality, just fork this repo and create pull request.
164 |
165 | ### How autoFormly works
166 |
167 | Basically it parses simpleSchema structure and creates formly configuration for each field.
168 |
169 | For example, to mark field as required we can create the parser function to check if `optional` property is being used. If *opional* is not set to *true* then we're adding `required` validator from `wieldo:angular-formly-validator` package (see [formlyValidator](http://github.com/wieldo/angular-formly-validator) and source code in [required.js](lib/client/parsers/validators/required.js).
170 |
171 | #### What is parser?
172 |
173 | Parser is a function that receives simpleSchema key with configuration and reference of formly field configuration object.
174 |
175 | So basically, you can add properties to formly configuration by checking field's schema.
176 |
177 | ### Roadmap 1.0
178 |
179 | - [ ] Component to automate process of insertion or collection update
180 | - [ ] `schema.minCount` and `schema.maxCount` support
181 | - [ ] Support for ***Object*** type fields
182 | - [ ] Support for ***array of objects***
183 | - [ ] Interactive **demo**
184 | - [x] Extend SimpleSchema to use `autoformly` property
185 | - [x] Add optional manual formly configuration for each field
186 | - [x] More advanced field filtering (show all / hide all / add excluding)
187 | - [x] `schema.key` as `formly.key`
188 | - [x] `schema.label` as `formly.templateOptions.label`
189 | - [x] `schema.optional` and required validator
190 | - [x] `schema.max` for ***String*** and ***Number*** types as **maxlength** and **maxnumber** validator
191 | - [x] `schema.min` for ***String*** and ***Number*** types as **minlength** and **minnumber** validator
192 | - [x] `schema.regEx` as **pattern** validator
193 | - [x] `schema.defaultValue` as `formly.defaultValue`
194 | - [x] `schema.autoformly.templateOptions.rows` to be displayed as textarea
195 | - [x] ***Boolean*** type as checkbox
196 | - [x] `schema.autoformly.type` to be `formly.type`
197 | - [x] `schema.allowedValues` as select element (schema type is a String)
198 | - [x] validation for `schema.allowedValues`
199 | - [x] Support for ***Date*** type fields with min and max
200 | - [x] Support for server-side validation errors (like *unique*\)
201 |
202 | Contact
203 | -------
204 |
205 | You can find me on [Gitter](https://gitter.im/wieldo/meteor-autoformly).
206 |
--------------------------------------------------------------------------------
/docs/auto-formly-parsers.md:
--------------------------------------------------------------------------------
1 | autoFormlyParsers
2 | ==========
3 |
4 | ```
5 | AngularJS service.
6 | ```
7 |
8 | __File: [lib/client/auto-formly-parsers.js](../lib/client/auto-formly-parsers.js)__
9 |
10 | -
11 |
12 | ### *autoFormlyParsers*.register(parser)
13 |
14 | ```
15 | Register new parsing function
16 | ```
17 |
18 | __Arguments__
19 |
20 | * __collection__ *{Function}*
21 |
22 | Parsing function with three arguments:
23 |
24 | - *{string}* field's key
25 | - *{object}* copy of field's schema from SimpleSchema object
26 | - *{object}* object with formly configuration for field
27 |
28 |
29 | __Returns__ *{undefined}*
30 |
31 | There is no need to return something. Use formly configuration object as reference.
32 |
--------------------------------------------------------------------------------
/docs/auto-formly.md:
--------------------------------------------------------------------------------
1 | autoFormly
2 | ==========
3 |
4 | ```
5 | AngularJS service.
6 | ```
7 |
8 | __File: [lib/client/auto-formly.js](../lib/client/auto-formly.js)__
9 |
10 | -
11 |
12 | ### *autoFormly*.collection(collection, fields)
13 |
14 | ```
15 | Parse Mongo.Collection to get array with fields
16 | ```
17 |
18 | __Arguments__
19 |
20 | * __collection__ *{CollectionCollection|AngularMeteorCollection}*
21 |
22 | Mongo Collection used directly or with $meteor AngularJS service
23 |
24 | * __options__ *{array|object|undefined}*
25 |
26 | Optional filtering fields using array with collection's keys
27 | or options object.
28 |
29 | * __options.all__ *{boolean}*
30 |
31 | Show all fields when true. Otherwise only these defined (see below)
32 |
33 | * __options.fields__ *{object}*
34 |
35 | Object with the field's key as property and formly field configuration (extends the auto-generated configuration).
36 | Instead of using formly configuration you can set field as visible or not using boolean value (true visible, false not used)
37 |
38 |
39 | __Returns__ *{Array}*
40 |
41 | Array with fields to use in formly-form.
42 |
43 | -
44 |
45 | ### *autoFormly*.schema(schema, options)
46 |
47 | ```
48 | Parse SimpleSchema object to get array with fields
49 | ```
50 |
51 | __Arguments__
52 |
53 | * __schema__ *{SimpleSchema}*
54 |
55 | SimpleSchema instance
56 |
57 | * __options__ *{array|object|undefined}*
58 |
59 | See collection()
60 |
61 | __Returns__ *{Array}*
62 |
63 | Array with fields to use in formly-form.
64 |
65 | -
66 |
67 | ### *autoFormly*.errors(collection, fields)
68 |
69 | ```
70 | Gets errors of fields and sets them in form controls. Use it when insertion or collection update fails.
71 |
72 | See example in readme.
73 | ```
74 |
75 | __Arguments__
76 |
77 | * __collection__ *{SimpleSchema}*
78 |
79 | SimpleSchema instance
80 |
81 | * __fields__ *{array}*
82 |
83 | Array with fields
84 |
--------------------------------------------------------------------------------
/lib/client/auto-formly-component.js:
--------------------------------------------------------------------------------
1 | const {SetModule, Component, View,Inject} = angular2now;
2 |
3 | SetModule('autoFormly');
4 | @Component({
5 | selector: 'auto-formly',
6 | bind: {
7 | collection: '=',
8 | options: '=?',
9 | doc: '=?',
10 | onSuccess: '=?',
11 | onError: '=?'
12 | }
13 | })
14 | @View({
15 | templateUrl: angularTemplateUrl('wieldo:autoformly', 'lib/client/auto-formly-component.ng.html'),
16 | transclude: true
17 | })
18 | @Inject(['autoFormly', '$meteor'])
19 | class autoFormlyComponent extends autoFormlyHelpers {
20 | // injectables
21 | autoFormly;
22 | $meteor;
23 |
24 | /**
25 | * collection (with set and get)
26 | */
27 | _collection;
28 | /**
29 | * options (with set and get)
30 | */
31 | _options;
32 | /**
33 | * document (with set and get)
34 | */
35 | _doc;
36 | /**
37 | * success callback (with set and get)
38 | */
39 | _onSuccess;
40 | /**
41 | * error callback (with set and get)
42 | */
43 | _onError;
44 | /**
45 | * auto-bound array with formly fields
46 | */
47 | formFields;
48 | /**
49 | * auto-bound object with formly model
50 | */
51 | formModel;
52 | /**
53 | * auto-bound object with formly options
54 | */
55 | formOptions;
56 | /**
57 | * auto-bound object with formly form
58 | */
59 | form;
60 | /**
61 | * auto-bound string with form name
62 | */
63 | formName;
64 |
65 | constructor(autoFormly, $meteor) {
66 | super();
67 | this.autoFormly = autoFormly;
68 | this.$meteor = $meteor;
69 |
70 | this.formFields = this.createFormFields();
71 | this.formModel = this.createFormModel();
72 | }
73 |
74 | /**
75 | * Create fields based on collection and options
76 | * @returns {array}
77 | */
78 | createFormFields() {
79 | return this.autoFormly.collection(this.collection, this.options);
80 | }
81 |
82 | /**
83 | * Create model based on document
84 | * @returns {Object}
85 | */
86 | createFormModel() {
87 | return this.doc || {};
88 | }
89 |
90 | /**
91 | * Submit form and save form model in collection
92 | */
93 | submit() {
94 | if (!this.form.$valid) {
95 | this.callError(false);
96 | return;
97 | }
98 |
99 | this.$meteor.collection(this.getCollection(this.collection), false)
100 | .save(this.formModel)
101 | .then((result) => {
102 | // reset model
103 | this.formModel = {};
104 | // reset form
105 | this.form.$setPristine();
106 | this.form.$setUntouched();
107 | // callback
108 | this.callSuccess(result);
109 | })
110 | .catch((error) => {
111 | // set validity on fields
112 | this.autoFormly.errors(this.collection, this.formFields);
113 | // callback
114 | this.callError(error);
115 | });
116 | }
117 |
118 | //
119 | // collection
120 | //
121 | set collection(collection) {
122 | this._collection = collection;
123 | }
124 |
125 | get collection() {
126 | return this._collection;
127 | }
128 |
129 | //
130 | // options
131 | //
132 | set options(options) {
133 | if (!angular.isObject(options)) {
134 | throw this.createError('Invalid options. Expected object');
135 | }
136 | this._options = options;
137 | }
138 |
139 | get options() {
140 | return this._options;
141 | }
142 |
143 | //
144 | // document
145 | //
146 | set doc(doc) {
147 | if (!angular.isObject(doc)) {
148 | throw this.createError('Invalid document. Expected object');
149 | }
150 | this._doc = angular.copy(doc);
151 | }
152 |
153 | get doc() {
154 | return this._doc;
155 | }
156 |
157 | //
158 | // onSuccess
159 | //
160 | set onSuccess(onSuccess) {
161 | if (!angular.isFunction(onSuccess)) {
162 | throw this.createError("Invalid success callback. Expected function");
163 | }
164 | this._onSuccess = onSuccess;
165 | }
166 |
167 | get onSuccess() {
168 | return this._onSuccess;
169 | }
170 |
171 | /**
172 | * call success callback if defined
173 | * @param {Object|Array} result
174 | */
175 | callSuccess(result) {
176 | if (this.onSuccess) {
177 | this.onSuccess(result);
178 | }
179 | }
180 |
181 | //
182 | // onError
183 | //
184 | set onError(onError) {
185 | if (!angular.isFunction(onError)) {
186 | throw this.createError("Invalid error callback. Expected function");
187 | }
188 | this._onError = onError;
189 | }
190 |
191 | get onError() {
192 | return this._onError;
193 | }
194 |
195 | /**
196 | * call error callback if defined
197 | * @param {boolean|Error} error
198 | */
199 | callError(error) {
200 | if (this.onError) {
201 | this.onError(error);
202 | }
203 | }
204 | }
--------------------------------------------------------------------------------
/lib/client/auto-formly-component.ng.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/client/auto-formly-helpers.js:
--------------------------------------------------------------------------------
1 | autoFormlyHelpers = class autoFormlyHelpers {
2 | createError(msg) {
3 | return new Error(`[AutoFormly] ${msg}`);
4 | }
5 |
6 | createNestedObject(obj, path) {
7 | path = this.pathNestedObject(path);
8 | for (let i = 0; i < path.length; i++) {
9 | obj = obj[path[i]] = obj[path[i]] || {};
10 | }
11 | }
12 |
13 | getNestedObject(obj, path) {
14 | path = this.pathNestedObject(path);
15 | let objCopy = angular.copy(obj);
16 | for (let i = 0; i < path.length; i++) {
17 | if (!objCopy.hasOwnProperty(path[i])) {
18 | objCopy = undefined;
19 | break;
20 | } else {
21 | objCopy = objCopy[path[i]];
22 | }
23 | }
24 |
25 | return objCopy;
26 | }
27 |
28 | pathNestedObject(path) {
29 | if ("string" === typeof path) {
30 | path = path.split('.');
31 | }
32 | return path;
33 | }
34 |
35 | getSchema(collection) {
36 | if (!collection) {
37 | return;
38 | }
39 |
40 | // Mongo Collection
41 | if (angular.isFunction(collection.simpleSchema)) {
42 | return collection.simpleSchema();
43 | }
44 |
45 | // AngularMeteorCollection
46 | if (collection.$$collection && angular.isFunction(collection.$$collection.simpleSchema)) {
47 | return collection.$$collection.simpleSchema();
48 | }
49 |
50 | return;
51 | }
52 |
53 | getCollection(collection) {
54 | if (this.isCollection(collection)) {
55 | return collection;
56 | }
57 |
58 | if (this.isAngularMeteorCollection(collection)) {
59 | return collection.$$collection;
60 | }
61 |
62 | return;
63 | }
64 |
65 | isCollection(collection) {
66 | return collection && collection._c2;
67 | }
68 |
69 | isAngularMeteorCollection(collection) {
70 | return collection && collection.$$collection && this.isCollection(collection.$$collection);
71 | }
72 |
73 | isSchema(schema) {
74 | return schema && schema instanceof SimpleSchema;
75 | }
76 | };
--------------------------------------------------------------------------------
/lib/client/auto-formly-parsers.js:
--------------------------------------------------------------------------------
1 | /* global autoFormlyHelpers */
2 | let {SetModule, Service} = angular2now;
3 |
4 | SetModule('autoFormly');
5 | @Service('autoFormlyParser')
6 | class autoFormlyParser extends autoFormlyHelpers {
7 |
8 | parsers = [];
9 |
10 | constructor() {
11 | super();
12 | }
13 |
14 | /**
15 | * register parser function.
16 | * Parser arguments:
17 | * - {string} fieldKey - absolute name of SimpleSchema field
18 | * - {object} fieldSchema - field's schema from SimpleSchema object
19 | * - {object} formlyField - formly field configuration object
20 | *
21 | * @public
22 | * @param {function} parser
23 | */
24 | register(parser) {
25 | if (!angular.isFunction(parser)) {
26 | throw this.createError("Parser has to be a function");
27 | }
28 |
29 | // push new parser
30 | this.parsers.push(parser);
31 | }
32 |
33 | /**
34 | *
35 | * @public
36 | * @param {Object} schema
37 | * @returns {array} Array of field configuration objects
38 | */
39 | schema(schema) {
40 | let fieldKey;
41 | const fields = [];
42 |
43 | for (fieldKey in schema) {
44 | fields.push(this.field(fieldKey, schema[fieldKey]));
45 | }
46 |
47 | // remove undefined and without type
48 | return _.reject(_.compact(fields), (field) => "undefined" === typeof field.type);
49 | }
50 |
51 | /**
52 | *
53 | * @param {string} fieldKey
54 | * @param {Object} fieldSchema
55 | * @returns {Object}
56 | */
57 | field(fieldKey, fieldSchema) {
58 | // todo: support for array of objects
59 | // maybe something like foo.$.bar -> foo[$key]bar will do the work
60 | if (fieldKey.indexOf('$') !== -1) {
61 | return;
62 | }
63 |
64 | const formlyField = fieldSchema.autoformly ? fieldSchema.autoformly : {};
65 |
66 | this.runParsers(fieldKey, fieldSchema, formlyField);
67 |
68 | return formlyField;
69 | }
70 |
71 | /**
72 | *
73 | * @public
74 | * @param {string} fieldKey
75 | * @param {object} fieldSchema
76 | * @param {object} formlyField
77 | */
78 | runParsers(fieldKey, fieldSchema, formlyField) {
79 | this.parsers.forEach((parser) => {
80 | // call with deep copy of fieldSchema to avoid overwriting
81 | parser.call({}, fieldKey, angular.copy(fieldSchema), formlyField);
82 | });
83 | }
84 | }
--------------------------------------------------------------------------------
/lib/client/auto-formly.js:
--------------------------------------------------------------------------------
1 | /* global autoFormlyHelpers */
2 | let {SetModule, Service, Inject} = angular2now;
3 |
4 | SetModule('autoFormly');
5 | @Service('autoFormly')
6 | @Inject(['autoFormlyParser'])
7 | /**
8 | * AngularJS Service
9 | * @property autoFormly
10 | * @public
11 | */
12 | class autoFormly extends autoFormlyHelpers {
13 |
14 | // injectables
15 | autoFormlyParser;
16 |
17 | constructor(autoFormlyParser) {
18 | super();
19 |
20 | this.autoFormlyParser = autoFormlyParser;
21 | }
22 |
23 | /**
24 | * Parse Mongo.Collection object
25 | *
26 | * @public
27 | * @method autoFormly.collection
28 | * @param {Collection|AngularMeteorCollection} collection - used directly or with $meteor service
29 | * @param {array|object} options - schema keys you want to use or formly fields configuration (optional)
30 | * @returns {array}
31 | */
32 | collection(collection, options) {
33 | if (!this.isCollection(collection) && !this.isAngularMeteorCollection(collection)) {
34 | throw this.createError("Collection is not extended by Collection2");
35 | }
36 |
37 | let schema = this.getSchema(this.getCollection(collection));
38 |
39 | if (!schema) {
40 | throw this.createError("Collection has no schema");
41 | }
42 |
43 | return this.schema(schema, options);
44 | }
45 |
46 | /**
47 | * Parse SchemaSchema object
48 | *
49 | * @public
50 | * @method autoFormly.schema
51 | * @param {SimpleSchema} schema
52 | * @param {array|object} options - schema keys you want to use or formly fields configuration (optional)
53 | * @returns {array}
54 | */
55 | schema(schema, options) {
56 | if (!this.isSchema(schema)) {
57 | throw this.createError("Schema has to be instance of SimpleSchema");
58 | }
59 |
60 | let sortedSchema;
61 | const schemaCopy = angular.copy(schema);
62 |
63 | /**
64 | * @deprecated avoid filtering with fields keys as array, use object configuration instead
65 | */
66 | // filter and return
67 | if (angular.isArray(options)) {
68 | return this.fields(this.filterSchema(schemaCopy, options));
69 | }
70 |
71 | // no options
72 | if (angular.isUndefined(options)) {
73 | return this.fields(schemaCopy.schema());
74 | }
75 |
76 | //
77 | // handle options object
78 | //
79 |
80 | // pass only object
81 | if (!angular.isObject(options)) {
82 | throw this.createError("Options have to be an array or object");
83 | }
84 |
85 | // use filter?
86 | if (options.all === false) {
87 | // pass only with defined fields
88 | if (!angular.isObject(options.fields)) {
89 | throw this.createError("Missing or invalid property fields in options");
90 | }
91 | // skip fields marked as unused ("fieldKey": false)
92 | sortedSchema = this.filterSchema(schemaCopy, Object.keys(_.omit(options.fields, (val) => val === false)));
93 | } else {
94 | sortedSchema = schemaCopy.schema();
95 | }
96 |
97 | // check each field
98 | if (options.fields) {
99 | _.each(sortedSchema, (fSchema, fKey) => {
100 | // and skip field if marked as unused
101 | if (options.fields[fKey] === false) {
102 | delete sortedSchema[fKey];
103 | }
104 | // or extend autoformly in schema using defined field extension
105 | if (angular.isObject(options.fields[fKey])) {
106 | sortedSchema[fKey].autoformly = angular.merge({}, fSchema.autoformly, options.fields[fKey]);
107 | }
108 | });
109 | }
110 |
111 | return this.fields(sortedSchema);
112 | }
113 |
114 | /**
115 | * @param {object} schema
116 | * @param {array} fields - schema keys you want to use (optional)
117 | * @returns {object}
118 | */
119 | filterSchema(schema, fields) {
120 | if (!angular.isArray(fields)) {
121 | throw this.createError("Fields to filter have to be an array");
122 | }
123 |
124 | const sorted = {};
125 |
126 | fields.forEach((field) => {
127 | if (!schema.schema(field)) {
128 | throw this.createError(`There is no '${field}' in schema`);
129 | }
130 | sorted[field] = schema.schema(field);
131 | });
132 |
133 | return sorted;
134 | }
135 |
136 | /**
137 | * @param {object} sortedSchema
138 | * @returns {array}
139 | */
140 | fields(sortedSchema) {
141 | return this.autoFormlyParser.schema(sortedSchema);
142 | }
143 |
144 | /**
145 | * Handle errors and set validity on fields
146 | *
147 | * @public
148 | * @param {Collection|AngularMeteorCollection} collection
149 | * @param {array} fields formly fields
150 | * @param {string} context validation context
151 | */
152 | errors(collection, fields, context) {
153 | // get things
154 | let col = this.getCollection(collection);
155 | let schema = this.getSchema(collection);
156 |
157 | // make sure fields variable is an array
158 | if (!angular.isArray(fields)) {
159 | throw this.createError("Missing or invalid fields");
160 | }
161 |
162 | // check collection
163 | if (!col) {
164 | throw this.createError("Collection is not extended by Collection2");
165 | }
166 |
167 | // check schema
168 | if (!schema) {
169 | throw this.createError("Collection has no schema");
170 | }
171 |
172 | // get keys with error types
173 | const invalidKeys = schema.namedContext(context).invalidKeys();
174 | // transform error type from SimpleSchema to autoFormly
175 | const typeTransform = {
176 | notUnique: "unique",
177 | minString: "minlength",
178 | maxString: "maxlength",
179 | minNumber: "minnumber",
180 | maxNumber: "maxnumber",
181 | regEx: "pattern"
182 | };
183 |
184 | // go through errors
185 | invalidKeys.forEach((key) => {
186 | // match error with field object
187 | let field = _.find(fields, (field) => field.key === key.name);
188 |
189 | // if found
190 | if (field) {
191 | if (!field.formControl) {
192 | throw this.createError(`Field "${field.key}" has no formControl`);
193 | }
194 | // and has formControl property
195 | field.formControl.$setValidity(typeTransform[key.type] || key.type, false);
196 | }
197 | });
198 | }
199 | }
--------------------------------------------------------------------------------
/lib/client/formly-validator/unique.js:
--------------------------------------------------------------------------------
1 | const {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly').run(['formlyValidator', (formlyValidator) => {
4 | formlyValidator.register('unique', () => {
5 | return true;
6 | });
7 | }]);
--------------------------------------------------------------------------------
/lib/client/main.js:
--------------------------------------------------------------------------------
1 | angular2now.options({controllerAs: 'vm'});
2 | const {SetModule} = angular2now;
3 |
4 | SetModule('autoFormly', ['angular-meteor', 'formlyValidator']);
--------------------------------------------------------------------------------
/lib/client/parsers/defaultvalue.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (angular.isDefined(fieldSchema.defaultValue)) {
8 | formlyField.defaultValue = fieldSchema.defaultValue;
9 | }
10 | });
11 |
12 | }]);
--------------------------------------------------------------------------------
/lib/client/parsers/key.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | formlyField.key = fieldKey;
8 | });
9 |
10 | }]);
--------------------------------------------------------------------------------
/lib/client/parsers/template-options/label.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | autoFormlyParser.createNestedObject(formlyField, 'templateOptions');
8 |
9 | // prevent overwriting
10 | if (!autoFormlyParser.getNestedObject(formlyField, 'templateOptions.label')) {
11 | formlyField.templateOptions.label = fieldSchema.label ? fieldSchema.label : fieldKey;
12 | }
13 | });
14 |
15 | }]);
16 |
--------------------------------------------------------------------------------
/lib/client/parsers/template-options/max-date.js:
--------------------------------------------------------------------------------
1 | const {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (!formlyField.templateOptions) {
8 | formlyField.templateOptions = {};
9 | }
10 |
11 | if (formlyField.type === 'datepicker' && angular.isDefined(fieldSchema.max)) {
12 | formlyField.templateOptions.maxDate = fieldSchema.max;
13 | }
14 | });
15 |
16 | }]);
17 |
--------------------------------------------------------------------------------
/lib/client/parsers/template-options/min-date.js:
--------------------------------------------------------------------------------
1 | const {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (!formlyField.templateOptions) {
8 | formlyField.templateOptions = {};
9 | }
10 |
11 | if (formlyField.type === 'datepicker' && angular.isDefined(fieldSchema.min)) {
12 | formlyField.templateOptions.minDate = fieldSchema.min;
13 | }
14 | });
15 |
16 | }]);
17 |
--------------------------------------------------------------------------------
/lib/client/parsers/template-options/options.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (!formlyField.templateOptions) {
8 | formlyField.templateOptions = {};
9 | }
10 |
11 | if (formlyField.type === 'select' && angular.isDefined(fieldSchema.allowedValues)) {
12 | formlyField.templateOptions.options = fieldSchema.allowedValues.map((value) => {
13 | return {
14 | name: value,
15 | value: value
16 | }
17 | });
18 | }
19 | });
20 |
21 | }]);
22 |
--------------------------------------------------------------------------------
/lib/client/parsers/type.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 |
8 | if (autoFormlyParser.getNestedObject(fieldSchema, 'autoformly.type')) {
9 | formlyField.type = fieldSchema.autoformly.type;
10 | return;
11 | }
12 |
13 | if (fieldSchema.type === String) {
14 |
15 | if (angular.isDefined(fieldSchema.allowedValues)) {
16 | formlyField.type = 'select';
17 | } else if (autoFormlyParser.getNestedObject(fieldSchema, 'autoformly.templateOptions.rows')) {
18 | formlyField.type = 'textarea';
19 | } else {
20 | formlyField.type = 'input';
21 | }
22 | return;
23 | }
24 |
25 | if (fieldSchema.type === Number) {
26 | formlyField.type = 'input';
27 | return;
28 | }
29 |
30 | if (fieldSchema.type === Date) {
31 | formlyField.type = 'datepicker';
32 | return;
33 | }
34 |
35 | if (fieldSchema.type === Boolean) {
36 | formlyField.type = 'checkbox';
37 | return;
38 | }
39 | });
40 |
41 | }]);
42 |
--------------------------------------------------------------------------------
/lib/client/parsers/validation/messages.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', (autoFormlyParser) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (autoFormlyParser.getNestedObject(fieldSchema, 'autoformly.validation.messages')) {
8 | autoFormlyParser.createNestedObject(formlyField, 'validation.messages');
9 | formlyField.validation.messages = fieldSchema.autoformly.validation.messages;
10 | }
11 | });
12 |
13 | }]);
14 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/allowed.js:
--------------------------------------------------------------------------------
1 | const {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.allowedValues) {
8 | formlyValidator.setFieldValidator(formlyField, 'allowed', fieldSchema.allowedValues);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/maxlength.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.max && fieldSchema.type === String) {
8 | formlyValidator.setFieldValidator(formlyField, 'maxlength', fieldSchema.max);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/maxnumber.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.max && fieldSchema.type === Number) {
8 | formlyValidator.setFieldValidator(formlyField, 'maxnumber', fieldSchema.max);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/minlength.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.min && fieldSchema.type === String) {
8 | formlyValidator.setFieldValidator(formlyField, 'minlength', fieldSchema.min);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/minnumber.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.min && fieldSchema.type === Number) {
8 | formlyValidator.setFieldValidator(formlyField, 'minnumber', fieldSchema.min);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/pattern.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.regEx) {
8 | formlyValidator.setFieldValidator(formlyField, 'pattern', fieldSchema.regEx);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/required.js:
--------------------------------------------------------------------------------
1 | var {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (!fieldSchema.optional) {
8 | formlyValidator.setFieldValidator(formlyField, 'required', true);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/client/parsers/validators/unique.js:
--------------------------------------------------------------------------------
1 | const {SetModule} = angular2now;
2 |
3 | SetModule('autoFormly')
4 | .run(['autoFormlyParser', 'formlyValidator', (autoFormlyParser, formlyValidator) => {
5 |
6 | autoFormlyParser.register((fieldKey, fieldSchema, formlyField) => {
7 | if (fieldSchema.unique) {
8 | formlyValidator.setFieldValidator(formlyField, 'unique', true);
9 | }
10 | });
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/lib/schema.js:
--------------------------------------------------------------------------------
1 | // Extend the schema options allowed by SimpleSchema
2 | SimpleSchema.extendOptions({
3 | autoformly: Match.Optional(Object)
4 | });
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | var both = ['client', 'server'];
2 | var client = 'client';
3 |
4 | Package.describe({
5 | name: "wieldo:autoformly",
6 | summary: "Create angular-formly forms with automatic insert and update, and automatic reactive validation.",
7 | version: "0.8.0",
8 |
9 | documentation: 'README.md',
10 | git: 'https://github.com/wieldo/meteor-autoformly.git'
11 | });
12 |
13 | Package.onUse(function (api) {
14 |
15 | var packages = {
16 | use: [
17 | 'aldeed:simple-schema@1.1.0',
18 | 'aldeed:collection2@2.0.0',
19 | 'underscore',
20 | 'check',
21 | 'angular@1.2.0',
22 | 'pbastowski:angular-babel@1.0.9',
23 | 'pbastowski:angular2-now@1.1.5',
24 | 'mys:angular-template-url@0.0.1',
25 | 'formly:angular-formly@7.3.9_3',
26 | 'wieldo:angular-formly-validator@1.5.0'
27 | ],
28 | imply: [
29 | 'mys:angular-template-url',
30 | 'pbastowski:angular2-now',
31 | 'aldeed:simple-schema',
32 | 'aldeed:collection2',
33 | 'formly:angular-formly',
34 | 'wieldo:angular-formly-validator'
35 | ]
36 | };
37 |
38 | api.versionsFrom("METEOR@1.0");
39 |
40 | api.use(packages.use);
41 |
42 | api.imply(packages.imply);
43 |
44 | api.addFiles([
45 | 'lib/client/main.js',
46 | 'lib/client/auto-formly-helpers.js',
47 | 'lib/client/auto-formly-parsers.js',
48 | 'lib/client/auto-formly.js',
49 | 'lib/client/auto-formly-component.ng.html',
50 | 'lib/client/auto-formly-component.js',
51 | // parsers
52 | 'lib/client/parsers/key.js',
53 | 'lib/client/parsers/type.js',
54 | 'lib/client/parsers/template-options/label.js',
55 | 'lib/client/parsers/template-options/options.js',
56 | 'lib/client/parsers/template-options/min-date.js',
57 | 'lib/client/parsers/template-options/max-date.js',
58 | 'lib/client/parsers/defaultvalue.js',
59 | // validation
60 | 'lib/client/parsers/validation/messages.js',
61 | // validators
62 | 'lib/client/parsers/validators/required.js',
63 | 'lib/client/parsers/validators/minlength.js',
64 | 'lib/client/parsers/validators/maxlength.js',
65 | 'lib/client/parsers/validators/minnumber.js',
66 | 'lib/client/parsers/validators/maxnumber.js',
67 | 'lib/client/parsers/validators/pattern.js',
68 | 'lib/client/parsers/validators/unique.js',
69 | 'lib/client/parsers/validators/allowed.js',
70 | // extend formlyValidator
71 | 'lib/client/formly-validator/unique.js'
72 | ], client);
73 |
74 | api.addFiles([
75 | 'lib/schema.js'
76 | ], both);
77 |
78 | });
79 |
80 | Package.onTest(function (api) {
81 | api.use([
82 | 'mongo',
83 | 'underscore',
84 | 'sanjo:jasmine@0.21.0',
85 | 'velocity:helpers',
86 | 'velocity:console-reporter',
87 | 'angular:angular-mocks@1.4.7',
88 | 'pbastowski:angular-babel',
89 | 'wieldo:autoformly'
90 | ]);
91 |
92 | api.addFiles([
93 | 'tests/client/schema.js',
94 | 'tests/client/collection.js'
95 | ], both);
96 |
97 | api.addFiles([
98 | 'tests/client/auto-formly-parsers-spec.js',
99 | 'tests/client/auto-formly-spec.js',
100 | // parsers
101 | 'tests/client/parsers/key-spec.js',
102 | 'tests/client/parsers/type-spec.js',
103 | 'tests/client/parsers/defaultvalue-spec.js',
104 | 'tests/client/parsers/template-options/label-spec.js',
105 | 'tests/client/parsers/template-options/min-date-spec.js',
106 | 'tests/client/parsers/template-options/max-date-spec.js',
107 | // parsers validation
108 | 'tests/client/parsers/validation/messages-spec.js',
109 | // parsers validators
110 | 'tests/client/parsers/validators/required-spec.js',
111 | 'tests/client/parsers/validators/pattern-spec.js',
112 | 'tests/client/parsers/validators/minnumber-spec.js',
113 | 'tests/client/parsers/validators/maxnumber-spec.js',
114 | 'tests/client/parsers/validators/minlength-spec.js',
115 | 'tests/client/parsers/validators/maxlength-spec.js',
116 | 'tests/client/parsers/validators/unique-spec.js',
117 | 'tests/client/parsers/validators/allowed-spec.js'
118 | ], client);
119 | });
120 |
--------------------------------------------------------------------------------
/tests/client/auto-formly-parsers-spec.js:
--------------------------------------------------------------------------------
1 | describe('autoFormlyParser', () => {
2 | let autoFormlyParser;
3 |
4 | const emptyParsers = () => {
5 | autoFormlyParser.parsers = [];
6 | };
7 |
8 | const throwErrorOnRegister = (parsers) => {
9 | parsers.forEach((parser) => {
10 | expect(() => {
11 | autoFormlyParser.register(parser);
12 | }).toThrowError(Error, "[AutoFormly] Parser has to be a function");
13 | });
14 | };
15 |
16 | beforeEach(() => {
17 | module('autoFormly');
18 |
19 | inject((_autoFormlyParser_) => {
20 | autoFormlyParser = _autoFormlyParser_;
21 | });
22 | });
23 |
24 | describe('register()', () => {
25 |
26 | it('should throw error when using number as parser', () => {
27 | throwErrorOnRegister([1, -1, 0, "1", "-1", "0"]);
28 | });
29 |
30 | it('should throw error when using empty value as parser', () => {
31 | throwErrorOnRegister(["", null, undefined]);
32 | });
33 |
34 | it('should throw error when using boolean value as parser', () => {
35 | throwErrorOnRegister([true, false]);
36 | });
37 |
38 | it('should throw error when using object value as parser', () => {
39 | throwErrorOnRegister([{}, []]);
40 | });
41 |
42 | it('should be able to register parser function', () => {
43 | const before = autoFormlyParser.parsers.length;
44 |
45 | autoFormlyParser.register(() => {
46 | });
47 | expect(autoFormlyParser.parsers.length).toBe(before + 1);
48 | });
49 | });
50 |
51 | describe('runParsers()', () => {
52 |
53 | it('should be able to run parsers with field key, schema and formly configuration', () => {
54 | emptyParsers();
55 | const spy = jasmine.createSpy('spy');
56 |
57 | autoFormlyParser.register(spy);
58 | autoFormlyParser.runParsers("test1", {}, {key: 'test'});
59 |
60 | expect(spy).toHaveBeenCalledWith("test1", {}, {key: 'test'});
61 | });
62 | it('shoud pass copy of fieldSchema in each parser', () => {
63 | emptyParsers();
64 | const spy = jasmine.createSpy('spy');
65 | const fieldSchema = {
66 | name: "test"
67 | };
68 |
69 | autoFormlyParser.register((fk, fs) => {
70 | spy();
71 | fs.name = "test3";
72 | });
73 | autoFormlyParser.runParsers("test", fieldSchema, {});
74 |
75 | expect(spy).toHaveBeenCalled();
76 | expect(fieldSchema.name).toBe("test");
77 | });
78 |
79 | });
80 |
81 | describe('field()', () => {
82 | it('should not be able to handle schema field with array of objects type TODO', () => {
83 | expect(autoFormlyParser.field("parent.$.child")).toBeUndefined();
84 | expect(autoFormlyParser.field("parent.$")).toBeUndefined();
85 | });
86 |
87 | it("should extend formly field based on schema's autoformly property", () => {
88 | const fieldKey = "test";
89 | const fieldSchema = {
90 | name: "test",
91 | autoformly: {
92 | type: "test"
93 | }
94 | };
95 | emptyParsers();
96 | autoFormlyParser.register((fKey, fSchema, fFormly) => {
97 | fFormly.key = fSchema.name;
98 | });
99 |
100 | expect(autoFormlyParser.field(fieldKey, fieldSchema)).toEqual({
101 | key: "test",
102 | type: "test"
103 | });
104 | });
105 |
106 | it('should run parsers', () => {
107 | const fieldKey = "test";
108 | const fieldSchema = {
109 | name: "test"
110 | };
111 |
112 | emptyParsers();
113 | autoFormlyParser.register((fKey, fSchema, fFormly) => {
114 | fFormly.key = fSchema.name;
115 | });
116 |
117 | expect(autoFormlyParser.field(fieldKey, fieldSchema)).toEqual({
118 | key: "test"
119 | });
120 | });
121 | });
122 |
123 | describe('schema()', () => {
124 | it('should be handle run parsers and reject keys with $ sign', () => {
125 | emptyParsers();
126 | autoFormlyParser.register((fKey, fSchema, fFormly) => {
127 | fFormly.key = fKey;
128 | fFormly.type = 'input';
129 | });
130 |
131 | const fields = autoFormlyParser.schema(UserSchema.schema());
132 |
133 | expect(fields.length).toBe(20);
134 | });
135 | });
136 |
137 | });
--------------------------------------------------------------------------------
/tests/client/auto-formly-spec.js:
--------------------------------------------------------------------------------
1 | describe('autoFormly', () => {
2 | //
3 | // vars
4 | //
5 |
6 | let autoFormly;
7 | let $meteor;
8 |
9 | //
10 | // helpers
11 | //
12 |
13 | function fieldExist(key, fields) {
14 | return "undefined" !== typeof _.find(fields, (field) => field.key === key)
15 | }
16 |
17 | function collectionFail(values, message) {
18 | if (!angular.isArray(values)) {
19 | values = [values];
20 | }
21 | values.forEach((value) => {
22 | expect(() => {
23 | autoFormly.collection(value);
24 | }).toThrowError(Error, `[AutoFormly] ${message}`);
25 | });
26 | }
27 |
28 | function collectionPass(values) {
29 | if (!angular.isArray(values)) {
30 | values = [values];
31 | }
32 | values.forEach((value) => {
33 | expect(() => {
34 | autoFormly.collection(value);
35 | }).not.toThrowError();
36 | });
37 | }
38 |
39 | //
40 | // tests
41 | //
42 |
43 | beforeEach(() => {
44 | module('angular-meteor');
45 | module('autoFormly');
46 |
47 | inject(function (_autoFormly_, _$meteor_) {
48 | autoFormly = _autoFormly_;
49 | $meteor = _$meteor_;
50 | });
51 | });
52 |
53 | describe("collection()", () => {
54 | it("should fail on non collection2 objects", () => {
55 | const values = [undefined, null, false, true, "", {}, "asd", 0, 1, -1];
56 | values.push(() => {
57 | });
58 | collectionFail(values, "Collection is not extended by Collection2");
59 | });
60 |
61 | it("should fail on collection not extended by Collection2", () => {
62 | collectionFail([CollectionFAIL, $meteor.collection(CollectionFAIL)], "Collection is not extended by Collection2");
63 | });
64 |
65 | it("should pass collection extended by Collection2", () => {
66 | collectionPass([CollectionOK, $meteor.collection(CollectionOK)]);
67 | });
68 | });
69 |
70 | describe("filterSchema()", () => {
71 | it("should fail when fields are not an array", () => {
72 | const values = ["s", "", 0, 1, true, false, undefined, null, {}, () => {
73 | }];
74 |
75 | values.forEach((val) => {
76 | expect(() => {
77 | autoFormly.filterSchema({}, val);
78 | }).toThrowError(Error, "[AutoFormly] Fields to filter have to be an array");
79 | });
80 | });
81 |
82 | it('should pass on array fields', () => {
83 | expect(() => {
84 | autoFormly.filterSchema({}, []);
85 | }).not.toThrowError(Error, "[AutoFormly] Fields to filter have to be an array");
86 | });
87 |
88 | it("should filter correctly", () => {
89 | const fields = autoFormly.filterSchema(UserSchema, ['username', 'createdAt']);
90 | expect(fields.username).toBeDefined();
91 | expect(fields.createdAt).toBeDefined();
92 | expect(fields.services).toBeUndefined();
93 | });
94 | });
95 |
96 | describe('schema()', () => {
97 | it("should filter correctly using object", () => {
98 | const fields = autoFormly.schema(UserSchema, {
99 | fields: {
100 | username: true,
101 | createdAt: true,
102 | services: false
103 | }
104 | });
105 | const keys = {
106 | username: false,
107 | createdAt: false,
108 | services: false
109 | };
110 |
111 | _.each(keys, (val, key) => {
112 | keys[key] = fieldExist(key, fields);
113 | });
114 |
115 | expect(keys.username).toBeTruthy();
116 | expect(keys.createdAt).toBeTruthy();
117 | expect(keys.services).toBeFalsy();
118 | });
119 |
120 | it("should extend autoformly configuration in schema", () => {
121 | const fields = autoFormly.schema(UserSchema, {
122 | fields: {
123 | username: {
124 | templateOptions: {
125 | label: "Test label"
126 | }
127 | }
128 | }
129 | });
130 | const field = _.find(fields, (field) => field.key === 'username');
131 | expect(field.templateOptions.label).toBe("Test label");
132 | });
133 |
134 | it('should show all fields excluding one', () => {
135 | // test all:true without fields
136 | const allFields = autoFormly.schema(UserSchema, {
137 | all: true
138 | });
139 |
140 | // check all:true with one field
141 | expect(autoFormly.schema(UserSchema, {
142 | all: true,
143 | fields: {
144 | username: false
145 | }
146 | }).length).toEqual(allFields.length - 1);
147 | });
148 |
149 | it('should show only specified fields', () => {
150 | const fields = autoFormly.schema(UserSchema, {
151 | all: false,
152 | fields: {
153 | username: true,
154 | createdAt: false
155 | }
156 | });
157 | expect(fieldExist('username', fields)).toBeTruthy();
158 | expect(fieldExist('createdAt', fields)).toBeFalsy();
159 | });
160 |
161 | it('should fail on non SimpleSchema objects', () => {
162 | const values = ["s", "", 0, 1, true, false, undefined, null, {}, () => {
163 | }];
164 |
165 | values.forEach((val) => {
166 | expect(() => {
167 | autoFormly.schema(val);
168 | }).toThrowError(Error, "[AutoFormly] Schema has to be instance of SimpleSchema");
169 | });
170 | });
171 | });
172 |
173 | describe("errors()", () => {
174 |
175 | it("should fail on missing fields", () => {
176 | expect(() => {
177 | autoFormly.errors(CollectionOK);
178 | }).toThrowError(Error, "[AutoFormly] Missing or invalid fields");
179 | });
180 |
181 | it("should fail on invalid fields", () => {
182 | const fields = [{}, null, true, ""];
183 | fields.forEach((field) => {
184 | expect(() => {
185 | autoFormly.errors(CollectionOK, field);
186 | }).toThrowError(Error, "[AutoFormly] Missing or invalid fields");
187 | });
188 | });
189 |
190 | it("should fail on missing collection", () => {
191 | expect(() => {
192 | autoFormly.errors(undefined, []);
193 | }).toThrowError(Error, "[AutoFormly] Collection is not extended by Collection2");
194 | });
195 |
196 | it("should fail on invalid collection", () => {
197 | expect(() => {
198 | autoFormly.errors(CollectionFAIL, []);
199 | }).toThrowError(Error, "[AutoFormly] Collection is not extended by Collection2");
200 | });
201 |
202 | it("should pass on valid collection and fields", () => {
203 | expect(() => {
204 | autoFormly.errors(CollectionOK, []);
205 | }).not.toThrowError();
206 | });
207 |
208 | describe("with collection errors", () => {
209 | const CollectionOKMock = angular.copy(CollectionOK);
210 | const fieldMock = {
211 | key: 'profile.firstname',
212 | formControl: {
213 | $setValidity() {
214 |
215 | }
216 | }
217 | };
218 | const error = {name: fieldMock.key, type: "minString"};
219 |
220 | CollectionOKMock.simpleSchema()
221 | .namedContext()
222 | .addInvalidKeys([error]);
223 |
224 | it("should set validity and properly transform error type", () => {
225 | spyOn(fieldMock.formControl, '$setValidity');
226 | autoFormly.errors(CollectionOKMock, [fieldMock]);
227 |
228 | expect(fieldMock.formControl.$setValidity).toHaveBeenCalledWith("minlength", false);
229 | });
230 |
231 | it("should fail on field without formControl", () => {
232 | spyOn(fieldMock.formControl, '$setValidity');
233 |
234 | expect(() => {
235 | autoFormly.errors(CollectionOKMock, [{key: fieldMock.key}]);
236 | }).toThrowError(Error, `[AutoFormly] Field "${fieldMock.key}" has no formControl`);
237 | expect(fieldMock.formControl.$setValidity).not.toHaveBeenCalled();
238 | });
239 | });
240 | });
241 |
242 | });
--------------------------------------------------------------------------------
/tests/client/collection.js:
--------------------------------------------------------------------------------
1 | CollectionOK = new Mongo.Collection('usersOK');
2 | CollectionFAIL = new Mongo.Collection('usersFAIL');
3 |
4 | CollectionOK.attachSchema(UserSchema);
--------------------------------------------------------------------------------
/tests/client/parsers/defaultvalue-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser defaultValue", () => {
2 | //
3 | // vars
4 | //
5 |
6 | let autoFormlyParser;
7 |
8 | //
9 | // tests
10 | //
11 |
12 | beforeEach(() => {
13 | module('autoFormly');
14 |
15 | inject((_autoFormlyParser_) => {
16 | autoFormlyParser = _autoFormlyParser_;
17 | });
18 | });
19 |
20 | it("should set default value on formly field", () => {
21 | const field = autoFormlyParser.field("test", {
22 | defaultValue: "test"
23 | });
24 |
25 | expect(field.defaultValue).toBe("test");
26 | });
27 |
28 | it("should set default value on formly field even if empty", () => {
29 | const field = autoFormlyParser.field("test", {
30 | defaultValue: ""
31 | });
32 |
33 | expect(field.defaultValue).toBe("");
34 | });
35 |
36 | it("should set default value on formly field even if equals null", () => {
37 | const field = autoFormlyParser.field("test", {
38 | defaultValue: null
39 | });
40 |
41 | expect(field.defaultValue).toBe(null);
42 | });
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/tests/client/parsers/key-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser key", () => {
2 | let autoFormlyParser;
3 |
4 | beforeEach(() => {
5 | module('autoFormly');
6 |
7 | inject((_autoFormlyParser_) => {
8 | autoFormlyParser = _autoFormlyParser_;
9 | });
10 | });
11 |
12 | it("should set key property on formly field", () => {
13 | const field = autoFormlyParser.field("test", {
14 | type: String
15 | });
16 |
17 | expect(field.key).toBe("test");
18 | });
19 | });
--------------------------------------------------------------------------------
/tests/client/parsers/template-options/label-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser templateOptions.label", () => {
2 | let autoFormlyParser;
3 |
4 | beforeEach(() => {
5 | module('autoFormly');
6 |
7 | inject((_autoFormlyParser_) => {
8 | autoFormlyParser = _autoFormlyParser_;
9 | });
10 | });
11 |
12 | it("should set label property on formly field templateOptions when schema.label exists", () => {
13 | const field = autoFormlyParser.field("test", {
14 | type: String,
15 | label: "test-label"
16 | });
17 |
18 | expect(field.templateOptions.label).toBe("test-label");
19 | });
20 |
21 | it("should set key as label property on formly field templateOptions when schema.label does not exist", () => {
22 | const field = autoFormlyParser.field("test", {
23 | type: String
24 | });
25 |
26 | expect(field.templateOptions.label).toBe("test");
27 | });
28 | });
--------------------------------------------------------------------------------
/tests/client/parsers/template-options/max-date-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser templateOptions.maxDate", () => {
2 | let autoFormlyParser;
3 |
4 | beforeEach(() => {
5 | module('autoFormly');
6 |
7 | inject((_autoFormlyParser_) => {
8 | autoFormlyParser = _autoFormlyParser_;
9 | });
10 | });
11 |
12 | it("should set templateOptions.minDate", () => {
13 | const date = new Date(1995, 11, 17);
14 | const field = autoFormlyParser.field("test", {
15 | type: Date,
16 | max: date
17 | });
18 |
19 | expect(field.templateOptions.maxDate).toEqual(date);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/tests/client/parsers/template-options/min-date-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser templateOptions.minDate", () => {
2 | let autoFormlyParser;
3 |
4 | beforeEach(() => {
5 | module('autoFormly');
6 |
7 | inject((_autoFormlyParser_) => {
8 | autoFormlyParser = _autoFormlyParser_;
9 | });
10 | });
11 |
12 | it("should set templateOptions.minDate", () => {
13 | const date = new Date(1995, 11, 17);
14 | const field = autoFormlyParser.field("test", {
15 | type: Date,
16 | min: date
17 | });
18 |
19 | expect(field.templateOptions.minDate).toEqual(date);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/tests/client/parsers/type-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers type", () => {
2 | let autoFormlyParser;
3 |
4 | beforeEach(() => {
5 | module('autoFormly');
6 |
7 | inject((_autoFormlyParser_) => {
8 | autoFormlyParser = _autoFormlyParser_;
9 | });
10 | });
11 |
12 | it("should set input as formly field type on String type", () => {
13 | const field = autoFormlyParser.field("test", {
14 | type: String
15 | });
16 |
17 | expect(field.type).toBe("input");
18 | });
19 |
20 | it("should set input as formly field type on Number type", () => {
21 | const field = autoFormlyParser.field("test", {
22 | type: Number
23 | });
24 |
25 | expect(field.type).toBe("input");
26 | });
27 |
28 | it("should set datepicker as formly field type on Date type", () => {
29 | const field = autoFormlyParser.field("test", {
30 | type: Date
31 | });
32 |
33 | expect(field.type).toBe("datepicker");
34 | });
35 |
36 | it("should not set formly field type on Array type", () => {
37 | const field = autoFormlyParser.field("test", {
38 | type: Array
39 | });
40 |
41 | expect(field.type).toBeUndefined();
42 | });
43 |
44 | it("should not set formly field type on Object type", () => {
45 | const field = autoFormlyParser.field("test", {
46 | type: Object
47 | });
48 |
49 | expect(field.type).toBeUndefined();
50 | });
51 |
52 | it('should set field type if schema.autoformly.type is defined', () => {
53 | const field = autoFormlyParser.field("test", {
54 | type: Object,
55 | autoformly: {
56 | type: "input"
57 | }
58 | });
59 |
60 | expect(field.type).toBe("input");
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/tests/client/parsers/validation/messages-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParser validation.messages", () => {
2 | //
3 | // vars
4 | //
5 |
6 | let autoFormlyParser;
7 |
8 | //
9 | // tests
10 | //
11 |
12 | beforeEach(() => {
13 | module('autoFormly');
14 |
15 | inject((_autoFormlyParser_) => {
16 | autoFormlyParser = _autoFormlyParser_;
17 | });
18 | });
19 |
20 | it("should set validation messages on formly field", () => {
21 | const field = autoFormlyParser.field("test", {
22 | autoformly: {
23 | validation: {
24 | messages: {
25 | required: true
26 | }
27 | }
28 | }
29 | });
30 |
31 | expect(field.validation.messages.required).toBe(true);
32 | });
33 |
34 | });
35 |
--------------------------------------------------------------------------------
/tests/client/parsers/validators/allowed-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators allowed", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set allowed validator on schema field with allowed values", () => {
15 | const allowedValues = ['foo', 'bar'];
16 | const field = autoFormlyParser.field("test", {
17 | type: String,
18 | allowedValues: allowedValues
19 | });
20 |
21 | expect(formlyValidator.getFieldValidator(field, 'allowed')).toEqual(allowedValues);
22 | });
23 |
24 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/maxlength-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators maxlength", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set maxlength validator on String with min value", () => {
15 | const field = autoFormlyParser.field("test", {
16 | type: String,
17 | max: 10
18 | });
19 |
20 | expect(formlyValidator.getFieldValidator(field, 'maxlength')).toEqual(10);
21 | });
22 |
23 | it("should set maxlength validator on String with min and max values", () => {
24 | const field = autoFormlyParser.field("test", {
25 | type: String,
26 | min: 10,
27 | max: 20
28 | });
29 |
30 | expect(formlyValidator.getFieldValidator(field, 'maxlength')).toEqual(20);
31 | });
32 |
33 | it("should not set maxlength validator on String without max value", () => {
34 | const field = autoFormlyParser.field("test", {
35 | type: String,
36 | min: 20
37 | });
38 |
39 | expect(formlyValidator.getFieldValidator(field, 'maxlength')).toBeUndefined();
40 | });
41 |
42 | it("should not set maxlength validator on Number with min value", () => {
43 | const field = autoFormlyParser.field("test", {
44 | type: Number,
45 | max: 20
46 | });
47 |
48 | expect(formlyValidator.getFieldValidator(field, 'maxlength')).toBeUndefined();
49 | });
50 |
51 | it("should not set maxlength validator on Date with min value", () => {
52 | const field = autoFormlyParser.field("test", {
53 | type: Date,
54 | max: 20
55 | });
56 |
57 | expect(formlyValidator.getFieldValidator(field, 'maxlength')).toBeUndefined();
58 | });
59 |
60 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/maxnumber-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators maxnumber", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set maxnumber validator on Number with max value", () => {
15 | const field = autoFormlyParser.field("test", {
16 | type: Number,
17 | max: 10
18 | });
19 |
20 | expect(formlyValidator.getFieldValidator(field, 'maxnumber')).toEqual(10);
21 | });
22 |
23 | it("should set maxnumber validator on Number with max and min values", () => {
24 | const field = autoFormlyParser.field("test", {
25 | type: Number,
26 | min: 10,
27 | max: 20
28 | });
29 |
30 | expect(formlyValidator.getFieldValidator(field, 'maxnumber')).toEqual(20);
31 | });
32 |
33 | it("should not set maxnumber validator on Number without max value", () => {
34 | const field = autoFormlyParser.field("test", {
35 | type: Number,
36 | min: 20
37 | });
38 |
39 | expect(formlyValidator.getFieldValidator(field, 'maxnumber')).toBeUndefined();
40 | });
41 |
42 | it("should not set maxnumber validator on String with max value", () => {
43 | const field = autoFormlyParser.field("test", {
44 | type: String,
45 | max: 20
46 | });
47 |
48 | expect(formlyValidator.getFieldValidator(field, 'maxnumber')).toBeUndefined();
49 | });
50 |
51 | it("should not set maxnumber validator on Date with max value", () => {
52 | const field = autoFormlyParser.field("test", {
53 | type: Date,
54 | max: 20
55 | });
56 |
57 | expect(formlyValidator.getFieldValidator(field, 'maxnumber')).toBeUndefined();
58 | });
59 |
60 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/minlength-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators minlength", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set minlength validator on String with min value", () => {
15 | const field = autoFormlyParser.field("test", {
16 | type: String,
17 | min: 10
18 | });
19 |
20 | expect(formlyValidator.getFieldValidator(field, 'minlength')).toEqual(10);
21 | });
22 |
23 | it("should set minlength validator on String with min and max value", () => {
24 | const field = autoFormlyParser.field("test", {
25 | type: String,
26 | min: 10,
27 | max: 20
28 | });
29 |
30 | expect(formlyValidator.getFieldValidator(field, 'minlength')).toEqual(10);
31 | });
32 |
33 | it("should not set minlength validator on String without min value", () => {
34 | const field = autoFormlyParser.field("test", {
35 | type: String,
36 | max: 20
37 | });
38 |
39 | expect(formlyValidator.getFieldValidator(field, 'minlength')).toBeUndefined();
40 | });
41 |
42 | it("should not set minlength validator on Number with min value", () => {
43 | const field = autoFormlyParser.field("test", {
44 | type: Number,
45 | min: 20
46 | });
47 |
48 | expect(formlyValidator.getFieldValidator(field, 'minlength')).toBeUndefined();
49 | });
50 |
51 | it("should not set minlength validator on Date with min value", () => {
52 | const field = autoFormlyParser.field("test", {
53 | type: Date,
54 | min: 20
55 | });
56 |
57 | expect(formlyValidator.getFieldValidator(field, 'minlength')).toBeUndefined();
58 | });
59 |
60 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/minnumber-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators minnumber", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set minnumber validator on Number with min value", () => {
15 | const field = autoFormlyParser.field("test", {
16 | type: Number,
17 | min: 10
18 | });
19 |
20 | expect(formlyValidator.getFieldValidator(field, 'minnumber')).toEqual(10);
21 | });
22 |
23 | it("should set minnumber validator on Number with min and max value", () => {
24 | const field = autoFormlyParser.field("test", {
25 | type: Number,
26 | min: 10,
27 | max: 20
28 | });
29 |
30 | expect(formlyValidator.getFieldValidator(field, 'minnumber')).toEqual(10);
31 | });
32 |
33 | it("should not set minnumber validator on Number without min value", () => {
34 | const field = autoFormlyParser.field("test", {
35 | type: Number,
36 | max: 20
37 | });
38 |
39 | expect(formlyValidator.getFieldValidator(field, 'minnumber')).toBeUndefined();
40 | });
41 |
42 | it("should not set minnumber validator on String with min value", () => {
43 | const field = autoFormlyParser.field("test", {
44 | type: String,
45 | min: 20
46 | });
47 |
48 | expect(formlyValidator.getFieldValidator(field, 'minnumber')).toBeUndefined();
49 | });
50 |
51 | it("should not set minnumber validator on Date with min value", () => {
52 | const field = autoFormlyParser.field("test", {
53 | type: Date,
54 | min: 20
55 | });
56 |
57 | expect(formlyValidator.getFieldValidator(field, 'minnumber')).toBeUndefined();
58 | });
59 |
60 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/pattern-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators pattern", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set pattern validator on schema.regEx", () => {
15 | const field = autoFormlyParser.field("test", {
16 | regEx: SimpleSchema.RegEx.Email
17 | });
18 |
19 | expect(formlyValidator.getFieldValidator(field, 'pattern')).toEqual(SimpleSchema.RegEx.Email);
20 | });
21 |
22 | it("should not set pattern validator on missing schema.regEx", () => {
23 | const field = autoFormlyParser.field("test", {});
24 |
25 | expect(formlyValidator.getFieldValidator(field, 'pattern')).toBeUndefined();
26 | });
27 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/required-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators required", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set required validator on optional:false", () => {
15 | const field = autoFormlyParser.field("test", {
16 | optional: false
17 | });
18 |
19 | expect(field.transformers.validators.required).toBeTruthy();
20 | });
21 |
22 | it("should set required validator on missing optional property", () => {
23 | const field = autoFormlyParser.field("test", {});
24 |
25 | expect(formlyValidator.getFieldValidator(field, 'required')).toBeTruthy();
26 | });
27 |
28 | it("should not set required validator on optional:true", () => {
29 | const field = autoFormlyParser.field("test", {
30 | optional: true
31 | });
32 |
33 | expect(formlyValidator.getFieldValidator(field, 'required')).toBeUndefined();
34 | });
35 | });
--------------------------------------------------------------------------------
/tests/client/parsers/validators/unique-spec.js:
--------------------------------------------------------------------------------
1 | describe("autoFormlyParsers validators unique", () => {
2 | let autoFormlyParser;
3 | let formlyValidator;
4 |
5 | beforeEach(() => {
6 | module('autoFormly');
7 |
8 | inject((_autoFormlyParser_, _formlyValidator_) => {
9 | autoFormlyParser = _autoFormlyParser_;
10 | formlyValidator = _formlyValidator_;
11 | });
12 | });
13 |
14 | it("should set allowed validator on schema field with allowed values", () => {
15 | const field = autoFormlyParser.field("test", {
16 | type: String,
17 | unique: true
18 | });
19 |
20 | expect(formlyValidator.getFieldValidator(field, 'unique')).toEqual(true);
21 | });
22 |
23 | });
--------------------------------------------------------------------------------
/tests/client/schema.js:
--------------------------------------------------------------------------------
1 | const userProfile = new SimpleSchema({
2 | firstname: {
3 | type: String,
4 | min: 3,
5 | max: 10
6 | },
7 | lastname: {
8 | type: String,
9 | min: 5,
10 | max: 15
11 | },
12 | birthday: {
13 | type: Date,
14 | optional: true
15 | },
16 | gender: {
17 | type: String,
18 | allowedValues: ['Male', 'Female'],
19 | optional: true,
20 | defaultValue: "Male"
21 | },
22 | language: {
23 | type: String,
24 | allowedValues: ['PL', 'EN'],
25 | defaultValue: 'EN',
26 | optional: true
27 | }
28 | });
29 |
30 | const userLinkedServices = new SimpleSchema({
31 | facebook: {
32 | type: Boolean,
33 | defaultValue: false
34 | },
35 | google: {
36 | type: Boolean,
37 | defaultValue: false
38 | },
39 | profile: {
40 | type: userProfile
41 | }
42 | });
43 |
44 | /**
45 | * Users schema
46 | * @type {SimpleSchema}
47 | */
48 | UserSchema = new SimpleSchema({
49 | username: {
50 | type: String,
51 | optional: true
52 | },
53 | registered_emails: {
54 | type: [Object],
55 | blackbox: true,
56 | optional: true
57 | },
58 | emails: {
59 | type: Array,
60 | optional: true
61 | },
62 | "emails.$": {
63 | type: Object
64 | },
65 | "emails.$.address": {
66 | type: String,
67 | regEx: SimpleSchema.RegEx.Email
68 | },
69 | "emails.$.verified": {
70 | type: Boolean
71 | },
72 | createdAt: {
73 | type: Date
74 | },
75 | profile: {
76 | type: userProfile
77 | },
78 | linkedServices: {
79 | type: userLinkedServices
80 | },
81 | // Make sure this services field is in your schema if you're using any of the accounts packages
82 | services: {
83 | type: Object,
84 | optional: true,
85 | blackbox: true
86 | }
87 | });
--------------------------------------------------------------------------------