I have been using Angular for over 3 years. A few months ago Angular 1.5 came out and they introduced the .component() method, which is basically the same as an element directive but with a much simpler API. Since then I’ve fallen more and more in love with Angular so I decided to write a small todo app utilizing the component architecture along with some cool things in the Angular world.

First of all I’m not much of a designer so I want to thank TodoMVC for the UI.

Anyway, the app consists of:

Angular 1.5 because of components!

UI-Router 1.0.0-beta.1 so I can route to components

MobX for managing my state

Webpack for module bundling

I’m not gonna talk much about these in depth, only high-level about what they are and why I chose them. This article will mainly be about how I decided to structure and implement the app.

I decided to write this in ES5 because most Angular 1.x applications are still in ES5. But it would be cool to rewrite this in ES6 (ES2015) and TypeScript, just for the comparison.

Here’s a demo

Here’s the code

I’m using NPM for the project, to pull in the Node.js modules I need. Then I use Webpack for module dependencies and bundling of the application. It’s very powerful and simple to setup and config. Also with the benefits of loaders and plugins, you can require almost everything from anywhere. Without going into further details, Webpack is pure awesome! I highly recommend you look into it!

Architecture

First of all I’m going to talk a little about the application architecture. My goal was to create a simple app with component architecture, unidirectional data-flow, one-way data-binding and a global accessible store that holds the state of the application.

Here’s the setup of the component hierarchy of the application:

Project structure

The way I structure my app is the root contains a dist folder with the compiled/bundled output, node_modules and src folders, along with my package.json, .gitignore, .editorconfig, README.md and webpack.config.js. Under src I keep my application source code, where as I keep my components together in a folder where I only seperate the container components. Then I have a seperate folder for my store, because you never know if you later on add some more stores.

Each component is in its own folder, has its own controller and a template, which are then required via Webpack. The controller is defined in the same file as the component, but it might just well as be in a seperate file and then just required from the component. Webpack’s html-loader then fetches the template content and loads as a JavaScript string, which is then bound to the component itself. I always name the component file as index.js because that makes it possible to require the component without having to specify the filename or the extension.

I only export pure objects/functions in general. The /src/components folder then has an entry file, index.js , which handles requiring all the components and binding them to Angular. As you can see the components and the store is exported just as pure functions. In my opinion this makes the switch to ES6 (ES2015) more easier, because you just export a class instead.

Application state

Ever since I began my Angular SPA journey, there has always been a question on my mind: Where do I keep the state? and How do I persist the state between pages/routes? Today it’s recommended to keep the state global so you can access it everywhere. Also it’s a single source of truth. However, if you have data which isn’t needed outside a particular component and which you don’t need to stick around when that component goes away, local state is often enough.

The two hottest state containers and Flux-like frameworks today are Redux and MobX. I don’t have much experience with Redux but I found a little bit hard to get the hang of it. However the alternative MobX, what I have seen is fairly simple and straight forward. Also it doesn’t tell you where to store the state or how to process events. So you can split up your stores and mutate the state however you want.

MobX is based on the Observer Pattern. It consists of observables, observers, actions, computed values and reactions. Basically you mark some data structure as an observable (the state), then you mutate the state, the state is derived (computed values, rendering, etc.), the observers are notified of the change and the reactions are run. The reactions then trigger some processing (I/O, DOM updates, networking, etc.). The flow diagram is fairly straight forward.

Routing and configuration

I’m using UI-Router 1.0.0-beta.1 which means I’m able to route to components, which is awesome! I only have one routed component todo , which we’ll route to with different filter input. So let’s begin by setting up the index HTML file, routing and configuration of the application.

/src/index.html

<!doctype html> <html lang=en ng-app=todoApp> <head> <meta charset=utf-8> <meta name=viewport content=width=device-width, initial-scale=1> <title>TodoMVC</title> </head> <body> <ui-view></ui-view> <footer class=info> <a href=https://github.com/gaui/todoApp-angular-mobx-webpack> <img src=http://fossari.is/img/github.png alt=GitHub> </a> <p>Double-click to edit a todo</p> <!-- Remove the below line ↓ --> <p>Template by <a href=http://sindresorhus.com>Sindre Sorhus</a></p> <!-- Change this out with your name and url ↓ --> <p>Created by <a href=http://todomvc.com>you</a></p> <p>Part of <a href=http://todomvc.com>TodoMVC</a></p> </footer> <!-- Scripts here. Don't remove ↓ --> <script src=vendors.js></script> <script src=app.js></script> </body> </html>

This is just a simple HTML document where UI-Router handles injecting the application into the <ui-view> based on which routing state we’re on. See the configuration phase below.

/src/index.js

This is the entry point for the application. Webpack then bundles the application and outputs to dist/app.js

var todoStore = require('./stores/todoStore'); // Styles require('./index.less'); angular.module('todoApp', ['ui.router']) .service('todoStore', todoStore) .config(config); function config($stateProvider, $httpProvider, $urlRouterProvider, $locationProvider) { $urlRouterProvider.otherwise('/'); $locationProvider.html5Mode(false); $stateProvider .state('todo', { abstract: true, url: '/', template: '<ui-view />' }) .state('todo.all', { url: '', component: 'todo', resolve: { filter: function () { return 'all' } } }) .state('todo.active', { url: 'active', component: 'todo', resolve: { filter: function () { return 'active' } } }) .state('todo.completed', { url: 'completed', component: 'todo', resolve: { filter: function () { return 'completed' } } }); } require('./components');

I begin by requiring the things I need. I require the store (pure function) and the styles for the application. Webpack loaders handle this. This is a so called CommonJS module syntax that Webpack uses.

Then I create an Angular module todoApp , which is the name of our app, with only one dependency; ui.router . Then I create the store that I required above and setup the config phase of my application.

In my config phase I defined four routing states. As you can see they all route to the todo component and pass in a different filter value, based on how we want to filter our todo list.

A parent state that is abstract

A child state with filter all

A child state with filter active

A child state with filter completed

Store

The store holds the state of the application and my store is fairly straight forward.

/src/stores/todoStore.js

var mobx = require('mobx'); function todoStore() { var store = this; var todoList = mobx.observable([]); store.getAllTodos = function getAllTodos() { return todoList; }; store.addTodo = function addTodo(todo) { var newTodo = Object.assign({}, todo, { completed: false }); todoList.push(newTodo); }; store.deleteTodo = function deleteTodo(index) { todoList.splice(index, 1); }; store.updateTodo = function updateTodo(index, todo) { todoList[index].description = todo.description; }; store.toggleTodo = function toggleTodo(index) { todoList[index].completed = !todoList[index].completed; }; store.toggleAllTodos = function toggleAllTodos() { todoList.forEach(function(item) { item.completed = !item.completed; }); }; store.clearCompleted = function clearCompleted() { var filteredArray = todoList.filter(function(item) { return !item.completed; }); todoList.replace(filteredArray); }; } module.exports = todoStore;

The todoStore function is an Angular service and all Angular services/factories are singletons, which means they only have one instance through the application. When the Angular application is bootstrapped, an instance of todoStore is created. It then creates a private variable todoList that is an MobX observable array and is persisted through out the application lifecycle. So when that todoList array is mutated (item added, item changed, item deleted) all observers are notified of the change.

The todoStore function has a relatively simple API. It just knows how to get all todos, add a todo, delete a todo, update a todo, toggle a todo, toggle all todos and clear completed todos.

For simplicity’s sake I’m using the array’s index to locate the todo item, but in the real world I would use some unique identifier.

Components

Each component is an isolated unit. It has inputs (often called bindings or props), outputs and a responsibility. Inputs are passed into the component from its parent component via one-way data-binding. Output is the data that is passed from the component to its parents or children. If it’s passing data back to its parent component, it’s delivered back to the parent component by calling a callback function that the parent component passes down. If it’s passing data down to a child component, it’s delivered via inputs for that child component (often called bindings or props).

The responsibility is what the component is supposed to do with the inputs and outputs. The best way is to pass methods/callbacks from parents and then the child component calls that method on for example a user interaction. It’s best to let each component have as little responsibility as possible.

A small example: A father tells his kid some information and asks him what he thinks. That information is an output from the father (parent component) and the input for the kid (child component). The father gives his kid his phone number so he can call back when he’s done processing that information. The phone number is an input for the kid and can be thought of as a callback function from the parent component. The kid then calls his father afterwards to tell him what he thinks. That phone call and what he says to his father, is the output from the kid. Then the father takes a desicion based on that phone call. The parent component processes the data from the child component.

Stateful vs. Stateless

The key difference between a stateful component (often called container or smart components) and a stateless component (often called presentational or dumb components), is that often the stateful/smart components contain state or know how to talk to a store that contains the state. That’s why they are smart. They provide data and methods to other child dumb presentational components. However stateless components hardly ever contain any state. If they do, it’s only used inside that component (local state). They get data and methods from their parent and render a UI. If the user can interact with it, they often call a higher-level smart component that handles processing of that output event/data.

Dan Abramov has written an article describing the difference between container components and presentational components. They are also sometimes called stateful and stateless components or smart and dumb components.

These are the components in my app:

todo – stateful

todo-form – stateless

todo-list – stateless

todo-item – stateful (local state, a editing flag)

todo-footer – stateless

/src/components/index.js

This file is the entry point for all the components and is required in /src/index.js. This file just handles requiring all the components (pure objects) and binding them to Angular.

var todoContainer = require('./containers/todo'); var todoForm = require('./todo-form'); var todoList = require('./todo-list'); var todoItem = require('./todo-item'); var todoFooter = require('./todo-footer'); angular.module('todoApp') .component('todo', todoContainer) .component('todoForm', todoForm) .component('todoList', todoList) .component('todoItem', todoItem) .component('todoFooter', todoFooter);

Some people choose to do this differently, by exporting the component and its name and declaring it as a dependency on a seperate app.components module. Todd Motto recommends this. I however like having all my components under a single Angular module and to export only pure objects/functions without tying each component to angular.module() . When moving to ES6 (ES2015), you can export pure classes the same way.

todo

This is the most important component of them all, so called container component. These container components are stateful/smart. Their purpose is to communicate with the store and pass data/methods down to the stateless/dumb components.

/src/components/containers/todo/index.js

var mobx = require('mobx'); var todoContainer = { controller: todoContainerController, template: require('./todo.html'), bindings: { filter: '<' } }; function todoContainerController(todoStore, $state) { var self = this; var dispose = mobx.autorun(function () { var todoList = todoStore.getAllTodos(); self.todoList = getListBasedOnFilter(todoList, self.filter); self.incompletedItems = getListBasedOnFilter(todoList, 'active').length; console.log('%cNEW STATE:', 'font-weight: bold'); console.log(JSON.stringify(mobx.toJS(todoList), null, 2)); }); self.$onDestroy = function $onDestroy() { dispose(); }; self.addTodo = function addTodo(event) { todoStore.addTodo(event.todo); }; self.deleteTodo = function deleteTodo(event) { todoStore.deleteTodo(event.index); }; self.updateTodo = function updateTodo(event) { todoStore.updateTodo(event.index, event.todo); }; self.toggleTodo = function toggleTodo(event) { todoStore.toggleTodo(event.index); }; self.toggleAllTodos = function toggleAllTodos() { todoStore.toggleAllTodos(); }; self.clearCompleted = function clearCompleted() { todoStore.clearCompleted(); }; function getListBasedOnFilter(list, filter) { if (!filter) return list; var filterMap = { all: function (item) { return true; }, active: function (item) { return !item.completed }, completed: function (item) { return item.completed } }; return list.filter(filterMap[filter]); } } module.exports = todoContainer;

The only input for this component is the filter to apply on the list of todos; all, active or completed, and it’s bound to the controller using one-way data-binding ( < ).

Its responsibility is to communicate with the store, render and pass data from the store down to child components.

Angular components are bound to the controller’s instance and have isolated scope. That means that everything in the controller is bound to this (which is a reference to the controller’s instance/context). I always create a variable self that points to this , because sometimes this changes (based on in what context you are). Then I bind all my variables/functions to self because then they get bound to the correct this instance.

Take a look at the mobx.autorun() method. This is the reaction in MobX I mentioned above. When an observable changes, the observers are notified of the change and the reactions are run. The reaction when the todoStore.todoList changes is to get a list of all the todos and filter them ( getListBasedOnFilter() ) based on the filter passed in by UI-Router’s resolve, count how many todos are active (not completed) and then output the new state in JSON to the console.

The reason why I put the autorun in a dispose variable is so I can dispose/destroy the autorun when the component gets destroyed ( $onDestroy lifecycle hook). By assigning the autorun function to a variable and then calling that function, the autorun gets disposed and is never called again.

Let’s take a look at the template.

/src/components/containers/todo/todo.html

<section class=todoapp> <header class=header> <h1>todos</h1> <todo-form on-submit=$ctrl.addTodo($event)></todo-form> </header> <!-- This section should be hidden by default and shown when there are todos --> <section class=main ng-if=$ctrl.todoList.length > 0> <input class=toggle-all type=checkbox ng-click=$ctrl.toggleAllTodos()> <label for=toggle-all>Mark all as complete</label> <todo-list list=$ctrl.todoList on-delete=$ctrl.deleteTodo($event) on-update=$ctrl.updateTodo($event) on-toggle=$ctrl.toggleTodo($event)> </todo-list> </section> <!-- This footer should hidden by default and shown when there are todos --> <todo-footer items-left=$ctrl.incompletedItems on-clear-completed=$ctrl.clearCompleted()> </todo-footer> </section>

The template for the component just contains some basic HTML and a <todo-form> , a <todo-list> and a <todo-footer> child components and passes data and callback methods down to them.

Take a look at how I prefix all variables/methods with $ctrl . This is because Angular’s default component behavior is to specify controllerAs: '$ctrl' . That means the controller’s instance ( this ) is bound to $ctrl in the component’s template. You can change this by specifying controller: 'Controller as $whatever' or controllerAs: '$whatever' in the Angular component object. But I think it’s nice to always use $ctrl .

todo-form

This is the form of the app and is a child component of the todo component. It only has an input element which is tied to a ngModel and its only responsibility is to let the user enter a new todo description and submit the form.

/src/components/todo-form/index.js

var todoForm = { controller: todoFormController, template: require('./todo-form.html'), bindings: { onSubmit: '&' } }; function todoFormController() { var self = this; self.$onInit = function $onInit() { self.newTodo = {}; resetTodo(); }; self.submitForm = function submitForm() { // Call parent self.onSubmit({ $event: { todo: self.newTodo } }); resetTodo(); }; function resetTodo() { self.newTodo = {}; } } module.exports = todoForm;

When the component is initialized it fires the $onInit lifecyle hook. This is where I create a new ngModel newTodo which I bind user’s input to.

The only input for this component is a method to call when the form has been submitted. The method onSubmit is passed in from the parent component and is bound to the controllers instance. This is the same method as you can see in the bindings of the component. This input binding method is then called from the submitForm method in the controller. This component doesn’t know anything about what happens after the form is submitted, because its only responsibility is to call a function when the form is submitted.

I always name the functions that are triggered on an event with the on prefix. It makes it clear that it’s triggered on some event.

Take a look at the submitForm method. I pass the new todo item back up to its parent by wrapping the object in an $event object. This is best practice according to the Angular gods, because of Angular 2.

For understanding the difference between & , < , @ and = bindings, I recommend you read this. But I’m only using < for objects and values that are one-way data-bound and & for function callbacks.

/src/components/todo-form/todo-form.html

<form ng-submit=$ctrl.submitForm()> <input class=new-todo ng-model=$ctrl.newTodo.description placeholder=What needs to be done? autofocus> </form>

The HTML template for the component is really simple, just a simple form with one input that is bound to an ngModel and a callback method that is called when the form is submitted.

todo-list

This is the todo list itself and is a child component of the todo component. Its only responsibility is to render a list of todo items and let each todo item know what to call when something happens.

/src/components/todo-list/index.js

var todoList = { controller: todoListController, template: require('./todo-list.html'), bindings: { list: '<', onDelete: '&', onUpdate: '&', onToggle: '&' } }; function todoListController() { var self = this; self.deleteTodo = function deleteTodo(event) { // Call parent self.onDelete({ $event: { index: event.index } }); }; self.updateTodo = function updateTodo(event) { // Call parent self.onUpdate({ $event: { index: event.index, todo: event.todo } }); }; self.toggleTodo = function toggleTodo(event) { // Call parent self.onToggle({ $event: { index: event.index } }); }; } module.exports = todoList;

The input for this component is a list of todos and 3 methods: onDelete , onUpdate and onToggle .

The component implements these methods and only calls the parents methods that came as input. So it basically acts as a gateway. Then these new methods are passed down to each child component (the actual todo item).

Let’s take a look at the template.

/src/components/todo-list/todo-list.html

<ul class=todo-list> <!-- These are here just to show the structure of the list items --> <!-- List items should get the class `editing` when editing and `completed` when marked as completed --> <div ng-repeat=todo in $ctrl.list> <todo-item index=$index description=todo.description completed=todo.completed on-delete=$ctrl.deleteTodo($event) on-update=$ctrl.updateTodo($event) on-toggle=$ctrl.toggleTodo($event)> </todo-item> </div> </ul>

The template for the component just renders a list of todo-item components with ng-repeat and passes down data and callback methods to each one.

todo-item

This component is for each todo item and is a child of the todo-list component. Its responsibility is to render the todo item, allow the user to edit the description and to toggle or delete the item.

/src/components/todo-item/index.js

var todoItem = { controller: todoItemController, template: require('./todo-item.html'), bindings: { index: '<', description: '<', completed: '<', onDelete: '&', onUpdate: '&', onToggle: '&' } }; function todoItemController() { var self = this; self.$onInit = function $onInit() { self.editing = false; }; self.enableEditing = function enableEditing() { self.editing = true; }; self.deleteTodo = function deleteTodo() { // Call parent self.onDelete({ $event: { index: self.index } }); }; self.updateTodo = function updateTodo() { // Call parent self.onUpdate({ $event: { index: self.index, todo: { description: self.description } } }); self.editing = false; }; self.toggleTodo = function toggleTodo() { // Call parent self.onToggle({ $event: { index: self.index } }); }; } module.exports = todoItem;

The input for this component is an index of the todo item in the list, description, whether the item is completed and 3 methods: onDelete , onUpdate and onToggle . Instead of passing description and completed values seperate, you could pass down the item/object itself, but I chose to do it differently so the component’s API/inputs are more clear.

When an event happens (delete, edit or toggle) the component calls the parents methods that came as input. It doesn’t know what will happen when those events are triggered, only that it has to call some method from the parent component. The rest is handled in the parent component.

This component is rather complex and has too many responsibilities, so it could very well be split into two different components (based on if the todo item is being edited or not), but I decided to let the component handle both the viewing and editing and have a local state; A boolean (true/false) for editing.

Let’s take a look at the template.

/src/components/todo-item/todo-item.html

<li ng-class={'editing': $ctrl.editing, 'completed': $ctrl.completed}> <div class=view ng-dblclick=$ctrl.enableEditing()> <input class=toggle type=checkbox ng-checked=$ctrl.completed ng-click=$ctrl.toggleTodo()> <label>{{$ctrl.description}}</label> <button class=destroy ng-click=$ctrl.deleteTodo()></button> </div> <form ng-submit=$ctrl.updateTodo()> <input class=edit ng-model=$ctrl.description> </form> </li>

The template consists of two units, one for viewing (just a div) and one for editing (a form with an input). Which one is displayed depends on if the editing class is on the <li> element or not.

When the item is double-clicked we call a function enableEditing() on the controller, which toggles the editing flag which toggles the class and displays the form and the input, to allow the user to edit the todo item. This variable/flag is kept as a local state in the component.

As I said, this component is rather complex and has too many responsibilities so it could be split into two components, one for viewing and one for editing.

todo-footer

This is the footer of the app and is a child component of the todo component. Its responsibility is to render how many items are not completed, to allow the user to switch filtered todos (all, active, completed) and allow the user to clear all completed todo items.

/src/components/todo-footer/index.js

var todoFooter = { controller: todoFooterController, template: require('./todo-footer.html'), bindings: { itemsLeft: '<', onClearCompleted: '&' } }; function todoFooterController() { var self = this; self.clearCompleted = function clearCompleted() { // Call parent self.onClearCompleted(); }; } module.exports = todoFooter;

The input for this component is how many items are left and 1 method: onClearCompleted .

The component doesn’t know how to clear all completed items. It only knows how to call the parents method that came as input.

Let’s take a look at the template.

/src/components/todo-footer/todo-footer.html

<footer class=footer> <!-- This should be `0 items left` by default --> <span class=todo-count><strong>{{$ctrl.itemsLeft}}</strong> items left</span> <!-- Remove this if you don't implement routing --> <ul class=filters> <li> <a href ui-sref=todo.all ui-sref-active=selected>All</a> </li> <li> <a href ui-sref=todo.active ui-sref-active=selected>Active</a> </li> <li> <a href ui-sref=todo.completed ui-sref-active=selected>Completed</a> </li> </ul> <!-- Hidden if no completed items are left ↓ --> <button class=clear-completed ng-click=$ctrl.clearCompleted()>Clear completed</button> </footer>

Fairly simple. It uses the ui-sref directive from UI-Router to render a link to a routing state and applies the selected class if the state is active. Very neat.

Conclusion

This is my attempt to write a simple todo app utilizing best practices. Component architecture, unidirectional data-flow and one-way data-binding.

If you’ve got any questions or comments, I’ll be happy to answer them. Just comment below or hit me up at Twitter.

If you want to learn more about the awesome new things introduced in Angular 1.5, Todd Motto has written some great articles which I highly recommend: