Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Angular custom elements support
/* NOTE: that this code was written for https://github.com/CanopyTax and some parts might not be suitable for the generic use case.
It assumes that string data can be passed as both a property or an html attribute, and it prefers properties over attributes for everything.
USAGE:
- <x-foo attr1="'string'" />
- <button is="my-button" />
- <x-foo attr2="objOnScope" />
*/
import angular from 'angular';
import {forEach, kebabCase, includes} from 'lodash';
angular.module('app').directive('cpCustomElement', ['$parse',
function customElement($parse) {
return {
restrict: "A",
compile(preElem, attrs) {
forEach(attrs, (value, key) => {
if (shouldProcess(key)) {
preElem[0].removeAttribute(kebabCase(key));
}
})
return {
post(scope, elem) {
forEach(attrs, (value, key) => {
if (!shouldProcess(key)) return;
if (key.startsWith('on')) {
elem[0].addEventListener(key.slice(2).toLowerCase(), (e) => {
scope.$evalAsync(() => {
$parse(attrs[key])(scope, {e});
});
});
} else {
const value = $parse(attrs[key])(scope);
setValue(elem[0], key, value);
scope.$watch(() => $parse(attrs[key])(scope), (newVal) => {
setValue(elem[0], key, newVal);
})
}
})
}
}
},
}
}
])
function shouldProcess(key) {
if (key.startsWith('$') || key.startsWith('ng') || key.startsWith('uib-') || key.startsWith('ui-'))
return false;
if (includes(['cpCustomElement', 'is', 'class', 'ignore-double-click', 'download'], key))
return false;
return true;
}
function setValue(element, propertyName, value) {
if (typeof value === 'string') {
element.setAttribute(kebabCase(propertyName), value);
} else {
delete element[propertyName];
element[propertyName] = value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.