Angular 2 Patterns in Angular 1

Not too long ago Angular 2 hit "Final Release" which means a lot more people will be trying it in the coming months. Moving from Angular 1 to Angular 2 introduces some new concepts, patterns, and tools for building your front end applications. The changes will take a bit of adjusting to adapt to, but the good news is you don't need to press delete on your existing Angular code base to use these patterns. 

The title of this post is "Angular 2 patterns in Angular 1" but truth be told these patterns are not specific to Angular 2. The adoption of these patterns by Angular 2 is more representative of Angular 2 embracing modern best practices and tooling being used by JavaScript front-end developers today.

In this post we're going to focus on the implementation into Angular 1 of these patterns the goal being twofold, one - to familiarize ourselves with these patterns and the value they provide; and two - demonstrate that you can implement these patterns in Angular 1 and in the process make the transition to Angular 2 that much easier.

Components

So what are components?

I don't know if there is an exact definition - I would define a component as a reusable unit of HTML + JavaScript + CSS that can be represented as an HTML element tag. Some people may disagree on the inclusion of the element tag part or css, but I think they are both integral to the encapsulation and re-usability that characterizes a component.

Why use components?

  • encapsulation
  • separation of concerns
  • loosely coupled
  • re-usability

One or two of these characteristics would definitely make a pattern or tool worth looking into, but getting all of these makes a compelling argument to use components in your architecture. Its easy to see how you can build a framework where large parts or maybe even whole applications can be composed by combining "base" components into to bigger "feature" level components.

Child Views

What are Child Views?

Child Views are the "detail" in the Master-Detail view pattern. It would be the detail view you would navigate to if selecting something from a list. The concept is so ubiquitous to web development that you've probably used the pattern without even noticing. Its relevance in this discussion is that Angular 1 had no native support for child views and often required workarounds to implement, but in Angular 2 the concept is baked into the framework

Why use Child Views?

  • separation of concerns
  • encapsulation
  • re-usability

I think as a concept it's easy to see the use case- right ? We're not carving out new territory here, but for due diligence lets point out a few things. The pattern allows the details/child view to share some common "parent" component versus other clumsier ways to possibly implement the "parent child" view concept. I've seen html with all the views present and JavaScript orchestrating what is shown and not shown, or even sadly enough duplicating markup across multiple html files - not ideal to say the least - using child views takes that pain away and makes for better code.

One Way Data Flow

What is One Way Data Flow?

One way data flow is a pattern that has emerged as a byproduct of dealing with the issues of poor performance and state management with two way binding. The concept is simple, all data or "state" in your application flows from one source - to change data - changes are applied to the source and the source then updates all data consumers in the application.

Why use One Way Data Flow?

  • traceable state
  • better performance
  • easier debugging
  • decreased code complexity

Once you apply this "one source" approach, as part of your One Way Data flow pattern, tracking changes in your application becomes easy. Once you start logging state changes a lot of possibilities open up - - when debugging -- easily review the changes in state at the time the error occurred; -- need to "undo" -- easily identify each change that needs to rollback; -- need test data -- re-use the log to identify the exact data/state you need to run your test. Let's also not forget it makes you code easier to understand because all changes run thru one central location. In comparison to two-way binding in Angular 1, we know changes to state can come from multiple directions, users updating a field, variables bound to other variables - it can be hard to understand what's going on in the app. We would also be remiss if we didn't mention the performance cost tied to watchers and digest cycles.

Events

What are Events?

Events are another one of those concepts that we are all familiar with and have worked with in one form of another. In this context we're talking about the expanded role their playing in a lot of current front end development and the different patterns being used to leverage them to greater effectiveness. The increased popularity of paradigms like "Reactive Programming" and frameworks like Rxjs are causing events to be looked at in a different light. In Angular 2 this is evidenced by the "embedded" use of Rxjs in its architecture and doing things like using "Input" and "Output" events for Component communication.

Why use Events?

  • loose coupling
  • separation of concerns

When we say "use" Events we're talking about using them to create leaner architectures. The use of an event pipeline in your architecture, lets your code just plug into the pipeline as needed and is freed of any requirement to be aware of, or directly interact with, the producer of the event. With regard to Angular, using something like a "Publish/Subscribe" event pattern greatly streamlines your code. Think about two-way binding in Angular, specifically think about one of the classic examples where input text is bound to a label or header. Everything plays nice when working from the same controller and view, what if we needed to have two-way binding across controllers or components - say bind to a field in the header or footer - think about the code you would need to write to wire these two pieces together - not so easy to do or maintain - leveraging a pattern like Publish/Subscribe provides a clean maintainable implementation.

Tools

Its important to note that we also rely on a couple of tools that play a pretty standard role in Angular 2 development, Typescript and Webpack. We'll give you a quick overview, but definitely get to know them better as they have a lot to offer

Typescript, is a superset of JavaScript that allows you to use classes, types, interfaces and a number of other conventions in your JavaScript code, one of its main selling points is that it can provide type safety which because of JavaScript's dynamic typing can become problematic with larger JavaScript applications.

Webpack is a module bundler. What that means is - it allows you to write you front end code using module's, like you would in node js, and bundle the output together. The thing about Webpack is that it allows you to bundle more than JavaScript, like CSS. Webpack has a large ecosystem and comes with a lot of great features and tools.

Implementation

Now that we are familiar with the concepts and some helpful tools, lets dive into the application and understand how we use them in Angular 1.

I've gone ahead and created two demo apps that incorporate these practices and tools. The app is the "At the Movies" dvd store, to allow for comparison, we have an Angular 1 version and an Angular 2 version of the app, . Click on the link to download and experiment with the apps at your leisure, but its functionality is pretty simple and does the following

  • users can select a movie
  • users can read reviews
  • users can add a review
  • users can buy a dvd
  • the app tracks the best-selling movie
  • the app tracks the best-reviewed movie

Below is a diagram of the of the architecture for reference, while reading or looking at the code.

Let's now look at how we implement each of these patterns

Components

  • Angular 1 - angular directives + Webpack
  • Angular 2 - native angular 2

In Angular 1 we apply our formula of HTML + CSS + JavaScript = <component element tag> using Angular directives. With Angular directives we get native support for creating element tags and it allows us to package our HTML and JavaScript together - so just with an Angular directive we are a little more than two-thirds done with creating a component, to add the final ingredient we'll leverage Webpack to include our CSS.

I know what you're thinking, doesn't the latest versions of Angular 1 have a "Component" directive?

Current versions of Angular 1 do have a "Component" directive which I purposely decided not to use as I wanted to demonstrate with even older versions of angular it's still possible to create components.

Now lets look at our "movie-list" folder which has all the ingredients for a component

A couple of things to point out

  • we are using Typescript classes which at compile time will result in a module, wrapping our code in Typescript classes and having it output as a module, allows for the "class" to be used as a dependency in other parts of our code via the "require" or "import" statement.

  • we are using Webpack as our JavaScript bundler. When we use Webpack it not only bundles the code you point it at but by using the "require" or "import" statements in the code it will find those dependencies and include them into the bundled output. This is how the app is put together, by pointing Webpack to one file that specifies all dependencies; and the dependencies specify dependencies; and so on and so on. As we mentioned earlier, Webpack can also be configured to include non-JavaScript dependencies into our bundle, notice that the html template in our directive definition, below, is wrapped in a "require" statement. This ability to bundle non-JavaScript dependencies is the magic that allows us to add our final CSS ingredient to our above mentioned recipe. This technique allows us to create a component in two ways - one, Webpack can be configured to point to a file listing the JavaScript, CSS and HTML dependencies of the component and bundle it into a JavaScript output file that can then be dropped on to an html page or - two, as were doing in our demo app, by using "require" to point to the contents of movie-list folder and treat the contents of our component folder as one dependency.

  • By grouping our component code into a folder and specifying an index file that acts like a manifest, also referred to as a "barrel", the Webpack config can leverage this as an entry point for creating an output file as mentioned above or as a manifest of dependencies when referred to via a "require" statement - as shown in the app.ts file below. It is through this index file that we compose the contents of our component trinity of HTML + CSS + JavaScript.

With this setup, assuming you using this pattern in other applications, you can copy your movie-list folder into another application and just "require" it or you can configure Webpack to bundle it into an output file that can be included on an html page. Now, just to leave you hungry for more, think about the other stuff Webpack can bundle into this component for you, like Angular Services or you Jasmine unit tests...hmmmmmm...

Child Views

  • Angular 1 - ui-router
  • Angular 2 - native angular 2

One of the best ways to implement child views in Angular 1 is with ui-router. The ui-router solution is pretty popular and considered a best practice by many with regard to routing - here is a great article spelling out its merits

In our app we use child views for our main page content and in our movie page to pop in reviews, input form view for adding a review, and a purchase view for users to buy a movie.

the implementation revolves around three steps

  • a place for views to land, which is <ui-view>, this is the angular equivalent of ng-view. Here we see the examples from the app and movie HTML.

  • routing to views, done by using ui-sref instead of href.

  • last but not least is the configuration of the router. One thing we should point out, as you can see below, is that our route configurations are setup to route to components; and child views are really just "child" components. We can see an example of child views/components in the configuration of the "review", "reviews", and "purchase" routes as they configured with a "parent" parameter which is the "movie" route. As you can see, creating application features as components is a pattern that fits well with routing, so much so that this approach is exactly how Angular 2 has designed its routing to work.

One Way Data Flow

  • Angular 1 - ngRedux
  • Angular 2 - ng2Redux

One Way Data Flow is implemented with the use of Redux and Redux is a tool the comes to us from the React js community. Redux has quickly established itself as "the" way to implement the Flux pattern, which is the prescribed pattern for working with React js.

There are no real differences in the implementation between Angular 1 and 2, there is an "angular" Redux version for both. The concept behind redux is relatively simple

  • some event generated by the application requires action on the application state
  • the designated code that will perform the action will take a copy of existing state, apply the action to the copy and return the copy as the new state of the application.

There is more to the pattern, and requirements around using pure functions and maintaining immutability with regard to application state --- follow up on the links above for details.

In our case we use Redux to implement this "one source of data" requirement of the One Way Data Flow pattern. Redux has all the tooling to implement the pattern and it is what helps our movie information stay in sync, the implementation of Redux revolves around three steps

  • actions - which are objects that have two properties a "type" and a "payload". The "type" is a description of the event that has just taken place and the "payload" is whatever data is required to implement the required action triggered by the event.

  • reducers - which take application state and an "action" and execute the "action" logic required to transform state

  • an application store which manages our data and uses three methods to work with the application
    • dispatch method - which takes an action and applies the reducer code
    • getState method - which returns state
    • subscribe method - which allows application code to get notified when application state changes

Events

  • Angular 1 - Rxjs
  • Angular 2 - Rxjs

As hinted at above we leverage the "Publish/Subscribe" Event pattern to keep our code decoupled- to do this we use Rxjs. Like Redux the implementation is the same for both versions, but unlike Redux you can use the same Rxjs code in both, there is no need for Angular 1/2 differentiation.

Rxjs is a pretty big tool set that comes with a lot of utilities for processing streams of event data. The use case we've implemented uses something known as a "Subject" which allows us to "publish" and "subscribe" to events, we've wrapped our Subject in a Angular service to provide some encapsulation and control over its use. Let's review the implementation

  • Potential publishers would use the service to publish information to the pipeline, in our case we broadcast to the system that a new movie review has just been created, shown below

  • As you see in the code below, potential subscribers use the service to register a handler that gets notified of the event and applies the corresponding logic.

As you see, implementing this pattern with Rxjs is very lightweight, other approaches could've been used to apply the "Publish/Subscribe" event pattern but I'd be hard pressed to find one that does it so cleanly. The other upside is that the Rxjs tooling allows for lots of options with regard to manipulating the subscribed stream of data, think in terms of an object(s) being passed thru the pipeline and the ability to apply collection logic like "map" or "filter" on them. This is exactly the kind of thing Angular 2 has done by wrapping the output of its "http" service as a subscribe-able data stream via Rxjs.

Summary

In summary we've talked about some significant patterns and have implemented them in Angular 1, fair to say that each of these topics could be a post unto themselves and definitely demand further exploration. I've purposely kept things light and tried to hone in on the main idea or principles behind some of these patterns, to serve as a starting point. Hopefully it's sparked a bit of inspiration and curiosity and started the wheels turning on how you can improve your existing code base via one of these topics.