A*genda in Angular 2

Developing A*genda in Angular 2

For the final project of CS3216, our team decided to develop a web app A*genda that helps event organizers to build web-based agenda for their events.

A*genda - screenshot of PyCon SG 2016 agenda for event participants

A*genda – screenshot of PyCon SG 2016 public agenda, used by event participants

A*genda - screenshot of agenda builder interface, used by event organizers to create event agenda

A*genda – screenshot of agenda builder interface, used by event organizers to create event agenda

This was an unfortunate timing (October 2016) for our team since Angular 2 just came out of beta, and Angular 1 is going to be the “legacy” framework soon. As a team that has no experience with other frameworks like React.js or vue.js, we were stuck between Angular 1 and Angular 2, and the final decision was latter.

Why Use Angular 2 Over Angular 1?

Simply put, we believe Angular 2 represents the future (Thanks, Apple). It has better overall approach to the web application compared to Angular 1, with a component-based architecture and a set of useful toolsets:

  • TypeScript – TypeScript “adds Java into JavaScript”, alleviating the issue of scalability of code and making the code generally less error-prone.
  • RxJS – RxJS represents the best solution to asynchronous programing and event-driven apps as of ES6. RxJS Observable is compatible with the old Promise and adds the ability of subscription on top of it.
  • Component-based Architecture – This allows the developer to focus on each part of the application as a separate component with its own well-defined lifecycle, view and input/output, increasing code modularity and cohesiveness.
  • Ahead-of-Time(AoT) Compilation – AoT allows reduction in app size and improves performance by compiling the app before it is served to the user.

Data Synchronization Across Components

For our project, we need to handle the problem of synchronizing data across different components. As an agenda app, we have event sessions scattered in different components, according to the date of the event session. A new session might be created in the parent component via a global action. We want to update the corresponding child component of that date to reflect the new addition. One approach is to have a separate data model for each child component and update the child component manually via component interactions.

Synchronization via Component Interactions

In Angular 2, there are various ways to do component interactions, you can call a child component from the parent component, notify the parent component from a child component using EventEmitter. However, the most versatile way is to communicate with a service.

Using RxJS, we can have Subject and Observable in the service and subscribe to them in our components individually, allowing each subscription to be managed independently inside various components while maintaining the ability to delete all the subscriptions within the service. When one change happens in a component, it can notify using the service to all the observers for that change and the components can handle the changes independently. This is one way to synchronize data across different components. From a software engineering perspective, this is a directly usage of the Observer pattern as a mechanism for change propagation within the MVC framework.

Synchronization without Component Interactions

There is another way to synchronize data across components without component interactions. In Angular 2, the change detection happens implicitly, and you can no longer “listen” to changes. This means the template will change automatically once the data binded to it changes, even across different components. Hence, to avoid manipulating data unnecessarily, we can minimize component interactions and modify the underlying data model directly inside each component. In this way, all the template bindings and component-scoped data will update correctly since we pass our entire data model into each component by reference. From a software engineering perspective, this is similar to the (Shared) Repository Pattern.

The downside to this approach is that we need to know the correct subset of sessions in the entire session list for each child component. That can be tricky since both our child component and sessions have dynamic properties that can change any time. A simple array is not sufficient for the identifying sessions belonging to each child component.

A Mixed Strategy Depending on Nature of Data

In practice, we used the first approach of component interaction for handling more complex data structures that needs more careful handling. On the other hand, we used the second approach of modifying the underlying data model directly for simple data such as speakers and venues, which are easily modelled via 1-dimensional arrays.

Issues with Using Angular 2 at This Stage

Obviously there are drawbacks of using Angular 2 at this stage:

  • Lack of Styling and 3rd Party Support – As of now, official Angular 2 Material is still in alpha with lots of components not completed. There are some 3rd party components but the quality varies a lot and the features are very limited.
  • Breaking Syntax Changes – Often when searching online or reading other code snippets, we encounter outdated syntax used in various release candidate (RC) versions that has been depreciated. This will likely go away as we move into more stable releases, but as of now it is a pain to work with.
  • Lots of tooling – If you think there are too much web app tooling, then you will not like Angular 2. By default it uses SystemJS loader but there is a guide on how to use Angular 2 with webpack. You need knowledge of npm, TypeScript and either SystemJS or webpack to do the setup and adding 3rd party libraries. And trust me, it is not easy.

Leave a Reply