Last active
August 29, 2015 14:05
-
-
Save dgs700/42979b32529e34d786d0 to your computer and use it in GitHub Desktop.
AngularJS 1.x service that constructs and registers Custom Elements in the DOM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This depends on a custom element polyfill for browsers | |
// other than chrome and opera - 9/1/14 | |
angular.module('CustomElemFactory', []) | |
.service('customElem', [ | |
'$window', | |
function($window){ | |
// hash of registered element types | |
// that Angular knows about | |
// note that this would NOT include CEs registered from | |
// elsewhere | |
var customElements = {}; | |
var noop = function(){}; | |
// generic custom element registration function | |
var registerElem = function(name, protoName, callbacks, members){ | |
// if the element is already registered, exit | |
// since the DOM will throw errors otherwise | |
if(customElements[name]) return customElements[name]; | |
// special properties and methods all elems of this type get | |
members = members || {}; | |
// must be an existing DOM element interface | |
protoName = protoName || $window.HTMLElement; | |
// create and populate what will become the custom element | |
// prototype | |
var CustomElemProto = Object.create(protoName.prototype, members); | |
// these are the "current as of 9/14" names of the custom | |
// element lifecycle callbacks | |
// createdCallback executes upon instantiation | |
CustomElemProto.createdCallback = callbacks.createdCallback || noop; | |
// attachedCallback is queued when the element is added to the DOM | |
CustomElemProto.attachedCallback = callbacks.attachedCallback || noop; | |
// detachedCallback is queued when the element is removed from the DOM | |
CustomElemProto.detachedCallback = callbacks.detachedCallback || noop; | |
// attributeChangedCallback is queued when something adds/alters an attr | |
CustomElemProto.attributeChangedCallback = callbacks.attributeChangedCallback || noop; | |
// call the new DOM API method to make this element | |
// a first class citizen of the DOM | |
var CustomElem = $window.document.registerElement( name, { | |
prototype: CustomElemProto | |
}); | |
// add the newly registered element to the tracking hash | |
customElements[name] = CustomElem; | |
return CustomElem; | |
} | |
return registerElem; | |
}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('uiComponents.smartButton', ['CustomElemFactory']) | |
// An example of how an AngularJS 1.x "component" directive | |
// might be defined including the Angular independent | |
// custom element config that is exported to the DOM | |
.directive('smartButton', [ | |
'customElem', function(customElem){ | |
return { | |
template: tpl, | |
transclude: true, | |
// create an isolate (component) scope | |
scope: {}, | |
// must restrict directive matching to custom element name | |
restrict: 'E', | |
// must not overwrite the custom element markup | |
replace: false, | |
// housing the custom element config code in a directive | |
// controller may or may not be the ideal place to store | |
// the custom element config code depending on situation | |
controller: function($scope, $element, $attrs, $window){ | |
// custom elements must include hyphens | |
// in the real world we'd use a namespace of 3 letters | |
var elemName = 'smart-button'; | |
// this will be a descendent of <button> | |
var parent = $window.HTMLButtonElement; | |
// define the element's lifecycle logic | |
var callbacks = { | |
createdCallback: function(){ | |
// this is where most of the instance | |
// config would occur | |
//alert('created') | |
}, | |
attachedCallback: function(){ | |
//alert('attached to DOM') | |
}, | |
detachedCallback: function(){ | |
//test in dev tools by deleting a node | |
//alert('detached from DOM') | |
}, | |
attributeChangedCallback: function(attr, oldVal, newVal){ | |
//console.warn(attr, oldVal, newVal) | |
} | |
}; | |
// add any special class props and methods | |
var members = { | |
testMember: { | |
get: function() { return "foo"; }, | |
enumerable: true, | |
configurable: true | |
} | |
}; | |
// invoke the Custom Element factory service | |
var SmartButton = customElem(elemName, parent, callbacks, members); | |
... | |
// rest of directive definition |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment