Ionic Framework Inside a Visual Studio Cordova Application using Typescript Part 3

Part 1 – Tools and a first glance
Part 2 – Ionic meets Visual Studio
Part 3 – Enter Typescript

In part 2 we made the ionic application run inside Visual Studio. Now how about

Adding Typescript

 

We want more meaningful detail pages when navigating to the … well, detail page of a playlist. What happens when we click on a playlist inside the playlists list?

  1. App navigates to the new href, in this case /playlists/<playlistId>
  2. UI-Router compares that against its route repository and selects the matching route (called app.single)
  3. It then activates the corresponding controller (PlaylistCtrl) and makes the id of the selected playlist available as $stateparams.playlistId

Have a look at app.js to see the router definitions.

Hmm – so we’re only getting the id of the playlist? But we need to have the full object! What’s the best practice to pass data around in AngularJS? Services! Right.

Currently, we’re creating a bit of dummy data directly inside PlaylistsController (plural, master view).


.controller('PlaylistsCtrl', function($scope) {
    $scope.playlists = [
        { title: 'Reggae', id: 1 },
        { title: 'Chill', id: 2 },
        { title: 'Dubstep', id: 3 },
        { title: 'Indie', id: 4 },
        { title: 'Rap', id: 5 },
        { title: 'Cowbell', id: 6 }
    ];
})

We need to refactor that into a service if we want to access these objects inside PlaylistCtrl (singular, detail view). We need to create a new Typescript file called services.ts inside /scripts/app.

Optional, but good stuff: To get Intellisense support (one of the benefits of working with Typescript), right click on angular.js inside /scripts folder and hit “Search for Typescript Typings”. In the list that NuGet Manager shows, select angularjs.TypeScript.DefinitelyTyped and click Install. This will include a set of *.d.ts files inside /scripts/typings

Now when you start typing “angular.mod” inside a Typscript file (such as services.ts) you will get Intellisense completion.

Typescript-Intellisense

Good stuff, as I said. Remember to include services.js inside index.html.

And now for some structure

Apparently, we’re dealing with playlists here. Let’s create a model for that


class Playlist {
    constructor(public id: number, public title: string){}
}

In case you’re wondering what this is doing exactly, have a look at the Typescript handbook section for classes and optionally run this code through the Typescript playground to see the resulting Javascript.
Next is a small service that holds our dummy playlist data and includes two methods (sorry, functions) to return all playlists or find a single playlist by id.


class PlaylistSvc {
    private playlists: Playlist[];
    constructor() {
        this.playlists = [
            new Playlist(1, 'Reggae'),
            new Playlist(2, 'Chill'),
            new Playlist(3, 'Dubstep'),
            new Playlist(4, 'Indie'),
            new Playlist(5, 'Rap'),
            new Playlist(6, 'Cowbell')
        ];
    }
    all() {
        return this.playlists;
    }
    find(id) {
        return this.playlists[id - 1];
    }
}

Not on my watch

What’s the benefit of using

new Playlist(1, 'Reggae')

over

{ title: 'Reggae', id: 1 }

inside the list? Well, since this.playlists has to be an array of Playlist objects, the Typescript compiler can check for a number of things:

Object type inside the array

Typescript-Wrong-Type

Number and type of constructor parameters for each object

Typescript-No-Match-Call-Target

Make sure Playlist is called as constructor, not as function

Typescript-Function-Insteadof-Constructor

All of these things could happen accidentally with plain Javascript, and I think it’s a good thing Typescript can help us here.

I have to admit that my implementation of find(id) probably leaves some room for improvement. I am sort of cheating on the indexing id here, but for the sake of clarity … Anyway, we have written this service and we need to tell Angular about it so we can get it via dependency injection.


angular.module('starter.services', [])
.service('playlistSvc', () => new starter.PlaylistSvc())

We can now use this service to refactor our already existing PlaylistsController. To do that, I copied the contents of controllers.js, deleted the file, recreated it as Typescript file (controllers.ts) and pasted the content back in. Then I added a modification to PlaylistsCtrl to define the type of playlistSvc I want injected:

.controller('PlaylistsCtrl', function ($scope, playlistSvc: starter.PlaylistSvc) {
    $scope.playlists = playlistSvc.all();
})

A similar thing happens with PlaylistController, where we additionally need $stateParams

.controller('PlaylistCtrl', function($scope, $stateParams, playlistSvc: starter.PlaylistSvc) {
    $scope.playlist = playlistSvc.find($stateParams.playlistId);
})

And to finalize: In Playlist.html template we will display the title property of our playlist object

<ion-view title="Playlist">
  <ion-content class="has-header">
    <h1>Playlist <i>{{playlist.title}}</i></h1>
  </ion-content>
</ion-view>

Now, when we navigate into the detail view for a playlist, we are presented with its name. As we continue to add members to the Playlist class, we can get access to all these members through the same mechanism.

To get the complete code for this step, refer to commit #3 on the github repository: “Refactoring playlists into service and adding type definitions”

Hope that helps
.jonas

Advertisements

8 thoughts on “Ionic Framework Inside a Visual Studio Cordova Application using Typescript Part 3

  1. Pingback: Ionic Framework Inside a Visual Studio Cordova Application using Typescript Part 1 | Developing with your head in the clouds

  2. Pingback: Ionic Framework Inside a Visual Studio Cordova Application using Typescript Part 2 | Developing with your head in the clouds

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s