Getting enum keys in TypeScript

They can be your friend..

They can be your friend..

While working on a task, my colleague stumbled upon a quirky problem.

He tried to fetch all keys out of an enum but ended up with both the keys and values. We tried figuring out why this happens and once we saw the compiled javascript everything was clear.

Let’s have a look:

enum SomeEnum { 
    A,
    B,
    C,
    D
}

The enum above will be transpiled into:

var SomeEnum;
(function (SomeEnum) {
    SomeEnum[SomeEnum["A"] = 0] = "A";
    SomeEnum[SomeEnum["B"] = 1] = "B";
    SomeEnum[SomeEnum["C"] = 2] = "C";
    SomeEnum[SomeEnum["D"] = 3] = "D";
})(SomeEnum || (SomeEnum = {}));

The thing here that is important is to realize that with this output the final object will have A, B, C, and D as keys as well as 0, 1, 2, and 3.

Because of the SomeEnum[“A”] = 0 assignment we will create a property “A” with the value of 0 and then (as part of the larger SomeEnum[SomeEnum["A"] = 0] = "A"; assignment) create a property “0” with the value of "A” .

If you try to get the keys (with Object.keys()) you will get the mentioned A, B, C, D, 0, 1, 2, and 3.

To get only they keys or member names you can do something like this:

let enums = Object.keys(SomeEnum).filter(x => !(parseInt(x) >= 0));
console.log("Enums", enums); //Enums: A, B, C, D

Hope this will help you out in your TypeScript quest.

Until next time.

Happy Coding!

Error when creating a new Ionic project - ZlibError

Now that Ionic 4(!!!) is out I wanted to take it for a ride. I opened up VS Code and entered the following command into the terminal

> ionic start ionic4test tabs

After a second or two the process stopped with the following error

- Downloading and extracting tabs starter (100.00%)
events.js:193
      throw er; // Unhandled 'error' event
      ^

ZlibError: zlib: Cannot read property 'length' of null
    at Unzip.Zlib.(anonymous function) (C:\Users\Ivan Karacic\AppData\Roaming\npm\node_modules\ionic\node_modules\minizlib\index.js:126:21)
    at Unzip.write (C:\Users\Ivan Karacic\AppData\Roaming\npm\node_modules\ionic\node_modules\minizlib\index.js:247:21)
    at Unzip.flush (C:\Users\Ivan Karacic\AppData\Roaming\npm\node_modules\ionic\node_modules\minizlib\index.js:206:10)
    at Unzip.end (C:\Users\Ivan Karacic\AppData\Roaming\npm\node_modules\ionic\node_modules\minizlib\index.js:213:10)
    at Unpack.end (C:\Users\Ivan Karacic\AppData\Roaming\npm\node_modules\ionic\node_modules\tar\lib\parse.js:416:21)
    at IncomingMessage.onend (_stream_readable.js:598:10)
    at Object.onceWrapper (events.js:322:30)
    at emitNone (events.js:120:20)
    at IncomingMessage.emit (events.js:218:7)
    at endReadableNT (_stream_readable.js:1054:12)

I first tried updating the minizlib Node module but that didn’t help.

After some random web searches I found out what the issue is.

A simple upgrade to a 10+ Node.js version did the trick.

It took me around 30 minutes to figure this one out so I hope that this might help you get to the answer a little quicker.

Until next time,
happy coding.

Passing data back from a child page (Ionic tips and tricks)

When working with Ionic (3), I came across the need to pass between pages.

Full steam ahead!

Here is what the Ionic docs have to say about it:

push(page, params, opts) 

//Push a new component onto the current navigation stack.
//Pass any aditional information along as an object.
//This additional information is accessible through NavParams

Let’s try it out!

export class StartPage {
    constructor(public navCtrl: NavController) {
    }

    pushPage(): void {
        this.navCtrl.push(OtherPage, {
          id: "123",
          name: "Carl"
        });
    }
}

class OtherPage {
    constructor(private navParams: NavParams) {
        let id = navParams.get('id');
        let name = navParams.get('name');
    }
}

As you can see above, it’s quite straight forward. You push a new component on the navigation stack and pass an object as your navigation parameter and then get those parameters in the child page.

Going back the other way

There might be situations where you want to pass data from your child page to the parent. The user might select something and you want this information in the parent to fill out a form for example.

That’s where things get a little tricky.

Here the documentation say:

pop(opts) 
//Call to navigate back from a current component.
//Similar to push(), you can also pass navigation options.

However, those navigation options don’t offer you all that much

Property   Value    Description
animate    boolean  Whether or not the transition should animate.
animation  string   What kind of animation should be used.
direction  string   The conceptual direction the user is navigating. For example, is the user navigating forward, or back?
duration   number   The length in milliseconds the animation should take.
easing     string   The easing for the animation.

We will have to come up with some other way of passing data back to the parent.

The bad

Two approaches I don’t like at all are: having a global object and having some kind of pub/sub mechanism.

When you maintain a global object which will keep informations for all pages to be read from things can get quite complicate. Once your application gets quite large this starts to look like a mess and having a single file grow to a few hundreds or even thousands of lines (I have worked once on a project that had a globalSettings object was a nightmare) is not really something to look up to.

Another approach is to have some kind of pub/sub functionality where one page would publish/broadcast something and then all other views would just pick it up update their state. I don’t really like this approach since you, again, rely on a single object to take care of everything.

The good

One solution I like quite a lot is the use of Promises. You pass the resolve callback as a parameter to the child view and once the view pops you execute the resolve callback and pass data to the parent.

Your code could look something like this:

export class StartPage {
    constructor(public navCtrl: NavController) {
    }

    pushPage(){
        new Promise((resolve, reject) => {
            this.navCtrl.push(OtherPage, {
                id: "123",
                name: "Carl",
                resolve: resolve
            });
        }).then((data) => {
          console.log(data); // 'some data'
        });
    }
}

class OtherPage {
    private resolve: Function;
    constructor(private navParams: NavParams) {
        let id = navParams.get('id');
        let name = navParams.get('name');
        resolve = navParams.get('resolve'); 
    }
    
    returnData(): void {
        this.navCtrl.pop().then(() => this.resolve('some data'))
    }   
}

This looks nice and there isn’t a lot of overhad involved but, unfortunately, couples your parent its child.

My favorite approach

One thing that bugs me about the above approach is the new Promise we have to create and then wire up to get it working. That’s why the next approach is by far my favorite:

export class StartPage {
    constructor(public navCtrl: NavController) {
    }

    pushPage(): void {
        this.navCtrl.push(OtherPage, {
          id: "123",
          name: "Carl",
          callback: this.handleChildPage
        });
    }
    
    handleChildPage(data): void {
        console.log(data); // 'some data'
    }
}

class OtherPage {
    private callback: Function;
    constructor(private navParams: NavParams) {
        let id = navParams.get('id');
        let name = navParams.get('name');
        callback = navParams.get('callback'); 
    }
    
    returnData(): void {
        this.callback('some data');
        this.navCtrl.pop();
    }   
}

It doesn’t look much different than the solution with promises but I like this one a little more because we have avoided two .then(…) statements which make the code look a little more cluttered than I like. But, just as the example above, this one also couples your two views and that’s something we will have to live with (for now).

The ideal solution

I am looking forward where we will be able to pass navParams into the pop function and then just pick them up in the parent and use them.

Let me know about your approaches in the comments below.

Until next time,

Happy coding

Showing image only when fully loaded (Angular 1)

While working for a client, a requirement came up requesting for images only to be visible when fully downloaded.

The reason for this is that currently the images would load line by line which doesn't look quite nice. 

I started playing around a little but nothing worked as I would have liked, so I had to go deeper.

inceptius-meme-generator-we-have-to-go-deeper-014848.jpg

Directives to the rescue!

I ended up creating a new directive and hooked it up in my markup.

//.js
angular.module('app', [])
.directive("dynamicImage", function () {
  return {
    restrict: 'E', //restrict only to elements
      scope: {
        imageSource: '=src' //hook up to the outside scope
      },
      template: '<img ng-show="showImage" src="{{ imageSource }}">',
      //get the element and bind to the load event
      link: function ($scope, iElm, iAttrs, controller) {
        $scope.showImage = false;
        iElm.find('img').bind('load', function (e) {
        //when loaded show the image            
        $scope.$apply('showImage = true');
       });
    }
  }
});

//.html
//keep in mind that you don't need interpolation here
//so pass only the property without the '{{}}'
<dynamic-image src="propertyHoldingTheImageSource"></dynamic-image>

If you try it out now you won't see the image until fully loaded. 

To enhance the user experience a little more you can add a background image to the parent <div> which can serve as a placeholder but this is a topic for another time :)

Until then, happy coding!

*ngIf in Angular with a twist

Showing and hiding content in is usually done by using the *ngIf directive:

<p *ngIf="isButtonClicked">Button is clicked!</p>

If you want to display something if the condition isn't satisfied you would probably do something like this:

<p *ngIf="isButtonClicked">Button clicked!</p>
<p *ngIf="!isButtonClicked">Button not clicked</p>

This looks a little clumsy and, also, forces you to repeat yourself. You are biding to the same property and if the name changes you will have to change it in multiple places - not a good thing to do.

A more elegant way of achieving the same thing looks can be seen below:

<p *ngIf="isButtonClicked; else buttonNotClicked">Button clicked!</p>

<ng-template #buttonNotClicked>
    <p>Button not clicked :(</p>
</ng-template>

The final result can be seen here:

ngif.gif

One added benefit is that you can handle these special cases anywhere in your file and Angular will do the rest

Simulating geolocation changes in the VisualStudio Emulator for Android

For almost a year now I have been developing a few mobile applications using Apache Cordova. It's a pretty nice technology (as far as writing HTML and CSS for mobile devices can be) and I have written a few blog posts about it already.

Developing Cordova apps in Visual Studio 2015 is really cool. You get all the power Visual Studio can offer you (despite sometimes hanging or freezing) and on top of that you get excellent emulators created by Microsoft which are miles ahead of the ones Google offers (Genymotion is in second place but I have some problems setting it up on my machine so I can't really talk about it a lot).

While working on my latest project I had to use Geolocation to simulate users movements on streets.

"Easy-peasy", I thought and dug right into it. I downloaded the geolocation plugin (everything is done with plugins in Cordova) and wrote a little piece of code.

    function onSuccess(position) {
      var element = document.getElementById('geolocation');
      element.innerHTML = 'Latitude: ' + position.coords.latitude + '<br />' +
                          'Longitude: ' + position.coords.longitude + '<br />' +
                          'Speed: ' + position.coords.speed + '<br />' +
                          'Heading: ' + position.coords.heading + '<br />' +
                          '<hr />';
    }

    function onError(error) {
      alert('code: ' + error.code + '\n' +
            'message: ' + error.message + '\n');
    }

    var watchID = navigator.geolocation.watchPosition(onSuccess, onError, {
      timeout: 30000
    });

What this essentially does is hook up to the geolocation plugin and wait for 30 second to get something back from it. If it get something I grab an element with the ID geolocation and display some information, otherwise I show an error message letting the user know something's wrong.

Another awesome feature of the Visual Studio emulator for Android is the Location tab which lets you pick a route and then select the speed at which you want to move along the route.

I set up my route, hit start and ... nothing happened. What the %$&#??? What's going on? I hook up a phone to my PC and just start it up and ... it works like expected. What the %$&#???

You can imagine how puzzled I was but as I had to get my work done I started working exclusively on the device until I couldn't get away anymore without "moving" on the road.

I asked for help on StackOverflow but the solutions there didn't really help me. Another week passed and I finally found the solution I was looking for.

I looked once again into the docs for the Cordova plugin and I found that the watchPosition function accepts a few more options apart from timeoute.

One of them was enableHighAccurac. The docs say this about this option.

enableHighAccuracy: Provides a hint that the application needs the best possible results. By default, the device attempts to retrieve a Position using network-based methods. Setting this property to true tells the framework to use more accurate methods, such as satellite positioning. (Boolean)

Application needs the best possible results? Sign me up for that!

I added this option to the watchPosition function so that it now looks like this:

    var watchID = navigator.geolocation.watchPosition(onSuccess, onError, {
      timeout: 30000,
      enableHighAccuracy: true 
    });

And lo and behold the damn thing spits out my new position, speed, heading and a lot of other information my way.

I guess that by setting enableHighAccuracy to true forces the phone to use GPS to get it's location and that was what the Location tool was providing from the beginning.

Usually your phone tries a lot of other methods to get it's position (WiFi signals, your carriers antennas, etc.) because they all drain your batter less then listening to the GPS satelites but since this is running on an emulator we have to relay only on the GPS signal which is generated by the phone so we have to tell the phone to ignore the battery and go straight to GPS.

This has been really a frustrating two weeks where I was trying a ton of different things to get this working but I found the light at the end of the tunel and really hope that at least someone will save a few days of research by reading this.

Until next time, happy coding :)