Angular2 Dart - My experience so far

In the last month, I've experimented with many frameworks and multiple languages to find a fitting tool for a new project.

I've played around with KotlinJS, a transpiler that compiles Kotlin to JavaScript, KotlinJS however currently compiles one-to-one to JavaScript, doesn't currently remove dead code, doesn't do any minification (which I easily resolved by adding a Google Clojure Compiler maven plugin to automatically minify everything) and it doesn't do much polyfilling, it's one-to-one. The KotlinJS experience was great, but it's not ready for prime-time yet.

ScalaJS, another transpiler which compiles to JS, my Scala skills are fairly limited and it didn't seem like a great idea learning another JVM language just for the sake of compiling to JS considering the steep learning curve with Scala. (I received a message asking why I went through all the trouble of learning KotlinJS, but not ScalaJS - answer: I already knew Kotlin and picked it up in a day, Scala feels very foreign whereas I picked up Kotlin in a day)

JavaScript with React and Angular2 ... with React, there were so many things I had to manually do to get up and running and the same goes for Angular2, although slightly less on the Angular side since the router and many other useful things just came included, but I still had to manually run my JS via grunt and hope that the minification process doesn't destroy my JS (especially on the Angular side where it's doing dependency injection using a very strange syntax), still had to manually compile my less / sass files or setup build scripts and I had little assurance that my code was type-safe in the critical parts. (I recently discovered the licensing terms for React, if at any point you are competing with facebook, your license is revoked, if at any point two companies are suing each other and both are using React, their license is also revoked - giving facebook the power over when you can and can't use the framework is definitely a no-go for me)

I've decided to give TypeScript a go with Angular2 TS, the experience was somewhat better than JS, but yet again, a lot of manual stuff that had to be done to get up and running, a package.json file, tsconfig.json, typings.json, ... ugh, so much config just to get up and running with a simple hello word and docs that tell you

Scary error messages in red may appear during install. The install typically recovers from these errors and finishes successfully.

Not re-assuring at all, why are they called error messages if you are supposed to ignore them, horrible!!! :-| (somebody on Reddit linking to the article mentioned that the Angular2 CLI fixes the boilerplate problem, I haven't tried that, maybe that makes the Typescript version more bearable)

I've re-visited GWT for a bit and it was as clunky and slow as always and it seems like it's hardly maintained and used by a very small number of people. (I've revisited GWT again last month testing out Angular2-GWT and I was getting much better speeds this time, the syntax is still clunky as hell, the improvements Java8 brought along is not enough to make me switch back to it - give me KotlinGWT, then we're in business)

I've taken TeaVM for a ride, the TeaVM experience was a lot better than KotlinJS and GWT since it had dead code removal, a proper transpiler, but it seemed like a pet-project of someone which made me a bit nervous including it into something that needs to run in the enterprise. (I had a conversation with the creator of TeaVM, he's now on the KotlinJS team)

I finally went full circle back to Dart, I haven't used Angular1 Dart, so had no idea how to get started with Angular2 Dart either. Skimmed through the docs and 5 minutes later I was up and running.

A simple pubspec.yaml file containing the following (note, a single config file):

name: projectname
version: 0.0.1
description: Project Description Goes Here
environment:
  sdk: '>=1.13.0 <2.0.0'
dependencies:
  angular2: 2.0.0-beta.17
  bootjack: any
  bootjack_datepicker: any
  browser: ^0.10.0
  event_bus: any
  http: any
  less_dart: any
  dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
    entry_points: web/main.dart
- dart_to_js_script_rewriter
- less_dart:
    entry_points: [web/styles/main.less]
    build_mode: dart

And voila, I had a less compiler working out of the box, fantastic minification with full Angular2 support and stuff just works.

In my main.dart I simply have the following code to bootstrap everything:

void main() {
    // bootstrap angular2
    bootstrap(AppComponent, [
        ROUTER_PROVIDERS,
        provide(APP_BASE_HREF, useValue: '/'),
        provide(LocationStrategy, useClass: HashLocationStrategy)
    ]);
}

Then I have an AppComponent which takes care of the routing:

@Component(
    selector: 'myapp',
    template: '<router-outlet></router-outlet>',
    directives: const [ROUTER_DIRECTIVES]
)
@RouteConfig(const [
    const Route(path: '/dashboard', component: DashboardPage, name: 'DashboardPage', useAsDefault: true),
    const Route(path: '/home', component: HomePage, name: 'HomePage'),    
])
class AppComponent {

    String name = "Sample App";

}

Since everything is a component, even pages are components, here's my dashboard component

@Component(
    selector: 'dashboard-page',
    templateUrl: '../templates/dashboard-page.html',
    directives: const [Navigation]
)
class DashboardPage {}

Using components are as easy as annotating with @Component and templates can be inlined if they are small enough (like react does):

@Component(
    selector: 'navigation',
    template: '''
        <div class="btn-group br">
            <button type="button" class="btn btn-primary goto-first">
                <span class="glyphicon glyphicon-fast-backward"></span>
            </button>
            <button type="button" class="btn btn-primary goto-prev">
                <span class="glyphicon glyphicon-step-backward"></span>
            </button>
            <button type="button" class="btn btn-primary clear-search">
                <span class="glyphicon glyphicon-refresh"></span>
            </button>
            <button type="button" class="btn btn-primary goto-next">
                <span class="glyphicon glyphicon-step-forward"></span>
            </button>
            <button type="button" class="btn btn-primary goto-last">
                <span class="glyphicon glyphicon-fast-forward"></span>
            </button>
        </div>
    ''')
class Navigation {


}

Want to use components inside other components? Also simple! Let's look at my Item component:

@Component(
    selector: 'item',
    template: '')
class Item implements AfterContentInit {

    @Input() String type = "missing-type";
    @Input() String text = "missing-text";
    @Input() String classes = "";
    @Input() String position = "center";

    @override
    ngAfterContentInit() {

    }

}

Now I can use that Item component inside another component:

<button-search>
                <item type="identifier" text="Identifier"></item>
                <item type="title" text="Title"></item>
                <item type="province" text="Province"></item>
                <item type="city" text="City"></item>
                <item type="suburb" text="Suburb"></item>
                <item type="town" text="Town"></item>
                <item type="address" text="Address"></item>
                <item type="postal" text="Postal"></item>
                <item type="divider"></item>
                <item type="clear" text="Clear Search"></item>
            </button-search>

... and inside my ButtonSearch component I can now get those items to render the SearchButton component.

@Component(
    selector: 'button-search'
    directives: const [NgFor, NgIf, NgClass],
    template: \'''
        <ng-content></ng-content>
        <div class="btn-group search-bar br">
            <div class="input-group">
                <span class="input-group-btn">
                    <a href="#" class="btn btn-primary qr-code" disabled="disabled">
                        <span class="glyphicon glyphicon-qrcode"></span>
                    </a>
                </span>
                <input class="form-control search top focus" type="search" name="search" placeholder="Search">
                <div class="input-group-btn">
                    <button type="button" class="btn btn-primary search top" tabindex="-1">
                        <span class="glyphicon glyphicon-search"></span>
                        Search
                    </button>
                    <button type="button" class="btn btn-primary dropdown-toggle top" data-toggle="dropdown" tabindex="-1">
                        <span class="caret"></span>
                        <span class="sr-only">Toggle Dropdown</span>
                    </button>
                    <ul class="dropdown-menu dropdown-menu-right">
                        <li *ngFor="let item of items" ngClass="{{item.type}}">
                            <a ngClass="{{item.type}}" *ngIf="item.type != 'divider'" href="#">{{item.text}}</a>
                        </li>
                    </ul>
                </div>
            </div>
        </div>\'''
)
class ButtonSearch implements AfterContentInit {

    @ContentChildren(Item) QueryList<Item> items;

    @override
    ngAfterContentInit() {

    }

}

title here

Angular2 Dart - batteries included, Dart polyfilling features that are not completely supported in all modern browsers (so proper cross-browser compatibility out of the box), elegant code and it just works. As far as I'm aware, things are stabilizing now, the router component might get some further rework according to sources close to the team, but otherwise now is a good time to get into Angular2 Dart. The guys on Dart's slack channel also helped me tremendously and a day later, I'm building Angular2 Dart components like a rock star.

Write your comment…

29 comments

Very good read and welcome to the Dart world! :)

One thing I cannot stress enough about Dart is it's super helpful guys on it's Slack channels.

I've been looking at Angular 2 Dart as well for the past couple months and the experience was very similar to yours - feeling like a Rock Star. An interesting thing I noticed was tiny size of the built JS files of my project. Generally speaking, dart2js can produce large files, especiall if mirroring is used but this does seem to be the case, the compiled application was smaller than the dependencies of the TS version. I was quickly won over!

Show all replies

I hardly have the need for reflection in the frontend, if I do need it, it seems I'll need to go do a refresher in the docs :-)

Reply to this…

Share your programming knowledge and learn from the best developers on Hashnode

Get started

I've re-visited GWT for a bit and it was as clunky and slow as always and it seems like it's hardly maintained and used by a very small number of people.

That's not really correct. GWT 2.8 supports Java8 syntax that means you can leverage lambdas which make async code even more concise than the ES6 version. Furthermore SuperDevMode is really very fast. It's also not true that it is only used by few people and not maintained (check the github logs: https://github.com/gwtproject/gwt/commits/master, most commits are from Google Members but also contribution from the community). Also GWT is used for Google Inbox, Google Spreadsheet and used to write business code once in java and use it in iOS, Android and the Web. GWT 2.8 supports a brand new JsInterop (zero cost abstraction) that currently even easier to use than the Dart's JsInterop. Google is also working on GWT 3.0 which will be a pure Java to ES6 transpiler and reduce the compiler complexity a lot. There is also work done on leveraging Typescripts type definitions for various JS libraries to automatically create JsInterop Java interfaces to be used from GWT.

Show all replies

Also based on Google Trends, GWT has seen a decline in interest since 2011, in 2013 AngularJS just went inferno. https://www.google.com/trends/explore#q=%2Fm%2F0d6jq1%2C%20GWT%2C%20%2Fm%2F012l1vxv%2C%20%2Fm%2F0j45p7w&cmpt=q&tz=Etc%2FGMT-2

Reply to this…

That has been our experience with Angular2.dart as well. Welcome! We are excited for it to get even better!

Looking forward :-D

Reply to this…

If you are looking for a corporate ready, serious framework, I would recommend Ember.js also. With ES6, and with ember-cli, it is a real a game changer and solid as rock. And it is already a proven solution for serious frontend apps.

Show all replies

querySelector is a good example, it's only partially supported in some browsers (partial support in IE8 and buggy on IOS) - if I use it in JavaScript, chances are that it might work in some browsers and might break in another browser - I now need to go check which JS APIs I can use and can't use based on the browsers I want to support (painful)

Use querySelector in Dart and it'll work across all browsers that Dart says is supported, if not you file a bug and Google fixes it.

Reply to this…

Hi, great article!

How would you recommend to approach internationalisation in an angular 2 dart application? I'm building a web application that needs to support multiple languages.

Show all replies

Hello Vlad, another approach would be not to localize your website on code level but rather translate it with a translation proxy solution. Easyling is a very well known one - guess what language was chosen for it's front-end ;)

Very little to no extra coding is required to get a translated website up and running with it. Sign up for a demo, they'd be happy to show you around!

Reply to this…

Load more responses