Formly for Angular is an AngularJS module which has directives to help customize and render JavaScript configured forms. The directive originated from a need to allow our users to create surveys and distribute them easily. Buckle up, because angular-formly is very powerful.
<formly-form model="formData" fields="formFields"></formly-form>
There were some significant changes that you'll want to be aware of. In order to upgrade and get all the cool features, you're going to need to change your field configurations. Here is a tool that should help make that process easier. Also, if you are not able to update the configuration very easily, see this issue for ideas on how to ease things a little.
http://formly-js.github.io/angular-formly/
- Angular - HTML enhanced for web apps
- apiCheck.js - VanillaJS version of ReactJS propTypes
- Install with bower or npm (or just download the script)
$ bower install angular api-check angular-formly --save
or
$ npm install angular api-check angular-formly --save
- Include the javascript file in your index.html, Formly without any form templates. You can create your own or use some of our prebuilt templates which cover basic form types, then extend with your own as needed.
<script src="node_modules/api-check/dist/apiCheck.min.js"></script>
<script src="node_modules/angular/angular.min.js"></script>
<script src="node_modules/angular-formly/dist/formly.min.js"></script>
and
angular.module('yourModule', ['formly']);
or
var angular = require('angular');
angular.module('yourModule', [require('angular-formly')]);
While it is recommended to create your own templates for ultimate customization and flexibility, there are prebuilt templates you can use:
- Vanilla HTML
- Bootstrap
- LumX
- angular-material (WIP)
- Ionic: (WIP, owner needed)
- Foundation: (WIP, owner needed)
Regardless of which flavor you use (or if you use no flavor at all), you can create your own templates with
formlyConfigProvider
. This is the recommended approach if you want to customize your templates at all.
Note: This README.md
is for the latest version of formly
. Be sure to check that you're reading the right docs!
https://github.com/formly-js/angular-formly/tree/{{YOUR_VERSION}} <-- insert your version
Here's an example using the vanilla template properties
You can add a formly-form in your HTML templates as shown below.
<formly-form model="formData" fields="formFields">
<button ng-click="onSubmit()">Hello World</button>
</formly-form>
Example data as it would be set in the controller
$scope.formData = {};
$scope.formFields = [
{
//the key to be used in the model values {... "username": "johndoe" ... }
key: 'username',
type: 'input',
templateOptions: {
label: 'Username',
placeholder: 'johndoe',
required: true,
description: 'Descriptive text'
}
},
{
key: 'password',
type: 'input',
templateOptions: {
type: 'password',
label: 'Password',
required: true
},
expressionProperties: {
'templateOptions.disabled': '!model.username' // disabled when username is blank
}
}
];
$scope.onSubmit = function() {
console.log('form submitted:', $scope.formData);
};
When constructing fields use the options below to customize each field object. You must set at least a type
,
template
, or templateUrl
.
You can only specify these properties. Additional properties will result in an error. If you need custom properties, use
templateOptions
or data
.
type
is the type of field to be rendered. Either type, template, or templateUrl must be set.
template
can be set instead oftype
ortemplateUrl
to use a custom html template form field. Should be used with one-liners mostly (like a directive). Useful for adding functionality to fields.
Note: This can be used to add HTML instead of a form field.
Examples:
template: '<p>Some text here</p>'
template: '<hr />'
templateUrl
can be set instead oftype
ortemplate
to use a custom html template form field. Set a path relative to the root of the application. iedirectives/custom-field.html
By default form models are keyed by location in the form array, you can override this by specifying a
key
.
Whether to hide the field (uses
ng-if
)
By default, the
model
passed to theformly-field
directive is the same as themodel
passed to theformly-form
. However, if the field has amodel
specified, then the specifiedmodel
is used for that field (and that field only). Also, a deep watch is added to theformly-field
directive's scope to run theexpressionProperties
when the specifiedmodel
changes.
expressionProperties
is an object where the key is a property to be set on the main field config (can be an angular expression) and the value is an expression used to assign that property. The expression can be a function or string expression and will be evaluated usingformlyEval
fromformlyUtils
see below for more information. The returned value is wrapped in$q.when
so you can return a promise from your function :-)
For example:
vm.fields = [
{
key: 'myThing',
type: 'someType',
expressionProperties: {
'templateOptions.label': '$viewValue', // this would make the label change to what the user has typed
// this would set that property on data to be whether or not model.myThing.length > 5
'data.someproperty.somethingdeeper.whateveryouwant': 'model.myThing.length > 5'
}
}
];
data
is reserved for the developer. You have our guarantee to be able to use this and not worry about future versions of formly overriding your usage and preventing you from upgrading :-)
templateOptions
is reserved for the templates. Any template-specific options go in here. Look at your specific template implementation to know the options required for this.
wrapper
makes reference tosetWrapper
in the formlyConfigProvider. It is expected to be the name of the wrapper specified there. The formly field will be wrapped by the first wrapper, then the second, then the third, etc.
ngModelAttrs
is used in an angular-formly created templateManipulator to automatically add attributes to the ng-model element of field templates. You will likely not use this often. This object is a little complex, but extremely powerful. It's best to explain this api via an example. See the bottom for the example of this api.
controller
is a great way to add custom behavior to a specific field. You can also set the controller to a type as well. It is injectable with the $scope of the field, and anything else you have in your injector.
link
allows you to specify a link function. It is invoked after your template has finished compiling. You are passed the normal arguments for a normal link function.
optionsTypes
allows you to specify extra types to get options from. Duplicate options are overridden in later priority (index1
will override index0
properties). Also, these are applied after thetype
'sdefaultOptions
and hence will override any duplicates of those properties as well.
modelOptions
allows you to take advantage ofng-model-options
directive. Formly's built-in templateManipulator (see below) will add this attribute to yourng-model
element automatically if this property exists. Note, if you use thegetter/setter
option, formly's templateManipulator will change the value ofng-model
tooptions.value
which is a getterSetter that formly adds to field options. For more information on ng-model-options, see these egghead lessons.
watcher
is an object which has at least two properties calledexpression
andlistener
. Thewatch.expression
is added to theformly-form
directive's scope. If it's a function, it will be wrapped and called with the field as the first argument, followed by the normal arguments for a watcher, followed the watcher'sstop
function. If it's not defined, it will default to the value of the field. Thelistener
will also be wrapped and called with the field as the first argument, followed by the normal arguments for a watch listener. You can also specify a type ($watchCollection
or$watchGroup
) via thetype
property (defaults to$watch
) and whether you want it to be a deep watch via thedeep
property (defaults tofalse
).
How the api differs from a normal $watch
:
// normal watcher
$scope.$watch(function expression(theScope) {}, function listener(newValue, oldValue, theScope) {});
// field watcher
$scope.$watch(function expression(field, theScope, stop) {}, function listener(field, newValue, oldValue, theScope, stop) {});
validators
is an object where the keys are the name of the validity (to be passed to$setValidity
) and the values are functions or expressions which returns true if it is valid. Templates can pass this option to theformly-custom-validation
directive which will add a parser (or validator, see note) to thengModel
controller of the field. The validator can be a function or string expression and will be evaluated usingformlyEval
fromformlyUtils
see below for more information.
Async validation: All function validators can return true/false/Promise. A validator passes if it returns true or a promise that is resolved. A validator fails if it returns false or a promise that is rejected.
1.2: Formly defaults to use the
$validators
api, which is only available in angular 1.3. If you are using 1.2, then the$parsers
api is used which doesn't support async validation out of the box. However, formly will keep track of the validations for you and ensure that the most recently resolved/rejected promise is what takes priority. Also, while the validation is in flight, formly emulates the$pending
api of 1.3 for your use in 1.2 as well, so you can safely use this and upgrade to 1.3 without worrying about the upgrade path for this api. You're welcome :-)
NOTE: You can alternatively specify a validator as an object with an
expression
and amessage
. This will unify how templates reference messages for when the validator has failed. Also, this should be used only for one-off messages (useng-messages-include
for generic messages).message
in this case should be an expression that is evaluated in exactly the same way a validator is evaluated. Theformly-custom-validation
directive will then add an object to the field options calledvalidationMessages
which is a map of functions where the key is the validation name and the value is a to function which returns the evaluated message.
validation
is an object with a few useful properties mostly handy when used in combination with ng-messages
validation.messages
a map of functions mapped to message names. These messages come from the validators. Invoke these and angular-formly will evaluate them usingformlyUtil.formlyEval
(which is how validators themselves are evaluated.
validation.errorExistsAndShouldBeVisible
a boolean indicating whether an error message should be shown. Because you generally only want to show error messages when the user has interacted with a specific field, this value is set to true based on this rule:field invalid && (field touched || validation.show)
validation.show
is a boolean you as the developer can set to specify to forceerrorExistsAndShouldBeVisible
to be set to true when there are$errors
. This is useful when you're trying to call the user's attention to some fields for some reason.
Formly will add a few properties to your field config for convenience in templates
This is the NgModelController for the field. It
provides you with awesome stuff like $errors
:-)
This is a getter/setter function for the value that your field is representing. Useful when using getterSetter: true
in the modelOptions
(in fact, if you don't disable the templateManipulator that comes built-in with formly, it will
automagically change your field's ng-model
attribute to use value
.
It is not likely that you'll ever want to invoke this function. It simply runs the expressionProperties
expressions.
It is used internally and you shouldn't have to use it, but you can if you want to.
The resulting form element has the class formly
and each field has the class formly-field
.
Formly uses angular's built-in validation mechanisms. See the angular docs for
more information on this. (Note, if you're using Angular 1.3, formly utilizies the new $validators
and
$asyncValidators
pipelines, otherwise, it falls back to good old $parsers
. Either way, your API is the same, though
you can't do asynchornous validation with 1.2.x).
The form controller is bound to what you specify as the form
attribute on the formly-form
directive. Make sure to
specify a name on any ng-model
in your custom templates to ensure that the formControl
is added to the options
. If
you're using Angular 1.3, the name
attribute is interpolateable (you can use {{id}}
). If you are stuck on 1.2.x, you
can use the formly-dynamic-name
directive where the value is an expression which would return the name (so,
formly-dynamic-name="id"
). Formly will add a formControl
property to the field, and you can reference that in your
template with options.formControl
to get access to properties like $invalid
or $error
. See the bootstrap templates
for an example.
You can also specify custom validation in your JSON. See the field called validators
for more information on this. If
you wish to leverage this in a custom template, use the formly-custom-validation
directive and pass
options.validators
to it.
This the the main directive you'll use throughout your code. A word of advice, create your own directive that wraps this one. This will make any upgrades easier if the api changes at all. If you want an example of how to do this, file an issue and I'll demonstrate :-D
The attributes allowed on the directive are as follows:
The model to be represented by the form.
The field configurations for building the form
The variable to bind the NgFormController
to.
You will not likely use this often. The value given will control what is used for the formly-form's root element. It
defaults to an ng-form
, but if you want it to use a form
or a div
then you would specify root-el="form"
or
root-el="div"
(respectively). If you choose anything except a form
or ng-form
, make sure to wrap it in your own
ng-form
or form
and provide that with a name
. Then pass that name
to the form
attribute so all the
formControls
of the fields will have somewhere to be added to.
You will not likely need to use this directive, but if you do just know that unless you're using it inside formly-form
you're fields are not going to get all the treatment (like watchers
for example).
The field config. Must have a type
OR template
OR templateUrl
. Everything else is optional, but it is limited to
the options mentioned above. Any extra options will result in an error.
The model for the field to represent
The id of the form, used to generate the id for the field which is used in the name
(for the formControl
) and the id
of the field (useful for a label
's for
attribute)
The index of the field, used if key
is not defined on the field.
The other fields. As convenience if needed.
The NgFormController
that will be used to get and set the formControl
for the field.
This is an attribute directive. The given value should be a validators
object.
This is an attribute directive. It will watch the given value and focus the element when the given value is truthy. You
can also optionally add a refocus
attribute and this will cause focus to be returned to the previous element with
focus when the formly-focus
value is set to falsey (unless the user has clicked away from the focused element).
This is where you'll be configuring angular-formly to inform it of your templates and other options. You can do most
things in either the config
function with the formlyConfigProvider
or in the run
function with the formlyConfig
.
Allows you to specify a custom type
// object api (single type with a template)
formlyConfig.setType({
name: 'input',
template: '<input ng-model="[options.key]" />'
});
// with a templateUrl
formlyConfig.setType({
name: 'checkbox',
templateUrl: 'custom-formly-fields-checkbox.html'
});
// array api (multiple types)hi
formlyConfig.setType([
{
name: 'radio',
templateUrl: 'custom-formly-fields-radio.html'
},
{
name: 'button',
templateUrl: '<button ng-click="options.templateOptions">{{options.label}}</button>'
}
]);
// also, you can specify wrappers for a type
formlyConfig.setType({
name: 'select',
templateUrl: 'custom-formly-fields-select.html',
wrapper: ['inner', 'outer', 'evenOuterOuter']
});
// you can also set default options for fields of this type. This can be done with or without a template or templateUrl
// useful when combined with the field's `optionsTypes` property.
formlyConfig.setType({
name: 'phone',
defaultOptions: {
templateOptions: {
pattern: '^1[2-9]\d{2}[2-9]\d{6}$'
}
}
});
// you also have the option to specify a controller and a link function
formlyConfig.setType({
name: 'uploadButton',
controller: function($scope, $upload) {
$scope.onUploadClicked = function(file) {
return $upload.start(file); // whatever...
}
},
link: function(scope, el) {
el.addClass('manipulate-the-dom');
}
});
The name of the template type. You use this in the type
option of a field.
The template for the field. This is required if there is no templateUrl
or defaultOptions
. Angular-formly will throw
an error if this is present with a templateUrl
(but works fine with defaultOptions
).
A url pointing to a template for the field. This is required if there is no template
or defaultOptions
.
Angular-formly will throw an error if this is present with a template
(but works fine with defaultOptions
).
Options to be used by default for the field. These are merged with the field options for all fields of this type as well
as all fields specifying this type as an optionsTypes
. This is required if there is no template
or templateUrl
specified. And works fine if supplied in addition to either. If a function is supplied, it will be passed the options of
the field and is supposed to return the default options (don't do the merging yourself, just pass what you want to be
used for the default for this configuration).
This allows you to extend the functionality of other types. It merges the options specified with the parent's options and it will even gracefully handle situations where the parent has link/controller/defaultOptions functions as well. Note: in the case of a wrapper conflict, don't use this feature as it just gets too complicated, create a new type instead.
Specify the name of wrappers that you want fields of this type to be wrapped in by default.
This function will be invoked (using the $controller
service) at the end of the formly-field
controller (before the
field's controller
if specified). It can inject anything in the $injector
as well as the $scope
of the
formly-field
. If it is a string, it must be the name of a controller that has been registered with angular. If this
type extends another, this function will be run after the parent controller function is run.
This function will be invoked after the formly-field
link function has been invoked (before the field's link
if
specified). It is invoked with all the normal arguments of a regular link function. If the type extends another, this
function will be run after the parent link function is run.
This is specific to the use of the apiCheck.js
library. This is the preferred method for validating options as it
allows for tooling to discover what the api to your type is.
ngModule.constant('yourOwnCheck', apiCheck({
output: {prefix: 'you app/lib name'}
}));
ngModule.run(function(formlyConfig, yourOwnCheck) {
formlyConfig.setType({
name: 'input',
template: '<input class="to.className" ng-model="model[options.key]" />',
apiCheck: {
templateOptions: yourOwnCheck.shape({
className: yourOwnCheck.string
})
},
apiCheckInstance: yourOwnCheck
});
});
Your own instance of apiCheck so you have the correct prefix/suffix/url/etc.
Allows you to customize whether your check throws and error or simple warns. Defaults to warn.
The options to use when the check fails. Defaults to something sensible.
Note: It is recommended that you use apiCheck
with apiCheckInstance
rather than validateOptions
.
This function will be invoked with the options of the field after it has been merged with it's optionsDefaults
and
any types that its type extends
. Feel free to log warnings to the console or throw errors here to help users use your
types correctly. Recommended: Use apiCheck.js as this is what formly uses
and will already be available to you. You can inject this dependency with apiCheck
. You can use it like so:
ngModule.run(function(formlyConfig, yourOwnCheck) {
formlyConfig.setType({
name: 'input',
template: '<input ng-model="model[options.key]" />',
validateOptions: function(options) {
yourOwnCheck.throw(yourOwnCheck.object, arguments);
}
});
});
Allows you to set a template for your formly templates. You can have a default (used by all templates), named template wrappers, and typed template wrappers (used by fields with the specified type). All template wrappers must follow these rules
- Use
<formly-transclude></formly-transclude>
in them to specify where the field template should be placed. - Have at least one, and only one of
templateUrl
ortemplate
- Not override another by name or type
For example:
// simple argument api
formlyConfigProvider.setWrapper(
'<div>This is the default because <formly-transclude></formly-transclude> there is no name specified</div>'
);
formlyConfigProvider.setWrapper(
'<div>This is not the default because <formly-transclude></formly-transclude> there is a name specified</div>',
'theName'
);
// object api
formlyConfigProvider.setWrapper({
name: 'inputWrapper', // optional. Defaults to name || types.join(' ') || 'default'
template: 'the template with <formly-transclude></formly-transclude> in it', // must have this OR templateUrl
templateUrl: 'path/to/template.html', // the resulting template MUST have <formly-transclude></formly-transclude> in it and must have templateUrl OR template (not both)
types: 'stringOrArray' // this can be a string or an array of strings that map to types specified by setTemplate and setTemplateUrl
});
// array api
formlyConfigProvider.setWrapper([
{ /* same configuration as the object api */ },
{ /* same configuration as the object api */ },
{ /* same configuration as the object api */ },
{ /* same configuration as the object api */ }
]);
removeWrapperByName
and removeWrappersForType
are helpful if you're using a template library but want to customize
your own wrappers. The api is simple:
formlyConfigProvider.removeWrapperByName('inputWrapper'); // removes the wrapper that's called 'inputWrapper'
formlyConfigProvider.removeWrappersForType('select'); // removes all wrappers that apply to the type of 'select'
Also, note, that if you want to remove the default wrapper, this is done by passing 'default'
to the
removeWrapperByName
function.
Another note, you can instead override wrappers (and types as well) without a warning if you specify an
overwriteOk: true
property.
See the website for examples on usage
This allows you to manipulate the template of a specific field. This gives you a great deal of power without sacrificing performance by having bindings which you will never need as well as save repetition in your templates. The api to this feature is as follows:
// note, most of the formlyConfigProvider functions can
// actually be done in the `run` function as well using `formlyConfig`.
formlyConfigProvider.templateManipulators.preWrapper.push(function(template, options, scope) {
// determine if you wish to do anything with this template,
// manipulated as needed, and return either the old template,
// the new template, or a promise that will resolve with the
// new template... for example
if (options.data.addWarningMessage) {
return template + '<div>This is a warning message!!!</div>';
} else {
return template;
}
});
// or, if you wanted to load a template, you would do it in the
// run function so you can get $http, and $templateCache, then do:
formlyConfig.templateManipulators.preWrapper.push(function(template, options, scope) {
return $http.get('the/template.html', {cache: $templateCache}).then(function(response) {
return response.data.replace('where-the-template-goes', template);
});
});
Note! This is probably one of the coolest parts of angular-formly! There is a built-in templateManipulator
that
automatically adds attributes to the ng-model
element(s) of your templates for you. Here are the things you need to
know about it:
- It will never override existing attributes
- To prevent it from running on your field, simply set
data: {noTouchy: true}
and this template manipulator will skip yours - This can be disabled globally by setting
formlyConfigProvider.extras.disableNgModelAttrsManipulator = true
- It wont do anything to the template if it can't find any elements with the attribute
ng-model
. - It first goes through the
bound
andunbound
ngModelAttrs
specified for the field (read more about that above) - It adds a
name
andid
attribute (thescope.id
for both of them) - It adds the
formly-custom-validation
directive if the field hasoptions.validators
- It adds
ng-model-options
directive if the field hasoptions.modelOptions
- It utilizes the
ngModelAttrs
api to add a bunch of attributes automagically. This is probably one of the coolest things about angular-formly. See below for examples of how to use this.
{
templateOptions: {
placeholder: 'This will be automagically added',
required: true, // will add a required attribute
maxlength: 6, // this would add a maxlength attribute, but see expressionProperties
onBlur: 'options.data.hasBeenBlurred = true' // this adds ng-blur
},
expressionProperties: {
'templateOptions.maxlength': 'someExpression' // this adds the ng-maxlength attribute
}
}
This is incredibly powerful because it makes the templates require much less bloat AND it allows you to avoid paying the cost of watchers that you'd never use (like a field that will never be required for example).
Here are the built-in supported attributes
both attribute or regular attribute -> required, disabled, pattern, maxlength, and minlength attribute only -> placeholder, min, max, tabindex, and type expression types -> onChange, onKeydown, onKeyup, onKeypress, onClick, onFocus, and onBlur
You can add more custom attributes using the ngModelAttrs
api. It's a little complex, but quite powerful.
Formly gives some useful warnings when you attempt to use a template that doesn't exist or there's a problem loading a
template. You can disable these warnings via formlyConfigProvider.disableWarnings = true
This service allows you to control what messages gets added to each field's validation.messages
which can ultimately
be used in an ng-messages
context to great effect. It has a messages
property which is what is used to attach the
messages
to the field's config. The messages here should be set as angular expressions (or functions) similar to how
expressionProperties
or validators
works. You can always interact with messages
on your own, but there are two
helper methods in this service
formlyValidationMessages.addTemplateOptionValueMessage(name, prop, prefix, suffix, alternate);
// for example
formlyValidationMessages.addTemplateOptionValueMessage('max', 'max', 'The max value allowed is', '', 'Too big');
formlyValidationMessages.addTemplateOptionValueMessage('minlength', 'minlength', '', 'is the minimum length', 'Too short');
formlyValidationMessages.addTemplateOptionValueMessage('pattern', 'patternValidationMessage', '', '', 'Invalid Input');
// the last could be used like so:
var field = {
type: 'whatever',
templateOptions: {
pattern: /some_crazyPattern/,
patternValidationMessage: '"Needs to match " + options.templateOptions.pattern'
}
};
formlyValidationMessages.addStringMessage(name, string);
// for example
formlyValidationMessages.addStringMessage('required', 'This field is required');
Please see the Wiki for tips and tricks from the community.
There are four places where you can put expressions. The context in which these expressions are evaluated is important. There are two different types of context and each is explained below:
-
watcher - expression and listener can be functions or expression strings. This is a regular angular
$watch
(depending on the specifiedtype
) function and it is created on theformly-form
scope, despite being applied to a specific field. This allows the expressions to run even if the field's scope has been destroyed (via an ng-if like when the field is hidden). The function signature differs from a normal$watch
however. See above for more details. -
expressionProperties, validators, & messages - these expressions can be functions or expression strings. If it's a function, it's invoked with the arguments
$viewValue
,$modelValue
, andscope
. The scope in this case, is the field's scope. If it's an expression string, it is evaluated using$scope.$eval
with a locals object that has$viewValue
and$modelValue
(however, in the case ofexpressionProperties
,$viewValue
will simply be the$modelValue
because ok into thengModelController
but we want to keep the api consistent).
You have a lot of freedom when it comes to writing templates. You don't even need to use the model
which means that
you can have fields that are just part of the look and feel of your form. Because of angular-formly's
ngModelAttrsTemplateManipulator, you really only have to put the ng-model
element
where you want it (if you want it at all) and formly will take care of most of the rest. If you want to have any extra
properties, you have pretty much full reign over the options.templateOptions
object. Just be aware that angular-formly
does make use of common parameters like required
or onClick
to automatically add attributes to ng-model
elements.
angular-formly uses apiCheck.js to do type validation to help you use
formly correctly. If you wish to disable this (in production that is recommended) then simply inject apiCheck
and
disable it with apiCheck.disable()
.
- See the issues labeled enhancement
Please see the CONTRIBUTING Guidelines.
A special thanks to Nimbly for creating/sponsoring Angular-Formly's development. Thanks to Kent C. Dodds for his continued support on the project.
This api is a little complex. Hopefully these examples will be instructive.
Config like this:
{
ngModelAttrs: {
myCustomValue: {
bound: 'ng-my-custom-value',
attribute: 'my-custom-value'
}
},
templateOptions: {
myCustomValue: 3
}
}
Would yield something like this:
<input ng-model="model[options.key]" my-custom-value="3" />
The value is simply placed on the element using the attribute specified in attribute
.
Whereas if you changed the config to have an expressionProperty like this:
{
ngModelAttrs: {
myCustomValue: {
bound: 'ng-my-custom-value',
attribute: 'my-custom-value'
}
},
templateOptions: {
myCustomValue: 3
},
expressionProperties: {
'templateOptions.myCustomValue': 'someEvaluationToGetCustomValue'
}
}
Then the output would look like this:
<input ng-model="model[options.key]" ng-my-custom-value="options.templateOptions['myCustomValue']" />
Because the value of templateOptions.myCustomValue
can change, it now uses the bound
version of the attribute.
However, if there is no bound
version specified, but it is still an expression property like so:
{
ngModelAttrs: {
myCustomValue: {
attribute: 'my-custom-value'
}
},
templateOptions: {
myCustomValue: 3
},
expressionProperties: {
'templateOptions.myCustomValue': 'someEvaluationToGetCustomValue'
}
}
Then the output would look like this:
<input ng-model="model[options.key]" my-custom-value="{{options.templateOptions['myCustomValue']}}" />
You also have expression
. For expression
a config like this:
{
ngModelAttrs: {
doAction: {
expression: 'do-something-awesome'
}
},
templateOptions: {
doAction: 'options.data.actionDone = true'
}
}
Would result in output like this:
<input ng-model="model[options.key]" do-something-awesome="$eval(options.templateOptions['doAction'])" />
However, if the templateOptions.doAction
is a function instead, like this:
{
ngModelAttrs: {
doAction: {
expression: 'do-something-awesome'
}
},
templateOptions: {
doAction: function(value, options, scope, $event) {
options.data.actionDone = true;
}
}
}
Then the output would look more like this:
<input ng-model="model[options.key]" do-something-awesome="options.templateOptions['doAction'](model[options.key], options, this, $event)" />
Which allows you to have access to the value
, options
, scope
, and $event
as you see in the example.
Finally, you can specify the custom attribute as a value
. In this case, a config like this:
{
ngModelAttrs: {
'{{options.data.whatever}}': {
value: 'my-whatever-attribute'
}
}
}
<input ng-model="model[options.key]" my-whatever-attribute="{{options.data.whatever}}" />
Which gives you the liberty to specify exactly the value you wish for your attribute in the template.