13 of the best JavaScript frameworks to try

JavaScript frameworks: AngularJS logo

Best for:

  • Large projects in need of structure
Applications with lots of changing data

AngularJS is an open source frontend web application framework developed by Google. It offers declarative templates with data-binding, MVW, MVVM, MVC, and dependency injection, all implemented using pure client-side JavaScript. 

Here, we'll show you how to use AngularJS to create reusable code blocks known as custom decorators, serve content to your users quicker, and create performant and easy to control animations with ease.

Create custom decorators

TypeScript is a superset that sits on top of JavaScript. It supplies features such as static typing, classes and interfaces that are lacking in the native language. This means that when creating large applications developers can get feedback on how best to work with external code and avoid unnecessary bugs.

Angular is built exclusively on top of TypeScript, so it is important to understand how to utilise it correctly. Combining the strengths of both provides a solid foundation for the application as it grows. There are not many better techniques to demonstrate this than with decorators.

function ClassLogger(hooks : string[]) : ClassDecorator {
  return function (target : any) {
    hooks.forEach(hook => {
      const original = target.prototype[hook];
      target.prototype[hook] = function(...args) {
        console.log(`${hook} - ${target.name}`);  
        if (original) {
          original.apply(this, ...args);

Decorators are special functions designed to supply behaviour to whatever it is applied to. Angular makes extensive use of them to provide hints to the compiler, like with @Component on classes or @Input on properties. 

The aim is to make these functions as reusable as possible and are often used to provide utility functions, such as logging. In the example above, @ClassLogger is supplied to a component to log to the console when certain lifecycle hooks are fired. This could be applied to any component to track its behaviour.

The ClassLogger example above returns a function, which enables us 
to customise the behaviour of the decorator as it is created. This is known as the decorator factory pattern, which is used by Angular 
to create its own decorators. 

  selector: 'decorated-component',
  template: '<div></div>'
class DecoratedComponent {}

To apply a decorator, it needs to be positioned just before what it is decorating. Because of the way they are designed, decorators can be stacked on top of each other, including Angular's own. TypeScript will chain these decorators together and combine their behaviours.

Decorators are not just limited to classes. They can be applied to properties, methods and parameters inside of them as well. All of these follow similar patterns, but are slightly different in their implementations.

function MethodLogger(target, key, descriptor) {
    const method = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`${key} was called with ${args}`);
        return method.apply(this, args);
class ExampleComponent {
  loggedMethod(a : any, b : any) {}

This is an example of a plain method decorator. These take three arguments – the object targeted, the name of the method, and the descriptor that provides details on its implementation. By hooking into the value of that descriptor we can replace the behaviour of the method based on 
the needs of the decorator.

Build platform-level animations

Animations are a great way to introduce a friendly side to an interface. But trying to control animations in JavaScript can be problematic. Adjusting dimensions like height is bad for performance, while toggling classes 
can quickly get confusing. The Web Animations API is a good approach, but working with it inside Angular can be tricky.

Angular provides a module that enables components to be animated by integrating with the properties already within the class. It uses a syntax similar to CSS-based animations, which gets passed in as component metadata.

  animations: [
    trigger('hidden', [
      state('true', style({
        transform: 'scale(0)'
      transition('true => false', animate('250ms ease-in')),
      transition('false => true', animate('250ms ease-out'))
  ] })

Each animation is defined by a 'trigger' – a grouping of states and transition effects. Each state is a string value that, when matched, applies the associated styles to the element. The transition values define different ways the element should move between those states. In this example, once the value bound to hidden evaluates to true, the element will shrink out of view.

Two other special states are also defined: void and *. The void state relates to a component that was not in the view at the time and can be used to animate it in or out. The wildcard * will match with any state and could be used to provide a dimming effect while any transition occurs.

template: '<div

Inside the template, the trigger is bound to a value within the component that represents the state. As that value changes, as does the state of the animation.

That bound value can be supplied either as a plain property or as the output of a method, but the result needs to evaluate into a string that can be matched against an animation state.

These animations also provide callbacks such as when they start or stop. This can be useful for removing components that are no longer visible. 

Serve content quicker with server rendering

HTML parsers struggle with JavaScript frameworks. Web crawlers are often not sophisticated enough to understand how Angular works, so they only see a single, blank element and not the whole application.

By rendering the application on the server, it sends down an initial view for the users to look at while Angular and the rest of the functionality downloads in the background. Once the application arrives, it silently picks up from where the server left off.

The tools needed to achieve this in Angular are now a native part of the platform as of version 4. With a bit of set up, any application can be server rendered with just a few tweaks.

  imports: [
      appId: 'web-designer-example'
  bootstrap: [AppComponent]

Both server and browser builds need their own modules, but share a lot of common logic. Both need a special version of BrowserModule, which allows Angular to replace the contents on-screen when it loads in. The server also needs ServerModule to generate the appropriate HTML. 

Servers also need their own entry points where they can bootstrap their unique behaviours as necessary. That behaviour depends on the app, but will also likely mirror much of the main browser entry point.

    "outDir": "dist-server",
    "main": "server.main.ts",
    "platform": "server",

If using the CLI, that also needs to be aware of how to build the project for the server by pointing to the new entry point. This can be triggered by using the "--app" flag when building 
for the server.

The application is now ready to be server rendered. Implementations will vary based on the server technology used, but the base principles remain the same. For example, Angular provide an Express engine for Node, which can be used to populate the index page based on the request sent. All the server needs to do is serve that file. Server rendering is a complex subject with many edge cases (look here for more information).

Next page: Polymer

Thank you for reading 5 articles this month* Join now for unlimited access

Enjoy your first month for just £1 / $1 / €1

*Read 5 free articles per month without a subscription

Join now for unlimited access

Try first month for just £1 / $1 / €1

A senior developer advocate for Microsoft, Burke is a big fan of sarcasm and JavaScript.