AngularJS custom element module provides functionality to wrap directive/component with custom element. Internally in Conta we use the service to reuse existing AngularJS directives/components in Elm.
The service has accompany Elm module.
The service uses ES5 syntax to create custom elements. You'll need to include two pollyfils before you include a code with your custom elements:
- @webcomponents/webcomponentsjs/custom-elements-es5-adapter.js - this is for new browsers in order to understand ES5 syntax.
- @webcomponents/custom-elements/custom-elements.min.js - this is for old browsers without
customElements
support.
You can add them to your index.html
file in the following way. Make sure to add it before adding you app scripts.
<div id="custom-elements-adapter">
<!-- Trick to include custom elements es5 adapter only if custom elements are supported -->
<script type="text/javascript">
if ('customElements' in window === false) {
var adapter = document.getElementById('custom-elements-adapter');
adapter.parentNode.removeChild(adapter);
adapter = undefined;
}
</script>
<script type="text/javascript" src="vendor/custom-elements-es5-adapter.js"></script>
</div>
<div id="custom-elements-polyfill">
<!-- Trick to include custom elements polyfill only if custom elements are not supported -->
<script type="text/javascript">
if ('customElements' in window) {
var polyfill = document.getElementById('custom-elements-polyfill');
polyfill.parentNode.removeChild(polyfill);
polyfill = undefined;
}
</script>
<script type="text/javascript" src="vendor/custom-elements.min.js"></script>
</div>
Include the file in HTML
<script src="/node_modules/lodash/lodash.js"></script>
<script src="/node_modules/@contasystemer/angularjs-assert/src/angularjs-assert.js"></script>
<script src="/node_modules/@contasystemer/angularjs-custom-element/src/angularjs-custom-element.js"></script>
or require the file
require('@contasystemer/angularjs-custom-element');
In JavaScript
csCustomElement.create('cs-component', {
// Can be used to specify special element for AngularJS directive which will be used as attribute.
attributeDirective: {
element: 'div',
attributeValue: '{{ vm.csExtraData }}',
},
attributes: ['cs-required', 'cs-change-year'],
interpolations: ['csApiUrl', 'csMainAddressLabel'],
scope: {
csExtraData: csCustomElement.decode.string,
},
bindings: {
csIntegerBinding: csCustomElement.decode.integer,
csBooleanBinding: csCustomElement.decode.boolean,
},
customBindings: {
csCustomBinding: {
attribute: 'custom-attribute',
attributeValue: '{{ vm.someCustomValue }}',
decode: {
set: function (value) {
this.$scope.vm.someCustomValue = value;
}
}
}
},
events: {
csOnChange: {
model: function (value) {
return value === 'my string' : 'Yes, I have got what I wanted' : 'Oops, failed';
},
data: {
argumentName: 'vm.someScopeValue',
encode: csCustomElement.encode.identity,
},
init: csCustomElement.encode.identity
}
}
});
In Elm:
viewContaComponent : Html Msg
viewContaComponent =
AngularCustomElement.viewWithTransclusion
{ componentName = "cs-component-element"
, attributes =
[ Attrs.attribute "cs-required" ""
, Attrs.attribute "cs-change-year" ""
, Attrs.property "csApiUrl" (Encode.string "some/url")
, Attrs.property "csMainAddressLabel" (Encode.string "My address in Oslo")
, Attrs.property "csExtraData" (Encode.string "Some extra data")
, Attrs.property "csIntegerBinding" (Encode.int 42)
, Attrs.property "csBooleanBinding" (Encode.bool True)
, Attrs.property "csCustomBinding" (Encode.string "My custom string")
, Decode.decode MyMessage
|> Decode.requiredAt [ "detail", "model" ] Decode.string
|> Decode.requiredAt [ "detail", "data" ] Decoder.int
|> Decode.requiredAt [ "detail", "init" ] Decode.bool
|> Events.on "csOnChange"
]
-- `transclude` takes one parameter with type `List (Html Never)`.
-- Which means any content which does not produce any messages.
, transclude = [ Html.text "Add some extra content here." ]
}
From cs-component
a custom element will be created with name cs-component-element
.
For more details/examples please read the source code.
The service exposes helper functions for decoding and encoding common types.
The service exposes helper.decode
function to construct custom decoding functions.
Use module.decorator to augment decoders and encoders.
E.g. at Conta we have decoders for moment
values, etc..
To augment scope's vm
for each custom element use module.decorator to override extendVm
method.
E.g. at Conta we use extendVm
method to augment each custom element scope's vm
with sendToElm
method.
sendToElm
method allows us to send messages from AngularJS to Elm directly (depends on internal implementation).