├── demo
├── .meteor
│ ├── .gitignore
│ ├── release
│ ├── platforms
│ ├── .id
│ ├── .finished-upgraders
│ ├── packages
│ └── versions
├── client
│ ├── components
│ │ ├── demo-index
│ │ │ ├── demo-index.html
│ │ │ └── demo-index.js
│ │ ├── side-menu
│ │ │ ├── side-menu.css
│ │ │ ├── side-menu.html
│ │ │ └── side-menu.js
│ │ ├── menu-heading
│ │ │ ├── menu-heading.html
│ │ │ ├── menu-heading.css
│ │ │ └── menu-heading.js
│ │ ├── menu-link
│ │ │ ├── menu-link.html
│ │ │ ├── menu-link.css
│ │ │ └── menu-link.js
│ │ ├── demo
│ │ │ ├── demo.css
│ │ │ ├── demo.html
│ │ │ └── demo.js
│ │ ├── demo-view-form
│ │ │ ├── demo-view-form.html
│ │ │ └── demo-view-form.js
│ │ ├── side-menu-item
│ │ │ ├── side-menu-item.css
│ │ │ ├── side-menu-item.html
│ │ │ └── side-menu-item.js
│ │ ├── menu-toggle
│ │ │ ├── menu-toggle.html
│ │ │ ├── menu-toggle.css
│ │ │ └── menu-toggle.js
│ │ ├── demo-view-source
│ │ │ ├── demo-view-source.html
│ │ │ └── demo-view-source.js
│ │ └── demo-view
│ │ │ ├── demo-view.html
│ │ │ └── demo-view.js
│ ├── index.html
│ └── data
│ │ ├── examples
│ │ ├── switch.js
│ │ ├── checkbox.js
│ │ ├── label.js
│ │ ├── chips.js
│ │ ├── textarea.js
│ │ ├── slider.js
│ │ ├── radio.js
│ │ ├── select.js
│ │ ├── divider.js
│ │ └── input.js
│ │ ├── examples.js
│ │ ├── menu.js
│ │ └── codepen.js
└── .eslintrc
├── tests
├── runs
│ ├── index.js
│ └── class-name-spec.js
├── helpers
│ ├── index.js
│ └── ng-model-attrs-manipulator-spec.js
├── index-spec.js
├── wrappers
│ ├── index.js
│ ├── input-container-spec.js
│ ├── messages-spec.js
│ ├── divider-spec.js
│ └── label-spec.js
├── test-utils.js
└── types
│ ├── index.js
│ ├── checkbox-spec.js
│ ├── switch-spec.js
│ ├── slider-spec.js
│ ├── datepicker-spec.js
│ ├── textarea-spec.js
│ ├── chips-spec.js
│ ├── radio-spec.js
│ ├── input-spec.js
│ └── select-spec.js
├── src
├── types
│ ├── input
│ │ ├── input.html
│ │ └── input.js
│ ├── textarea
│ │ ├── textarea.html
│ │ └── textarea.js
│ ├── slider
│ │ ├── slider.html
│ │ └── slider.js
│ ├── chips
│ │ ├── chips.html
│ │ └── chips.js
│ ├── switch
│ │ ├── switch.html
│ │ └── switch.js
│ ├── datepicker
│ │ ├── datepicker.html
│ │ └── datepicker.js
│ ├── checkbox
│ │ ├── checkbox.html
│ │ └── checkbox.js
│ ├── select
│ │ ├── select.html
│ │ └── select.js
│ ├── radio
│ │ ├── radio.html
│ │ └── radio.js
│ └── index.js
├── runs
│ ├── index.js
│ └── class-name.js
├── wrappers
│ ├── input-container
│ │ ├── input-container.html
│ │ └── input-container.js
│ ├── divider
│ │ ├── divider.html
│ │ └── divider.js
│ ├── messages
│ │ ├── messages.js
│ │ └── messages.html
│ ├── label
│ │ ├── label.html
│ │ └── label.js
│ └── index.js
├── index.js
└── helpers
│ └── index.js
├── docs
├── wrappers
│ ├── messages.md
│ ├── label.md
│ ├── input-container.md
│ └── divider.md
└── types
│ ├── switch.md
│ ├── checkbox.md
│ ├── textarea.md
│ ├── input.md
│ ├── slider.md
│ ├── radio.md
│ ├── datepicker.md
│ ├── select.md
│ └── chips.md
├── .eslintignore
├── webpack
├── dist.js
├── index.js
├── prod.js
├── test.js
└── common.js
├── webpack.config.js
├── .npmignore
├── .editorconfig
├── .eslintrc
├── bower.json
├── package.js
├── LICENSE
├── .travis.yml
├── .gitignore
├── karma.conf.js
├── package.json
├── README.md
├── CHANGELOG.md
└── dist
├── formly-material.min.js
└── formly-material.js
/demo/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/demo/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@1.2.1
2 |
--------------------------------------------------------------------------------
/demo/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/tests/runs/index.js:
--------------------------------------------------------------------------------
1 | import './class-name-spec';
2 |
--------------------------------------------------------------------------------
/src/types/input/input.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/client/components/demo-index/demo-index.html:
--------------------------------------------------------------------------------
1 | Getting started!
2 |
--------------------------------------------------------------------------------
/tests/helpers/index.js:
--------------------------------------------------------------------------------
1 | import './ng-model-attrs-manipulator-spec';
2 |
--------------------------------------------------------------------------------
/src/types/textarea/textarea.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/wrappers/messages.md:
--------------------------------------------------------------------------------
1 | messages
2 | ========
3 |
4 | ng-messages
5 | -----------
6 |
--------------------------------------------------------------------------------
/src/runs/index.js:
--------------------------------------------------------------------------------
1 | import className from './class-name';
2 |
3 | export default [className];
4 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu/side-menu.css:
--------------------------------------------------------------------------------
1 | side-menu ul {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
--------------------------------------------------------------------------------
/demo/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./../.eslintrc",
3 | "globals": {
4 | "angular": false
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/docs/wrappers/label.md:
--------------------------------------------------------------------------------
1 | label
2 | =====
3 |
4 | label
5 | -----
6 |
7 | ### templateOptions.label *{String}*
8 |
--------------------------------------------------------------------------------
/src/types/slider/slider.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | docs
3 | node_modules
4 | webpack
5 | package.js
6 | karma.conf.js
7 | webpack.config.js
8 |
--------------------------------------------------------------------------------
/docs/wrappers/input-container.md:
--------------------------------------------------------------------------------
1 | input-container
2 | ===============
3 |
4 | md-input-container
5 | ------------------
6 |
--------------------------------------------------------------------------------
/webpack/dist.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./common')({
2 | output: {
3 | filename: '[name].js'
4 | }
5 | });
6 |
--------------------------------------------------------------------------------
/demo/client/components/menu-heading/menu-heading.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/types/chips/chips.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/types/switch/switch.html:
--------------------------------------------------------------------------------
1 |
2 | {{to.label}}
3 |
4 |
--------------------------------------------------------------------------------
/tests/index-spec.js:
--------------------------------------------------------------------------------
1 | import './../src';
2 |
3 | import './helpers';
4 | import './runs';
5 | import './types';
6 | import './wrappers';
7 |
--------------------------------------------------------------------------------
/tests/wrappers/index.js:
--------------------------------------------------------------------------------
1 | import './input-container-spec';
2 | import './label-spec';
3 | import './messages-spec';
4 | import './divider-spec';
5 |
--------------------------------------------------------------------------------
/src/types/datepicker/datepicker.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/wrappers/input-container/input-container.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/types/checkbox/checkbox.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{to.label}}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | require('argv-set-env')();
2 | var webpack = require('./webpack')(process.env.NODE_ENV === 'production' ? 'prod' : 'dist');
3 |
4 | module.exports = webpack;
5 |
--------------------------------------------------------------------------------
/demo/client/components/menu-link/menu-link.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu/side-menu.html:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/wrappers/divider/divider.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | coverage
3 | demo
4 | node_modules
5 | bower_components
6 | src
7 | tests
8 | webpack
9 | .editorconfig
10 | .eslintrc
11 | .travis.yml
12 | karma.conf.js
13 | package.js
14 | webpack.config.js
15 |
--------------------------------------------------------------------------------
/demo/client/components/demo/demo.css:
--------------------------------------------------------------------------------
1 | #demo-sidenav {
2 | background: #35176A;
3 | }
4 |
5 | #demo-sidenav-content {
6 | background: transparent;
7 | }
8 |
9 | .purple-headline {
10 | color: #673AB7;
11 | }
12 |
--------------------------------------------------------------------------------
/tests/test-utils.js:
--------------------------------------------------------------------------------
1 | export default class testUtils {
2 | static getFormTemplate() {
3 | return ``;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/wrappers/messages/messages.js:
--------------------------------------------------------------------------------
1 | import template from './messages.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setWrapper({
5 | template,
6 | name: 'messages'
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/src/wrappers/input-container/input-container.js:
--------------------------------------------------------------------------------
1 | import template from './input-container.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setWrapper({
5 | template,
6 | name: 'inputContainer'
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/webpack/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(type) {
2 | const types = ['dist', 'prod', 'test'];
3 |
4 | if (types.indexOf(type) === -1) {
5 | throw new Error('Unknown webpack configuration');
6 | }
7 |
8 | return require('./' + type);
9 | };
10 |
--------------------------------------------------------------------------------
/src/types/select/select.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ option[to.labelProp || 'name'] }}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/wrappers/label/label.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/webpack/prod.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 |
3 | module.exports = require('./common')({
4 | output: {
5 | filename: '[name].min.js'
6 | },
7 | devtool: 'source-map',
8 | plugins: [
9 | new webpack.optimize.UglifyJsPlugin()
10 | ]
11 | });
12 |
--------------------------------------------------------------------------------
/demo/client/components/menu-heading/menu-heading.css:
--------------------------------------------------------------------------------
1 | menu-heading .menu-heading {
2 | display: block;
3 | line-height: 32px;
4 | margin: 0;
5 | padding: 8px 16px;
6 | text-align: left;
7 | color: rgba(255, 255, 255, 0.6);
8 | text-transform: uppercase;
9 | }
10 |
--------------------------------------------------------------------------------
/tests/types/index.js:
--------------------------------------------------------------------------------
1 | import './checkbox-spec';
2 | import './chips-spec';
3 | import './datepicker-spec';
4 | import './input-spec';
5 | import './radio-spec';
6 | import './select-spec';
7 | import './slider-spec';
8 | import './switch-spec';
9 | import './textarea-spec';
10 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view-form/demo-view-form.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu-item/side-menu-item.css:
--------------------------------------------------------------------------------
1 | side-menu ul.side-menu > li.opened {
2 | background: #432677;
3 | }
4 |
5 | side-menu ul.side-menu > li {
6 | border-bottom: 1px solid #673AB7;
7 | }
8 |
9 | side-menu ul.side-menu > li:last-child {
10 | border-bottom: 0 none;
11 | }
12 |
--------------------------------------------------------------------------------
/src/wrappers/messages/messages.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | {{message(fc.$viewValue, fc.$modelValue, this)}}
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/client/components/menu-toggle/menu-toggle.html:
--------------------------------------------------------------------------------
1 |
4 |
9 |
--------------------------------------------------------------------------------
/src/wrappers/label/label.js:
--------------------------------------------------------------------------------
1 | import template from './label.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setWrapper({
5 | template,
6 | name: 'label',
7 | apiCheck: (check) => ({
8 | templateOptions: {
9 | label: check.string
10 | }
11 | })
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu/side-menu.js:
--------------------------------------------------------------------------------
1 | const { Component, View } = angular2now;
2 |
3 | @Component({
4 | selector: 'side-menu',
5 | bind: {
6 | menu: '='
7 | }
8 | })
9 | @View({
10 | templateUrl: 'client/components/side-menu/side-menu.html'
11 | })
12 | class SideMenuComponent {
13 | constructor() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo/client/index.html:
--------------------------------------------------------------------------------
1 |
2 | FormlyMaterial demo
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/wrappers/divider.md:
--------------------------------------------------------------------------------
1 | divider
2 | =======
3 |
4 | md-divider
5 | ----------
6 |
7 | ### templateOptions.divider *{String}*
8 |
9 | Expects one of:
10 |
11 | - **after** (default) - moves divider after the field or other wrappers
12 | - **before** - moves divider before the field or other wrappers
13 |
14 | Make sure you use lower cases
15 |
--------------------------------------------------------------------------------
/demo/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | fy74xsbb3je312muj19
8 |
--------------------------------------------------------------------------------
/demo/client/components/menu-heading/menu-heading.js:
--------------------------------------------------------------------------------
1 | const { Component, View } = angular2now;
2 |
3 | @Component({
4 | selector: 'menu-heading',
5 | bind: {
6 | name: '='
7 | }
8 | })
9 | @View({
10 | templateUrl: 'client/components/menu-heading/menu-heading.html'
11 | })
12 | class MenuHeadingComponent {
13 | constructor() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/types/radio/radio.html:
--------------------------------------------------------------------------------
1 |
2 |
6 | {{option[to.labelProp || 'name']}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/wrappers/divider/divider.js:
--------------------------------------------------------------------------------
1 | import template from './divider.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setWrapper({
5 | template,
6 | name: 'divider',
7 | apiCheck: (check) => ({
8 | templateOptions: {
9 | divider: check.oneOf(['before', 'after']).optional
10 | }
11 | })
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/src/wrappers/index.js:
--------------------------------------------------------------------------------
1 | import inputContainerWrapper from './input-container/input-container';
2 | import labelWrapper from './label/label';
3 | import messagesWrapper from './messages/messages';
4 | import dividerWrapper from './divider/divider';
5 |
6 | export default [
7 | inputContainerWrapper,
8 | labelWrapper,
9 | messagesWrapper,
10 | dividerWrapper
11 | ];
12 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view-source/demo-view-source.html:
--------------------------------------------------------------------------------
1 | Scope
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/client/components/demo-index/demo-index.js:
--------------------------------------------------------------------------------
1 | const { Component, View, State } = angular2now;
2 |
3 | @Component({
4 | selector: 'demo-index'
5 | })
6 | @View({
7 | templateUrl: 'client/components/demo-index/demo-index.html'
8 | })
9 | @State({
10 | name: 'demo.index',
11 | url: '/',
12 | defaultRoute: '/demo/'
13 | })
14 | class DemoIndexComponent {
15 | constructor() {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/webpack/test.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./common')({
2 | entry: './tests/index-spec.js',
3 | output: undefined,
4 | module: {
5 | loaders: [
6 | // transpile and instrument only testing sources with isparta
7 | {
8 | test: /\.js$/,
9 | include: /src/,
10 | exclude: /node_modules/,
11 | loader: 'isparta'
12 | }
13 | ]
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/demo/client/components/menu-link/menu-link.css:
--------------------------------------------------------------------------------
1 | menu-link .menu-link {
2 | border-radius: 0;
3 | color: white;
4 | cursor: pointer;
5 | display: block;
6 | align-items: inherit;
7 | line-height: 40px;
8 | margin: 0;
9 | max-height: 40px;
10 | overflow: hidden;
11 | padding: 0px 16px;
12 | text-align: left;
13 | text-decoration: none;
14 | white-space: normal;
15 | width: 100%;
16 | }
17 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view-form/demo-view-form.js:
--------------------------------------------------------------------------------
1 | const { Component, View } = angular2now;
2 |
3 | @Component({
4 | selector: 'demo-view-form',
5 | bind: {
6 | fields: '=',
7 | model: '=?',
8 | options: '=?',
9 | form: '=?'
10 | }
11 | })
12 | @View({
13 | templateUrl: 'client/components/demo-view-form/demo-view-form.html'
14 | })
15 | class DemoViewFormComponent {
16 | constructor() {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is Awesome: http://editorconfig.org
2 |
3 | # Top-most EditorConfig file.
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file.
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | charset = utf-8
11 | indent_style = space
12 | indent_size = 2
13 | trim_trailing_whitespace = true
14 |
15 | # Don't trim whitespace in Markdown in order to be able
16 | # to do two spaces for line breaks.
17 | [*.md]
18 | trim_trailing_whitespace = false
19 |
--------------------------------------------------------------------------------
/demo/client/components/menu-toggle/menu-toggle.css:
--------------------------------------------------------------------------------
1 | menu-toggle .menu-toggle {
2 | border-radius: 0;
3 | color: white;
4 | cursor: pointer;
5 | display: block;
6 | align-items: inherit;
7 | line-height: 40px;
8 | margin: 0;
9 | max-height: 40px;
10 | overflow: hidden;
11 | padding: 0px 16px;
12 | text-align: left;
13 | text-decoration: none;
14 | white-space: normal;
15 | width: 100%;
16 | }
17 |
18 | menu-toggle menu-link .menu-link {
19 | padding: 0px 16px 0 32px;
20 | }
21 |
--------------------------------------------------------------------------------
/docs/types/switch.md:
--------------------------------------------------------------------------------
1 | # switch
2 | ## md-switch
3 |
4 | ### Example
5 |
6 | ```javascript
7 | {
8 | type: "switch",
9 | key: "terms",
10 | templateOptions: {
11 | label: "Terms and Conditions",
12 | theme: "custom"
13 | }
14 | }
15 | ```
16 |
17 | ### Configuration
18 |
19 | #### templateOptions.label _: string_
20 |
21 | #### templateOptions.theme _: string_
22 |
23 | #### templateOptions.disabled _: boolean_
24 |
25 | #### templateOptions.className _: string | expression | array_
26 |
--------------------------------------------------------------------------------
/src/runs/class-name.js:
--------------------------------------------------------------------------------
1 | import { ngModelAttrsTransformer } from './../helpers';
2 |
3 | export default (formlyConfigProvider) => {
4 | // add only step attribute because min and max are both built-in
5 | formlyConfigProvider.extras.fieldTransform.push((fields) => {
6 | return ngModelAttrsTransformer(fields, (field) => (
7 | field.templateOptions && typeof field.templateOptions.className !== 'undefined'
8 | ), 'className', {
9 | bound: 'ng-class'
10 | });
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/src/types/radio/radio.js:
--------------------------------------------------------------------------------
1 | import template from './radio.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'radio',
7 | wrapper: ['label'],
8 | apiCheck: (check) => ({
9 | templateOptions: {
10 | options: check.arrayOf(check.object),
11 | labelProp: check.string.optional,
12 | valueProp: check.string.optional,
13 | theme: check.string.optional
14 | }
15 | })
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/docs/types/checkbox.md:
--------------------------------------------------------------------------------
1 | # checkbox
2 | ## md-checkbox
3 |
4 | ### Example
5 |
6 | ```javascript
7 | {
8 | type: "checkbox",
9 | key: "terms",
10 | templateOptions: {
11 | label: "Terms and Conditions",
12 | theme: "custom"
13 | }
14 | }
15 | ```
16 |
17 | ### Configuration
18 |
19 | #### templateOptions.label _: string_
20 |
21 | #### templateOptions.theme _: string_
22 |
23 | #### templateOptions.disabled _: boolean_
24 |
25 | #### templateOptions.className _: string | expression | array_
26 |
--------------------------------------------------------------------------------
/demo/client/data/examples/switch.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | type: 'switch',
8 | key: 'terms',
9 | templateOptions: {
10 | label: 'Terms and conditions'
11 | }
12 | });
13 |
14 | // set example
15 | Examples.set('switch', {
16 | fields
17 | }, 'types/switch.md');
18 |
19 | // add menu item to types
20 | Menu.addChild('types', 'switch');
21 | }]);
22 |
--------------------------------------------------------------------------------
/demo/client/data/examples/checkbox.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | key: 'terms',
8 | type: 'checkbox',
9 | templateOptions: {
10 | label: 'Terms and Conditions'
11 | }
12 | });
13 |
14 | // set example
15 | Examples.set('checkbox', {
16 | fields
17 | }, 'types/checkbox.md');
18 |
19 | // add menu item to types
20 | Menu.addChild('types', 'checkbox');
21 | }]);
22 |
--------------------------------------------------------------------------------
/src/types/checkbox/checkbox.js:
--------------------------------------------------------------------------------
1 | import template from './checkbox.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'checkbox',
7 | defaultOptions: {
8 | ngModelAttrs: {
9 | disabled: {
10 | bound: 'ng-disabled'
11 | }
12 | }
13 | },
14 | apiCheck: (check) => ({
15 | templateOptions: {
16 | disabled: check.bool.optional,
17 | theme: check.string.optional
18 | }
19 | })
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/demo/client/data/examples/label.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | key: 'terms',
8 | type: 'switch',
9 | wrapper: ['label'],
10 | templateOptions: {
11 | label: 'Terms and conditions'
12 | }
13 | });
14 |
15 | // set example
16 | Examples.set('label', {
17 | fields
18 | }, 'wrappers/label.md');
19 |
20 | // add menu item to wrappers
21 | Menu.addChild('wrappers', 'label');
22 | }]);
23 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view/demo-view.html:
--------------------------------------------------------------------------------
1 |
2 | Example
3 | Go to API
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/types/switch/switch.js:
--------------------------------------------------------------------------------
1 | import template from './switch.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'switch',
7 | defaultOptions: {
8 | templateOptions: {
9 | disabled: false
10 | },
11 | ngModelAttrs: {
12 | disabled: {
13 | bound: 'ng-disabled'
14 | }
15 | }
16 | },
17 | apiCheck: (check) => ({
18 | templateOptions: {
19 | disabled: check.bool.optional,
20 | theme: check.string.optional
21 | }
22 | })
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/demo/client/data/examples/chips.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | type: 'chips',
8 | key: 'tags',
9 | templateOptions: {
10 | placeholder: '+tags',
11 | secondaryPlaceholder: 'Add tag',
12 | deleteButtonLabel: 'Remove',
13 | deleteHint: 'Remove tag'
14 | }
15 | });
16 |
17 | // set example
18 | Examples.set('chips', {
19 | fields
20 | }, 'types/chips.md');
21 |
22 | // add menu item to types
23 | Menu.addChild('types', 'chips');
24 | }]);
25 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 |
3 | import runs from './runs';
4 | import wrappers from './wrappers';
5 | import types from './types';
6 |
7 | const ngModuleName = 'formlyMaterial';
8 |
9 | angular.module(ngModuleName, ['ngMessages', 'ngMaterial', 'formly'])
10 | .config(['formlyConfigProvider', (formlyConfigProvider) => {
11 | const configs = [runs, wrappers, types];
12 |
13 | configs.forEach((config) => {
14 | let i = 0;
15 | for (; i < config.length; i++) {
16 | config[i](formlyConfigProvider);
17 | }
18 | });
19 | }]);
20 |
21 | export default ngModuleName;
22 |
--------------------------------------------------------------------------------
/src/types/index.js:
--------------------------------------------------------------------------------
1 | import checkboxType from './checkbox/checkbox';
2 | import chipsType from './chips/chips';
3 | import datepickerType from './datepicker/datepicker';
4 | import inputType from './input/input';
5 | import radioType from './radio/radio';
6 | import selectType from './select/select';
7 | import sliderType from './slider/slider';
8 | import switchType from './switch/switch';
9 | import textareaType from './textarea/textarea';
10 |
11 | export default [
12 | checkboxType,
13 | chipsType,
14 | datepickerType,
15 | inputType,
16 | radioType,
17 | selectType,
18 | sliderType,
19 | switchType,
20 | textareaType
21 | ];
22 |
--------------------------------------------------------------------------------
/demo/client/components/menu-link/menu-link.js:
--------------------------------------------------------------------------------
1 | const { Component, View, Inject } = angular2now;
2 |
3 | @Component({
4 | selector: 'menu-link',
5 | bind: {
6 | sectionId: '=',
7 | sectionName: '=',
8 | }
9 | })
10 | @View({
11 | templateUrl: 'client/components/menu-link/menu-link.html'
12 | })
13 | @Inject(['$mdSidenav'])
14 | class MenuLinkComponent {
15 | constructor($mdSidenav) {
16 | this.$mdSidenav = $mdSidenav;
17 |
18 | this.componentId = 'left';
19 | }
20 |
21 | close() {
22 | if (!this.$mdSidenav(this.componentId).isLockedOpen()) {
23 | this.$mdSidenav(this.componentId).close();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu-item/side-menu-item.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/client/data/examples/textarea.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | key: 'text-grow',
8 | type: 'textarea',
9 | templateOptions: {
10 | label: 'Growing textarea'
11 | }
12 | });
13 |
14 | fields.push({
15 | key: 'text-notgrow',
16 | type: 'textarea',
17 | templateOptions: {
18 | label: 'Not growing textarea',
19 | grow: false
20 | }
21 | });
22 |
23 | // set example
24 | Examples.set('textarea', {
25 | fields
26 | }, 'types/textarea.md');
27 |
28 | // add menu item to types
29 | Menu.addChild('types', 'textarea');
30 | }]);
31 |
--------------------------------------------------------------------------------
/demo/client/components/side-menu-item/side-menu-item.js:
--------------------------------------------------------------------------------
1 | const { Component, View, Inject } = angular2now;
2 |
3 | @Component({
4 | selector: 'side-menu-item',
5 | replace: true,
6 | bind: {
7 | section: '='
8 | }
9 | })
10 | @View({
11 | templateUrl: 'client/components/side-menu-item/side-menu-item.html'
12 | })
13 | @Inject(['$animate', '$element'])
14 | class SideMenuItemComponent {
15 | constructor($animate, $element) {
16 | this.$animate = $animate;
17 | this.$element = $element;
18 |
19 | this.opened = false;
20 | }
21 |
22 | onOpen() {
23 | this.$animate.addClass(this.$element, 'opened');
24 | this.opened = true;
25 | }
26 |
27 | onClose() {
28 | this.$animate.removeClass(this.$element, 'opened');
29 | this.opened = false;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docs/types/textarea.md:
--------------------------------------------------------------------------------
1 | textarea
2 | ========
3 |
4 | textarea
5 | --------
6 |
7 | ### Example
8 |
9 | ```javascript
10 | {
11 | type: "textarea",
12 | key: "bio",
13 | templateOptions: {
14 | label: "Biography",
15 | theme: "custom",
16 | rows: 5,
17 | grow: false
18 | }
19 | }
20 | ```
21 |
22 | #### Configuration
23 |
24 | #### templateOptions.label *: string*
25 |
26 | #### templateOptions.theme *: string*
27 |
28 | #### templateOptions.disabled _: boolean_
29 |
30 | #### templateOptions.className _: string | expression | array_
31 |
32 | #### templateOptions.rows *: integer*
33 |
34 | Number of rows
35 |
36 | #### templateOptions.grow *: boolean (default true)*
37 |
38 | Equivalent to md-no-autogrow
39 |
40 | When present, textareas will not grow automatically.
41 |
--------------------------------------------------------------------------------
/demo/client/data/examples/slider.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | type: 'slider',
8 | key: 'rate-discrete',
9 | templateOptions: {
10 | label: 'Rate (with discrete)',
11 | min: 1,
12 | max: 5,
13 | step: 0.5,
14 | discrete: true
15 | }
16 | });
17 |
18 | fields.push({
19 | type: 'slider',
20 | key: 'rate',
21 | templateOptions: {
22 | label: 'Rate',
23 | min: 1,
24 | max: 5,
25 | step: 0.5
26 | }
27 | });
28 |
29 | // set example
30 | Examples.set('slider', {
31 | fields
32 | }, 'types/slider.md');
33 |
34 | // add menu item to types
35 | Menu.addChild('types', 'slider');
36 | }]);
37 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view/demo-view.js:
--------------------------------------------------------------------------------
1 | const { Component, View, State, Inject } = angular2now;
2 |
3 | @Component({
4 | selector: 'demo-view'
5 | })
6 | @View({
7 | templateUrl: 'client/components/demo-view/demo-view.html'
8 | })
9 | @State({
10 | name: 'demo.view',
11 | url: '/{id:[a-z\-]+}'
12 | })
13 | @Inject(['$stateParams', 'Examples'])
14 | class DemoViewComponent {
15 | constructor($stateParams, Examples) {
16 | this.id = $stateParams.id;
17 | this.Examples = Examples;
18 |
19 | const example = Examples.get(this.id);
20 |
21 | if (example) {
22 | this.fields = angular.copy(example.formly.fields);
23 | this.model = angular.copy(example.formly.model) || {};
24 | this.options = angular.copy(example.formly.options) || {};
25 | this.api = example.api;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/demo/client/data/examples/radio.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | type: 'radio',
8 | key: 'name',
9 | templateOptions: {
10 | label: 'Name',
11 | labelProp: 'firstName',
12 | valueProp: 'id',
13 | options: [
14 | {
15 | firstName: 'Sarah',
16 | id: 1
17 | },
18 | {
19 | firstName: 'Jessica',
20 | id: 2
21 | },
22 | {
23 | firstName: 'Parker',
24 | id: 3
25 | }
26 | ]
27 | }
28 | });
29 |
30 | // set example
31 | Examples.set('radio', {
32 | fields
33 | }, 'types/radio.md');
34 |
35 | // add menu item to types
36 | Menu.addChild('types', 'radio');
37 | }]);
38 |
--------------------------------------------------------------------------------
/demo/client/components/menu-toggle/menu-toggle.js:
--------------------------------------------------------------------------------
1 | const { Component, View } = angular2now;
2 |
3 | @Component({
4 | selector: 'menu-toggle',
5 | bind: {
6 | sectionName: '=',
7 | sectionState: '=',
8 | sectionChildren: '=',
9 | onOpen: '&?',
10 | onClose: '&?'
11 | }
12 | })
13 | @View({
14 | templateUrl: 'client/components/menu-toggle/menu-toggle.html'
15 | })
16 | class MenuToggleComponent {
17 | constructor() {
18 | this.opened = false;
19 | }
20 |
21 | open() {
22 | this.opened = true;
23 | this.onOpen();
24 | }
25 |
26 | close() {
27 | this.opened = false;
28 | this.onClose();
29 | }
30 |
31 | toggle() {
32 | if (this.opened === true) {
33 | this.close();
34 | } else {
35 | this.open();
36 | }
37 | }
38 |
39 | isOpen() {
40 | return this.opened === true;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/demo/client/components/demo-view-source/demo-view-source.js:
--------------------------------------------------------------------------------
1 | const { Component, View } = angular2now;
2 |
3 | @Component({
4 | selector: 'demo-view-source',
5 | bind: {
6 | fields: '=',
7 | model: '=?',
8 | options: '=?',
9 | form: '=?'
10 | }
11 | })
12 | @View({
13 | templateUrl: 'client/components/demo-view-source/demo-view-source.html'
14 | })
15 | class DemoViewSourceComponent {
16 | constructor() {
17 | this.sources = [];
18 | // make copy of fields
19 | this.fieldsInits = angular.copy(this.fields);
20 |
21 | this.add('fieldsInits', 'Initial fields');
22 | this.add('fields', 'Fields');
23 | this.add('model', 'Model');
24 | this.add('form', 'Form');
25 | this.add('options', 'Options');
26 | }
27 |
28 | add(key, label) {
29 | this.sources.push({
30 | label,
31 | key
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/demo/client/data/examples/select.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | type: 'select',
8 | key: 'names',
9 | templateOptions: {
10 | label: 'Names',
11 | multiple: true,
12 | labelProp: 'firstName',
13 | valueProp: 'id',
14 | options: [
15 | {
16 | firstName: 'Sarah',
17 | id: 1
18 | },
19 | {
20 | firstName: 'Jessica',
21 | id: 2
22 | },
23 | {
24 | firstName: 'Parker',
25 | id: 3
26 | }
27 | ]
28 | }
29 | });
30 |
31 | // set example
32 | Examples.set('select', {
33 | fields
34 | }, 'types/select.md');
35 |
36 | // add menu item to types
37 | Menu.addChild('types', 'select');
38 | }]);
39 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "./node_modules/eslint-config-airbnb/rules/best-practices.js",
4 | "./node_modules/eslint-config-airbnb/rules/errors.js",
5 | "./node_modules/eslint-config-airbnb/rules/legacy.js",
6 | "./node_modules/eslint-config-airbnb/rules/node.js",
7 | "./node_modules/eslint-config-airbnb/rules/strict.js",
8 | "./node_modules/eslint-config-airbnb/rules/style.js",
9 | "./node_modules/eslint-config-airbnb/rules/variables.js",
10 | "./node_modules/eslint-config-airbnb/rules/es6.js"
11 | ],
12 | "parser": "babel-eslint",
13 | "env": {
14 | "browser": true,
15 | "node": true,
16 | "meteor": true,
17 | "mongo": true,
18 | "jasmine": true,
19 | "es6": true
20 | },
21 | "globals": {
22 | "inject": false,
23 | "angular2now": false
24 | },
25 | "rules": {
26 | "new-cap": 1,
27 | "no-unused-vars": 1,
28 | "comma-dangle": 0
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/demo/client/data/examples/divider.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | key: 'terms1',
8 | type: 'switch',
9 | wrapper: ['divider'],
10 | templateOptions: {
11 | label: 'Terms #1'
12 | }
13 | });
14 |
15 | fields.push({
16 | key: 'terms2',
17 | type: 'switch',
18 | wrapper: ['divider'],
19 | templateOptions: {
20 | label: 'Terms #2'
21 | }
22 | });
23 |
24 | fields.push({
25 | key: 'terms3',
26 | type: 'switch',
27 | templateOptions: {
28 | label: 'Terms #3'
29 | }
30 | });
31 |
32 | // set example
33 | Examples.set('divider', {
34 | fields,
35 | model: {
36 | terms2: true
37 | },
38 | }, 'wrappers/divider.md');
39 |
40 | // add menu item to wrappers
41 | Menu.addChild('wrappers', 'divider');
42 | }]);
43 |
--------------------------------------------------------------------------------
/docs/types/input.md:
--------------------------------------------------------------------------------
1 | input
2 | =====
3 |
4 | md-input
5 | --------
6 |
7 | Example
8 | -------
9 |
10 | ```javascript
11 | {
12 | type: "input",
13 | key: "firstName",
14 | templateOptions: {
15 | type: "text",
16 | label: "First name",
17 | pattern: "[a-zA-Z]+"
18 | theme: "custom"
19 | }
20 | }
21 | ```
22 |
23 | ### Configuration
24 |
25 | #### templateOptions.type *: string*
26 |
27 | #### templateOptions.label *: string*
28 |
29 | #### templateOptions.theme *: string*
30 |
31 | Value of md-theme directive
32 |
33 | #### templateOptions.className _: string | expression | array_
34 |
35 | #### templateOptions.disabled _: boolean_
36 |
37 | #### templateOptions.step *: number*
38 |
39 | only if templateOptions.type is 'number'
40 |
41 | #### templateOptions.min *: number*
42 |
43 | #### templateOptions.max *: number*
44 |
45 | #### templateOptions.pattern *: string | RegExp*
46 |
47 | Value of ng-pattern directive
48 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-formly-material",
3 | "description": "Material design templates for angular-formly",
4 | "main": "dist/formly-material.js",
5 | "authors": [
6 | "Kamil Kisiela "
7 | ],
8 | "license": "MIT",
9 | "homepage": "https://github.com/formly-js/angular-formly-templates-material",
10 | "keywords": [
11 | "AngularJs",
12 | "form",
13 | "formly",
14 | "json",
15 | "html",
16 | "material"
17 | ],
18 | "ignore": [
19 | "**/.*",
20 | "coverage",
21 | "demo",
22 | "node_modules",
23 | "src",
24 | "tests",
25 | "webpack",
26 | "karma.conf.js",
27 | "package.js",
28 | "webpack.config.js"
29 | ],
30 | "dependencies": {
31 | "angular": "~1.4.0",
32 | "angular-messages": "~1.4.0",
33 | "angular-animate": "~1.4.0",
34 | "angular-aria": "~1.4.0",
35 | "angular-material": "~1.0.0",
36 | "angular-formly": "~7.3.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/docs/types/slider.md:
--------------------------------------------------------------------------------
1 | # slider
2 | ## md-slider
3 |
4 | ### Example
5 |
6 | ```javascript
7 | {
8 | type: "slider",
9 | key: "rate",
10 | templateOptions: {
11 | theme: "custom",
12 | min: 1,
13 | max: 5,
14 | step: 0.5,
15 | discrete: true
16 | }
17 | }
18 | ```
19 |
20 | ### Configuration
21 |
22 | #### templateOptions.label _: string_
23 |
24 | #### templateOptions.theme _: string_
25 |
26 | #### templateOptions.disabled _: boolean_
27 |
28 | #### templateOptions.className _: string | expression | array_
29 |
30 | #### templateOptions.min _: number (default: 0)_
31 | The minimum value the user is allowed to pick.
32 |
33 | #### templateOptions.max _: number (default: 100)_
34 | The maximum value the user is allowed to pick.
35 |
36 | #### templateOptions.step _: number (default: 1)_
37 | The distance between values the user is allowed to pick.
38 |
39 | #### templateOptions.discrete _: boolean (default: false)_
40 | Whether to enable discrete mode
41 |
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | // package metadata file for AtmosphereJS
2 |
3 | Package.describe({
4 | name: 'formly:angular-formly-templates-material',
5 | summary: '(official): Material design templates for angular-formly',
6 | version: '0.14.3',
7 | documentation: 'README.md',
8 | git: 'https://github.com/formly-js/angular-formly-templates-material.git'
9 | });
10 |
11 | Package.onUse(function formlyMaterialOnUse(api) {
12 | var packages = {
13 | use: [
14 | 'angular@1.0.0',
15 | 'angular:angular-messages@1.4.7',
16 | 'angular:angular-material@1.0.0',
17 | 'formly:angular-formly@7.3.9_3'
18 | ],
19 | imply: [
20 | 'angular:angular@1.4.7',
21 | 'angular:angular-messages',
22 | 'angular:angular-material',
23 | 'formly:angular-formly'
24 | ]
25 | };
26 |
27 | api.versionsFrom(['METEOR@1.0']);
28 |
29 | api.use(packages.use);
30 | api.imply(packages.imply);
31 |
32 | api.addFiles([
33 | 'dist/formly-material.js'
34 | ], 'client');
35 | });
36 |
--------------------------------------------------------------------------------
/demo/client/components/demo/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | formlyMaterial
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Demo
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/types/radio.md:
--------------------------------------------------------------------------------
1 | # radio
2 | ## md-radio-group | md-radio-button
3 |
4 | ### Example
5 |
6 | ```javascript
7 | {
8 | type: "radio",
9 | key: "name",
10 | templateOptions: {
11 | label: "Name",
12 | theme: "custom",
13 | labelProp: "firstName",
14 | valueProp: "id",
15 | options: [
16 | {firstName: "Sarah", id: 1},
17 | {firstName: "Jessica", id: 2},
18 | {firstName: "Parker", id: 3}
19 | ]
20 | }
21 | }
22 | ```
23 |
24 | ### Configuration
25 |
26 | #### templateOptions.label _: string_
27 |
28 | #### templateOptions.theme _: string_
29 |
30 | #### templateOptions.disabled _: boolean_
31 |
32 | #### templateOptions.className _: string | expression | array_
33 |
34 | #### templateOptions.options _: array_
35 |
36 | Array with available options
37 |
38 | #### templateOptions.labelProp _: string (default: name)_
39 |
40 | Name of property with option's label
41 |
42 | #### templateOptions.valueProp _: string_
43 |
44 | Name of property with option's value
45 |
--------------------------------------------------------------------------------
/demo/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base # Packages every Meteor app needs to have
8 | mobile-experience # Packages for a great mobile UX
9 | mongo # The database Meteor supports right now
10 | session # Client-side reactive dictionary for your app
11 | jquery # Helpful client-side library
12 | tracker # Meteor's client-side reactive programming library
13 |
14 | standard-minifiers # JS/CSS minifiers run for production mode
15 | es5-shim # ECMAScript 5 compatibility for older browsers.
16 |
17 | angular
18 | pbastowski:angular2-now
19 | formly:angular-formly-templates-material
20 | angularui:angular-ui-router
21 | underscore
22 | planettraining:material-design-icons
23 | simple:highlight.js
24 |
--------------------------------------------------------------------------------
/demo/client/data/examples/input.js:
--------------------------------------------------------------------------------
1 | const { SetModule } = angular2now;
2 |
3 | SetModule('demo').run(['Examples', 'Menu', (Examples, Menu) => {
4 | const fields = [];
5 |
6 | fields.push({
7 | key: 'name',
8 | type: 'input',
9 | templateOptions: {
10 | label: 'Name',
11 | pattern: '[a-zA-Z]+'
12 | },
13 | validation: {
14 | messages: {
15 | pattern: () => 'a-zA-Z only'
16 | }
17 | }
18 | });
19 |
20 | fields.push({
21 | key: 'sum',
22 | type: 'input',
23 | templateOptions: {
24 | type: 'number',
25 | label: 'Sum',
26 | step: 0.5,
27 | min: 0,
28 | max: 10
29 | },
30 | validation: {
31 | messages: {
32 | max: () => '10 is max',
33 | min: () => '0 is min',
34 | number: () => 'Invalid format'
35 | }
36 | }
37 | });
38 |
39 | // set example
40 | Examples.set('input', {
41 | fields
42 | }, 'types/input.md');
43 |
44 | // add menu item to types
45 | Menu.addChild('types', 'input');
46 | }]);
47 |
--------------------------------------------------------------------------------
/src/types/slider/slider.js:
--------------------------------------------------------------------------------
1 | import template from './slider.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'slider',
7 | wrapper: ['label'],
8 | defaultOptions: {
9 | templateOptions: {
10 | disabled: false
11 | },
12 | ngModelAttrs: {
13 | disabled: {
14 | bound: 'ng-disabled'
15 | },
16 | min: {
17 | attribute: 'min'
18 | },
19 | max: {
20 | attribute: 'max'
21 | },
22 | step: {
23 | attribute: 'step'
24 | },
25 | discrete: {
26 | bound: 'md-discrete'
27 | }
28 | }
29 | },
30 | apiCheck: (check) => ({
31 | templateOptions: {
32 | disabled: check.bool.optional,
33 | min: check.number.optional,
34 | max: check.number.optional,
35 | step: check.number.optional,
36 | discrete: check.bool.optional,
37 | theme: check.string.optional
38 | }
39 | })
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/docs/types/datepicker.md:
--------------------------------------------------------------------------------
1 | # datepicker
2 | ## md-datepicker
3 |
4 | ### Example
5 |
6 | ```javascript
7 | {
8 | type: "datepicker",
9 | key: "start",
10 | templateOptions: {
11 | theme: "custom",
12 | placeholder: "Start date",
13 | minDate: minDate, // instance of Date
14 | maxDate: maxDate, // instance of Date
15 | filterDate: function(date) {
16 | // only weekends
17 | var day = date.getDay();
18 | return day === 0 || day === 6;
19 | }
20 | }
21 | }
22 | ```
23 |
24 | ### Configuration
25 |
26 | #### templateOptions.label _: string_
27 |
28 | #### templateOptions.theme _: string_
29 |
30 | #### templateOptions.disabled _: boolean_
31 |
32 | #### templateOptions.className _: string | expression | array_
33 |
34 | #### templateOptions.placeholder _: string_
35 | The date input placeholder value
36 |
37 | #### templateOptions.minDate _: Date_
38 | Min date of choice
39 |
40 | #### templateOptions.maxDate _: Date_
41 | Max date of choice
42 |
43 | #### templateOptions.filterDate _: function_
44 | Function expecting a date and returning a boolean whether it can be selected or not.
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Kamil Kisiela
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demo/client/data/examples.js:
--------------------------------------------------------------------------------
1 | const { SetModule, Service } = angular2now;
2 |
3 | SetModule('demo');
4 |
5 | @Service({
6 | name: 'Examples'
7 | })
8 | class Examples {
9 | constructor() {
10 | this.examples = new Map();
11 | }
12 |
13 | /**
14 | * Add new example
15 | *
16 | * @param {String} id unique value for state `id` parameter
17 | * @param {Object} options formly configuration
18 | * @param {String} api it can be an absolute url or just `types/input.md` (see docs local variable)
19 | */
20 | set(id, { fields, model, options }, api) {
21 | const docs = 'https://github.com/formly-js/angular-formly-templates-material/blob/master/docs/';
22 |
23 | this.examples.set(id, {
24 | api: (typeof api === 'string' && !api.match('^http')) ? docs + api : api,
25 | formly: {
26 | fields,
27 | model,
28 | options
29 | }
30 | });
31 | }
32 |
33 | /**
34 | * Get example
35 | *
36 | * @param {String} id example's identifier
37 | * @return {Object} example's data with API url and formly configuration
38 | */
39 | get(id) {
40 | return this.examples.get(id);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/types/datepicker/datepicker.js:
--------------------------------------------------------------------------------
1 | import template from './datepicker.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'datepicker',
7 | wrapper: ['label', 'messages'],
8 | defaultOptions: {
9 | templateOptions: {
10 | disabled: false
11 | },
12 | ngModelAttrs: {
13 | disabled: {
14 | bound: 'ng-disabled'
15 | },
16 | placeholder: {
17 | attribute: 'md-placeholder'
18 | },
19 | minDate: {
20 | bound: 'md-min-date'
21 | },
22 | maxDate: {
23 | bound: 'md-max-date'
24 | },
25 | filterDate: {
26 | bound: 'md-date-filter'
27 | }
28 | }
29 | },
30 | apiCheck: (check) => ({
31 | templateOptions: {
32 | disabled: check.bool.optional,
33 | placeholder: check.string.optional,
34 | minDate: check.instanceOf(Date).optional,
35 | maxDate: check.instanceOf(Date).optional,
36 | filterDate: check.func.optional,
37 | theme: check.string.optional
38 | }
39 | })
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/tests/wrappers/input-container-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 |
3 | describe('formlyMaterial - inputContainer wrapper', () => {
4 | //
5 | // vars
6 | //
7 | let $compile;
8 | let $rootScope;
9 | let $scope;
10 | let element;
11 |
12 | //
13 | // helpers
14 | //
15 |
16 | function compile() {
17 | $scope = $rootScope.$new();
18 | $scope.fields = [{
19 | key: 'testField',
20 | type: 'checkbox',
21 | wrapper: ['inputContainer'],
22 | templateOptions: {
23 | label: 'test field'
24 | }
25 | }];
26 |
27 | const form = $compile(testUtils.getFormTemplate())($scope);
28 | $scope.$digest();
29 | element = form.find('md-input-container');
30 | }
31 |
32 | //
33 | // tests
34 | //
35 |
36 | beforeEach(() => {
37 | window.module('formlyMaterial');
38 |
39 | inject((_$compile_, _$rootScope_) => {
40 | $compile = _$compile_;
41 | $rootScope = _$rootScope_;
42 | });
43 |
44 | compile();
45 | });
46 |
47 | it('should exist', () => {
48 | expect(element.length).toBe(1);
49 | });
50 |
51 | it('should contain field', () => {
52 | expect(element.find('md-checkbox').length).toBe(1);
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | cache:
3 | directories:
4 | - node_modules
5 | notifications:
6 | email: false
7 | node_js:
8 | - iojs
9 | before_install:
10 | - npm install
11 | - export DISPLAY=:99.0
12 | - sh -e /etc/init.d/xvfb start
13 | before_script:
14 | - npm prune
15 | script:
16 | - npm run test
17 | - npm run lint
18 | after_success:
19 | - npm run coverage:codecov
20 | - npm run coverage:coveralls
21 | - npm run coverage:codacy
22 | deploy:
23 | provider: npm
24 | email: "kamil.kisiela@ster-project.pl"
25 | api_key:
26 | secure: in2pTjQm665cn37CW0Y4VuHkoXvZMmXRMRSmUCP2SUcTrbd69g7Sql+Y0o5RKv97cEGv53StZCWIcXwLMKxnTOTMvzztnvQjB4QhrVifS3/YmNTPTrFrjQDa+2SEpVqDk9lbl98KXwespN4lEG1OmooZrQjD7QXQjjQgkpG/zAzhn/8gaeGZgMumrg4/y5MDv2XhyJUnc4pwc6ZxsHKjjfhvsqPR87v5smxuCOXz3Pibtn88rohQE/Pjz/qqXyPvtzeEG84mTgqviP+r4R68IUWUT26uqp0l1QwwHbJspH7s/J+1VGinYJuA+AIafuoOII1Sm+wgM5hsl4MaF2AjCkYD8B03O80pDiSabwTJS14tXiFK5fF4uNVn8KQROjNkKAqNf49vjOQF2oo5G/GZCK4dLEnkU1Vj7WlRTm+0afD0qGsYfdCuKjU2PtFWt3adW5fBLmshsHQKNKd35tvRWiqvXkF3uGb2xqTUgRcgsvy1Gm3u/kzQncU4JtMh9EA0kyOhpaZstCu1tvkWvXhkQou5yo1aM1986ZsZKhqRkfaE3NCQTpd4cOn+o9H8BLWVaTvX5X2UBOmAjnjRQGSin8NG9ELRxZzj2M46G/R9sD1yqK5bW4lC8bHIp/5dE9YeGQ0DM9Ht/hnf7XoeI40ikKA699A9zq0MRXdsEcHEYSw=
27 | on:
28 | tags: true
29 |
--------------------------------------------------------------------------------
/tests/wrappers/messages-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 |
3 | describe('formlyMaterial - messages wrapper', () => {
4 | //
5 | // vars
6 | //
7 | let $compile;
8 | let $rootScope;
9 | let $scope;
10 | let element;
11 |
12 | //
13 | // helpers
14 | //
15 |
16 | function compile() {
17 | $scope = $rootScope.$new();
18 | $scope.fields = [{
19 | key: 'testField',
20 | type: 'checkbox',
21 | wrapper: ['messages'],
22 | templateOptions: {
23 | label: 'test field'
24 | }
25 | }];
26 |
27 | const form = $compile(testUtils.getFormTemplate())($scope);
28 |
29 | $scope.$digest();
30 | element = form.find('[ng-messages]');
31 | }
32 |
33 | //
34 | // tests
35 | //
36 |
37 | beforeEach(() => {
38 | window.module('formlyMaterial');
39 |
40 | inject((_$compile_, _$rootScope_) => {
41 | $compile = _$compile_;
42 | $rootScope = _$rootScope_;
43 | });
44 |
45 | compile();
46 | });
47 |
48 | it('should exist', () => {
49 | expect(element.length).toBe(1);
50 | });
51 |
52 | it('should be after the field', () => {
53 | expect(element.find('md-checkbox').length).toBe(0);
54 | expect(element.prev('.ng-scope').children('md-checkbox').length).toBe(1);
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/src/types/textarea/textarea.js:
--------------------------------------------------------------------------------
1 | import template from './textarea.html';
2 | import { ngModelAttrsTransformer } from './../../helpers';
3 |
4 | export default (formlyConfigProvider) => {
5 | formlyConfigProvider.setType({
6 | template,
7 | name: 'textarea',
8 | wrapper: ['label', 'messages', 'inputContainer'],
9 | defaultOptions: {
10 | ngModelAttrs: {
11 | disabled: {
12 | bound: 'ng-disabled'
13 | },
14 | rows: {
15 | attribute: 'rows'
16 | },
17 | cols: {
18 | attribute: 'cols'
19 | }
20 | },
21 | templateOptions: {
22 | grow: true
23 | }
24 | },
25 | apiCheck: (check) => ({
26 | templateOptions: {
27 | disabled: check.bool.optional,
28 | rows: check.number.optional,
29 | cols: check.number.optional,
30 | grow: check.bool.optional,
31 | theme: check.string.optional
32 | }
33 | })
34 | });
35 |
36 | formlyConfigProvider.extras.fieldTransform.push((fields) => {
37 | return ngModelAttrsTransformer(fields, (field) => (
38 | field.type === 'textarea' &&
39 | field.templateOptions &&
40 | field.templateOptions.grow === false
41 | ), 'grow', {
42 | attribute: 'md-no-autogrow'
43 | });
44 | });
45 | };
46 |
--------------------------------------------------------------------------------
/demo/client/components/demo/demo.js:
--------------------------------------------------------------------------------
1 | const {
2 | SetModule, Component, View, State, Inject, bootstrap, options
3 | } = angular2now;
4 |
5 | options({
6 | controllerAs: 'vm'
7 | });
8 |
9 | SetModule('demo', [
10 | 'angular-meteor',
11 | 'ui.router',
12 | 'formlyMaterial',
13 | 'hljs'
14 | ]).config(['$mdThemingProvider', '$mdIconProvider', ($mdThemingProvider, $mdIconProvider) => {
15 | $mdThemingProvider.theme('default')
16 | .primaryPalette('deep-purple')
17 | .accentPalette('green')
18 | .warnPalette('red')
19 | .backgroundPalette('grey');
20 |
21 | $mdIconProvider.iconSet('navigation',
22 | `/packages/planettraining_material-design-icons/bower_components/material-design-icons/sprites/svg-sprite/svg-sprite-navigation.svg`);
23 | }]);
24 |
25 | @Component({
26 | selector: 'demo'
27 | })
28 | @View({
29 | templateUrl: 'client/components/demo/demo.html'
30 | })
31 | @State({
32 | name: 'demo',
33 | url: '/demo',
34 | abstract: true,
35 | html5Mode: true
36 | })
37 | @Inject(['Menu', '$mdSidenav'])
38 | class DemoComponent {
39 | constructor(Menu, $mdSidenav) {
40 | this.$mdSidenav = $mdSidenav;
41 |
42 | this.menu = Menu.get();
43 | }
44 |
45 | toggleMenu() {
46 | this.$mdSidenav('left')
47 | .toggle();
48 | }
49 | }
50 |
51 | bootstrap(DemoComponent);
52 |
--------------------------------------------------------------------------------
/src/types/input/input.js:
--------------------------------------------------------------------------------
1 | import template from './input.html';
2 | import { ngModelAttrsTransformer } from './../../helpers';
3 |
4 | export default (formlyConfigProvider) => {
5 | formlyConfigProvider.setType({
6 | template,
7 | name: 'input',
8 | wrapper: ['label', 'messages', 'inputContainer'],
9 | defaultOptions: {
10 | templateOptions: {
11 | type: 'text',
12 | disabled: false
13 | },
14 | ngModelAttrs: {
15 | mdMaxlength: {
16 | bound: 'md-maxlength'
17 | },
18 | // XXX angular-formly#8042d2a so we want to keep it compatible
19 | // with angular-formly releases before that commit
20 | step: {
21 | attribute: 'step'
22 | },
23 | disabled: {
24 | bound: 'ng-disabled'
25 | },
26 | pattern: {
27 | bound: 'ng-pattern'
28 | }
29 | }
30 | },
31 | apiCheck: (check) => {
32 | return {
33 | templateOptions: {
34 | disabled: check.bool.optional,
35 | type: check.string,
36 | step: check.number.optional,
37 | pattern: check.oneOfType([
38 | check.string,
39 | check.instanceOf(RegExp)
40 | ]).optional,
41 | theme: check.string.optional
42 | }
43 | };
44 | }
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/webpack/common.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var webpack = require('webpack');
3 | var pkg = require('../package.json');
4 |
5 | function concatArrays(objValue, srcValue) {
6 | if (_.isArray(objValue)) {
7 | return _.uniq(objValue.concat(srcValue));
8 | }
9 | }
10 |
11 | module.exports = function(cfg) {
12 | var common = {
13 | stats: {
14 | colors: true,
15 | reasons: true
16 | },
17 | entry: {
18 | 'dist/formly-material': './src/index'
19 | },
20 | output: {
21 | libraryTarget: 'umd',
22 | library: 'ngFormlyMaterial'
23 | },
24 | resolve: {
25 | extensions: ['', '.js', '.html']
26 | },
27 | externals: {
28 | angular: 'angular'
29 | },
30 | babel: {
31 | presets: ['es2015']
32 | },
33 | module: {
34 | loaders: [{
35 | test: /\.js$/,
36 | include: [
37 | /tests/,
38 | /src/
39 | ],
40 | exclude: /node_modules/,
41 | loader: 'babel'
42 | }, {
43 | test: /\.html$/,
44 | exclude: /node_modules/,
45 | include: [/src/],
46 | loader: 'html'
47 | }]
48 | },
49 | plugins: [
50 | new webpack.BannerPlugin(pkg.name + ' v' + pkg.version + ' | MIT | built with ♥ by ' + pkg.author)
51 | ]
52 | };
53 |
54 | return _.merge({}, common, cfg, concatArrays);
55 | };
56 |
--------------------------------------------------------------------------------
/src/types/chips/chips.js:
--------------------------------------------------------------------------------
1 | import template from './chips.html';
2 |
3 | export default (formlyConfigProvider) => {
4 | formlyConfigProvider.setType({
5 | template,
6 | name: 'chips',
7 | wrapper: ['label'],
8 | defaultOptions: {
9 | defaultValue: [],
10 | ngModelAttrs: {
11 | placeholder: {
12 | attribute: 'placeholder'
13 | },
14 | secondaryPlaceholder: {
15 | attribute: 'secondary-placeholder'
16 | },
17 | deleteButtonLabel: {
18 | attribute: 'delete-button-label'
19 | },
20 | deleteHint: {
21 | attribute: 'delete-hint'
22 | },
23 | onAdd: {
24 | statement: 'md-on-add'
25 | },
26 | onRemove: {
27 | statement: 'md-on-remove'
28 | },
29 | onSelect: {
30 | statement: 'md-on-select'
31 | }
32 | }
33 | },
34 | apiCheck: (check) => ({
35 | templateOptions: {
36 | placeholder: check.string.optional,
37 | secondaryPlaceholder: check.string.optional,
38 | deleteButtonLabel: check.string.optional,
39 | deleteHint: check.string.optional,
40 | onAdd: check.func.optional,
41 | onRemove: check.func.optional,
42 | onSelect: check.func.optional,
43 | theme: check.string.optional
44 | }
45 | })
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/src/types/select/select.js:
--------------------------------------------------------------------------------
1 | import template from './select.html';
2 | import { ngModelAttrsManipulator } from './../../helpers';
3 |
4 | export default (formlyConfigProvider) => {
5 | formlyConfigProvider.setType({
6 | template,
7 | name: 'select',
8 | wrapper: ['label', 'messages', 'inputContainer'],
9 | defaultOptions: {
10 | templateOptions: {
11 | disabled: false
12 | },
13 | ngModelAttrs: {
14 | disabled: {
15 | bound: 'ng-disabled'
16 | },
17 | onClose: {
18 | statement: 'md-on-close'
19 | },
20 | onOpen: {
21 | statement: 'md-on-open'
22 | }
23 | }
24 | },
25 | apiCheck: (check) => ({
26 | templateOptions: {
27 | disabled: check.bool.optional,
28 | options: check.arrayOf(check.object),
29 | multiple: check.bool.optional,
30 | labelProp: check.string.optional,
31 | valueProp: check.string.optional,
32 | onClose: check.func.optional,
33 | onOpen: check.func.optional,
34 | theme: check.string.optional
35 | }
36 | })
37 | });
38 |
39 | formlyConfigProvider.templateManipulators.preWrapper.push((tpl, options) => {
40 | const to = options.templateOptions || {};
41 | // adds multiple only when:
42 | // templateOptions.multiple equals true
43 | return to.multiple === true ? ngModelAttrsManipulator(tpl, options, 'multiple') : tpl;
44 | });
45 | };
46 |
--------------------------------------------------------------------------------
/docs/types/select.md:
--------------------------------------------------------------------------------
1 | select
2 | ======
3 |
4 | md-select
5 | ---------
6 |
7 | ### Example
8 |
9 | ```javascript
10 | {
11 | type: "select",
12 | key: "name",
13 | templateOptions: {
14 | label: "Name",
15 | theme: "custom",
16 | multiple: true,
17 | labelProp: "firstName",
18 | valueProp: "id",
19 | options: [
20 | {firstName: "Sarah", id: 1},
21 | {firstName: "Jessica", id: 2},
22 | {firstName: "Parker", id: 3}
23 | ],
24 | onOpen: () => {
25 | console.log('select is opened');
26 | },
27 | onClose: () => {
28 | console.log('select is closed');
29 | }
30 | }
31 | }
32 | ```
33 |
34 | ### Configuration
35 |
36 | #### templateOptions.label *: string*
37 |
38 | #### templateOptions.theme *: string*
39 |
40 | #### templateOptions.disabled _: boolean_
41 |
42 | #### templateOptions.className _: string | expression | array_
43 |
44 | #### templateOptions.options *: array*
45 |
46 | Array with available options
47 |
48 | #### templateOptions.labelProp *: string (default: name)*
49 |
50 | Name of property with option's label
51 |
52 | #### templateOptions.valueProp *: string*
53 |
54 | Name of property with option's value
55 |
56 | #### templateOptions.multiple *: boolean*
57 |
58 | Multiple choice
59 |
60 | #### templateOptions.onOpen *: function*
61 |
62 | Bound to md-on-open.
63 |
64 | Expression to be evaluated when the select is opened.
65 |
66 | If expression returns a promise, it will display a loading indicator while it is being resolved.
67 |
68 | #### templateOptions.onClose *: function*
69 |
70 | Bound to md-on-close.
71 |
72 | Expression to be evaluated when the select is closed.
73 |
--------------------------------------------------------------------------------
/docs/types/chips.md:
--------------------------------------------------------------------------------
1 | chips
2 | =====
3 |
4 | md-chips
5 | --------
6 |
7 | ### Example
8 |
9 | ```javascript
10 | {
11 | type: "chips",
12 | key: "tags",
13 | templateOptions: {
14 | theme: "custom",
15 | placeholder: "+tags",
16 | secondaryPlaceholder: "Add tag",
17 | deleteButtonLabel: "Remove",
18 | deleteHint: "Remove tag",
19 | onAdd: function() {
20 | console.log('new chip');
21 | },
22 | onRemove: function() {
23 | console.log('chip removed');
24 | }
25 | }
26 | }
27 | ```
28 |
29 | ### Configuration
30 |
31 | #### templateOptions.label *: string*
32 |
33 | #### templateOptions.theme *: string*
34 |
35 | #### templateOptions.disabled _: boolean_
36 |
37 | #### templateOptions.className _: string | expression | array_
38 |
39 | #### templateOptions.placeholder *: string*
40 |
41 | Placeholder text that will be forwarded to the input.
42 |
43 | #### templateOptions.secondaryPlaceholder *: string*
44 |
45 | Placeholder text that will be forwarded to the input, displayed when there is at least on item in the list.
46 |
47 | #### templateOptions.deleteButtonLabel *: string*
48 |
49 | A label for the delete button. Also hidden and read by screen readers.
50 |
51 | #### templateOptions.deleteHint *: string*
52 |
53 | A string read by screen readers instructing users that pressing the delete key will remove the chip.
54 |
55 | #### templateOptions.onAdd *: function*
56 |
57 | An expression which will be called when a chip has been added.
58 |
59 | #### templateOptions.onRemove *: function*
60 |
61 | An expression which will be called when a chip has been removed.
62 |
63 | #### templateOptions.onSelect *: function*
64 |
65 | An expression which will be called when a chip has been selected.
66 |
--------------------------------------------------------------------------------
/tests/types/checkbox-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - checkbox type', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 | let elementScope;
13 |
14 | //
15 | // helpers
16 | //
17 |
18 | function compile(options) {
19 | $scope = $rootScope.$new();
20 | $scope.fields = [angular.merge({}, {
21 | key: 'testField',
22 | type: 'checkbox',
23 | templateOptions: {
24 | label: 'test field',
25 | theme: 'custom',
26 | disabled: true
27 | }
28 | }, options)];
29 |
30 | const form = $compile(testUtils.getFormTemplate())($scope);
31 |
32 | $scope.$digest();
33 | element = form.find('[ng-model]');
34 | elementScope = angular.element(element).scope();
35 | }
36 |
37 | //
38 | // tests
39 | //
40 |
41 | beforeEach(() => {
42 | window.module('formlyMaterial');
43 |
44 | inject((_$compile_, _$rootScope_) => {
45 | $compile = _$compile_;
46 | $rootScope = _$rootScope_;
47 | });
48 |
49 | compile();
50 | });
51 |
52 | it('should be md-checkbox element', () => {
53 | expect(element[0].nodeName).toBe('MD-CHECKBOX');
54 | });
55 |
56 | it('should have label', () => {
57 | expect(element.html()).toContain('test field');
58 | });
59 |
60 | it('should be disabled', () => {
61 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
62 | expect(elementScope.options.templateOptions.disabled).toBe(true);
63 | });
64 |
65 | it('should have proper theme when defined', () => {
66 | expect(element.is('.md-custom-theme')).toBe(true);
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/tests/wrappers/divider-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - divider wrapper', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 |
13 | //
14 | // helpers
15 | //
16 |
17 | function compile(options) {
18 | $scope = $rootScope.$new();
19 | $scope.fields = [angular.merge({}, {
20 | key: 'testField',
21 | type: 'checkbox',
22 | wrapper: ['divider']
23 | }, options)];
24 |
25 | const form = $compile(testUtils.getFormTemplate())($scope);
26 | $scope.$digest();
27 | element = form.find('md-divider');
28 | }
29 |
30 | //
31 | // tests
32 | //
33 |
34 | beforeEach(() => {
35 | window.module('formlyMaterial');
36 |
37 | inject((_$compile_, _$rootScope_) => {
38 | $compile = _$compile_;
39 | $rootScope = _$rootScope_;
40 | });
41 | });
42 |
43 | it('should exist', () => {
44 | compile();
45 | expect(element.length).toBe(1);
46 | });
47 |
48 | it('should be after the field by default', () => {
49 | compile();
50 | // not transcluded inner
51 | expect(element.find('md-checkbox').length).toBe(0);
52 | // checkbox transcluded before
53 | expect(element.prev('.ng-scope').children('md-checkbox').length).toBe(1);
54 | });
55 |
56 | it('should be before the field when divider option equals before', () => {
57 | compile({
58 | templateOptions: {
59 | divider: 'before'
60 | }
61 | });
62 | // not transcluded inner
63 | expect(element.find('md-checkbox').length).toBe(0);
64 | // checkbox transcluded before
65 | expect(element.next('.ng-scope').children('md-checkbox').length).toBe(1);
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/tests/types/switch-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - switch type', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 | let elementScope;
13 | let field;
14 | const theme = 'custom';
15 |
16 | //
17 | // helpers
18 | //
19 |
20 | function compile(options) {
21 | $scope = $rootScope.$new();
22 | $scope.fields = [angular.merge({}, {
23 | key: 'testField',
24 | type: 'switch',
25 | templateOptions: {
26 | theme,
27 | label: 'test field',
28 | disabled: true
29 | }
30 | }, options)];
31 |
32 | const form = $compile(testUtils.getFormTemplate())($scope);
33 |
34 | $scope.$digest();
35 | element = form.find('[ng-model]');
36 | elementScope = element.scope();
37 | field = $scope.fields[0];
38 | }
39 |
40 | //
41 | // tests
42 | //
43 |
44 | beforeEach(() => {
45 | window.module('formlyMaterial');
46 |
47 | inject((_$compile_, _$rootScope_) => {
48 | $compile = _$compile_;
49 | $rootScope = _$rootScope_;
50 | });
51 |
52 | compile();
53 | });
54 |
55 | it('should be md-switch element', () => {
56 | expect(element[0].nodeName).toBe('MD-SWITCH');
57 | });
58 |
59 | it('should have proper theme when defined', () => {
60 | expect(element.is(`.md-${theme}-theme`)).toBe(true);
61 | });
62 |
63 | it('should have label', () => {
64 | expect(element.find('.md-label > span').html()).toContain(field.templateOptions.label);
65 | });
66 |
67 | it('should be able to be disabled', () => {
68 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
69 | expect(elementScope.options.templateOptions.disabled).toBe(true);
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/tests/runs/class-name-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - className manipulator', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 | let elementScope;
13 |
14 | //
15 | // helpers
16 | //
17 |
18 | function compile(options) {
19 | $scope = $rootScope.$new();
20 | $scope.fields = [angular.merge({}, {
21 | key: 'testField',
22 | type: 'switch',
23 | templateOptions: {
24 | className: 'custom',
25 | label: 'test field'
26 | }
27 | }, options)];
28 |
29 | const form = $compile(angular.element(testUtils.getFormTemplate()))($scope);
30 |
31 | $scope.$digest();
32 | element = form.find('[ng-model]');
33 | elementScope = element.scope();
34 | }
35 |
36 | //
37 | // tests
38 | //
39 |
40 | beforeEach(() => {
41 | window.module('formlyMaterial');
42 |
43 | inject((_$compile_, _$rootScope_) => {
44 | $compile = _$compile_;
45 | $rootScope = _$rootScope_;
46 | });
47 | });
48 |
49 | it('should be able to add ng-class directive', () => {
50 | compile();
51 | expect(element.attr('ng-class')).toBe(`options.templateOptions['className']`);
52 | });
53 |
54 | it('should pass one class as a string', () => {
55 | compile();
56 | expect(elementScope.options.templateOptions.className).toBe('custom');
57 | expect(element.attr('class')).toContain('custom');
58 | });
59 |
60 | it('should pass few classes as an array', () => {
61 | const classes = ['foo', 'bar', 'baz'];
62 |
63 | compile({
64 | templateOptions: {
65 | className: classes
66 | }
67 | });
68 |
69 | expect(elementScope.options.templateOptions.className).toEqual(classes);
70 |
71 | classes.forEach((clss) => {
72 | expect(element.attr('class')).toContain(clss);
73 | });
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Example user template template
3 | ### Example user template
4 |
5 | # IntelliJ project files
6 | .idea
7 | *.iml
8 | out
9 | gen### Node template
10 | # Logs
11 | logs
12 | *.log
13 | npm-debug.log*
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 |
26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
27 | .grunt
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directory
36 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
37 | node_modules
38 | bower_components
39 |
40 | ### JetBrains template
41 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
42 |
43 | *.iml
44 |
45 | ## Directory-based project format:
46 | .idea/
47 | # if you remove the above rule, at least ignore the following:
48 |
49 | # User-specific stuff:
50 | # .idea/workspace.xml
51 | # .idea/tasks.xml
52 | # .idea/dictionaries
53 |
54 | # Sensitive or high-churn files:
55 | # .idea/dataSources.ids
56 | # .idea/dataSources.xml
57 | # .idea/sqlDataSources.xml
58 | # .idea/dynamic.xml
59 | # .idea/uiDesigner.xml
60 |
61 | # Gradle:
62 | # .idea/gradle.xml
63 | # .idea/libraries
64 |
65 | # Mongo Explorer plugin:
66 | # .idea/mongoSettings.xml
67 |
68 | ## File-based project format:
69 | *.ipr
70 | *.iws
71 |
72 | ## Plugin-specific files:
73 |
74 | # IntelliJ
75 | /out/
76 |
77 | # mpeltonen/sbt-idea plugin
78 | .idea_modules/
79 |
80 | # JIRA plugin
81 | atlassian-ide-plugin.xml
82 |
83 | # Crashlytics plugin (for Android Studio and IntelliJ)
84 | com_crashlytics_export_strings.xml
85 | crashlytics.properties
86 | crashlytics-build.properties
87 |
88 |
--------------------------------------------------------------------------------
/demo/.meteor/versions:
--------------------------------------------------------------------------------
1 | angular@1.3.4
2 | angular-meteor-data@0.0.9
3 | angular-templates@0.0.3
4 | angular:angular@1.4.8
5 | angular:angular-animate@1.4.8
6 | angular:angular-aria@1.4.8
7 | angular:angular-material@1.0.1
8 | angular:angular-messages@1.4.8
9 | angularui:angular-ui-router@0.2.15
10 | autoupdate@1.2.4
11 | babel-compiler@5.8.24_1
12 | babel-runtime@0.1.4
13 | base64@1.0.4
14 | benjamine:jsondiffpatch@0.1.38_1
15 | binary-heap@1.0.4
16 | blaze@2.1.3
17 | blaze-tools@1.0.4
18 | boilerplate-generator@1.0.4
19 | caching-compiler@1.0.0
20 | caching-html-compiler@1.0.2
21 | callback-hook@1.0.4
22 | check@1.1.0
23 | dburles:mongo-collection-instances@0.3.4
24 | ddp@1.2.2
25 | ddp-client@1.2.1
26 | ddp-common@1.2.2
27 | ddp-server@1.2.2
28 | deps@1.0.9
29 | diff-sequence@1.0.1
30 | ecmascript@0.1.6
31 | ecmascript-runtime@0.2.6
32 | ejson@1.0.7
33 | es5-shim@4.1.14
34 | fastclick@1.0.7
35 | formly:angular-formly@7.3.9_3
36 | formly:angular-formly-templates-material@0.14.0
37 | geojson-utils@1.0.4
38 | hot-code-push@1.0.0
39 | html-tools@1.0.5
40 | htmljs@1.0.5
41 | http@1.1.1
42 | id-map@1.0.4
43 | jquery@1.11.4
44 | lai:collection-extensions@0.1.4
45 | launch-screen@1.0.4
46 | livedata@1.0.15
47 | logging@1.0.8
48 | meteor@1.1.10
49 | meteor-base@1.0.1
50 | minifiers@1.1.7
51 | minimongo@1.0.10
52 | mobile-experience@1.0.1
53 | mobile-status-bar@1.0.6
54 | mongo@1.1.3
55 | mongo-id@1.0.1
56 | npm-mongo@1.4.39_1
57 | observe-sequence@1.0.7
58 | ordered-dict@1.0.4
59 | pbastowski:angular-babel@1.0.8
60 | pbastowski:angular2-now@1.0.2
61 | planettraining:material-design-icons@2.1.1
62 | promise@0.5.1
63 | random@1.0.5
64 | reactive-dict@1.1.3
65 | reactive-var@1.0.6
66 | reload@1.1.4
67 | retry@1.0.4
68 | routepolicy@1.0.6
69 | session@1.1.1
70 | simple:highlight.js@1.2.0
71 | spacebars@1.0.7
72 | spacebars-compiler@1.0.7
73 | standard-minifiers@1.0.2
74 | templating-tools@1.0.0
75 | tracker@1.0.9
76 | ui@1.0.8
77 | underscore@1.0.4
78 | url@1.0.5
79 | webapp@1.2.3
80 | webapp-hashing@1.0.5
81 | wieldo:api-check@7.5.5
82 |
--------------------------------------------------------------------------------
/tests/helpers/ng-model-attrs-manipulator-spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | ngModelAttrsManipulator
3 | }
4 | from './../../src/helpers';
5 |
6 | import angular from 'angular';
7 |
8 | describe('formlyMaterial - ngModelAttrsManipulator', () => {
9 | it('should skip on skipNgModelAttrsManipulator', () => {
10 | const tpl = 'test';
11 | const result = ngModelAttrsManipulator(tpl, {
12 | extras: {
13 | skipNgModelAttrsManipulator: true
14 | }
15 | });
16 |
17 | expect(result).toBe(tpl);
18 | });
19 |
20 | it('should not modify on missing ngModel', () => {
21 | const tpl = 'test';
22 | const result = ngModelAttrsManipulator(tpl, {});
23 |
24 | expect(result).toBe(tpl);
25 | });
26 |
27 | it('should add attribute with value to ngModel', () => {
28 | const tpl = ``;
29 | const attr = {
30 | name: 'foo',
31 | value: 'bar'
32 | };
33 | const result = ngModelAttrsManipulator(tpl, {}, attr.name, attr.value);
34 | const element = angular.element(result);
35 |
36 | expect(result).not.toBe(tpl);
37 | expect(element.find('[ng-model]').attr(attr.name)).toBe(attr.value);
38 | });
39 |
40 | it('should add attribute with value to few elements with ngModel', () => {
41 | const tpl = ``;
42 | const attr = {
43 | name: 'foo',
44 | value: 'bar'
45 | };
46 | const result = ngModelAttrsManipulator(tpl, {}, attr.name, attr.value);
47 | const element = angular.element(result);
48 |
49 | expect(result).not.toBe(tpl);
50 | expect(element.find('[ng-model]').length).toBe(2);
51 | expect(element.find('[ng-model]:eq(0)').attr(attr.name)).toBe(attr.value);
52 | expect(element.find('[ng-model]:eq(1)').attr(attr.name)).toBe(attr.value);
53 | });
54 |
55 | it('should not overwrite attribute on ngModel', () => {
56 | const name = 'baz';
57 | const tpl = ``;
58 | const attr = {
59 | name: 'foo',
60 | value: 'bar'
61 | };
62 | const result = ngModelAttrsManipulator(tpl, {}, attr.name, attr.value);
63 | const element = angular.element(result);
64 |
65 | expect(result).not.toBe(tpl);
66 | expect(element.find('[ng-model]').attr(attr.name)).toBe(name);
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/tests/wrappers/label-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - label wrapper', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 | let field;
13 | const color = 'rgb(117, 117, 117)';
14 |
15 | //
16 | // helpers
17 | //
18 |
19 | function compile(options) {
20 | $scope = $rootScope.$new();
21 | $scope.fields = [angular.merge({}, {
22 | key: 'testField',
23 | type: 'checkbox',
24 | wrapper: ['label'],
25 | templateOptions: {
26 | label: 'test field'
27 | }
28 | }, options)];
29 |
30 | const form = $compile(testUtils.getFormTemplate())($scope);
31 |
32 | $scope.$digest();
33 | element = form.find('label');
34 | field = $scope.fields[0];
35 | }
36 |
37 | //
38 | // tests
39 | //
40 |
41 | beforeEach(() => {
42 | window.module('formlyMaterial');
43 |
44 | inject((_$compile_, _$rootScope_) => {
45 | $compile = _$compile_;
46 | $rootScope = _$rootScope_;
47 | });
48 | });
49 |
50 | it('should exist', () => {
51 | compile();
52 | expect(element.length).toBe(1);
53 | });
54 |
55 | it('should have proper value', () => {
56 | compile();
57 | expect(element.html()).toContain(field.templateOptions.label);
58 | });
59 |
60 | it('should be before the field', () => {
61 | compile();
62 | expect(element.find('md-checkbox').length).toBe(0);
63 | expect(element.next().children()[0].nodeName).toBe('MD-CHECKBOX');
64 | });
65 |
66 | it('should have styles added', () => {
67 | compile();
68 | expect(element.css('color')).toBe(color);
69 | });
70 |
71 | it('should not have styles added when used with input', () => {
72 | compile({
73 | type: 'input'
74 | });
75 | expect(element.css('color')).not.toBe(color);
76 | });
77 |
78 | it('should not have styles added when used with select', () => {
79 | compile({
80 | type: 'select',
81 | templateOptions: {
82 | options: [{
83 | name: 'foo',
84 | value: 'bar'
85 | }]
86 | }
87 | });
88 | expect(element.css('color')).not.toBe(color);
89 | });
90 |
91 | it('should not have styles added when used with textarea', () => {
92 | compile({
93 | type: 'textarea'
94 | });
95 | expect(element.css('color')).not.toBe(color);
96 | });
97 | });
98 |
--------------------------------------------------------------------------------
/tests/types/slider-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - slider type', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let form;
12 | let element;
13 | let elementScope;
14 | const theme = 'custom';
15 | const fieldConfig = {
16 | key: 'testField',
17 | type: 'slider',
18 | templateOptions: {
19 | theme,
20 | label: 'test field',
21 | disabled: true,
22 | min: 1,
23 | max: 5,
24 | step: 0.5,
25 | discrete: true
26 | }
27 | };
28 | //
29 | // helpers
30 | //
31 |
32 | function compile(options) {
33 | $scope = $rootScope.$new();
34 | $scope.fields = [angular.merge({}, fieldConfig, options)];
35 |
36 | form = $compile(testUtils.getFormTemplate())($scope);
37 | $scope.$digest();
38 | element = form.find('[ng-model]');
39 | elementScope = element.scope();
40 | }
41 |
42 | //
43 | // tests
44 | //
45 |
46 | beforeEach(() => {
47 | window.module('formlyMaterial');
48 |
49 | inject((_$compile_, _$rootScope_) => {
50 | $compile = _$compile_;
51 | $rootScope = _$rootScope_;
52 | });
53 |
54 | compile();
55 | });
56 |
57 | it('should be md-slider element', () => {
58 | expect(element[0].nodeName).toBe('MD-SLIDER');
59 | });
60 |
61 | it('should have proper theme when defined', () => {
62 | expect(element.is(`.md-${theme}-theme`)).toBe(true);
63 | });
64 |
65 | it('should support min option', () => {
66 | expect(parseFloat(element.attr('min'))).toEqual(fieldConfig.templateOptions.min);
67 | });
68 |
69 | it('should support max option', () => {
70 | expect(parseFloat(element.attr('max'))).toEqual(fieldConfig.templateOptions.max);
71 | });
72 |
73 | it('should support step option', () => {
74 | expect(parseFloat(element.attr('step'))).toEqual(fieldConfig.templateOptions.step);
75 | });
76 |
77 | it('should support discrete option', () => {
78 | expect(element.attr('md-discrete')).toEqual(`options.templateOptions['discrete']`);
79 | expect(elementScope.options.templateOptions.discrete).toBe(fieldConfig.templateOptions.discrete);
80 | });
81 |
82 | it('should be able to be disabled', () => {
83 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
84 | expect(elementScope.options.templateOptions.disabled).toBe(true);
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/src/helpers/index.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 |
3 | /**
4 | * Sets attribute with optional value.
5 | * Does not owerwrite.
6 | * @param {Array} nodes nodes
7 | * @param {String} attr attribute name
8 | * @param {String} val atrtibute value
9 | */
10 | function addIfNotPresent(nodes, attr, val) {
11 | angular.forEach(nodes, (node) => {
12 | if (!node.getAttribute(attr)) {
13 | node.setAttribute(attr, val);
14 | }
15 | });
16 | }
17 |
18 | /**
19 | * Gets all ngModels from node
20 | */
21 | function getNgModelNodes(node) {
22 | const query = '[ng-model], [data-ng-model]';
23 |
24 | return node.querySelectorAll(query);
25 | }
26 |
27 | /**
28 | * Adds attribute with optional value to all elements using ngModel directive.
29 | * Handles extras.skipNgModelAttrsManipulator
30 | * And does not overwrite attriutes
31 | *
32 | * @param {String} template Template provided by formly template manipulator
33 | * @param {Object} options Options provided by formly template manipulator
34 | * @param {String} attrName Attribute's name
35 | * @param {String|undefined} Attribute's value (optional)
36 | * @return {String} result
37 | */
38 | export function ngModelAttrsManipulator(template, options, attrName, attrValue) {
39 | const node = document.createElement('div');
40 | const skip = options.extras && options.extras.skipNgModelAttrsManipulator;
41 |
42 | if (skip === true) {
43 | return template;
44 | }
45 | node.innerHTML = template;
46 | const modelNodes = getNgModelNodes(node);
47 |
48 | if (!modelNodes || !modelNodes.length) {
49 | return template;
50 | }
51 |
52 | addIfNotPresent(modelNodes, attrName, attrValue);
53 |
54 | return node.innerHTML;
55 | }
56 |
57 | /**
58 | * Adds ngModelAttr to the field when specified condition is true.
59 | * @param {Array} fields fields provided by formly's fieldTranform
60 | * @param {Funcion} condition with field as only parameter
61 | * @param {String} name ngModelAttr's name
62 | * @param {Object} settings ngModelAttr's settings
63 | * @return {Array} returns fields
64 | */
65 | export function ngModelAttrsTransformer(fields, condition, name, settings) {
66 | (fields || []).forEach((field) => {
67 | if (condition(field) === true) {
68 | if (!field.ngModelAttrs) {
69 | field.ngModelAttrs = {};
70 | }
71 |
72 | if (field.templateOptions && typeof field.templateOptions[name] !== 'undefined') {
73 | field.ngModelAttrs[name] = settings;
74 | }
75 | }
76 | });
77 |
78 | return fields;
79 | }
80 |
--------------------------------------------------------------------------------
/demo/client/data/menu.js:
--------------------------------------------------------------------------------
1 | const { SetModule, Service, Inject } = angular2now;
2 |
3 | SetModule('demo');
4 |
5 | @Service({
6 | name: 'Menu'
7 | })
8 | @Inject(['Examples'])
9 | class Menu {
10 | constructor(Examples) {
11 | this.menu = [];
12 |
13 | // move it from here
14 | this.addHeading('basic');
15 | this.addToggle('types');
16 | this.addToggle('wrappers');
17 | this.addHeading('advanced');
18 | }
19 |
20 | /**
21 | * Add new menu item
22 | * @param {String} name Link's label
23 | * @param {String} type Can be heading, toggle or link
24 | * @param {String|undefined} id Used in /demo/:id
25 | */
26 | add(name, type, id) {
27 | if (typeof name !== 'string' || name.length === 0) {
28 | throw new Error(`[Menu] name has to be a string`);
29 | }
30 |
31 | if (typeof type === 'undefined' || ['toggle', 'link', 'heading'].indexOf(type) === -1) {
32 | throw new Error(`[Menu] type has to be one of: heading, link, toggle`);
33 | }
34 |
35 | this.menu.push({
36 | name,
37 | type,
38 | id
39 | });
40 | }
41 |
42 | /**
43 | * Shorthand method to add menu-link
44 | * @param {String} name
45 | * @param {String} id
46 | */
47 | addLink(name, id) {
48 | this.add(name, 'link', id || name);
49 | }
50 |
51 | /**
52 | * Shorthand method to add menu-heading
53 | * @param {String} name
54 | */
55 | addHeading(name) {
56 | this.add(name, 'heading');
57 | }
58 |
59 | /**
60 | * Shorthand method to add menu-toggle
61 | * @param {String} name
62 | */
63 | addToggle(name) {
64 | this.add(name, 'toggle');
65 | }
66 |
67 | /**
68 | * Add a child to menu-toggle
69 | * @param {String} parent Parent menu item id
70 | * @param {String} name item's label
71 | * @param {String} id item's identifier used as value of id parameter
72 | */
73 | addChild(parent, name, id) {
74 | const found = _.find(this.menu, (item) => item.name === parent);
75 |
76 | if (!found) {
77 | throw new Error(`[Menu] There is no ${parent} available`);
78 | }
79 |
80 | found.children = found.children || [];
81 |
82 | if (_.find(found.children, (child) => child.name === name)) {
83 | throw new Error(`[Menu] There is a child ${name} already`);
84 | }
85 |
86 | found.children.push({
87 | name,
88 | id: id || name
89 | });
90 |
91 | found.children = _.sortBy(found.children, 'name');
92 | }
93 |
94 | /**
95 | * Get menu
96 | * @return {Object}
97 | */
98 | get() {
99 | return {
100 | sections: this.menu
101 | };
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/tests/types/datepicker-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - datepicker type', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let form;
12 | let element;
13 | let elementScope;
14 | const theme = 'custom';
15 | const minDate = new Date(2015, 10, 19);
16 | const maxDate = new Date(2015, 11, 20);
17 | const filterDate = () => true;
18 |
19 | //
20 | // helpers
21 | //
22 |
23 | function compile(options) {
24 | $scope = $rootScope.$new();
25 | $scope.fields = [angular.merge({}, {
26 | key: 'testField',
27 | type: 'datepicker',
28 | templateOptions: {
29 | minDate,
30 | maxDate,
31 | filterDate,
32 | theme,
33 | disabled: true,
34 | label: 'test field',
35 | placeholder: 'Pick a date'
36 | }
37 | }, options)];
38 |
39 | form = $compile(testUtils.getFormTemplate())($scope);
40 | $scope.$digest();
41 | element = form.find('[ng-model]');
42 | elementScope = angular.element(element).scope();
43 | }
44 |
45 | //
46 | // tests
47 | //
48 |
49 | beforeEach(() => {
50 | window.module('formlyMaterial');
51 |
52 | inject((_$compile_, _$rootScope_) => {
53 | $compile = _$compile_;
54 | $rootScope = _$rootScope_;
55 | });
56 |
57 | compile();
58 | });
59 |
60 | it('should be md-chips element', () => {
61 | expect(element[0].nodeName).toBe('MD-DATEPICKER');
62 | });
63 |
64 | it('should have messages', () => {
65 | expect(form.find('[ng-messages]').length).toBe(1);
66 | });
67 |
68 | it('should have proper theme when defined', () => {
69 | expect(element.attr('md-theme')).toBe(theme);
70 | });
71 |
72 | it('should have min date', () => {
73 | expect(element.attr('md-min-date')).toBe(`options.templateOptions['minDate']`);
74 | expect(elementScope.options.templateOptions.minDate.toDateString()).toBe(minDate.toDateString());
75 | });
76 |
77 | it('should have max date', () => {
78 | expect(element.attr('md-max-date')).toBe(`options.templateOptions['maxDate']`);
79 | expect(elementScope.options.templateOptions.maxDate.toDateString()).toBe(maxDate.toDateString());
80 | });
81 |
82 | it('should have date filter', () => {
83 | expect(element.attr('md-date-filter')).toBe(`options.templateOptions['filterDate']`);
84 | expect(elementScope.options.templateOptions.filterDate).toBe(filterDate);
85 | });
86 |
87 | it('should be disabled', () => {
88 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
89 | expect(elementScope.options.templateOptions.disabled).toBe(true);
90 | });
91 | });
92 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | require('argv-set-env')();
2 | var webpack = require('./webpack')('test');
3 |
4 | var testFile = 'tests/index-spec.js';
5 | var ciEnv = process.env.NODE_ENV === 'ci';
6 |
7 | var preprocessors = {};
8 | preprocessors[testFile] = ['webpack'];
9 |
10 | module.exports = function(config) {
11 | var _config = {
12 |
13 | // base path that will be used to resolve all patterns (eg. files, exclude)
14 | basePath: '',
15 |
16 |
17 | // frameworks to use
18 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
19 | frameworks: ['jasmine'],
20 |
21 |
22 | // list of files / patterns to load in the browser
23 | files: [
24 | 'node_modules/jquery/dist/jquery.js',
25 | 'node_modules/api-check/dist/api-check.js',
26 | 'node_modules/angular/angular.js',
27 | 'node_modules/angular-mocks/angular-mocks.js',
28 | 'node_modules/angular-animate/angular-animate.js',
29 | 'node_modules/angular-aria/angular-aria.js',
30 | 'node_modules/angular-messages/angular-messages.js',
31 | 'node_modules/angular-material/angular-material.js',
32 | 'node_modules/angular-material/angular-material-mocks.js',
33 | 'node_modules/angular-formly/dist/formly.js',
34 | testFile
35 | ],
36 |
37 |
38 | // list of files to exclude
39 | exclude: [],
40 |
41 |
42 | // preprocess matching files before serving them to the browser
43 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
44 | preprocessors: preprocessors,
45 |
46 | webpack: webpack,
47 |
48 | coverageReporter: {
49 | reporters: [{
50 | type: 'lcov',
51 | dir: 'coverage/',
52 | subdir: '.'
53 | }, {
54 | type: 'json',
55 | dir: 'coverage/',
56 | subdir: '.'
57 | }, {
58 | type: 'text-summary'
59 | }]
60 | },
61 |
62 | // test results reporter to use
63 | // possible values: 'dots', 'progress'
64 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
65 | reporters: ['progress', 'coverage', 'kjhtml'],
66 |
67 | // web server port
68 | port: 9876,
69 |
70 | // enable / disable colors in the output (reporters and logs)
71 | colors: true,
72 |
73 | // level of logging
74 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
75 | logLevel: config.LOG_INFO,
76 |
77 | // enable / disable watching file and executing tests whenever any file changes
78 | autoWatch: !ciEnv,
79 |
80 | // start these browsers
81 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
82 | browsers: [(ciEnv ? 'Firefox' : 'Chrome')],
83 |
84 | // Continuous Integration mode
85 | // if true, Karma captures browsers, runs the tests and exits
86 | singleRun: ciEnv
87 | };
88 | config.set(_config);
89 | };
90 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-formly-material",
3 | "version": "0.14.3",
4 | "description": "Material design templates for angular-formly",
5 | "main": "dist/formly-material.js",
6 | "scripts": {
7 | "build:dist": "webpack --progress",
8 | "build:prod": "webpack --progress --set-env-NODE_ENV=production",
9 | "build": "npm run build:dist && npm run build:prod",
10 | "lint:src": "eslint src/**/*.js",
11 | "lint:tests": "eslint tests/**/*.js --no-ignore",
12 | "lint": "npm run lint:src && npm run lint:tests",
13 | "coverage:codecov": "cat ./coverage/lcov.info | node_modules/.bin/codecov",
14 | "coverage:coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
15 | "coverage:codacy": "cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage",
16 | "test": "karma start karma.conf.js --set-env-NODE_ENV=ci",
17 | "test:watch": "karma start karma.conf.js"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/formly-js/angular-formly-templates-material.git"
22 | },
23 | "keywords": [
24 | "AngularJs",
25 | "form",
26 | "formly",
27 | "json",
28 | "html",
29 | "material"
30 | ],
31 | "author": "Kamil Kisiela ",
32 | "license": "MIT",
33 | "bugs": {
34 | "url": "https://github.com/formly-js/angular-formly-templates-material/issues"
35 | },
36 | "homepage": "https://github.com/formly-js/angular-formly-templates-material#readme",
37 | "dependencies": {
38 | "angular": ">= 1.4.0-beta.0 || >= 1.5.0-beta.0",
39 | "angular-messages": ">= 1.4.0-beta.0 || >= 1.5.0-beta.0",
40 | "angular-animate": ">= 1.4.0-beta.0 || >= 1.5.0-beta.0",
41 | "angular-aria": ">= 1.4.0-beta.0 || >= 1.5.0-beta.0",
42 | "angular-material": "^1.0.0",
43 | "angular-formly": ">=7.3.0",
44 | "api-check": ">=7.0.0"
45 | },
46 | "devDependencies": {
47 | "angular-mocks": "^1.5.0",
48 | "argv-set-env": "^1.0.0",
49 | "babel": "^6.3.26",
50 | "babel-core": "^6.4.5",
51 | "babel-eslint": "^5.0.0--beta",
52 | "babel-loader": "^6.2.1",
53 | "babel-preset-es2015": "^6.3.13",
54 | "codacy-coverage": "^1.1.3",
55 | "codecov.io": "^0.1.6",
56 | "coveralls": "^2.11.4",
57 | "eslint": "^1.10.3",
58 | "eslint-config-airbnb": "^2.0.0",
59 | "html-loader": "^0.4.0",
60 | "isparta": "^4.0.0",
61 | "isparta-loader": "2.0.0",
62 | "jasmine-core": "^2.3.4",
63 | "jquery": "^2.1.4",
64 | "karma": "^0.13.19",
65 | "karma-babel-preprocessor": "^6.0.1",
66 | "karma-chrome-launcher": "^0.2.1",
67 | "karma-coverage": "^0.5.3",
68 | "karma-firefox-launcher": "^0.1.7",
69 | "karma-jasmine": "^0.3.6",
70 | "karma-jasmine-html-reporter": "^0.2.0",
71 | "karma-sourcemap-loader": "^0.3.6",
72 | "karma-webpack": "^1.7.0",
73 | "lodash": "^3.10.1",
74 | "mys-common-tools": "latest",
75 | "webpack": "^1.12.9"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/types/textarea-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - textarea type', () => {
5 | //
6 | // vars
7 | //
8 |
9 | let $compile;
10 | let $rootScope;
11 | let $scope;
12 | let form;
13 | let element;
14 | let elementScope;
15 | let field;
16 | const theme = 'custom';
17 |
18 | //
19 | // helpers
20 | //
21 |
22 | function compile(options) {
23 | $scope = $rootScope.$new();
24 | $scope.fields = [angular.merge({}, {
25 | key: 'testField',
26 | type: 'textarea',
27 | templateOptions: {
28 | theme,
29 | label: 'test field',
30 | disabled: true,
31 | rows: 5,
32 | cols: 6
33 | }
34 | }, options)];
35 |
36 | form = $compile(testUtils.getFormTemplate())($scope);
37 | $scope.$digest();
38 | field = $scope.fields[0];
39 | element = form.find('[ng-model]');
40 | elementScope = element.scope();
41 | }
42 |
43 | //
44 | // tests
45 | //
46 |
47 | beforeEach(() => {
48 | window.module('formlyMaterial');
49 |
50 | inject((_$compile_, _$rootScope_) => {
51 | $compile = _$compile_;
52 | $rootScope = _$rootScope_;
53 | });
54 |
55 | compile();
56 | });
57 |
58 | it('should be input element', () => {
59 | expect(element[0].nodeName).toBe('TEXTAREA');
60 | });
61 |
62 | it('should have messages wrapper', () => {
63 | expect(form.find('[ng-messages]').length).toBe(1);
64 | });
65 |
66 | it('should have label wrapper', () => {
67 | const label = form.find('label');
68 |
69 | expect(label.length).toBe(1);
70 | expect(label.html()).toContain(field.templateOptions.label);
71 | });
72 |
73 | it('should have proper theme when defined', () => {
74 | expect(element.parent().is(`.md-${theme}-theme`)).toBe(true);
75 | });
76 |
77 | it('should not auto grow', () => {
78 | expect(element.attr('md-no-autogrow')).toBeUndefined();
79 | });
80 |
81 | it('should be able to disable autogrowing', () => {
82 | compile({
83 | templateOptions: {
84 | grow: false
85 | }
86 | });
87 | expect(element.attr('md-no-autogrow')).toBeDefined();
88 | });
89 |
90 | it('should have inputContainer wrapper', () => {
91 | expect(form.find('md-input-container').length).toBe(1);
92 | });
93 |
94 | it('should be able to set rows', () => {
95 | expect(parseInt(element.attr('rows'), 10)).toEqual(field.templateOptions.rows);
96 | });
97 |
98 | it('should be able to set cols', () => {
99 | expect(parseInt(element.attr('cols'), 10)).toEqual(field.templateOptions.cols);
100 | });
101 |
102 | it('should be able to be disabled', () => {
103 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
104 | expect(elementScope.options.templateOptions.disabled).toBe(true);
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/demo/client/data/codepen.js:
--------------------------------------------------------------------------------
1 | const { SetModule, Service, Inject } = angular2now;
2 |
3 | SetModule('demo');
4 |
5 | @Service({
6 | name: 'Codepen'
7 | })
8 | @Inject(['$document'])
9 | class Codepen {
10 | constructor($document, Examples) {
11 | this.$document = $document;
12 | this.Examples = Examples;
13 | this.address = 'http://codepen.io/pen/define/';
14 | }
15 |
16 | open(exampleId) {
17 | // const data = codepenDataAdapter.translate(demo, $demoAngularScripts.all());
18 | // const example = this.Examples.get(exampleId);
19 | const data = {
20 | css_external: [
21 | '//npmcdn.com/angular-material@1.0.0/angular-material.min.css'
22 | ].join(';'),
23 | js_external: [
24 | '//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js',
25 | '//npmcdn.com/angular-animate@1.4.8/angular-animate.min.js',
26 | '//npmcdn.com/angular-aria@1.4.8/angular-aria.min.js',
27 | '//npmcdn.com/angular-material@latest/angular-material.min.js',
28 | '//npmcdn.com/angular-messages@1.4.8/angular-messages.min.js',
29 | '//npmcdn.com/api-check@latest/dist/api-check.js',
30 | '//npmcdn.com/angular-formly@latest/dist/formly.js',
31 | '//npmcdn.com/angular-formly-material@latest/dist/formly-material.js'
32 | ].join(';'),
33 | html: this._getHTML().trim()
34 | };
35 | const form = this._buildForm(data);
36 |
37 | this.$document.find('body').append(form);
38 | form[0].submit();
39 | form.remove();
40 | }
41 |
42 | _buildForm(data) {
43 | const form = angular.element(
44 | ``
45 | );
46 | const input = ``;
47 | form.append(input);
48 | return form;
49 | }
50 |
51 | _escapeJsonQuotes(json) {
52 | return JSON.stringify(json)
53 | .replace(/'/g, ''')
54 | .replace(/"/g, '"');
55 | }
56 |
57 | _getHTML() {
58 | return `
59 |
60 |
65 |
66 | `;
67 | }
68 |
69 | _getJS() {
70 | return `
71 | (function () {
72 | 'use strict';
73 | angular
74 | .module('demo', ['formlyMaterial'])
75 | .controller('DemoCtrl', DemoCtrl);
76 |
77 | function DemoCtrl () {
78 | var self = this;
79 |
80 | self.fields = ::field;
81 | self.model = ::model;
82 | self.form = ::form;
83 | self.options = ::options;
84 | self.submit = function() {}
85 | }
86 | })();
87 | `;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tests/types/chips-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - chips type', () => {
5 | //
6 | // vars
7 | //
8 | let $compile;
9 | let $rootScope;
10 | let $scope;
11 | let element;
12 | let field;
13 | let fieldScope;
14 | const theme = 'custom';
15 |
16 | function onAdd(/* $modelValue, $inputValue, scope, $event */) {
17 | return true;
18 | }
19 |
20 | function onRemove(/* $modelValue, $inputValue, scope, $event */) {
21 | return true;
22 | }
23 |
24 | function onSelect(/* $modelValue, $inputValue, scope, $event */) {
25 | return true;
26 | }
27 | //
28 | // helpers
29 | //
30 |
31 | function compile(options) {
32 | $scope = $rootScope.$new();
33 | $scope.fields = [angular.merge({}, {
34 | key: 'testField',
35 | type: 'chips',
36 | templateOptions: {
37 | onAdd,
38 | onRemove,
39 | onSelect,
40 | theme,
41 | label: 'test field',
42 | placeholder: '+tags',
43 | secondaryPlaceholder: 'Add tag',
44 | deleteButtonLabel: 'Remove',
45 | deleteHint: 'Remove tag',
46 | disabled: true
47 | }
48 | }, options)];
49 |
50 | const form = $compile(testUtils.getFormTemplate())($scope);
51 |
52 | $scope.$digest();
53 | field = $scope.fields[0];
54 | element = form.find('[ng-model]');
55 | fieldScope = angular.element(element).scope();
56 | }
57 |
58 | //
59 | // tests
60 | //
61 |
62 | beforeEach(() => {
63 | window.module('formlyMaterial');
64 |
65 | inject((_$compile_, _$rootScope_) => {
66 | $compile = _$compile_;
67 | $rootScope = _$rootScope_;
68 | });
69 |
70 | compile();
71 | });
72 |
73 | it('should be md-chips element', () => {
74 | expect(element[0].nodeName).toBe('MD-CHIPS');
75 | });
76 |
77 | it('should have placeholder', () => {
78 | expect(element.attr('placeholder')).toBe(field.templateOptions.placeholder);
79 | });
80 |
81 | it('should have proper theme when defined', () => {
82 | expect(element.is(`.md-${theme}-theme`)).toBe(true);
83 | });
84 |
85 | it('should have secondary placeholder', () => {
86 | expect(element.attr('secondary-placeholder')).toBe(field.templateOptions.secondaryPlaceholder);
87 | });
88 |
89 | it('should have delete button label', () => {
90 | expect(element.attr('delete-button-label')).toBe(field.templateOptions.deleteButtonLabel);
91 | });
92 |
93 | it('should have delete hint', () => {
94 | expect(element.attr('delete-hint')).toBe(field.templateOptions.deleteHint);
95 | });
96 |
97 | it('should have onAdd callback', () => {
98 | expect(element.attr('md-on-add')).toBe(`options.templateOptions['onAdd'](model[options.key], options, this, $event)`);
99 | expect(fieldScope.options.templateOptions.onAdd).toBe(onAdd);
100 | });
101 |
102 | it('should have onRemove callback', () => {
103 | expect(element.attr('md-on-remove')).toBe(`options.templateOptions['onRemove'](model[options.key], options, this, $event)`);
104 | expect(fieldScope.options.templateOptions.onRemove).toBe(onRemove);
105 | });
106 |
107 | it('should have onSelect callback', () => {
108 | expect(element.attr('md-on-select')).toBe(`options.templateOptions['onSelect'](model[options.key], options, this, $event)`);
109 | expect(fieldScope.options.templateOptions.onSelect).toBe(onSelect);
110 | });
111 |
112 | it('should be disabled and have readonly attribute', () => {
113 | expect(element[0].attributes.readonly.value).toBe('to.disabled');
114 | expect(fieldScope.options.templateOptions.disabled).toBe(true);
115 | });
116 | });
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FormlyMaterial
2 |
3 | Material Design Templates for [Angular-Formly](http://angular-formly.com). Modern & flexible forms configured easily in a JSON object.
4 |
5 | ---
6 |
7 | **Chat**
8 |
9 | [](https://gitter.im/formly-js/angular-formly-templates-material?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10 |
11 | **Versions**
12 |
13 | [](https://badge.fury.io/gh/formly-js%2Fangular-formly-templates-material)
14 | [](https://badge.fury.io/js/angular-formly-material)
15 | [](https://badge.fury.io/bo/angular-formly-material)
16 |
17 | **Code**
18 |
19 | [](https://travis-ci.org/formly-js/angular-formly-templates-material)
20 | [](https://coveralls.io/github/formly-js/angular-formly-templates-material?branch=master)
21 | [](https://www.codacy.com/app/mys-sterowiec/angular-formly-templates-material)
22 |
23 | ---
24 |
25 | ## Table of contents
26 |
27 | - [Install](#install)
28 | - [Getting Started](#getting-started)
29 | - [Demo](#demo)
30 | - [Requests?](#requests)
31 | - [Requirements](#requirements)
32 | - [Components](#components)
33 | - [Fields](#fields)
34 | - [Wrappers](#wrappers)
35 | - [Common settings](#common-settings)
36 | - [Theme](#theme-string)
37 |
38 | ---
39 |
40 | ## Install
41 |
42 | ```
43 | npm install angular-formly-material
44 | ```
45 |
46 | ```
47 | bower install angular-formly-material
48 | ```
49 |
50 | ```
51 | meteor add formly:angular-formly-templates-material
52 | ```
53 |
54 | ## Getting Started
55 |
56 | 1. Add package using one of methods above
57 | 2. Add the following dependencies to your AngularJS module:
58 |
59 | ```javascript
60 | angular.module('myAppName', [
61 | 'formlyMaterial'
62 | ])
63 | ```
64 |
65 | ## Demo
66 |
67 | Visit [formly-material.meteor.com](http://formly-material.meteor.com/demo/input)
68 |
69 | ## Requests?
70 |
71 | Maybe you need some new feature? Go here:
72 |
73 | https://github.com/formly-js/angular-formly-templates-material/issues/4
74 |
75 | ## Requirements
76 |
77 | - angular ~ 1.4.0
78 | - angular-messages ~ 1.4.0
79 | - angular-material ~ 1.0.0
80 | - angular-formly ~ 7.3.0
81 |
82 | ## Components
83 |
84 | Any requests? Add issue!
85 |
86 | ### Fields
87 |
88 | - [checkbox](docs/types/checkbox.md)
89 | - [chips](docs/types/chips.md)
90 | - [datepicker](docs/types/datepicker.md)
91 | - [input](docs/types/input.md)
92 | - [radio](docs/types/radio.md)
93 | - [select](docs/types/select.md)
94 | - [slider](docs/types/slider.md)
95 | - [switch](docs/types/switch.md)
96 | - [textarea](docs/types/textarea.md)
97 |
98 | ### Wrappers
99 |
100 | - [divider](docs/wrappers/divider.md)
101 | - [inputContainer](docs/wrappers/input-container.md)
102 | - [label](docs/wrappers/label.md)
103 | - [messages](docs/wrappers/messages.md)
104 |
105 | ### Common settings
106 |
107 | #### templateOptions.label *: string*
108 |
109 | #### templateOptions.theme *: string*
110 |
111 | Value of md-theme used on field
112 |
113 | #### templateOptions.disabled _: boolean_
114 |
115 | #### templateOptions.className _: expression_
116 |
117 | equivalent to ng-class on ng-model
118 |
119 | ---
120 |
121 | Requests (?). Post an issue.
122 |
--------------------------------------------------------------------------------
/tests/types/radio-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - radio type', () => {
5 | //
6 | // vars
7 | //
8 |
9 | let $compile;
10 | let $rootScope;
11 | let $scope;
12 | let form;
13 | let element;
14 | let optionsElements;
15 | let field;
16 | const theme = 'custom';
17 |
18 | //
19 | // helpers
20 | //
21 |
22 | function compile(options) {
23 | $scope = $rootScope.$new();
24 | $scope.fields = [angular.merge({}, {
25 | key: 'testField',
26 | type: 'radio',
27 | templateOptions: {
28 | theme,
29 | label: 'test field',
30 | options: [{
31 | name: 'first',
32 | nameUp: 'FIRST',
33 | value: 'f',
34 | valueUp: 'F'
35 | }, {
36 | name: 'second',
37 | nameUp: 'SECOND',
38 | value: 's',
39 | valueUp: 'S'
40 | }]
41 | }
42 | }, options)];
43 |
44 | form = $compile(testUtils.getFormTemplate())($scope);
45 | $scope.$digest();
46 | field = $scope.fields[0];
47 | element = form.find('[ng-model]');
48 | optionsElements = element.find('md-radio-button');
49 | }
50 |
51 | //
52 | // tests
53 | //
54 |
55 | beforeEach(() => {
56 | window.module('formlyMaterial');
57 |
58 | inject((_$compile_, _$rootScope_) => {
59 | $compile = _$compile_;
60 | $rootScope = _$rootScope_;
61 | });
62 | });
63 |
64 | it('should be md-radio-group element', () => {
65 | compile();
66 | expect(element[0].nodeName).toBe('MD-RADIO-GROUP');
67 | });
68 |
69 | it('should have proper theme when defined', () => {
70 | compile();
71 | expect(element.is(`.md-${theme}-theme`)).toBe(true);
72 | });
73 |
74 | it('should have options with default properties for name and value', () => {
75 | compile();
76 | expect(optionsElements.length).toBe(field.templateOptions.options.length);
77 |
78 | field.templateOptions.options.forEach((option, key) => {
79 | const el = angular.element(optionsElements[key]);
80 |
81 | expect(el.attr('value')).toBe(option.value);
82 | expect(el.find('.md-label > span').html()).toContain(option.name);
83 | });
84 | });
85 |
86 | it('should handle valueProp', () => {
87 | compile({
88 | templateOptions: {
89 | valueProp: 'valueUp'
90 | }
91 | });
92 | expect(optionsElements.length).toBe(field.templateOptions.options.length);
93 |
94 | field.templateOptions.options.forEach((option, key) => {
95 | const el = angular.element(optionsElements[key]);
96 |
97 | expect(el.attr('value')).toBe(option.valueUp);
98 | expect(el.find('.md-label > span').html()).toContain(option.name);
99 | });
100 | });
101 |
102 | it('should handle labelProp', () => {
103 | compile({
104 | templateOptions: {
105 | labelProp: 'nameUp'
106 | }
107 | });
108 | expect(optionsElements.length).toBe(field.templateOptions.options.length);
109 |
110 | field.templateOptions.options.forEach((option, key) => {
111 | const el = angular.element(optionsElements[key]);
112 |
113 | expect(el.attr('value')).toBe(option.value);
114 | expect(el.find('.md-label > span').html()).toContain(option.nameUp);
115 | });
116 | });
117 |
118 | it('should has disabled options', () => {
119 | compile({
120 | templateOptions: {
121 | disabled: true
122 | }
123 | });
124 |
125 | expect(optionsElements.length).toBe(field.templateOptions.options.length);
126 |
127 | field.templateOptions.options.forEach((option, key) => {
128 | const el = angular.element(optionsElements[key]);
129 |
130 | expect(el.attr('ng-disabled')).toBe('to.disabled');
131 | expect(el.scope().to.disabled).toBe(true);
132 | });
133 | });
134 | });
135 |
--------------------------------------------------------------------------------
/tests/types/input-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - input type', () => {
5 | //
6 | // vars
7 | //
8 |
9 | let $compile;
10 | let $rootScope;
11 | let $scope;
12 | let form;
13 | let element;
14 | let field;
15 | const theme = 'custom';
16 |
17 | //
18 | // helpers
19 | //
20 |
21 | function compile(options) {
22 | $scope = $rootScope.$new();
23 | $scope.fields = [angular.merge({}, {
24 | key: 'testField',
25 | type: 'input',
26 | templateOptions: {
27 | theme,
28 | disabled: true,
29 | type: 'email',
30 | label: 'test field'
31 | }
32 | }, options)];
33 |
34 | form = $compile(testUtils.getFormTemplate())($scope);
35 | $scope.$digest();
36 | field = $scope.fields[0];
37 | element = form.find('[ng-model]');
38 | }
39 |
40 | //
41 | // tests
42 | //
43 |
44 | beforeEach(() => {
45 | window.module('formlyMaterial');
46 |
47 | inject((_$compile_, _$rootScope_) => {
48 | $compile = _$compile_;
49 | $rootScope = _$rootScope_;
50 | });
51 | });
52 |
53 | describe('basics', () => {
54 | beforeEach(() => {
55 | compile();
56 | });
57 |
58 | it('should be input element', () => {
59 | expect(element[0].nodeName).toBe('INPUT');
60 | });
61 |
62 | it('should have proper type attribute', () => {
63 | expect(element.attr('type')).toBe(field.templateOptions.type);
64 | });
65 |
66 | it('should have proper theme when defined', () => {
67 | expect(element.parent().is(`.md-${theme}-theme`)).toBe(true);
68 | });
69 |
70 | it('should have messages wrapper', () => {
71 | expect(form.find('[ng-messages]').length).toBe(1);
72 | });
73 |
74 | it('should have label wrapper', () => {
75 | const label = form.find('label');
76 |
77 | expect(label.length).toBe(1);
78 | expect(label.html()).toContain(field.templateOptions.label);
79 | });
80 |
81 | it('should have inputContainer wrapper', () => {
82 | expect(form.find('md-input-container').length).toBe(1);
83 | });
84 | });
85 |
86 | it('should be disabled', () => {
87 | const scope = element.scope();
88 |
89 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
90 | expect(scope.options.templateOptions.disabled).toBe(true);
91 | });
92 |
93 | describe('pattern', () => {
94 | it('should accept string', () => {
95 | const pattern = '[a-z]+';
96 |
97 | compile({
98 | templateOptions: {
99 | pattern
100 | }
101 | });
102 |
103 | expect(element.attr('ng-pattern')).toEqual(field.templateOptions.pattern);
104 | });
105 |
106 | it('should accept RegExp', () => {
107 | const pattern = /[a-z]+/;
108 |
109 | compile({
110 | templateOptions: {
111 | pattern
112 | }
113 | });
114 |
115 | expect(element.attr('ng-pattern')).toEqual(`${field.templateOptions.pattern}`);
116 | });
117 | });
118 |
119 | describe('number type specific', () => {
120 | describe('step attribute', () => {
121 | // XXX BE instead of NOT BE because `step` attr is now fully supported
122 | // angular-formly#8042d2a
123 | it('should BE available on non number type', () => {
124 | compile({
125 | templateOptions: {
126 | type: 'text',
127 | step: 2
128 | }
129 | });
130 |
131 | expect(parseInt(element.attr('step'), 10)).toBe(field.templateOptions.step);
132 | });
133 |
134 | it('should be available on number type', () => {
135 | compile({
136 | templateOptions: {
137 | type: 'number',
138 | step: 2
139 | }
140 | });
141 |
142 | expect(parseInt(element.attr('step'), 10)).toEqual(field.templateOptions.step);
143 | });
144 | });
145 |
146 | describe('min attribute', () => {
147 | it('should be available on number type', () => {
148 | compile({
149 | templateOptions: {
150 | type: 'number',
151 | min: 2
152 | }
153 | });
154 |
155 | expect(parseInt(element.attr('min'), 10)).toEqual(field.templateOptions.min);
156 | });
157 | });
158 |
159 | describe('max attribute', () => {
160 | it('should be available on number type', () => {
161 | compile({
162 | templateOptions: {
163 | type: 'number',
164 | max: 2
165 | }
166 | });
167 |
168 | expect(parseInt(element.attr('max'), 10)).toEqual(field.templateOptions.max);
169 | });
170 | });
171 | });
172 | });
173 |
--------------------------------------------------------------------------------
/tests/types/select-spec.js:
--------------------------------------------------------------------------------
1 | import testUtils from './../test-utils';
2 | import angular from 'angular';
3 |
4 | describe('formlyMaterial - select type', () => {
5 | //
6 | // vars
7 | //
8 |
9 | let $compile;
10 | let $rootScope;
11 | let $scope;
12 | let $document;
13 | let $material;
14 | let form;
15 | let element;
16 | let elementScope;
17 | let field;
18 | const theme = 'custom';
19 |
20 | function onClose(/* $modelValue, $inputValue, scope, $event */) {
21 | return true;
22 | }
23 |
24 | function onOpen(/* $modelValue, $inputValue, scope, $event */) {
25 | return true;
26 | }
27 | //
28 | // helpers
29 | //
30 |
31 | function compile(options) {
32 | $scope = $rootScope.$new();
33 | $scope.fields = [angular.merge({}, {
34 | key: 'testField',
35 | type: 'select',
36 | templateOptions: {
37 | theme,
38 | label: 'test field',
39 | multiple: true,
40 | onClose,
41 | onOpen,
42 | options: [{
43 | name: 'first',
44 | nameUp: 'FIRST',
45 | value: 'f',
46 | valueUp: 'F'
47 | }, {
48 | name: 'second',
49 | nameUp: 'SECOND',
50 | value: 's',
51 | valueUp: 'S'
52 | }]
53 | }
54 | }, options)];
55 |
56 | form = $compile(testUtils.getFormTemplate())($scope);
57 | $scope.$digest();
58 | field = $scope.fields[0];
59 | element = form.find('[ng-model]');
60 | elementScope = element.scope();
61 | }
62 |
63 | function waitForSelectOpen() {
64 | $material.flushInterimElement();
65 | }
66 |
67 | function openSelect() {
68 | element.triggerHandler('click');
69 | }
70 |
71 | function closeSelect() {
72 | $document.find('md-select-menu').parent().remove();
73 | $document.find('body').attr('style', '');
74 | $document.find('md-backdrop').remove();
75 | }
76 |
77 | function selectOptions() {
78 | openSelect();
79 | waitForSelectOpen();
80 | const selectMenu = $document.find('md-select-menu');
81 |
82 | selectMenu.hide();
83 | $document.find('.md-scroll-mask').remove();
84 | return selectMenu.find('md-option');
85 | }
86 |
87 | //
88 | // tests
89 | //
90 |
91 | beforeEach(() => {
92 | window.angular.module('testMod', ['formlyMaterial', 'ngMaterial-mock']);
93 | window.module('testMod');
94 |
95 | inject((_$compile_, _$rootScope_, _$document_, _$material_) => {
96 | $compile = _$compile_;
97 | $rootScope = _$rootScope_;
98 | $document = _$document_;
99 | $material = _$material_;
100 | });
101 | });
102 |
103 | it('should be md-select element', () => {
104 | compile();
105 | expect(element[0].nodeName).toBe('MD-SELECT');
106 | });
107 |
108 | it('should be able to pick multiple options', () => {
109 | compile();
110 | expect(element.attr('multiple')).toBeDefined();
111 | });
112 |
113 | it('should have proper theme when defined', () => {
114 | compile();
115 | expect(element.is(`.md-${theme}-theme`)).toBe(true);
116 | });
117 |
118 | it('should not add multiple directive when does not equal true', () => {
119 | compile({
120 | templateOptions: {
121 | multiple: false
122 | }
123 | });
124 | expect(element.attr('multiple')).toBeUndefined();
125 | });
126 |
127 | it('should be able to bind md-on-close', () => {
128 | compile();
129 | expect(element.attr('md-on-close')).toBe(`options.templateOptions['onClose'](model[options.key], options, this, $event)`);
130 | expect(elementScope.options.templateOptions.onClose).toBe(onClose);
131 | });
132 |
133 | it('should be able to bind md-on-open', () => {
134 | compile();
135 | expect(element.attr('md-on-open')).toBe(`options.templateOptions['onOpen'](model[options.key], options, this, $event)`);
136 | expect(elementScope.options.templateOptions.onOpen).toBe(onOpen);
137 | });
138 |
139 | it('should be able to be disabled', () => {
140 | compile({
141 | templateOptions: {
142 | disabled: true
143 | }
144 | });
145 |
146 | expect(element.attr('ng-disabled')).toBe(`options.templateOptions['disabled']`);
147 | expect(elementScope.options.templateOptions.disabled).toBe(true);
148 | });
149 |
150 | describe('check options', () => {
151 | afterEach(() => {
152 | closeSelect();
153 | });
154 |
155 | it('should have options with default properties for name and value', () => {
156 | compile();
157 | const optionsEl = selectOptions();
158 |
159 | expect(optionsEl.length).toBe(field.templateOptions.options.length);
160 | field.templateOptions.options.forEach((option, key) => {
161 | const el = angular.element(optionsEl[key]);
162 |
163 | expect(el.attr('value')).toBe(option.value);
164 | expect(el.find('.md-text').html()).toContain(option.name);
165 | });
166 | });
167 |
168 | it('should have options with custom properties for name and value', () => {
169 | compile({
170 | templateOptions: {
171 | labelProp: 'nameUp',
172 | valueProp: 'valueUp'
173 | }
174 | });
175 | const optionsEl = selectOptions();
176 |
177 | expect(optionsEl.length).toBe(field.templateOptions.options.length);
178 | field.templateOptions.options.forEach((option, key) => {
179 | const el = angular.element(optionsEl[key]);
180 |
181 | expect(el.attr('value')).toBe(option.valueUp);
182 | expect(el.find('.md-text').html()).toContain(option.nameUp);
183 | });
184 | });
185 | });
186 | });
187 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [0.14.3](https://github.com/formly-js/angular-formly-templates-material/compare/v0.14.2...v0.14.3) - 2016-06-23
6 |
7 | ### Added
8 |
9 | - Allow to add step attribute on every field (6bc6989)
10 |
11 | ### Fixed
12 |
13 | - (chips, select) Bind callback functions by using statement (#45)
14 |
15 | ## [0.14.2](https://github.com/formly-js/angular-formly-templates-material/compare/v0.14.1...v0.14.2) - 2016-05-30
16 |
17 | ### Added
18 |
19 | - Support for higher versions of angular (#34)
20 |
21 | ### Fixed
22 |
23 | - (label) missing left padding (#29)
24 | - assumption of existence of `templateOptions` (#32)
25 |
26 | ## [0.14.1](https://github.com/formly-js/angular-formly-templates-material/compare/v0.14.0...v0.14.1) - 2016-01-27
27 |
28 | ### Added
29 |
30 | - Demo (formly-material.meteor.com)
31 |
32 | ### Fixed
33 |
34 | - #22
35 | - #23
36 |
37 | ## [0.14.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.13.0...v0.14.0)
38 |
39 | ### Added
40 |
41 | - (chips) support for **templateOptions.disabled** (#14) (eea2fcf, f2d2e40)
42 | - (radio) support for **templateOptions.disabled** (#13) (e6104ea, c04f63d)
43 | - (checkbox) support for **templateOptions.disabled** (bdbe651, aec4e60)
44 | - (datepicker) support for **templateOptions.disabled** (41b99d6, 7ee864a)
45 | - (input) support for **templateOptions.disabled** (2b528c3, 18c819f)
46 | - (select) support for **templateOptions.disabled** (2bb10e0, 9f76f0e)
47 | - (slider) support for **templateOptions.disabled** (27d1d2a, f6b5890)
48 | - (switch) support for **templateOptions.disabled** (7c1865c, 178ac76)
49 | - (textarea) support for **templateOptions.disabled** (858f9fa, 8a246f5)
50 | - **templateOptions.className** option (equivalent to ng-class) (#15, #16) (718c172, d656b4c)
51 |
52 | ## [0.13.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.12.0...v0.13.0)
53 |
54 | ### Added
55 |
56 | - (input) support for **ng-pattern** as **templateOptions.pattern** (#10)
57 | - (chips) has now **label** wrapper
58 | - (datepicker) has now **label** wrapper
59 | - (radio) has now **label** wrapper (#9)
60 | - (slider) has now **label** wrapper
61 |
62 | ## [0.12.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.11.0...v0.12.0) - 2015-12-30
63 |
64 | ### Added
65 |
66 | - (messages) support for `errorExistsAndShouldBeVisible` (#7)
67 | - (input) support for **min** attribute of 'number' type (#6)
68 | - (input) support for **max** attribute of 'number' type (#6)
69 | - (input) support for **step** attribute of 'number' type (#6)
70 |
71 | ## [0.11.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.10.0...v0.11.0) - 2015-12-18
72 |
73 | ### Added
74 |
75 | - (chips) onAdd callback (equivalent to md-on-add)
76 | - (chips) onRemove callback (equivalent to md-on-remove)
77 | - (chips) onSelect callback (equivalent to md-on-select)
78 |
79 | ## [0.10.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.9.0...v0.10.0) - 2015-12-17
80 |
81 | ### Added
82 |
83 | - (textarea) **grow** option (equivalent to md-no-autogrow)
84 | - **divider** wrapper ([see documentation](docs/wrappers/divider.md)\)
85 |
86 | ## [0.9.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.8.0...v0.9.0) - 2015-12-17
87 |
88 | ### Added
89 |
90 | - (select) **onClose** and **onOpen** options (equivalent to md-on-close and md-on-open)
91 |
92 | ## [0.8.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.7.3...v0.8.0) - 2015-12-16
93 |
94 | ### Changed
95 |
96 | - BREAKING CHANGE: requires now **angular-material v1.0.0**
97 | - BREAKING CHANGE: for meteor package uses now **formly:angular-formly** instead of wieldo:angular-formly
98 |
99 | ## [0.7.3](https://github.com/formly-js/angular-formly-templates-material/compare/v0.7.2...v0.7.3) - 2015-12-14
100 |
101 | ### Changed
102 |
103 | - Package name in AtmosphereJS (formly:angular-formly-templates-material)
104 |
105 | ## [0.7.2](https://github.com/formly-js/angular-formly-templates-material/compare/v0.7.1...v0.7.2) - 2015-12-08
106 |
107 | ### Added
108 |
109 | - Documentation for all fields and wrappers
110 | - Banner with version in dist files
111 |
112 | ### Changed
113 |
114 | - Links to repository after transfer from wieldo to formly-js
115 |
116 | ## [0.7.1](https://github.com/formly-js/angular-formly-templates-material/compare/v0.7.0...v0.7.1) - 2015-12-01
117 |
118 | ### Changed
119 |
120 | - use bound for datepicker's minDate, maxDate and filterDate instead of template manipulator
121 | - remove bound from slider's min, max and step attributes
122 |
123 | ## [0.7.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.6.0...v0.7.0) - 2015-11-29
124 |
125 | ### Added
126 |
127 | - support for npm and bower (angular-formly-material).
128 |
129 | ### Changed
130 |
131 | - Unit testing using karma instead of velocity (with coverage reports)
132 |
133 | ## [0.6.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.5.2...v0.6.0) - 2015-11-27
134 |
135 | ### Added
136 |
137 | - compatibility with Meteor releases lower then 1.2
138 |
139 | ## [0.5.2](https://github.com/formly-js/angular-formly-templates-material/compare/v0.5.1...v0.5.2) - 2015-11-19
140 |
141 | ### Fixed
142 |
143 | - missing md-theme attribute when using templateOptions.theme
144 |
145 | ### Added
146 |
147 | - Tests of all currently available functionality
148 |
149 | ### Removed
150 |
151 | - deprecated **mdInputContainer** wrapper. Use **inputContainer**
152 | - deprecated **mdMessages** wrapper. Use **messages**
153 |
154 | ## [0.5.1](https://github.com/formly-js/angular-formly-templates-material/compare/v0.5.0...v0.5.1) - 2015-11-18
155 |
156 | ### Changed
157 |
158 | - Refactor all files to use Strict Dependency Injection
159 |
160 | ## [0.5.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.4.0...v0.5.0) - 2015-11-18
161 |
162 | ### Added
163 |
164 | - multiple support for select field
165 | - slider field with min, max, step and discrete options
166 |
167 | ## [0.4.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.3.0...v0.4.0) - 2015-11-17
168 |
169 | ### Added
170 |
171 | - **md-chip** with placeholder, secondary-placeholder, delete-button-label and delete-hint
172 |
173 | ### Deprecated
174 |
175 | - **mdInputContainer** wrapper. Use **inputContainer**
176 | - **mdMessages** wrapper. Use **messages**
177 |
178 | ## [0.3.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.2.0...v0.3.0) - 2015-11-17
179 |
180 | ### Added
181 |
182 | - datepicker with date range and filtering *(currently in angular-material 1.0_RC4)*
183 | - Tests of formlyMaterial provider
184 |
185 | ## [0.2.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.1.0...v0.2.0) - 2015-11-17
186 |
187 | ### Added
188 |
189 | - Support for textarea with cols and rows
190 | - ApiCheck for label, radio and select
191 | - Support for md-theme
192 |
193 | ## [0.1.0](https://github.com/formly-js/angular-formly-templates-material/compare/v0.0.4...v0.1.0) - 2015-11-17
194 |
195 | ### Added
196 |
197 | - Support for md-select with valueProp and labelProp
198 | - Support for md-radio with valueProp and labelProp options
199 |
200 | ## [0.0.4](https://github.com/formly-js/angular-formly-templates-material/compare/v0.0.3...v0.0.4) - 2015-11-13
201 |
202 | ### Removed
203 |
204 | - es5-shim package
205 | - standard-minifier package
206 |
207 | ## [0.0.3](https://github.com/formly-js/angular-formly-templates-material/compare/v0.0.2...v0.0.3) - 2015-11-10
208 |
209 | ### Fixed
210 |
211 | - Invalid components templateUrl
212 |
213 | ### Changed
214 |
215 | - Package name: wieldo:angular-formly-templates-material
216 |
217 | ## [0.0.2](https://github.com/formly-js/angular-formly-templates-material/compare/v0.0.1...v0.0.2) - 2015-11-07
218 |
219 | ### Fixed
220 |
221 | - Add missing ngMessages
222 |
223 | ### Added
224 |
225 | - showError in Messages wrapper
226 | - md-checkbox
227 | - mdTheme to checkbox, switch
228 | - md-switch
229 |
230 | ## 0.0.1 - 2015-11-06
231 |
--------------------------------------------------------------------------------
/dist/formly-material.min.js:
--------------------------------------------------------------------------------
1 | /*! angular-formly-material v0.14.2 | MIT | built with ♥ by Kamil Kisiela */
2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("angular")):"function"==typeof define&&define.amd?define(["angular"],t):"object"==typeof exports?exports.ngFormlyMaterial=t(require("angular")):e.ngFormlyMaterial=t(e.angular)}(this,function(e){return function(e){function t(o){if(n[o])return n[o].exports;var a=n[o]={exports:{},id:o,loaded:!1};return e[o].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(1),l=o(a),r=n(2),i=o(r),u=n(5),d=o(u),s=n(14),p=o(s),f="formlyMaterial";l["default"].module(f,["ngMessages","ngMaterial","formly"]).config(["formlyConfigProvider",function(e){var t=[i["default"],d["default"],p["default"]];t.forEach(function(t){for(var n=0;n "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(9),l=o(a);t["default"]=function(e){e.setWrapper({template:l["default"],name:"label",apiCheck:function(e){return{templateOptions:{label:e.string}}}})}},function(e,t){e.exports=" "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(11),l=o(a);t["default"]=function(e){e.setWrapper({template:l["default"],name:"messages"})}},function(e,t){e.exports=' {{message(fc.$viewValue, fc.$modelValue, this)}}
'},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(13),l=o(a);t["default"]=function(e){e.setWrapper({template:l["default"],name:"divider",apiCheck:function(e){return{templateOptions:{divider:e.oneOf(["before","after"]).optional}}}})}},function(e,t){e.exports=" "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(15),l=o(a),r=n(17),i=o(r),u=n(19),d=o(u),s=n(21),p=o(s),f=n(23),c=o(f),m=n(25),b=o(m),g=n(27),v=o(g),_=n(29),y=o(_),h=n(31),M=o(h);t["default"]=[l["default"],i["default"],d["default"],p["default"],c["default"],b["default"],v["default"],y["default"],M["default"]]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(16),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"checkbox",defaultOptions:{ngModelAttrs:{disabled:{bound:"ng-disabled"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,theme:e.string.optional}}}})}},function(e,t){e.exports=" {{to.label}}
"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(18),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"chips",wrapper:["label"],defaultOptions:{defaultValue:[],ngModelAttrs:{placeholder:{attribute:"placeholder"},secondaryPlaceholder:{attribute:"secondary-placeholder"},deleteButtonLabel:{attribute:"delete-button-label"},deleteHint:{attribute:"delete-hint"},onAdd:{bound:"md-on-add"},onRemove:{bound:"md-on-remove"},onSelect:{bound:"md-on-select"}}},apiCheck:function(e){return{templateOptions:{placeholder:e.string.optional,secondaryPlaceholder:e.string.optional,deleteButtonLabel:e.string.optional,deleteHint:e.string.optional,onAdd:e.func.optional,onRemove:e.func.optional,onSelect:e.func.optional,theme:e.string.optional}}}})}},function(e,t){e.exports=""},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(20),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"datepicker",wrapper:["label","messages"],defaultOptions:{templateOptions:{disabled:!1},ngModelAttrs:{disabled:{bound:"ng-disabled"},placeholder:{attribute:"md-placeholder"},minDate:{bound:"md-min-date"},maxDate:{bound:"md-max-date"},filterDate:{bound:"md-date-filter"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,placeholder:e.string.optional,minDate:e.instanceOf(Date).optional,maxDate:e.instanceOf(Date).optional,filterDate:e.func.optional,theme:e.string.optional}}}})}},function(e,t){e.exports="
"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(22),l=o(a),r=n(4);t["default"]=function(e){e.setType({template:l["default"],name:"input",wrapper:["label","messages","inputContainer"],defaultOptions:{templateOptions:{type:"text",disabled:!1},ngModelAttrs:{mdMaxlength:{bound:"md-maxlength"},disabled:{bound:"ng-disabled"},pattern:{bound:"ng-pattern"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,type:e.string,step:e.number.optional,pattern:e.oneOfType([e.string,e.instanceOf(RegExp)]).optional,theme:e.string.optional}}}}),e.extras.fieldTransform.push(function(e){return(0,r.ngModelAttrsTransformer)(e,function(e){return"input"===e.type&&e.templateOptions&&"number"===e.templateOptions.type},"step",{attribute:"step"})})}},function(e,t){e.exports=""},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(24),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"radio",wrapper:["label"],apiCheck:function(e){return{templateOptions:{options:e.arrayOf(e.object),labelProp:e.string.optional,valueProp:e.string.optional,theme:e.string.optional}}}})}},function(e,t){e.exports=" {{option[to.labelProp || 'name']}} "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(26),l=o(a),r=n(4);t["default"]=function(e){e.setType({template:l["default"],name:"select",wrapper:["label","messages","inputContainer"],defaultOptions:{templateOptions:{disabled:!1},ngModelAttrs:{disabled:{bound:"ng-disabled"},onClose:{bound:"md-on-close"},onOpen:{bound:"md-on-open"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,options:e.arrayOf(e.object),multiple:e.bool.optional,labelProp:e.string.optional,valueProp:e.string.optional,onClose:e.func.optional,onOpen:e.func.optional,theme:e.string.optional}}}}),e.templateManipulators.preWrapper.push(function(e,t){var n=t.templateOptions||{};return n.multiple===!0?(0,r.ngModelAttrsManipulator)(e,t,"multiple"):e})}},function(e,t){e.exports=" {{ option[to.labelProp || 'name'] }} "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(28),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"slider",wrapper:["label"],defaultOptions:{templateOptions:{disabled:!1},ngModelAttrs:{disabled:{bound:"ng-disabled"},min:{attribute:"min"},max:{attribute:"max"},step:{attribute:"step"},discrete:{bound:"md-discrete"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,min:e.number.optional,max:e.number.optional,step:e.number.optional,discrete:e.bool.optional,theme:e.string.optional}}}})}},function(e,t){e.exports=""},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(30),l=o(a);t["default"]=function(e){e.setType({template:l["default"],name:"switch",defaultOptions:{templateOptions:{disabled:!1},ngModelAttrs:{disabled:{bound:"ng-disabled"}}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,theme:e.string.optional}}}})}},function(e,t){e.exports=" {{to.label}} "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(32),l=o(a),r=n(4);t["default"]=function(e){e.setType({template:l["default"],name:"textarea",wrapper:["label","messages","inputContainer"],defaultOptions:{ngModelAttrs:{disabled:{bound:"ng-disabled"},rows:{attribute:"rows"},cols:{attribute:"cols"}},templateOptions:{grow:!0}},apiCheck:function(e){return{templateOptions:{disabled:e.bool.optional,rows:e.number.optional,cols:e.number.optional,grow:e.bool.optional,theme:e.string.optional}}}}),e.extras.fieldTransform.push(function(e){return(0,r.ngModelAttrsTransformer)(e,function(e){return"textarea"===e.type&&e.templateOptions&&e.templateOptions.grow===!1},"grow",{attribute:"md-no-autogrow"})})}},function(e,t){e.exports=""}])});
3 | //# sourceMappingURL=formly-material.min.js.map
--------------------------------------------------------------------------------
/dist/formly-material.js:
--------------------------------------------------------------------------------
1 | /*! angular-formly-material v0.14.2 | MIT | built with ♥ by Kamil Kisiela */
2 | (function webpackUniversalModuleDefinition(root, factory) {
3 | if(typeof exports === 'object' && typeof module === 'object')
4 | module.exports = factory(require("angular"));
5 | else if(typeof define === 'function' && define.amd)
6 | define(["angular"], factory);
7 | else if(typeof exports === 'object')
8 | exports["ngFormlyMaterial"] = factory(require("angular"));
9 | else
10 | root["ngFormlyMaterial"] = factory(root["angular"]);
11 | })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
12 | return /******/ (function(modules) { // webpackBootstrap
13 | /******/ // The module cache
14 | /******/ var installedModules = {};
15 |
16 | /******/ // The require function
17 | /******/ function __webpack_require__(moduleId) {
18 |
19 | /******/ // Check if module is in cache
20 | /******/ if(installedModules[moduleId])
21 | /******/ return installedModules[moduleId].exports;
22 |
23 | /******/ // Create a new module (and put it into the cache)
24 | /******/ var module = installedModules[moduleId] = {
25 | /******/ exports: {},
26 | /******/ id: moduleId,
27 | /******/ loaded: false
28 | /******/ };
29 |
30 | /******/ // Execute the module function
31 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
32 |
33 | /******/ // Flag the module as loaded
34 | /******/ module.loaded = true;
35 |
36 | /******/ // Return the exports of the module
37 | /******/ return module.exports;
38 | /******/ }
39 |
40 |
41 | /******/ // expose the modules object (__webpack_modules__)
42 | /******/ __webpack_require__.m = modules;
43 |
44 | /******/ // expose the module cache
45 | /******/ __webpack_require__.c = installedModules;
46 |
47 | /******/ // __webpack_public_path__
48 | /******/ __webpack_require__.p = "";
49 |
50 | /******/ // Load entry module and return exports
51 | /******/ return __webpack_require__(0);
52 | /******/ })
53 | /************************************************************************/
54 | /******/ ([
55 | /* 0 */
56 | /***/ function(module, exports, __webpack_require__) {
57 |
58 | 'use strict';
59 |
60 | Object.defineProperty(exports, "__esModule", {
61 | value: true
62 | });
63 |
64 | var _angular = __webpack_require__(1);
65 |
66 | var _angular2 = _interopRequireDefault(_angular);
67 |
68 | var _runs = __webpack_require__(2);
69 |
70 | var _runs2 = _interopRequireDefault(_runs);
71 |
72 | var _wrappers = __webpack_require__(5);
73 |
74 | var _wrappers2 = _interopRequireDefault(_wrappers);
75 |
76 | var _types = __webpack_require__(14);
77 |
78 | var _types2 = _interopRequireDefault(_types);
79 |
80 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
81 |
82 | var ngModuleName = 'formlyMaterial';
83 |
84 | _angular2.default.module(ngModuleName, ['ngMessages', 'ngMaterial', 'formly']).config(['formlyConfigProvider', function (formlyConfigProvider) {
85 | var configs = [_runs2.default, _wrappers2.default, _types2.default];
86 |
87 | configs.forEach(function (config) {
88 | var i = 0;
89 | for (; i < config.length; i++) {
90 | config[i](formlyConfigProvider);
91 | }
92 | });
93 | }]);
94 |
95 | exports.default = ngModuleName;
96 |
97 | /***/ },
98 | /* 1 */
99 | /***/ function(module, exports) {
100 |
101 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
102 |
103 | /***/ },
104 | /* 2 */
105 | /***/ function(module, exports, __webpack_require__) {
106 |
107 | 'use strict';
108 |
109 | Object.defineProperty(exports, "__esModule", {
110 | value: true
111 | });
112 |
113 | var _className = __webpack_require__(3);
114 |
115 | var _className2 = _interopRequireDefault(_className);
116 |
117 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
118 |
119 | exports.default = [_className2.default];
120 |
121 | /***/ },
122 | /* 3 */
123 | /***/ function(module, exports, __webpack_require__) {
124 |
125 | 'use strict';
126 |
127 | Object.defineProperty(exports, "__esModule", {
128 | value: true
129 | });
130 |
131 | var _helpers = __webpack_require__(4);
132 |
133 | exports.default = function (formlyConfigProvider) {
134 | // add only step attribute because min and max are both built-in
135 | formlyConfigProvider.extras.fieldTransform.push(function (fields) {
136 | return (0, _helpers.ngModelAttrsTransformer)(fields, function (field) {
137 | return field.templateOptions && typeof field.templateOptions.className !== 'undefined';
138 | }, 'className', {
139 | bound: 'ng-class'
140 | });
141 | });
142 | };
143 |
144 | /***/ },
145 | /* 4 */
146 | /***/ function(module, exports, __webpack_require__) {
147 |
148 | 'use strict';
149 |
150 | Object.defineProperty(exports, "__esModule", {
151 | value: true
152 | });
153 | exports.ngModelAttrsManipulator = ngModelAttrsManipulator;
154 | exports.ngModelAttrsTransformer = ngModelAttrsTransformer;
155 |
156 | var _angular = __webpack_require__(1);
157 |
158 | var _angular2 = _interopRequireDefault(_angular);
159 |
160 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
161 |
162 | /**
163 | * Sets attribute with optional value.
164 | * Does not owerwrite.
165 | * @param {Array} nodes nodes
166 | * @param {String} attr attribute name
167 | * @param {String} val atrtibute value
168 | */
169 | function addIfNotPresent(nodes, attr, val) {
170 | _angular2.default.forEach(nodes, function (node) {
171 | if (!node.getAttribute(attr)) {
172 | node.setAttribute(attr, val);
173 | }
174 | });
175 | }
176 |
177 | /**
178 | * Gets all ngModels from node
179 | */
180 | function getNgModelNodes(node) {
181 | var query = '[ng-model], [data-ng-model]';
182 |
183 | return node.querySelectorAll(query);
184 | }
185 |
186 | /**
187 | * Adds attribute with optional value to all elements using ngModel directive.
188 | * Handles extras.skipNgModelAttrsManipulator
189 | * And does not overwrite attriutes
190 | *
191 | * @param {String} template Template provided by formly template manipulator
192 | * @param {Object} options Options provided by formly template manipulator
193 | * @param {String} attrName Attribute's name
194 | * @param {String|undefined} Attribute's value (optional)
195 | * @return {String} result
196 | */
197 | function ngModelAttrsManipulator(template, options, attrName, attrValue) {
198 | var node = document.createElement('div');
199 | var skip = options.extras && options.extras.skipNgModelAttrsManipulator;
200 |
201 | if (skip === true) {
202 | return template;
203 | }
204 | node.innerHTML = template;
205 | var modelNodes = getNgModelNodes(node);
206 |
207 | if (!modelNodes || !modelNodes.length) {
208 | return template;
209 | }
210 |
211 | addIfNotPresent(modelNodes, attrName, attrValue);
212 |
213 | return node.innerHTML;
214 | }
215 |
216 | /**
217 | * Adds ngModelAttr to the field when specified condition is true.
218 | * @param {Array} fields fields provided by formly's fieldTranform
219 | * @param {Funcion} condition with field as only parameter
220 | * @param {String} name ngModelAttr's name
221 | * @param {Object} settings ngModelAttr's settings
222 | * @return {Array} returns fields
223 | */
224 | function ngModelAttrsTransformer(fields, condition, name, settings) {
225 | (fields || []).forEach(function (field) {
226 | if (condition(field) === true) {
227 | if (!field.ngModelAttrs) {
228 | field.ngModelAttrs = {};
229 | }
230 |
231 | if (field.templateOptions && typeof field.templateOptions[name] !== 'undefined') {
232 | field.ngModelAttrs[name] = settings;
233 | }
234 | }
235 | });
236 |
237 | return fields;
238 | }
239 |
240 | /***/ },
241 | /* 5 */
242 | /***/ function(module, exports, __webpack_require__) {
243 |
244 | 'use strict';
245 |
246 | Object.defineProperty(exports, "__esModule", {
247 | value: true
248 | });
249 |
250 | var _inputContainer = __webpack_require__(6);
251 |
252 | var _inputContainer2 = _interopRequireDefault(_inputContainer);
253 |
254 | var _label = __webpack_require__(8);
255 |
256 | var _label2 = _interopRequireDefault(_label);
257 |
258 | var _messages = __webpack_require__(10);
259 |
260 | var _messages2 = _interopRequireDefault(_messages);
261 |
262 | var _divider = __webpack_require__(12);
263 |
264 | var _divider2 = _interopRequireDefault(_divider);
265 |
266 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
267 |
268 | exports.default = [_inputContainer2.default, _label2.default, _messages2.default, _divider2.default];
269 |
270 | /***/ },
271 | /* 6 */
272 | /***/ function(module, exports, __webpack_require__) {
273 |
274 | 'use strict';
275 |
276 | Object.defineProperty(exports, "__esModule", {
277 | value: true
278 | });
279 |
280 | var _inputContainer = __webpack_require__(7);
281 |
282 | var _inputContainer2 = _interopRequireDefault(_inputContainer);
283 |
284 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
285 |
286 | exports.default = function (formlyConfigProvider) {
287 | formlyConfigProvider.setWrapper({
288 | template: _inputContainer2.default,
289 | name: 'inputContainer'
290 | });
291 | };
292 |
293 | /***/ },
294 | /* 7 */
295 | /***/ function(module, exports) {
296 |
297 | module.exports = "\n \n\n";
298 |
299 | /***/ },
300 | /* 8 */
301 | /***/ function(module, exports, __webpack_require__) {
302 |
303 | 'use strict';
304 |
305 | Object.defineProperty(exports, "__esModule", {
306 | value: true
307 | });
308 |
309 | var _label = __webpack_require__(9);
310 |
311 | var _label2 = _interopRequireDefault(_label);
312 |
313 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
314 |
315 | exports.default = function (formlyConfigProvider) {
316 | formlyConfigProvider.setWrapper({
317 | template: _label2.default,
318 | name: 'label',
319 | apiCheck: function apiCheck(check) {
320 | return {
321 | templateOptions: {
322 | label: check.string
323 | }
324 | };
325 | }
326 | });
327 | };
328 |
329 | /***/ },
330 | /* 9 */
331 | /***/ function(module, exports) {
332 |
333 | module.exports = "\n\n";
334 |
335 | /***/ },
336 | /* 10 */
337 | /***/ function(module, exports, __webpack_require__) {
338 |
339 | 'use strict';
340 |
341 | Object.defineProperty(exports, "__esModule", {
342 | value: true
343 | });
344 |
345 | var _messages = __webpack_require__(11);
346 |
347 | var _messages2 = _interopRequireDefault(_messages);
348 |
349 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
350 |
351 | exports.default = function (formlyConfigProvider) {
352 | formlyConfigProvider.setWrapper({
353 | template: _messages2.default,
354 | name: 'messages'
355 | });
356 | };
357 |
358 | /***/ },
359 | /* 11 */
360 | /***/ function(module, exports) {
361 |
362 | module.exports = "\n\n
\n {{message(fc.$viewValue, fc.$modelValue, this)}}\n
\n
\n";
363 |
364 | /***/ },
365 | /* 12 */
366 | /***/ function(module, exports, __webpack_require__) {
367 |
368 | 'use strict';
369 |
370 | Object.defineProperty(exports, "__esModule", {
371 | value: true
372 | });
373 |
374 | var _divider = __webpack_require__(13);
375 |
376 | var _divider2 = _interopRequireDefault(_divider);
377 |
378 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
379 |
380 | exports.default = function (formlyConfigProvider) {
381 | formlyConfigProvider.setWrapper({
382 | template: _divider2.default,
383 | name: 'divider',
384 | apiCheck: function apiCheck(check) {
385 | return {
386 | templateOptions: {
387 | divider: check.oneOf(['before', 'after']).optional
388 | }
389 | };
390 | }
391 | });
392 | };
393 |
394 | /***/ },
395 | /* 13 */
396 | /***/ function(module, exports) {
397 |
398 | module.exports = "\n\n\n";
399 |
400 | /***/ },
401 | /* 14 */
402 | /***/ function(module, exports, __webpack_require__) {
403 |
404 | 'use strict';
405 |
406 | Object.defineProperty(exports, "__esModule", {
407 | value: true
408 | });
409 |
410 | var _checkbox = __webpack_require__(15);
411 |
412 | var _checkbox2 = _interopRequireDefault(_checkbox);
413 |
414 | var _chips = __webpack_require__(17);
415 |
416 | var _chips2 = _interopRequireDefault(_chips);
417 |
418 | var _datepicker = __webpack_require__(19);
419 |
420 | var _datepicker2 = _interopRequireDefault(_datepicker);
421 |
422 | var _input = __webpack_require__(21);
423 |
424 | var _input2 = _interopRequireDefault(_input);
425 |
426 | var _radio = __webpack_require__(23);
427 |
428 | var _radio2 = _interopRequireDefault(_radio);
429 |
430 | var _select = __webpack_require__(25);
431 |
432 | var _select2 = _interopRequireDefault(_select);
433 |
434 | var _slider = __webpack_require__(27);
435 |
436 | var _slider2 = _interopRequireDefault(_slider);
437 |
438 | var _switch = __webpack_require__(29);
439 |
440 | var _switch2 = _interopRequireDefault(_switch);
441 |
442 | var _textarea = __webpack_require__(31);
443 |
444 | var _textarea2 = _interopRequireDefault(_textarea);
445 |
446 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
447 |
448 | exports.default = [_checkbox2.default, _chips2.default, _datepicker2.default, _input2.default, _radio2.default, _select2.default, _slider2.default, _switch2.default, _textarea2.default];
449 |
450 | /***/ },
451 | /* 15 */
452 | /***/ function(module, exports, __webpack_require__) {
453 |
454 | 'use strict';
455 |
456 | Object.defineProperty(exports, "__esModule", {
457 | value: true
458 | });
459 |
460 | var _checkbox = __webpack_require__(16);
461 |
462 | var _checkbox2 = _interopRequireDefault(_checkbox);
463 |
464 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
465 |
466 | exports.default = function (formlyConfigProvider) {
467 | formlyConfigProvider.setType({
468 | template: _checkbox2.default,
469 | name: 'checkbox',
470 | defaultOptions: {
471 | ngModelAttrs: {
472 | disabled: {
473 | bound: 'ng-disabled'
474 | }
475 | }
476 | },
477 | apiCheck: function apiCheck(check) {
478 | return {
479 | templateOptions: {
480 | disabled: check.bool.optional,
481 | theme: check.string.optional
482 | }
483 | };
484 | }
485 | });
486 | };
487 |
488 | /***/ },
489 | /* 16 */
490 | /***/ function(module, exports) {
491 |
492 | module.exports = "\n \n {{to.label}}\n \n
\n";
493 |
494 | /***/ },
495 | /* 17 */
496 | /***/ function(module, exports, __webpack_require__) {
497 |
498 | 'use strict';
499 |
500 | Object.defineProperty(exports, "__esModule", {
501 | value: true
502 | });
503 |
504 | var _chips = __webpack_require__(18);
505 |
506 | var _chips2 = _interopRequireDefault(_chips);
507 |
508 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
509 |
510 | exports.default = function (formlyConfigProvider) {
511 | formlyConfigProvider.setType({
512 | template: _chips2.default,
513 | name: 'chips',
514 | wrapper: ['label'],
515 | defaultOptions: {
516 | defaultValue: [],
517 | ngModelAttrs: {
518 | placeholder: {
519 | attribute: 'placeholder'
520 | },
521 | secondaryPlaceholder: {
522 | attribute: 'secondary-placeholder'
523 | },
524 | deleteButtonLabel: {
525 | attribute: 'delete-button-label'
526 | },
527 | deleteHint: {
528 | attribute: 'delete-hint'
529 | },
530 | onAdd: {
531 | bound: 'md-on-add'
532 | },
533 | onRemove: {
534 | bound: 'md-on-remove'
535 | },
536 | onSelect: {
537 | bound: 'md-on-select'
538 | }
539 | }
540 | },
541 | apiCheck: function apiCheck(check) {
542 | return {
543 | templateOptions: {
544 | placeholder: check.string.optional,
545 | secondaryPlaceholder: check.string.optional,
546 | deleteButtonLabel: check.string.optional,
547 | deleteHint: check.string.optional,
548 | onAdd: check.func.optional,
549 | onRemove: check.func.optional,
550 | onSelect: check.func.optional,
551 | theme: check.string.optional
552 | }
553 | };
554 | }
555 | });
556 | };
557 |
558 | /***/ },
559 | /* 18 */
560 | /***/ function(module, exports) {
561 |
562 | module.exports = "\n";
563 |
564 | /***/ },
565 | /* 19 */
566 | /***/ function(module, exports, __webpack_require__) {
567 |
568 | 'use strict';
569 |
570 | Object.defineProperty(exports, "__esModule", {
571 | value: true
572 | });
573 |
574 | var _datepicker = __webpack_require__(20);
575 |
576 | var _datepicker2 = _interopRequireDefault(_datepicker);
577 |
578 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
579 |
580 | exports.default = function (formlyConfigProvider) {
581 | formlyConfigProvider.setType({
582 | template: _datepicker2.default,
583 | name: 'datepicker',
584 | wrapper: ['label', 'messages'],
585 | defaultOptions: {
586 | templateOptions: {
587 | disabled: false
588 | },
589 | ngModelAttrs: {
590 | disabled: {
591 | bound: 'ng-disabled'
592 | },
593 | placeholder: {
594 | attribute: 'md-placeholder'
595 | },
596 | minDate: {
597 | bound: 'md-min-date'
598 | },
599 | maxDate: {
600 | bound: 'md-max-date'
601 | },
602 | filterDate: {
603 | bound: 'md-date-filter'
604 | }
605 | }
606 | },
607 | apiCheck: function apiCheck(check) {
608 | return {
609 | templateOptions: {
610 | disabled: check.bool.optional,
611 | placeholder: check.string.optional,
612 | minDate: check.instanceOf(Date).optional,
613 | maxDate: check.instanceOf(Date).optional,
614 | filterDate: check.func.optional,
615 | theme: check.string.optional
616 | }
617 | };
618 | }
619 | });
620 | };
621 |
622 | /***/ },
623 | /* 20 */
624 | /***/ function(module, exports) {
625 |
626 | module.exports = "\n \n
\n";
627 |
628 | /***/ },
629 | /* 21 */
630 | /***/ function(module, exports, __webpack_require__) {
631 |
632 | 'use strict';
633 |
634 | Object.defineProperty(exports, "__esModule", {
635 | value: true
636 | });
637 |
638 | var _input = __webpack_require__(22);
639 |
640 | var _input2 = _interopRequireDefault(_input);
641 |
642 | var _helpers = __webpack_require__(4);
643 |
644 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
645 |
646 | exports.default = function (formlyConfigProvider) {
647 | formlyConfigProvider.setType({
648 | template: _input2.default,
649 | name: 'input',
650 | wrapper: ['label', 'messages', 'inputContainer'],
651 | defaultOptions: {
652 | templateOptions: {
653 | type: 'text',
654 | disabled: false
655 | },
656 | ngModelAttrs: {
657 | mdMaxlength: {
658 | bound: 'md-maxlength'
659 | },
660 | disabled: {
661 | bound: 'ng-disabled'
662 | },
663 | pattern: {
664 | bound: 'ng-pattern'
665 | }
666 | }
667 | },
668 | apiCheck: function apiCheck(check) {
669 | return {
670 | templateOptions: {
671 | disabled: check.bool.optional,
672 | type: check.string,
673 | step: check.number.optional,
674 | pattern: check.oneOfType([check.string, check.instanceOf(RegExp)]).optional,
675 | theme: check.string.optional
676 | }
677 | };
678 | }
679 | });
680 |
681 | // add only step attribute because min and max are both built-in
682 | formlyConfigProvider.extras.fieldTransform.push(function (fields) {
683 | return (0, _helpers.ngModelAttrsTransformer)(fields, function (field) {
684 | return field.type === 'input' && field.templateOptions && field.templateOptions.type === 'number';
685 | }, 'step', {
686 | attribute: 'step'
687 | });
688 | });
689 | };
690 |
691 | /***/ },
692 | /* 22 */
693 | /***/ function(module, exports) {
694 |
695 | module.exports = "";
696 |
697 | /***/ },
698 | /* 23 */
699 | /***/ function(module, exports, __webpack_require__) {
700 |
701 | 'use strict';
702 |
703 | Object.defineProperty(exports, "__esModule", {
704 | value: true
705 | });
706 |
707 | var _radio = __webpack_require__(24);
708 |
709 | var _radio2 = _interopRequireDefault(_radio);
710 |
711 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
712 |
713 | exports.default = function (formlyConfigProvider) {
714 | formlyConfigProvider.setType({
715 | template: _radio2.default,
716 | name: 'radio',
717 | wrapper: ['label'],
718 | apiCheck: function apiCheck(check) {
719 | return {
720 | templateOptions: {
721 | options: check.arrayOf(check.object),
722 | labelProp: check.string.optional,
723 | valueProp: check.string.optional,
724 | theme: check.string.optional
725 | }
726 | };
727 | }
728 | });
729 | };
730 |
731 | /***/ },
732 | /* 24 */
733 | /***/ function(module, exports) {
734 |
735 | module.exports = "\n \n {{option[to.labelProp || 'name']}}\n \n\n";
736 |
737 | /***/ },
738 | /* 25 */
739 | /***/ function(module, exports, __webpack_require__) {
740 |
741 | 'use strict';
742 |
743 | Object.defineProperty(exports, "__esModule", {
744 | value: true
745 | });
746 |
747 | var _select = __webpack_require__(26);
748 |
749 | var _select2 = _interopRequireDefault(_select);
750 |
751 | var _helpers = __webpack_require__(4);
752 |
753 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
754 |
755 | exports.default = function (formlyConfigProvider) {
756 | formlyConfigProvider.setType({
757 | template: _select2.default,
758 | name: 'select',
759 | wrapper: ['label', 'messages', 'inputContainer'],
760 | defaultOptions: {
761 | templateOptions: {
762 | disabled: false
763 | },
764 | ngModelAttrs: {
765 | disabled: {
766 | bound: 'ng-disabled'
767 | },
768 | onClose: {
769 | bound: 'md-on-close'
770 | },
771 | onOpen: {
772 | bound: 'md-on-open'
773 | }
774 | }
775 | },
776 | apiCheck: function apiCheck(check) {
777 | return {
778 | templateOptions: {
779 | disabled: check.bool.optional,
780 | options: check.arrayOf(check.object),
781 | multiple: check.bool.optional,
782 | labelProp: check.string.optional,
783 | valueProp: check.string.optional,
784 | onClose: check.func.optional,
785 | onOpen: check.func.optional,
786 | theme: check.string.optional
787 | }
788 | };
789 | }
790 | });
791 |
792 | formlyConfigProvider.templateManipulators.preWrapper.push(function (tpl, options) {
793 | var to = options.templateOptions || {};
794 | // adds multiple only when:
795 | // templateOptions.multiple equals true
796 | return to.multiple === true ? (0, _helpers.ngModelAttrsManipulator)(tpl, options, 'multiple') : tpl;
797 | });
798 | };
799 |
800 | /***/ },
801 | /* 26 */
802 | /***/ function(module, exports) {
803 |
804 | module.exports = "\n \n {{ option[to.labelProp || 'name'] }}\n \n\n";
805 |
806 | /***/ },
807 | /* 27 */
808 | /***/ function(module, exports, __webpack_require__) {
809 |
810 | 'use strict';
811 |
812 | Object.defineProperty(exports, "__esModule", {
813 | value: true
814 | });
815 |
816 | var _slider = __webpack_require__(28);
817 |
818 | var _slider2 = _interopRequireDefault(_slider);
819 |
820 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
821 |
822 | exports.default = function (formlyConfigProvider) {
823 | formlyConfigProvider.setType({
824 | template: _slider2.default,
825 | name: 'slider',
826 | wrapper: ['label'],
827 | defaultOptions: {
828 | templateOptions: {
829 | disabled: false
830 | },
831 | ngModelAttrs: {
832 | disabled: {
833 | bound: 'ng-disabled'
834 | },
835 | min: {
836 | attribute: 'min'
837 | },
838 | max: {
839 | attribute: 'max'
840 | },
841 | step: {
842 | attribute: 'step'
843 | },
844 | discrete: {
845 | bound: 'md-discrete'
846 | }
847 | }
848 | },
849 | apiCheck: function apiCheck(check) {
850 | return {
851 | templateOptions: {
852 | disabled: check.bool.optional,
853 | min: check.number.optional,
854 | max: check.number.optional,
855 | step: check.number.optional,
856 | discrete: check.bool.optional,
857 | theme: check.string.optional
858 | }
859 | };
860 | }
861 | });
862 | };
863 |
864 | /***/ },
865 | /* 28 */
866 | /***/ function(module, exports) {
867 |
868 | module.exports = "\n";
869 |
870 | /***/ },
871 | /* 29 */
872 | /***/ function(module, exports, __webpack_require__) {
873 |
874 | 'use strict';
875 |
876 | Object.defineProperty(exports, "__esModule", {
877 | value: true
878 | });
879 |
880 | var _switch = __webpack_require__(30);
881 |
882 | var _switch2 = _interopRequireDefault(_switch);
883 |
884 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
885 |
886 | exports.default = function (formlyConfigProvider) {
887 | formlyConfigProvider.setType({
888 | template: _switch2.default,
889 | name: 'switch',
890 | defaultOptions: {
891 | templateOptions: {
892 | disabled: false
893 | },
894 | ngModelAttrs: {
895 | disabled: {
896 | bound: 'ng-disabled'
897 | }
898 | }
899 | },
900 | apiCheck: function apiCheck(check) {
901 | return {
902 | templateOptions: {
903 | disabled: check.bool.optional,
904 | theme: check.string.optional
905 | }
906 | };
907 | }
908 | });
909 | };
910 |
911 | /***/ },
912 | /* 30 */
913 | /***/ function(module, exports) {
914 |
915 | module.exports = "\n {{to.label}}\n\n";
916 |
917 | /***/ },
918 | /* 31 */
919 | /***/ function(module, exports, __webpack_require__) {
920 |
921 | 'use strict';
922 |
923 | Object.defineProperty(exports, "__esModule", {
924 | value: true
925 | });
926 |
927 | var _textarea = __webpack_require__(32);
928 |
929 | var _textarea2 = _interopRequireDefault(_textarea);
930 |
931 | var _helpers = __webpack_require__(4);
932 |
933 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
934 |
935 | exports.default = function (formlyConfigProvider) {
936 | formlyConfigProvider.setType({
937 | template: _textarea2.default,
938 | name: 'textarea',
939 | wrapper: ['label', 'messages', 'inputContainer'],
940 | defaultOptions: {
941 | ngModelAttrs: {
942 | disabled: {
943 | bound: 'ng-disabled'
944 | },
945 | rows: {
946 | attribute: 'rows'
947 | },
948 | cols: {
949 | attribute: 'cols'
950 | }
951 | },
952 | templateOptions: {
953 | grow: true
954 | }
955 | },
956 | apiCheck: function apiCheck(check) {
957 | return {
958 | templateOptions: {
959 | disabled: check.bool.optional,
960 | rows: check.number.optional,
961 | cols: check.number.optional,
962 | grow: check.bool.optional,
963 | theme: check.string.optional
964 | }
965 | };
966 | }
967 | });
968 |
969 | formlyConfigProvider.extras.fieldTransform.push(function (fields) {
970 | return (0, _helpers.ngModelAttrsTransformer)(fields, function (field) {
971 | return field.type === 'textarea' && field.templateOptions && field.templateOptions.grow === false;
972 | }, 'grow', {
973 | attribute: 'md-no-autogrow'
974 | });
975 | });
976 | };
977 |
978 | /***/ },
979 | /* 32 */
980 | /***/ function(module, exports) {
981 |
982 | module.exports = "";
983 |
984 | /***/ }
985 | /******/ ])
986 | });
987 | ;
--------------------------------------------------------------------------------