<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<!-- Twitter bootstrap -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
<!-- apiCheck is used by formly to validate its api -->
<script src="//rawgit.com/kentcdodds/apiCheck.js/master/dist/api-check.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular-messages.min.js"></script>
<script src="//rawgit.com/formly-js/angular-formly/master/dist/formly.js"></script>
<title>Angular Formly Example</title>
</head>
<body ng-app="formlyExample" ng-controller="MainCtrl as vm">
<div>
<h1>angular-formly example: {{vm.exampleTitle}}</h1>
<div>
This was originally created based on <a href="https://twitter.com/kentcdodds/status/601765588533317632">this tweet</a>.
It describes some of the nuances of <code><form></code>, <code><ng-form></code>, and <code><formly-form></code>
</div>
<hr />
<div>
Below is an example of using the formly <code>setTemplateWrapper</code> feature to keep templates consistent.
In this example, we add validation (using the <code>validators</code> api in combination with angular-messages)
and we only need to add that in one place and it's exactly the same for all formly types.
<br />
This also demos how to specify different template wrappers for different types. Generally this is useful when you
have multiple types using the same template wrapper, but it can be useful if you want to use the formly template without the wrapper
(also demonstrated).
</div>
<hr>
<strong>Using <code>form</code> attribute on a <code><formly-form></code> and putting <code>ng-submit</code> on a parent <code><form></code> will not work because the parent form is the one submitted, not the formly-form.</strong>
<pre>exampleForm1.$submitted: {{ exampleForm1.$submitted | json }}</pre>
<form ng-submit="vm.onSubmit()" novalidate>
<formly-form model="vm.model" fields="vm.fields" form="exampleForm1">
<button type="submit" class="btn btn-primary submit-button">Submit won't update form $submitted</button>
</formly-form>
</form>
<hr/>
<strong>It's just like using the <code>name</code> attribute on a nested <code><ng-form></code> with <code>ng-submit</code> on a parent <code><form></code></strong>
<pre>exampleForm2.$submitted: {{ exampleForm2.$submitted | json }}</pre>
<form ng-submit="vm.onSubmit()" novalidate>
<ng-form name="exampleForm2">
<button type="submit" class="btn btn-primary submit-button">Submit won't update form $submitted</button>
</ng-form>
</form>
<hr/>
<strong>But if you put the <code>name</code> on the same <code><form></code> as the <code>ng-submit</code> is on, then <code>$submitted</code> gets updated as expected</strong>
<pre>exampleForm3.$submitted: {{ exampleForm3.$submitted | json }}</pre>
<form ng-submit="vm.onSubmit()" novalidate name="exampleForm3">
<formly-form model="vm.model" fields="vm.fields">
<button type="submit" class="btn btn-primary submit-button">Submit will update form $submitted</button>
</formly-form>
</form>
<hr/>
<strong>But if you try to put an <code>ng-submit</code> on an <code><ng-form></code> the statement wont even be called</strong>
<pre>exampleForm4.$submitted: {{ exampleForm4.$submitted | json }}</pre>
<div>
<ng-form name="exampleForm4" ng-submit="vm.onSubmit()">
<button type="submit" class="btn btn-primary submit-button">Submit won't even get called</button>
</ng-form>
</div>
<hr/>
<strong>Which is why an <code>ng-submit</code> on a <code><formly-form></code> with a <code>form</code> doesn't work either (because it actually just replaces itself with an <code><ng-form></code></strong>
<pre>exampleForm5.$submitted: {{ exampleForm5.$submitted | json }}</pre>
<div>
<formly-form form="exampleForm5" ng-submit="vm.onSubmit()" model="vm.model" fields="vm.fields">
<button type="submit" class="btn btn-primary submit-button">Submit won't work here either</button>
</formly-form>
</div>
<hr/>
<strong>This is due to limitations with <code><ng-form></code></strong>.
<hr/>
<strong>Solution 1: use <code>name</code> attribute on the parent <code><form></code> and pass the same value to the <code><formly-form></code>'s <code>form</code> attribute. <code><formly-form></code> will then use that exact same form (rather than the one it creates on its own)</strong>
<pre>exampleForm6.$submitted: {{ exampleForm6.$submitted | json }}</pre>
<form ng-submit="vm.onSubmit()" novalidate name="exampleForm6">
<formly-form model="vm.model" fields="vm.fields" form="exampleForm6">
<button type="submit" class="btn btn-primary submit-button">Submit will update form $submitted</button>
</formly-form>
</form>
<strong>Solution 2: use <code>name</code> attribute on the parent <code><form></code> and don't specify the same name in the <code>form</code> attribute on the <code><formly-form></code> (because you probably don't even need the <code>form</code> attribute).</strong>
<pre>exampleForm7.$submitted: {{ exampleForm7.$submitted | json }}</pre>
<form ng-submit="vm.onSubmit()" novalidate name="exampleForm7">
<formly-form model="vm.model" fields="vm.fields">
<button type="submit" class="btn btn-primary submit-button">Submit will update form $submitted</button>
</formly-form>
</form>
<hr />
<strong>Solution 3: Specify <code>"form"</code> as the <code>root-el</code> attribute on the <code><formly-form></code> which will have it use a <code><form></code> instead of an <code><ng-form></code>. Note: HTML doesn't allow nesting of <code><form></code>s. Which is why <code><ng-form></code> exists in the first place and why angular-formly uses it. You have been warned</strong>
<pre>exampleForm8.$submitted: {{ exampleForm8.$submitted | json }}</pre>
<formly-form model="vm.model" fields="vm.fields" ng-submit="vm.onSubmit()" form="exampleForm8" root-el="form">
<button type="submit" class="btn btn-primary submit-button">Submit will update form $submitted</button>
</formly-form>
<hr />
<strong>Solution 3: Modify <a href="https://gist.github.com/kentcdodds/47c76d3e579ae10b9c2d">this gist</a> to add support for <code><ng-form</code> which will make it work for <code><formly-form></code> as well. To be honest, this is probably not the best way to go about it though...</strong>
<pre>exampleForm9.$submitted: {{ exampleForm8.$submitted | json }}</pre>
<formly-form model="vm.model" fields="vm.fields" ng-submit="vm.onSubmit()" form="exampleForm9">
<button type="submit" class="btn btn-primary submit-button">Submit will update form $submitted (when you modify the gist and add it to your project)</button>
</formly-form>
<h2>Model</h2>
<pre>{{vm.model | json}}</pre>
<h2>Fields <small>(note, functions are not shown)</small></h2>
<pre>{{vm.originalFields | json}}</pre>
</div>
<div style="margin-top:30px">
<small>
This is an example for the
<a href="https://formly-js.github.io/angular-formly">angular-formly</a>
project made with ♥ by
<strong>
<span ng-if="!vm.author.name || !vm.author.url">
{{vm.author.name || 'anonymous'}}
</span>
<a ng-if="vm.author.url" ng-href="{{::vm.author.url}}">
{{vm.author.name}}
</a>
</strong>
<br />
This example is running angular version "{{vm.env.angularVersion}}" and formly version "{{vm.env.formlyVersion}}"
</small>
</div>
<!-- Put custom templates here -->
<script type="text/ng-template" id="validation.html">
<div ng-message="required">This field is required</div>
<div ng-message="minlength">Too short</div>
<div ng-message="maxlength">Too long</div>
<div ng-message="email">Invalid email address</div>
</script>
<script type="text/ng-template" id="input-template.html">
<input type="{{options.templateOptions.type || 'text'}}"
class="form-control"
id="{{id}}"
formly-dynamic-name="id"
formly-custom-validation="options.validators"
placeholder="{{options.templateOptions.placeholder}}"
aria-describedby="{{id}}_description"
ng-required="options.templateOptions.required"
ng-disabled="options.templateOptions.disabled"
ng-model="model[options.key]">
</script>
<script type="text/ng-template" id="checkbox-template.html">
<input type="checkbox"
id="{{id}}"
formly-dynamic-name="id"
formly-custom-validation="options.validators"
aria-describedby="{{id}}_description"
ng-required="options.templateOptions.required"
ng-disabled="options.templateOptions.disabled"
ng-model="model[options.key]">
{{options.templateOptions.label || 'Checkbox'}}
{{options.templateOptions.required ? '*' : ''}}
</script>
</body>
</html>
body {
margin: 20px
}
.formly-field {
margin-bottom: 20px;
}
.validation {
position: absolute;
font-size: .8em;
color: #a94442;
}
.formly-template-wrapper {
position: relative;
}
/* global angular */
(function() {
'use strict';
var app = angular.module('formlyExample', ['formly']);
app.controller('MainCtrl', function MainCtrl(formlyVersion) {
var vm = this;
// funcation assignment
vm.onSubmit = onSubmit;
// variable assignment
vm.author = { // optionally fill in your info below :-)
name: 'Kent C. Dodds',
url: 'https://twitter.com/kentcdodds'
};
vm.exampleTitle = 'how $submitted works'; // add this
vm.env = {
angularVersion: angular.version.full,
formlyVersion: formlyVersion
};
vm.model = {};
vm.fields = [];
vm.originalFields = angular.copy(vm.fields);
// function definition
function onSubmit() {
alert('Submitted!');
}
});
})();
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |