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 :)