Thursday, October 9, 2014

Angular Custom Element

Announcing Angular Custom Element !

Since my last post I've written an AngularJS provider and service that integrates AngularJS 1.x element directives with custom elements.

Check it out...

Monday, September 1, 2014

Creating Web Components (custom elements) in AngularJS 1.x

I'm continuously looking for ways to write UI code (JavaScript, HTML, CSS) that will have as long of a shelf life as possible.  This is despite the fact that web technologies and fads change every few months or so.  My main motivation is that I am lazy, as any good web developer should be.  I don't want to have to keep rewriting the same logic every few months.  A by product of being lazy, is code that is more cost effective because it can live longer.

It's a reasonably safe bet that Web Components APIs will become part of the lingua franca of the web in the near future, and JavaScript frameworks will either support them or die.  Standardization is still a ways off for some of the APIs, and due to various technical reasons most of the current polyfills cannot truly emulate the APIs reliably and completely across modern browsers, most notably, Shadow DOM. 

However, after reading TJ VanToll's blog post, it got me thinking about what can be done now in production ready, cross-browser code to help future proof components and apps.  It seems that Custom Elements can be polyfilled across all the latest browsers with two caveats.  The :unresolved pseudo element can't be used yet, and some of the method and callback names (not logic) may still change before standardization.  Both of these issues are minor and definitely not show stoppers.

Now it's not really debatable that Shadow DOM is the magical browser capability that UI component developers crave for encapsulation, especially for component CSS.  But Custom Elements provide more value than might be apparent on the surface. After all we can make up element names now and the browser won't complain, right?

Besides allowing new elements to become official citizens of the DOM rather than illegal aliens, Custom Elements allow us component developers to define the APIs that allow components to be export, imported, shared, and re-used within frameworks and across frameworks.  This is because APIs are plain old HTML element APIs- attributes, properties, methods, and events.

Lately I've been playing with W3C Custom Element generation from within AngularJS 1.x code.  When AngularJS 2.0 arrives, it will be integrated with Web Components APIs.  It will be able to import and export Custom Elements, and will have specialized directives including template and component directives to do this rather than the generic directive definitions we have now in 1.x.

Below is a GitHub Gist I posted of an AngularJS service that acts as a generic Custom Element factory, and what I would define as an AngularJS 1.x component directive that accesses it.  It works in Chrome and Opera without a polyfill, and the rest with a custom-element-only polyfill like https://github.com/WebReflection/document-register-element




This is the first version, and I have yet to play with it using existing AngularJS components, but I plan to do so extensively.  One of the big questions about creating custom element from inside a framework is where the framework should end and the DOM APIs begin.  In other words, should we now be thinking about placing most or all of the component's logic in it's DOM properties and methods, or will much of the logic still remain in the framework part of the "framework enhanced" component (i.e. $scope)?  Storing logic and data in the DOM makes custom element components independent of any framework, and therefore portable and sharable.  But then we have everyone accessing the global context!  

Monday, June 16, 2014

Salvaging Legacy Apps with AngularJS UI Components

Below is a useful excerpt from Chapter 7 of my upcoming book for those with jQuery/Backbone/Require.js app looking to upgrade to AngularJS:

Salvaging Legacy Apps with AngularJS UI Components


We'll finish this chapter by taking a bit of a detour from the topic of building and delivering our UI component library, and discuss a unique and very useful thing we can do with the UI components that we create.

If you are reading this book, it is very likely that you are one of two types of engineer.  The first type are those who are fortunate to have the luxury of being able to build new applications using the latest front-end technologies.  The second type are those who have the burden of maintaining legacy front-end applications that suffer from multiple revolving developers doing their own thing, bloated and repeated functionality everywhere, and performance so bad that loading and user responsiveness can be measured in seconds rather than milliseconds.  This section is for the second type. 

In the first few chapters, we extoled the benefits of AngularJS compared to older frameworks, especially in regards to drastically reducing binding boilerplate and other repeated code.  Bloated applications full of jQuery spaghetti are the direct result of poor planning, short term focus, and the dysfunctional layers of management found in most enterprise organization of significant size and age.  Marketing driven organizations often suffer from the misguided belief that you can produce a "Cloud" product faster by throwing scores of offshore contractors at the project.  A year later, the web based product might be functional, but it far from maintainable given all the corners that were cut to push the product out the door including testing, documentation, and other best practices.  Within two years, development grinds to a halt due to bloat and the inability to fix a bug without causing three more in the process.

In certain cases, it may be possible to salvage the application from the inside out by systematically replacing repeated functionality and code with common, reusable UI components built with AngularJS.  The assumption is that the page is under the control of a legacy framework, but if the application meets certain conditions it is salvageable including:

  • The app allows the developer control over lifecycle events resulting in DOM redraws
  • DOM redraws are template based, not JavaScript based
  • AngularJS core and UI component modules can be loaded with some control over order
  • Any jQuery in the page is a relatively recent version
  • The root element(s) that would contain the components are accessible


Existing frameworks that are highly configuration based (i.e. Extjs) are likely beyond repair because most of the DOM rendering is scattered deep in layers of its core JavaScript which is not accessible without modifying the framework.  Frameworks that are jQuery based (imperative), on the other hand, make excellent salvage candidates including Backbone.js.

Our example will include code snippets that illustrate how simple it is to embed an AngularJS UI component in a Backbone.js / Require.js application.  The first task is to make sure that AngularJS core is loaded and angular is available as a global.  If loading AngularJS core will be done via AMD with Require.js, it should be done early in the file used by Require.js to bootstrap all of the modules.  If jQuery is loaded here, AngularJS must be after jQuery if it is a dependency.  Likewise, the code containing the AngularJS modules must load after AngularJS core.  Loading these files asynchronously without a dependency loader that guarantees order will not work.

7.10 Embedding an AngularJS UI Component in Require/Backbone

// main.js
require([
    'underscore',
    'jquery',
    'backbone',
    'angular',
    'angularComponents',
    '...'
    ], function( mods ){
       ...
});

//////////////////////////////
<!-- template_for_view_below.hbs.html -->
...
<div id="attach_angular_here">
    <uic-dropdown ...></uic-dropdown>
</div>
...

//////////////////////////////
// view.js
define([
    'deps'
], function (deps) {
    return View.extend({
        className: 'name',
        initialize: function () {
            ...
        },
        render: function () {
            // give the parent view time to attach $el to the DOM
            _.defer(function () {
                try{
                    // this replaces <div ngApp=" uicDropdown "
                    angular.bootstrap('#attach_angular_here', ["uicDropdown"]);
                }catch(e){
                    console.error('there is a problem');
                }
            });
        });
    }
});


The pseudo code above demonstrates how and where to place the AngularJS code within the lifecycle of the Backbone.js application.  The important pieces include making sure the dependencies get loaded in the correct order and that the DOM element that contains the custom element and where we will bootstrap AngularJS is appended to the DOM before angular.bootstrap() is executed.  Using lodash defer or setTimeout places the contained code at the end of the JavaScript execution stack.  For robustness, the try block is included so any problems can fail gracefully without halting the UI.
AngularJS apps can be bootstrapped imperatively on multiple DOM elements assuming they are not part of the same hierarchy.  For best performance, however, the number of AngularJS app instantiations should be kept to a minimum by attaching to elements higher in the DOM hierarchy if possible.  The pattern above can be used to replace any of possibly several different dropdowns implementations throughout the application.  In the process, lines of source code will be reduced and performance will increase.


This is one scenario of injecting AngularJS into and existing application.  In practice, it make take some creativity and a few attempts to find a system that works for your particular application.  However the time spent can be well worth it given that the alternative would be to start from scratch and develop an entirely new application while having to maintain the old one until it is complete. 

Wednesday, May 14, 2014

Random Excerpt from Ch 4

Data Models in AngularJS


Developers new to AngularJS might be somewhat confused when the landing page of angularjs.org mentions that AngularJS models are plain POJOs or plain old JavaScript objects, but then there is this thing called $scope which is the data that is bound to the HTML in AngularJS' data-binding.  The distinction is that the last sentence was not entirely correct. It should be "which is what holds" the data that is bound to the HTML. To be clearer, the data in AngularJS is modeled in a basic JavaScript object, which may be converted to JSON and visa versa. That model is then attached to an AngularJS $scope object which provides a context for the data in the DOM hierarchy.

4.0 A model and a context in AngularJS
// Model is a plain old JavaScript object- no getters, setters, or inheritance
// It may start life as a JSON string from a REST call or from form field inputs
var aDataModel = {
    field_0: 'a string',
    field_1: 5
    field_2: false,
    field_3: {
        subField_0: ['an array']
    }
};

// $scope is a contextual container for a model
function ourController($scope){

       // Our data is now bound to the view, and so is another property and method
       // not a part of our data.
       $scope.data = aDataModel;
       $scope.method_0 = function(){};
       $scope.property_0 = '';
};

Models in AngularJS do not need to be part of any inheritance hierarchy or have OO style setters and getters, or other methods. On the other hand, scopes in AngularJS usually (but not always) are part of an inheritance hierarchy, and have a number of built-in methods and properties. Any developers with Backbone.js experience know that data models in that toolkit are inherited and have OO style encapsulation methods.

The reasoning behind using POJOs for models in AngularJS is for increased ease of testing, maintenance, and reusability. Tomorrow if we decide to switch to another framework or even Web Components, untangling the data will require minimal effort.

Data Representation in the View 


The $scope object in AngularJS is the container that allows both the view and the controller access to the data. When we attach our data object to a $scope object in AngularJS we have effectively created a ViewModel as most developers would define MVVM.  The AngularJS team refer to AngularJS as an MVC framework perhaps for marketing purposes or for attractiveness to back-end developers, but the distinction between VM and C is fuzzy at best and probably depends more on whether it is used for web apps or components.

Expressions and Bindings


In compiled template HTML, or the view, $scope data fields, methods, and properties are normally accessed and manipulated via AngularJS expressions. AngularJS expressions are snippets of JavaScript with a few distinctions. Expressions evaluate against the scope of the current element or directive, whereas, JavaScript expressions embedded in HTML always evaluate against the global (usually window) context. Attempting to evaluate a property that is null or undefined fails silently rather than throwing a reference error, and control flow logic (if, else, while, etc.) is not allowed since computational logic belongs in controllers, not templates.

4.1 Difference between AngularJS and JavaScript expressions
// setting and accessing a scope context
<div id="expExample" ng-controller="ourController" ng-click="angularExpression()"       onclick="globalExpression()">
    <span> {{ aScopeProperty }} </span>
    <input type=text ng-bind="aScopeProperty"/>
</div>

The code above is short, but represents much of a developer's everyday use of AngularJS. We are applying a scope to div#expExample, and binding properties and methods to elements on or within the scope.

The default AngularJS binding delimiters are {{}}. The can be changed if there is conflict with other client or server template delimiters.  {{}} is the read-only version of ng-bind.  {{}} is typically used when displaying a scope property as output text in HTML. ng-bind is typically used to give two-way binding to form input elements, although it can also be used in cases where a delay in the JavaScript execution thread might cause an undesired momentary flash of the raw "{{ var }}". Behind the scenes, the expressions are passed to the $eval() method on the $scope object analogous to JavaScript's eval() method with the exception that $eval() evaluates against the $scope context. It is a best-practice to keep statements for $eval() simple as in a property name or a function call that returns a value.

$scope creation and destruction


Automatic Scopes


The concept of scope, scope hierarchies and other inter-scope relationships are a source of massive hair loss among AngularJS noobs. "Why does a bound property change when I do this, but not when I do that?" The answer is almost always because of an attempt to access the same property, but within different, unexpected scope contexts due to a scope popping up out of nowhere for some reason. So it important to understand the various AngularJS activities that result in automatic scope creating- one of the downsides to a massive reduction in boilerplate.

So starting from the top, when an AngularJS app module is defined and attached to the DOM via ng-app, a root scope is automatically created on the ng-app element and is accessible from any sub scope via $rootScope. That said, my advice is to avoid at all costs directly referencing the  $rootScope  property from an inner scope as it leads to highly coupled dependencies. Accessing a $rootScope  from a UI component directive scope should never be done.

In AngularJS single page apps, scopes are most often created when ng-controller="myController" is placed in an element declaration. Any data-bindings within that DOM fragment will reference that scope until an inner element or directive that instantiates a new scope is reached.

Scopes are automatically created when a new template is inserted into the DOM via ng-route or ng-include. Same goes for a form element when given a name attribute, <form name="name">, and also for any directive that clones HTML templates, a new scope is created for each cloned template when attached to the DOM as with ng-repeat.

Manual Scope Creation


Behind the scenes, any scopes that are automatically created via one of the avenues above are done so with the $new() method, available on any existing $scope object. We may also purposely call $scope.$new()to create one manually, but the use cases are rare and is usually a clue that we are not doing something the AngularJS way.

Finally new scopes may be granted existence on purpose when a custom directive is instantiated, and we almost always want to create a new scope if our directive encapsulates a UI component. Recall the scope option in the directive definition object from the previous chapter. For the purpose of using directives to create re-usable UI components, we will focus closely on this type of scope creation.

Scope Inheritance Options for Directives


When defining a directive for the purpose of encapsulating a UI component, we typically want to do a few special tasks with any new scope that is created.  If we omit the scope option in our directive definition object, the default is no new scope, the same as if we declare scope:false. On the other hand, if we declare scope:true, a new scope is instantiated when the directive executes, but it inherits everything, prototypal style, from the parent scope.  This is the default for automatic scope creation, and the reason for the hair pulling when the property names are the same, but the values are not. 

Manipulating a value on a sub-scope creates a new variable overwriting the inherited value.

The third value for the scope option is scope:{}. This creates an isolated scope for the directive instance with no inheritance from any parent scope.  Because UI components should not know about state outside their boundaries, we typically want to use this option for our component directives. One side note with isolate scopes is that only one isolate scope can exist on an element, but this is usually not an issue with elements designated as component boundaries.

The value for the scope option does not need to be an empty object literal. We can include default properties, values and methods for the isolated scope using object literal notation. Also, the previous statement of no inheritance was not entirely correct. We can also selectively and purposely inherit specific properties from a parent or an ancestor scope, and we can also selectively accept values of the directive element attributes. Both of these abilities create some interesting options for defining APIs on our custom UI components.

Isolate Scopes as Component APIs


While directives are a great tool for creating re-usable UI components, the primary focus of the framework is toward being comprehensive for web application functionality. Therefore, there is no official AngularJS best-practice for defining UI component APIs beyond choosing a method that allows for loose coupling and dependency injection. The framework gives us multiple options for dependency injection, configuration, and API communication from the containing DOM. The option used should be the best fit for the use case and the user.

Directive API as HTML Attributes


Suppose we have some epic user-story that requires we create a pallet of UI widgets and components that might be used by designers or junior developers to create websites or webapps. The consumers of our pallet might not have a high level of programming skill, so we would want to give them a method to include any configuration or data declaratively, or as close to plain English as possible.
For example, we could create a custom search bar directive with our organization's look-and-feel that a page author could include via adding a custom element:

<my-search-bar></my-search-bar>

But this is of limited use since search bars are often needed in different contexts, locations, and with certain configurations.

If we were using jQuery UI widgets, any customization or configuration would need to happen by passing in a configuration object to the imperative statement the creates the widget on an element:

$('#elementId').searchBar({autoComplete:true});

This limits the accessibility of widget use to developers with an adequate knowledge of JavaScript.
However, via AngularJS directives we could give the page author the ability to pass in configuration information declaratively via element attributes:

<my-search-bar auto-complete="true"></my-search-bar>

removing the need to touch any JavaScript.  This is accomplished by configuring the isolate scope options in the directive definition object to use the values of matched attributes on our directive element.

4.2 Isolate scope attribute options
<my-search-bar auto-complete="true"></my-search-bar>

myModule.directive('mySearchBar', function factory(injectables) {
  var directiveDefinitionObj = {
    template: ...,
    restrict: 'E',
    scope: {
        autoComplete: '@', // matches an attribute of same name
         anotherModelName: '@autoComplete' // if using a different name
    },
    controller: ...,
    link: function postLink( ... ) { ... }
  };
  return directiveDefinitionObj;
});

Directive API as Selective Scope Inheritance 


The downside of UI component APIs using static attribute values like the example above is the restriction that only string values may be passed in since that is what all HTML attribute values are, and the value is not a live binding.  

If our use-case requires that the component consumer have the ability to pass in configuration information of all types and dynamically at run-time, then we more options available if the consumer is familiar with JavaScript and AngularJS at least somewhat.

By including a variable within AngularJS tags,
<my-search-bar auto-complete="{{ scopeVar }}"></my-search-bar>
as the value of an attribute we can create a live, read-only binding to a value on the parent scope. If scopeVar on the parent scope changes during the life of the directive instance, then so will the corresponding property on the directive scope.

Additional variable and method inheritance options for isolate scopes exist. Using '=' instead of '@' creates a live two-way binding between a value on a parent element scope and the directive scope, and using '&' allows the scope to call a function within the parent element's context. Both of these options can be useful for inner directives, but we should avoid using these options as UI component APIs since they allow a component directive to directly affect state outside its boundaries. If the world outside a component's boundaries needs to react to some change in component state, its is much better to use the publish-subscribe pattern made available to AngularJS scopes via:

$scope.$emit(evtName, args) //propagates up the scope hierarchy
$scope.$broadcast(evtName, args) //propagates down the scope hierarchy
$scope.$on(evtName, listenerFn)


Any scope with the same $rootScope can communicate via events whether isolate or not. Note that while the publish-subscribe pattern is discouraged in favor of data-binding in the official AngularJS documentation, for maintaining loosely coupled UI components, it is necessary.