AngularJS two-way binding for Polymer Web Components
Out of the box support for Iron, Paper, Gold and Google elements
AngularJS and Web Components both provide binding mechanisms, and for some cases you can bind the scope properties to Web Components attributes. For example, the following code works fine:
$scope.buttonLabel = 'Click me'; $scope.buttonAction = function() { alert('Button clicked'); };
<paper-button ng-click="buttonAction()" raised> {{buttonLabel}} </paper-button>
There are two cases where you can't get Web Components to work with your AngularJS models:
<paper-input value="{{myModel}}"></paper-input>will not change
myModel
when the user changes the input text.
<google-map map="{{myMap}}"><google-map>will not work because the expression
{{myMap}}
will be treated as a string.ng-polymer-elements creates directives for existing custom elements, allowing you to use them as you would any directive. The following example shows how you can use iron-input and paper-input with a model as if they were "plain" input:
<input type="text" ng-model="text"/> <input is="iron-input" ng-model="text"/> <paper-input ng-model="text""></paper-input>
Either install it with bower using bower install ng-polymer-elements
or download the release.
Add ng-polymer-elements
to your module's dependencies.
ng-polymer-elements uses Object.observe()
with properties of type Object
and Array
.
To support this on browsers that don't support Object.observe()
, add a polyfill.
The generated directives may be applied only after the custom elements have been registered.
This means that in browsers that don't support custom elements and rely on the polyfill, the generated directives
can be used only after the WebComponentsReady
event has been fired. If the initial view of the Angular
application contains these directives, you may want to consider manual bootstrap like so:
window.addEventListener('WebComponentsReady ', function() { angular.bootstrap(wrap(document), ['ng-polymer-elements-example']); });
Out of the box ng-polymer-elements supports the following Polymer elements:
Custom Element | Custom Element Property/Event | Mapped Directive Attribute |
---|---|---|
paper-input paper-textarea gold-email-input gold-phone-input gold-cc-expiration-input gold-cc-cvc-input gold-zip-input |
value | ng-model |
disabled | ng-disabled | |
focused | ng-focused | |
iron-selector paper-menu |
if "multi" - selectedValues , otherwise - selected | ng-model |
paper-radio-group paper-tabs |
selected | ng-model |
paper-checkbox paper-toggle-button |
checked | ng-model |
disabled | ng-disabled | |
iron-change | ng-change | |
paper-slider | value | ng-model |
value-change | ng-change | |
disabled | ng-disabled | |
paper-dialog | opened | ng-opened |
iron-overlay-opened | ng-overlay-opened | |
iron-overlay-closed | ng-overlay-closed | |
gold-cc-input | value | ng-model |
cardType | ng-card-type | |
disabled | ng-disabled | |
focused | ng-focused | |
google-feeds | results | ng-model |
loading | ng-loading | |
google-feeds-error | ng-error | |
google-feeds-queryerror | ng-query-error | |
google-feeds-queryresponse | ng-query-response | |
google-feeds-response | ng-response | |
google-multi-feeds-response | ng-multi-response | |
google-map | latitude | ng-latitude |
longitude | ng-longitude | |
map | ng-map | |
google-sheets | rows | ng-rows |
sheet | ng-sheet | |
tab | ng-tab |
The following example shows the binding of a paper-radio-group selected value:
<paper-radio-group ng-model="radio"> <paper-radio-button name="one" label="One"></paper-radio-button> <paper-radio-button name="two" label="Two"></paper-radio-button> <paper-radio-button name="three" label="Three"></paper-radio-button> </paper-radio-group> <span>Selected: {{radio}}</span>
The following example shows the binding of iron-input, paper-tabs, paper-slider, paper-menu and iron-selector to a numeric value:
<input type="number" is="iron-input" ng-model="number" min="0" max="5"/> <paper-slider ng-model="number" max="5"></paper-slider> <paper-tabs ng-model="number"> <paper-tab>0</paper-tab> <paper-tab>1</paper-tab> <paper-tab>2</paper-tab> <paper-tab>3</paper-tab> <paper-tab>4</paper-tab> <paper-tab>5</paper-tab> </paper-tabs> <paper-menu ng-model="number"> <paper-item>Zero</paper-item> <paper-item>One</paper-item> <paper-item>Two</paper-item> <paper-item>Three</paper-item> <paper-item>Four</paper-item> <paper-item>Five</paper-item> </paper-menu> <iron-selector ng-model="number"> <div>Zero</div> <div>One</div> <div>Two</div> <div>Three</div> <div>Four</div> <div>Five</div> </iron-selector>
The following example shows the binding of paper-checkbox and paper-toggle-button to a boolean value:
<paper-checkbox ng-model="boolean" ng-change="onChange()"> </paper-checkbox> <paper-toggle-button ng-model="boolean" ng-change="onChange()"> </paper-toggle-button>
Boolean values can be used to toggle paper-dialog on and off. The two way binding means that hiding the dialog will also set the bound value to false.
<paper-button ng-click="opened=true">Dialog</paper-button> <span>Dialog opened: {{opened}}</span> <paper-dialog ng-opened="dialog ng-overlay-opened="onOpened()" ng-overlay-closed="onClosed()"> <!-- dialog content --> </paper-dialog>
Some content goes here
When iron-selector and paper-menu are set with the multi attribute, ng-model is bound to the array of selected values:
<iron-selector ng-model="values" multi attr-for-selected="name"> <div name="one">One</div> <div name="two">Two</div> <div name="three">Three</div> <div name="four">Four</div> <div name="five">Five</div> </iron-selector> <paper-menu ng-model="values" multi attr-for-selected="name"> <paper-item name="one">One</paper-item> <paper-item name="two">Two</paper-item> <paper-item name="three">Three</paper-item> <paper-item name="four">Four</paper-item> <paper-item name="five">Five</paper-item> </paper-menu>
Gold elements work similarly to paper-input, and gold-cc-input also exposes the read-only ng-card-type.
<gold-email-input ng-model="email"></gold-email-input> <gold-phone-input ng-model="phone"></gold-phone-input> <gold-cc-input ng-model="cc" ng-card-type="ct"></gold-cc-input> <gold-cc-expiration-input ng-model="exp"></gold-cc-expiration-input> <gold-cc-cvc-input ng-model="cvc" card-type="{{ct}}"></gold-cc-cvc-input> <gold-zip-input ng-model="zip"></gold-zip-input>
In google-feeds , ng-model gets populated with the feed results.
<google-feeds feed="http://www.engadget.com/rss-full.xml" ng-model="result"></google-feeds> <pre>{{result|json}}</pre>
{{result|json}}
Google Map element supports binding of the center latitude and longitude, and the Maps API object.
<google-map ng-latitude="lat" ng-longitude="long"></google-map> <input type="number" ng-model="lat"/> <input type="number" ng-model="long"/>
google-sheet
<google-sheets key="0Anye-JMjUkZZdDBkMVluMEhZMmFGeHpYdDJJV1FBRWc" published ng-rows="rows" ng-sheet="sheet" ng-tab="tab"> </google-sheets> <pre>{{rows|json}}</pre> <pre>{{sheet|json}}</pre> <pre>{{tab|json}}</pre>
{{rows|json}}
{{sheet|json}}
{{tab|json}}
ng-polymer-elements uses a simple structure to map directive attributes to custom element properties.
You can extend the mapping by setting the $ngPolymerMappings
constant in the ng-polymer-elements
module with your mappings.
The mapping structure is an object where the keys are the directive names, and their values are objects that contain a key for each directive attribute you want to map. The values for the directives represent the custom element property or event, and can be constant or defined in runtime for each instance of the directive.
For constant mapping, use a string prefixed with "=" for property or "&" for event, and the property/event name.
For dynamic mapping, use a function named "property" or "event". The function received the element as a single argument during the directive linking and returns a property/event name as string (without "="/"&" prefix).
angular.module('ng-polymer-elements').constant('$ngPolymerMappings', { myElement: { ngModel: function property(element) { return element.hasAttribute('multi') ? 'selectedValues' : 'selected'; }, ngChange: '&iron-change' } });
In this example we add support for my-element
and map the ng-model
attribute in runtime to either
selectedValue
or selected
property, depending on the existence of the multi
attribute,
and we map the ng-change
attribute to the iron-change
event.
When mapping events, the original event will be available to AngularJS handlers as the $event
parameter.
See allMappings
in ng-polymer-elements.js for default mappings.