Mistakes I’ve Made in Angular 1

And is it right to choose Angular as the front-end?

As excited as we are to dive right in to the heart of the Gestalt challenge — to explain data clearly in a visual manner — we need to build the framework to lay the foundation for our work. We decided to go with Angular 1 for the front-end and web.py as the back-end because they allow us to quickly prototype our ideas (more details about the front-end decision at the end of the blog post). It goes without saying that my journey with Angular starts out bumpy. By sharing the mistakes I’ve made in Angular, I hope you can learn what Angular is and make a better informed decision when it is appropriate to use Angular versus another front-end framework.

Mistake #1: Not following the “Angular” way

Angular has a set of concrete rules. This is simply because it was created as an extension to HTML. It follows the HTML mindset in that you want to make as few changes to the DOM as possible. For those of you who do not know what the DOM is, here is a quick 101. DOM is the abstract embodiment of a webpage in the form of a tree. Changing the content of the webpage means changing the DOM too. You have to remember which component in the webpage is tied to which implementation. This becomes troublesome to keep track of, especially if there are multiple components that are dynamically changing in a webpage. Angular simplifies the manipulation of the DOM via its digest cycle. Like magic, it detects the changes and modifies the DOM as necessary. The benefit, unfortunately, comes with a cost: follow the Angular way or be prepared to have some pretty janky code that’s not maintainable.

John Papa’s and Todd Motto’s style guides are great references to use if you are not familiar with the Angular pattern. It helps produce code that is easier to maintain, debug, and scale.

Another common consequence of not following the Angular way is stumbling on code that’s not working as intended. One example of this is using capitalization or underscore in the directive’s name at the HTML level. The Angular compiler cannot accept that because HTML is case-insensitive, and therefore, Angular can only refer to the directive in the DOM by its lower-case form. To add to the confusion, the convention for directive’s name is camelCase in Javascript and dash-separated in HTML. Not knowing this minute detail can easily lead you astray from the actual solution.

So remember, follow the Angular way. Or Angular will just tell you to go take the highway.

Mistake #2: Thinking it’s similar to other front-ends

Since Angular provides the structure you need to develop a web application, getting started in Angular is delightfully easy. It is not until later when you demand a richer functionality in your application that you realize you need to take time to really understand the inner workings of Angular. I was short-sighted and thought that I can transition my knowledge to other front-end frameworks. Boy, was I in for a surprise! Not only is Angular 1 different than React and Ember, it is vastly different than Angular 2 that you can almost say they’re two separate front-end frameworks!

I can imagine how difficult it might be to integrate existing projects with other front-end framework that is not Angular. Fortunately for us, we are not tackling this problem.

Mistake #3: Grouping files by type vs feature

Angular employs the Model-View-Controller (MVC). The beauty of this methodology is the separation of concerns where the jobs that handle the user interface is separated from those that handle the logic of the application. As the diagram shown above, the controller handles all the requests for the application (i.e., user clicks on a visual diagram). It then communicates with the model to extract any data that is needed by the view. The view uses the data prepared by the controller to generate the right display for the request (i.e., user clicks on a visual diagram -> diagram zooms in on that particular target with additional information).

Angular uses a different naming convention than the standard Model-View-Controller. It can be summarized as follows:

Service (Model) : Service communicates with the back-end to get the data requested by the controller. Since it is a singleton, it persists throughout the lifetime of the application. $scope is then used in the controller as the Model container.

: Service communicates with the back-end to get the data requested by the controller. Since it is a singleton, it persists throughout the lifetime of the application. is then used in the controller as the Model container. Directive (View) : Directive handles the final presentation displayed to the user after the controller extracts the information it needs from the service. Directive should be the only one that manipulates the DOM.

: Directive handles the final presentation displayed to the user after the controller extracts the information it needs from the service. Directive should be the only one that manipulates the DOM. Controller (Controller): Controller requests the data it needs from the service and bound them to $scope for the view to use. It can administer complex logic, but it should be minimized to the request it handles. Because of this, controller lasts as long as its use case requires.

Knowing that Angular employs the Model-View-Controller framework, it might seem right for the first time to group the files by their respective types.

DO NOT FOLLOW THIS EXAMPLE app/

app.js

config.js

Service/

LoginService.js

WorkspaceService.js

Directive/

LoginDirective.js

WorkspaceDirective.js

Controller/

LoginController.js

WorkspaceController.js

HTML/

login.html

workspace.html

But a directory like the one above becomes increasingly difficult to follow with each additional feature. This also holds true for new team members who are not familiar with all the features the project has to offer. A better way to structure the directory is to group by the features and place the necessary MVC within the featured folder.

app/

app.js

config.js

Login/

login.html

LoginController.js

LoginDirective.js

LoginService.js

Workspace/

workspace.html

WorkspaceController.js

WorkspaceDirective.js

WorkspaceService.js

As you can see, you can find what you are looking for right off the bat and map out what features the project has (without having to dive right into the documentation page). Winning!

Mistake #4: Bloated controller

It’s very tempting to make the controller do so much. After all, it is the first to respond to an event and interacts with both the view and the model. But before we continue …

Let’s forget we even had that thought. Because the controller coordinates with the view and the model, it should be minimal so that testing is much simpler. It should never do what the directive does (manipulating DOM) nor should it ever store any data like what the service does. Controller will forget about the data after the application transitions states, so storing data in controller is a big no-no. Even if you managed to store it in the localStorage, it’s so much slower than storing it in a Javascript variable like $scope .

An example where I encountered such a problem is when I tried to have the controller handle what was supposed to be the job for the directive. After the controller provides a list of data to the HTML template, I wanted to iterate through the list and call a function for each item in the list. At the time, I assumed that the controller is the mastermind behind all the logics in the view. It was an incorrect assumption to make because once the data is passed from the controller to the view, it is the directive’s job to handle any changes in the view. Once this MVC intuition is set into my core thinking, everything just falls into place.

Mistake #5: Handling asynchronous calls

The most surprising aspect to wrap my head around is the idea of asynchronous calls in Javascript. Basically Javascript runs on a single thread in your browser. If I forced Javascript to execute in sequence, it will wait for one call to finish before moving on to the next. The user is then forced to interact with an unresponsive app. That’s why Javascript is the way as it is — asynchronous — to keep the application responsive. This is great when you are trying to develop a data visualization platform which makes multiple I/O calls to retrieve the data and has possibly multiple users interacting on the same field.

If an I/O call was dependent to a previous I/O call, how would you do it in Angular asynchronously? You can chain them. You can also have simultaneous I/O calls run in parallel before performing a logic on those data. Burleson Thomas wrote a great blog post on how to accomplish this.

Mistake #6: Watching too much

Do you remember how magical it was when you first discovered two way data-binding in Angular? Without a line of code, you can make an element fully dynamic by changing the value in the $scope . But there lurks a hidden problem even I did not foresee. Before we tread through this adventurous path, let’s try to understand two-way data binding better so that we know where this potential problem lies.

Storing the state of the application inside the DOM is generally bad practice because the view should not store data. So where can we stow the state of the application if we can’t store it in the DOM? Why, we can store it in Javascript of course! But what if the user wanted to view the retrieved data? Hmm, I guess we can also store it in the DOM? Here lies the beauty and the beast in two-way data binding.

Because Angular saves the state of the application both in Javascript and the DOM and sync really fast between the two (as shown in the image above), you are able to dynamically change the element without adding a line of code. But with increasing complexity in the application, the number of elements increases, and sometimes you want to add a watcher on an element to perform additional logic on top of it. Overtime, your application can be overrun by zombie-like watchers waiting for the change on their respective element. This eats up the resources on your browser, and your application becomes slow. It can be especially bad when you are building an application on mobile devices.

The solution to this problem is to avoid watchers if you can. Who says too much watching can be bad for you? Angular said. And if you know what’s good for you, always follow what Angular says (or you can transition over to Angular 2 that attempts to solve this issue). And please, don’t put a watcher in the controller. It’s already bloated.

Why choose Angular 1 then?

For those who are new to front-end development, Angular is a good place to start. It is not a quick way to start because there is a substantial learning curve involved that is not transferrable to other front-end frameworks. Even its successor Angular 2 is not the same as Angular 1.

Because Angular 1 employs the digest cycle to update its view, its performance can be questionable at times. Angular 2 supposedly fixes this performance issue by replacing the digest cycle (in the two-way data binding process) with a change detection algorithm that can check if the binding has changed and avoid scanning parts of the DOM tree that did not change. Sebastián Peyrott compared the performance of Angular 1 against that of Angular 2 as well as other front-end frameworks’ if you’re interested.

So why did we choose Angular 1 instead of Angular 2? Or Angular 1 instead of Ember with Flux? The stable release of Angular 2 was announced after the start of the Gestalt challenge. Since it is a fairly recent release, we know we have to update regularly and adjust with each new updates. Our focus in Gestalt is to figure out how to explain data clearly in a visual manner. We try to minimize the disturbances in the flow of operation by choosing Angular 1. But, if we have the second chance to do it all over again, we would use Angular 2. Angular 2 has better performance and is tailored not only for the browsers in your desktop but also the browsers in your mobile devices.

As for Ember with Flux, we did not get a chance to explore them yet. It will be good practice to do so in the future. Both Angular and Ember can be paired up with D3.js (and other data visualization tools) to build the platform needed for visualizing — and more importantly, explaining — data.