Upgrading Front-End Apps to AngularJS 1.3

NYPL's new Locations section was initially created using AngularJS 1.2 as the front-end framework. When the Digital Experience team began working on updating the Research Divisions page, we decided to use the newer AngularJS 1.3 version. Considering the relatively small size of the Research Divisions project, the appropriate code changes that were made for the upgrade were small and did not impact us at the time. But, when we decided to upgrade from the 1.2 version to the 1.3 version for the larger Locations project, the front-end team ran into large code changes, different coding styles, and best practice decisions we had to discuss.

Locations Map page
NYPL Locations map page

 

HTTP Interceptor

We are currently using an HTTP Interceptor by Jim Lavin to display a loading icon. While the page is fetching data the loading icon displays and once it resolves the data the loading icon is hidden. We made updates based on AngularJS' docs for interceptors for use in AngularJS 1.3. Originally, the nyplInterceptor function use to return a Javascript promise. With the 1.3 update, however, the function now returns an object. Another update is how the interceptor is added to the app. The interceptor is no longer pushed to AngularJS $httpProvider's `responseInterceptors` array. Instead, the interceptor function now needs to be added to the $httpProvider's `interceptors` array.

ng-repeat

An interesting change from AngularJS 1.2 to 1.3 is how the ng-if directive handles empty arrays. On individual library pages, we display sections of content based on their availability. On the 115th Street page, the library does not have any Featured content whereas the Stephen A. Schwarzman Building does contain Featured content. We output a library’s Featured content in the view layer with a simple check.

Looking at the Locations API, the location._embedded.features property is an array of featured content objects. If the array is empty, we do not display that section on the front-end. The same is true for the other sections, such as blogs, events, and exhibitions.

In AngularJS 1.3, our simple check still displayed the Featured content section even if the array was empty. In this particular case, a header with the title “FEATURED” is displayed with no content. This check makes sense since an empty array is considered to be truthy in javascript. We now had to update the section with a check ng-if directive to see if the features array contained at least one item. When the array is empty, we do not display the section.

One-time data binding

This is one of the best features from AngularJS 1.3 that helps add small boosts to performance when rendering data in the view. AngularJS keeps a watchers array of data bindings that it checks on every $digest cycle. If a change is made to a binding, the view updates accordingly. This can cause performance issues when the app has too many bindings that AngularJS has to process.

If we are binding data to the view and we know that it won't change throughout the app’s life cycle, we can use one-time binding to render it. After AngularJS' first $digest cycle, it will render the binding in the view and then remove it from the watchers array. Now AngularJS has one less binding to process and performance is improved.

In the Research Divisions page, we compose the filter labels from the data we get when fetching all the terms. The top level categories are Subjects and Media (we get the Locations filter category and terms based on the Divisions data) . Since we know that the labels will not change, we can use one-time data binding to render the category name.

This outputs the three filter buttons we have on the Research Division page.

Filter labels
Research Divisions filters

 

Strict Dependency Injection

The AngularJS team added the `ng-strict-di` directive in version 1.3 so that an app can be in "strict dependency injection" mode.

`< html id="ng-app" data-ng-app="nypl_locations" data-ng-strict-di>`

This is recommended from the team to promote best coding practices when creating AngularJS apps. The directive ensures that we always define the dependencies for our functions when creating them. For us, this means we can depend less on the ngAnnotate tool that injects dependencies for us. This change also means that we have to be explicit and use $inject for named functions.

Global functions

Always avoid polluting the global scope! Following Todd Motto’s Opinionated AngularJS Styleguide for teams post, we wrapped all our named functions inside closures and then assigned them to the corresponding AngularJS method.

Now, however, AngularJS' migration documentation mentions that the $controller method will no longer look for functions in the global scope. Although this change helps promote better coding practices, it goes against the style we choose for creating and adding functions to the AngularJS app.

When updating to 1.3, we did not run into any conflicts because of the closures we used to wrap our functions in. We are not polluting the global scope and we are using closures, immediately-invoked function expressions (IIFE) to be precise, so we decided to stay with our existing coding style. It also makes adding and removing functions to the AngularJS controller, filter, directive, and service methods much cleaner.

What's next?

The AngularJS team have two more big releases planned, AngularJS 1.4 and AngularJS 2.0. Although updating to AngularJS version 1.4 when it becomes stable won't be too difficult, we expect to encounter difficulty when migrating to version 2.0 because it's a whole rewrite of the AngularJS code base. For now, we are constantly reading about it, experimenting with its preview, and looking forward for its stable release.

Resources

Comments

Patron-generated content represents the views and interpretations of the patron, not necessarily those of The New York Public Library. For more information see NYPL's Website Terms and Conditions.

iOS app, where art thou?

Hi, I wanted to know what the story was behind the NYPL native iOS app (RIP); can you point me in the right direction? thx, Amitai

Hi Amitai, you can learn more

Hi Amitai, you can learn more here: http://www.nypl.org/mobile-help