Tuesday, May 17, 2016

Angular 2: Building a Google Map Component

Live Demo
Github Repo
 
In order to force myself dig deeper into Angular 2, I tried to build a component wrapper for Google Map JavaScript API. The end results is a demo component here: google_map.component.ts.

 

Sample Client Code

A sample client code using the component looks like this:

Features

The features including:
  • Drawing through Angular binding
  • Map events published as Angular events 

 

Tips

Here are some code snippets the highlights some of the lessons I have learned.

First, make sure Google Maps library is loaded from here:
    https://maps.googleapis.com/maps/api/js?key={YOUR_API_KEY}&libraries=visualization,place&callback=initMap
Add this line in typings.ts, so that we can have type definitions for Google Maps JavaScript API
    "googlemaps": "github:DefinitelyTyped/DefinitelyTyped/googlemaps/google.maps.d.ts"
Event handlers turns out to be tricky. My naive first implementation was something like this
this.map.addListener('click', function(e: google.maps.MouseEvent) {      
  this.mapClick.emit(e.latLng));
);
Turns out there are two big problems in this implementation:
  1. this inside the event handler does not have member mapClick. Because it is no longer the component class
  2. Once scope of this is fixed, I found data changes in the event handler does not trigger Angular change detection
Solutions for those problems? See the comments in my final implementation:

On the CSS side, it is very important to set height of Google Map component. If not done, it is automatically collapsed to nothing, and you won't see a map.

Demo 

Finally, a functional demo is here: google_map.html. Below is screenshot of the demo in action:

Monday, May 02, 2016

Angular 2: Injecting Parent and Child Component

Live Demo
Github Repo

To inject children component into a parent component, use ViewChildren (notice there is also ConentChildren which will inject children from content projection).

To inject a parent into child component, you simply need to inject parent in the constructor of child component. However, there is a bit of problem due to circular reference. The parent component has to reference child component as directive. If the child also depends on parent, we will get an error like this: EXCEPTION; Cannot resolve all parameters for '[ParentComponent]'.... So, the following slightly twisted injection is needed:
        contructor(@Inject(forwardRef(() => ParentComponent)) private _parent: ParentComponent)

A small working example showing both child and parent component injection can be downloaded here: https://github.com/huguogang/ng2tsdemo/blob/master/view_child.html.

Angular 2 Content, Content Projection, Transclusion

Live Demo
Github Repo

I guess under all these fancy words (especially Transclusion), there is a simple concept. And it seems to me, it is way easier to learn it by starting with looking at a working sample, make some changes and observe the changes.

I have created a bare minimum working example here: https://github.com/huguogang/ng2tsdemo/blob/master/content.html

Here are the key code fragments. Related elements are color coded.
Template for the directive:
<div>
  <h1><ng-content select="my-title"></ng-content></h1>
  <div>
    <ng-content select="content"></ng-content>
  </div>
  <br/>
  <em style="font-size:smaller"><ng-content select="footer"></ng-content></em>
</div>
Markup in the client component:
<multi-slot-content>
  <my-title>Angular 2 Content Demo</my-title>
  <content>The selectors defined in MultiSlotContent directive will find 
    the content element in this template, insert it into it's own template 
    section.</content>
  <footer>Footer: this feature was called transclusion in Angular 1.</footer>
</multi-slot-content>
Resulting HTML Markup:
<multi-slot-content>
  <div>
    <h1><my-title>Angular 2 Content Demo</my-title></h1>
    <div>
      <content>The selectors defined in MultiSlotContent directive will find 
        the content element in this template, insert it into it's own template 
        section.</content>
    </div>
    <br>
    <em style="font-size:smaller"><footer>Footer: this feature was called transclusion in Angular 1.</footer></em>
  </div>
</multi-slot-content>
Notice the key is to define proper Angular 2 selectors in the directive. Then in the client component, it just need to fill the content in the right selector target. The end result is the directive's ng-content elements got replaced by the fragments from client.

Sunday, May 01, 2016

Angular 2 HTTP JSON Service

Live Demo
Github Repo

Here is a bare minimum demo of how to use Angular 2 HTTP JSON Service:https://github.com/huguogang/ng2tsdemo/blob/master/json_service.html

The demo uses observable instead of promise. A few potential catches:
  • Import Rx.js in html file:
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    
  • Import rxjs/Rx in service:
    import 'rxjs/Rx'
  • Register HTTP_PROVIDERS

Angular 2 Renderer

Live Demo
Github Repo

Renderer in Angular 2 is a fascinating topic. It does not have an official documentation yet. As of this writing 5/1/2016, there is only a list of public method signatures here: https://angular.io/docs/ts/latest/api/core/Renderer-class.html.

It turns out it is very easy to get a hold of the renderer in your components. All it takes is to declare a Renderer in contructor, Angular 2 will inject it for you.

Code sample to inject renderer:
constructor(private _renderer: Renderer) { }

A working demo on github: https://github.com/huguogang/ng2tsdemo/blob/master/renderer.html