Tech Review: NativeScript

Mobile development is a world that, for me, is different than what I'm used to work with. I come from a .NET background and moved recently to a Full Stack Javascript developer, but I wanted to dive a little bit in creating mobile applications. After reading a lot, I saw that there is a bunch of technologies that abstract the native development into a different stack. Maybe, if you have reached this post, you have seen options like:

  1. Apache Cordova
  2. PhoneGap
  3. Ionic
  4. React Native
  5. Xamarin

However, this post, as the title suggest, is about NativeScript. A smaller contender that is trying to grow and compete on equal terms with the others. 

As we can see, comparing searches using Google Trends between NativeScript, Apache Cordova and PhoneGap demonstrates that there is a steady growth for our contender. But, if we do the same comparison against Xamarin or React Native, we will see that there is a big gap that need to be closed.

NativeScript is an open-source framework that builds native applications using other frameworks such as Vue.js or Angular and languages like Typescript or Javascript. It became publicly available in March 2015, so it's a relatively young technology (you might differ, in this world, two years is enough for something to be called old, haha). Since then, there has been 41 releases, with the current version being 4.1.1.

As I stated before, NativeScript is a framework that uses web technologies to create native applications, so this is a big advantage for web developers; having the ability to use the skills possessed to create mobile applications, is a really good selling point.

On Github, it possess more than 14.000 stars, 114 contributors and a really active community, you can follow the repository and see the activity in the issues feed. According to npm, it's licensed under Apache2.0, and it has more than 35.000 downloads per week. 

Even with those numbers, you might still question yourself if it's worthy to work with, well, there are companies that decided to trust on it; big companies like Bosch, Samsung, Qualcomm and others. 

How does it work?

Ok, enough with the introduction, let's move to more interesting topics. To explain how it works, here is a really good extensive post explaining that, but I'm going to explain it briefly now.

In short words, NativeScript uses Javascript virtual machines that are used to execute commands (V8 for Android and JavascriptCore for iOS). These machines execute the code compiled in JIT format that is then transformed to the native counterparts for each operative system. Also, if you are familiar with Reflection, NativeScript uses it to inject the available APIs to match with the Javascript versions of them. 

Using Nativescript

In this post, I'm not going to cover how to install NativeScript, for that, follow the quick setup installation guide from their official site. Also, one of the reasons I used NativeScript is the fact that it integrates with Angular easily, hence, I will not only focus on NativeScript, but also in how to use it with Angular. So, assuming you have a working environment and you are interested in using Angular, let's continue.

The main aspects I will cover for now are: typescript code to bind events and layouts examples, in a later post, I will do a more complete tutorial.

Layout examples

Even though that we are using web technologies like Javascript, the layouts change drastically. The HTML tags we know are no longer usable, instead, there are defined tags that we need to use, they are:

  1. AbsoluteLayout: it uses specific coordinates to allocate items inside of it. 
  2. DockLayout: it allocates items to the edges of the layout (top, bottom, left or right).
  3. GridLayout: it is useful to accommodate items in a table structure where you define the number of rows and columns.
  4. StackLayout: as the name suggests, this layout stacks its children based on the orientation defined.
  5. WrapLayout: this layout works similar to the StackLayout, however, when the items don't have any room left, it continues stacking them in a new row.
  6. FlexboxLayout: this layout mimics the CSS box layout.

Here is an example using some of these layouts:

<StackLayout class="menu-bg" orientation="vertical">
  <StackLayout orientation="horizontal" horizontalAlignment="center" height="100%">
    <DockLayout class="home-menu-container" stretchLastChild="true" verticalAlignment="middle">
      <Label dock="top" class="h1" [text]="title"></Label>
      <StackLayout dock="bottom" class="menu-options" orientation="vertical" verticalAlignment="middle">
        <Button text="Start New Game" class="button new-game" (tap)="onNewGameTap()"></Button>
        <Button text="Options" class="button options" (tap)="onOptionsTap()"></Button>
      </StackLayout>
    </DockLayout>
  </StackLayout>
</StackLayout>

We can still use classes as in HTML to assign styles using CSS or SCSS files. Other tags like Labels and Buttons also changed a little bit from their counterparts in HTML, labels for example use a text attribute to assign the value and buttons' click events are replaced with tap events.

Event and property binding

Like using Angular in a web page, we create components that will be rendered in the application. These components will handle some UI logic and call other providers or services that will handle the business logic. From these components, we will assign events or properties that will be bound by the two-way binding feature from Angular by using the proper wrappers. In the example we had before, we can see the following bindings:

  1. The label tag has a text property wrapped in square brackets that maps to the title property on the component.
  2. The button tag has a tap event wrapped in parenthesis that calls the onNewGame event on the component.

Here is the matching code example:

import { Component } from '@angular/core';
import { RouterExtensions } from 'nativescript-angular/router';
import { NEWMAZE, CONTINUEMAZE } from '~/shared/constants';

@Component({
    selector: 'menu',
    templateUrl: './menu/menu.component.html',
    styleUrls: ['./menu/menu.component.css']
})
export class MenuComponent {    
    title: string = "New Game"
    constructor(private router: RouterExtensions) { }
  
    onNewGameTap(){
        this.router.navigate([`maze/${NEWMAZE}`], { clearHistory: true });
    }

    onOptionsTap(){
        this.router.navigate(["options"], { clearHistory: true });
    }
}

Summary

NativeScript is a great framework that is growing in the community, hopefully, it will match others like Xamarin and React Native, but so far, the experience to develop on it has helped me to create mobile applications fast and easily. Even though that I've found some things that weren't easy to fix, there are always workarounds available. Hopefully, I will create a new post that will go deeper in details and maybe a tutorial, stay tuned.

If you have any comment, don't hesitate in contacting me or leaving a comment below. And remember to follow me on twitter to get updated on every new post.

Tech Review: Angular Stack (2/many)

The second entry of this series is going to talk about two things that are common problems in Javascript. If you have ever experience problems with Dates, then one of the libraries I'm reviewing here will facilitate your development experience a lot; the second library is about putting a loading indicator when there is an async request being executed. So let's dive in:

Dates

Let's start with the date management library. According with npmjs, at the time of writing this post, there has been more than 953 559 downloads in average per week, it's MIT licensed and currently on version 1.29.0. Also, according to github, this repository has over 11.000 stars, 98 contributors, and a pretty active community (I hope that with all of those stats, it gives enough background about how big it is). Bottom line, I present to you, if you didn't know about it, date-fns.

According to their home page, date-fns is like lodash but for dates. With over 140 functions to process dates, it doesn't fall short and pretty sure it will cover all the use cases that you can think of. 

So, why and how do I use it? I'm answering both questions of my review from the start, because they are tightly related. Some of the main functions that I look for when handling dates are: formatting a date to specific customer requirements and calculating dates in future. 

Formatting a date is really simple, for example you can have some code like this one:

import { format } from 'date-fns';

export class Utils {
  getDateFormatted(date: Date) {
    return format(date, "MM/DD/YYYY hh:mm:ss")
  }
}

Date calculation becomes really simple too, with the 140 functions or more that you can use, they export some useful like the ones below:

import { addDays, setSeconds } from 'date-fns';

export class Utils {
  getEmailTriggerDate(date: Date){
    return setSeconds(addDays(date, 7), 0);
  }
}

This example only mentions the functions addDays and setSeconds, but there are much more and I invite you to read the documentation over here.

Loading Indicator

Our second library has around 1.500 downloads per week, MIT licensed also and is on version 2.3.0. According to github, this repository has 170 stars and 2 contributors. I present to you mpalourdio's ng-http-loader.

Depending on the version of Angular that you are using, a different version of the library must be included when installing the package. This is the description from their home page:

"The latest compatible version with angular 4 is 0.3.4. If you want to use Angular 5, use versions 0.4.0 and above. The latest compatible version with angular 5 is version 0.9.1. Versions 1.0.0+ and 2.0.0+ are angular 6 / RxJS 6 compatible only."

First question, why do I use it? because I don't have to do anything basically! other than configuring the loader icon following the simple steps from the instructions they provide. This library was built with the condition to intercept all http requests performed using the HttpClientModule from Angular, in other words, as long as you use this module, the loader will appear automatically. 

Also, for the cases where you might use a third party tool that does not use that module, for example the AWS-SDK, then you can manually trigger the loader to appear using an Angular service they provide.

So, how do I use it? first let's discuss a little bit about the configuration. The most important thing is to include the main module from their library to our app module, so that we can use the library from our application.

import { NgHttpLoaderModule } from 'ng-http-loader/ng-http-loader.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    /** DECLARATIONS */
  ],
  imports: [
    /** OTHER IMPORTS */
    NgHttpLoaderModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

You can do some customization that is provided out of the box, like different spinners using the following configuration in the app.component.ts file.

import { Spinkit } from 'ng-http-loader/spinkits';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  private spinkit = Spinkit;
  spinnerType = this.spinkit.skWanderingCubes;
}

And a simple add in the app.component.html

<spinner [spinner]="spinnerType"></spinner>

With this default configuration, the spinner will appear every time a request is made, however, I also mentioned that there is a way to manually show the spinner. Here is how:

import { SpinnerVisibilityService } from 'ng-http-loader/services/spinner-visibility.service';

@Component({
    selector: 'my-component',
    templateUrl: 'my-component.component.html'
})
export class MyComponent extends OnInit{
  constructor(private spinner: SpinnerVisibilityService) {
  }
  
  someAction() {
    this.spinner.show();
    //Some more logic
    this.spinner.hide();
  }
}

Summary

I've nothing else to say except that I love this components and I'll keep using them as long as I can. Both of them simplify a lot my work and I definitely like using things that make my life easier.

If you have any comment, don't hesitate in contacting me or leaving a comment below. And remember to follow me on twitter to get updated on every new post.

Tech Review: Angular Stack (1/many)

Being the first post in my Tech Review series, I wanted to start with something I use often, so I'm gonna start writing about two components that are really common in enterprise applications, a grid and a UI notification mechanism.

Also, this time I'm not doing any type of comparison between the component I'm reviewing and others, nor I'm going to give a calification, this post is going to focus on the good things of each one, and some examples on using them. 

Grid Component

Let's start with the grid component. According with npmjs, at the time of writing this post, there has been more than 50.000 downloads in the last week, it's MIT licensed and currently on version 13.0.1. Also, according to github, this repository has over 2.700 stars, 111 contributors, and a pretty active community (I hope that with all of those stats, it gives enough background about how big it is). Bottom line, I present to you, if you didn't know about it, Swimlane's grid component.

First question in my review, why do I use it? and to answer that I have two words only: features and simplicity. I like components that are simple to use for the most basic requirements that I need to fulfill; and for more complex things, I use them as base for my custom made components. 

For this grid in particular, here are some of the features available out-of-the-box (taken from their main page)[1]:

  • Handle large data sets ( Virtual DOM )
  • Expressive Header and Cell Templates
  • Horizontal & Vertical Scrolling
  • Column Reordering & Resizing
  • Client/Server side Pagination & Sorting
  • Intelligent Column Width Algorithms ( Force-fill & Flex-grow )
  • Cell & Row Selection ( Single, Multi, Keyboard, Checkbox )
  • Fixed AND Fluid height
  • Row Detail View

The features I like the most are the column reordering, pagination, sorting, custom commands and the flexible fluid layout. Those are the ones that I care the most and covers almost the principal use cases that I've seen.

Second question, how do I use it? well, normally if you use a grid in an application, I'm pretty sure you will end up using it in more places, so the first thing I do is create a custom component that wraps the grid and enables more features that do not come out-of-the-box. For example, this is the current version of the GridComponent I'm using:

import { Component, Input, Output, EventEmitter, OnInit, ViewChild, SimpleChanges } from '@angular/core';
import { DatatableComponent } from '@swimlane/ngx-datatable';
import {Md5} from 'ts-md5/dist/md5';

@Component({
  selector: 'grid',
  templateUrl: './grid.component.html',

})

export class GridComponent implements OnInit {
    @Input() filtered: boolean = false;
    @Input() data: any;
    @Input() columns: any;
    @Input() rowClass: any;
    @Input() selectionType: string = 'single';
    @Output() rowSelected: EventEmitter<any> = new EventEmitter();
    @ViewChild('table') table: DatatableComponent;

    rows = [];
    lastSelectedRowHash;
    selectedRow = [];

    constructor() { }

    onRowSelected($event) {
        if(this.selectedRow == null) return;
        if(this.selectedRow.length <= 0) return;
        var stringifyObject = JSON.stringify(this.selectedRow[0]);
        var selectedObjectHash = Md5.hashStr(stringifyObject);
        if(this.lastSelectedRowHash == selectedObjectHash)
            return;
        this.lastSelectedRowHash = selectedObjectHash;
        this.rowSelected.emit(this.selectedRow);
    }

    cancelSelection(){
        this.selectedRow = [];
        this.lastSelectedRowHash = "";
    }

    updateFilter(event) {
        if(!this.filtered) return;
        const val = event.target.value.toLowerCase();
        const temp = this.data.filter((d) => {
            var matches = false;
            for(var index = 0; index < this.columns.length; index++){
                var property = this.columns[index].prop;
                var data = d[property] == null ? "" : d[property].toString();
                matches = data.toLowerCase().indexOf(val) !== -1 || !val;
                if(matches) break;
            }
            return matches;
        });
        this.rows = temp;
        this.table.offset = 0;
    }

    ngOnInit() {
        if(this.data){
            this.rows = this.data;
        }
    }

    ngOnChanges(changes: SimpleChanges){
        for(var prop in changes){
            if(prop == 'data'){
                this.rows = changes[prop].currentValue;
            }
        }
    }
}

As you can see, I've added things such as saving the last state of the selected element to avoid firing the event unnecessarily, an easy way to unselect all elements and filtering. Obviously, this has an HTML counterpart:

<div class="row mb-3">
    <div class="col-md-4">
        <input type='text'
            class="form-control"
            placeholder='Type to filter...'
            (keyup)='updateFilter($event)'
            *ngIf="filtered"/>
    </div>
</div>
<div class='panel-body'>
    <ngx-datatable #table
        class="material selection-cell"
        [rows]="rows"
        [loadingIndicator]="loadingIndicator"
        [columns]="columns"
        [columnMode]="'force'"
        [headerHeight]="40"
        [footerHeight]="40"
        [limit]="10"
        [rowHeight]="'auto'"
        [reorderable]="reorderable"
        [selectionType]="selectionType"
        [selected]="selectedRow"
        (select)='onRowSelected($event)'
        [rowClass]="rowClass">
    </ngx-datatable>
</div>

Creating an HTML wrapper allowed me to centralize common configurations like the column mode for the fluid layout I mentioned before, or the height of the rows, among other things.

UI Notification Mechanism

Continuing with the second component of this review, let's give some stats like before. According to npmjs, at the time of writing this post, there has been more than 20.000 downloads in the last week, it's MIT licensed and currently on version 8.8.0. Also, according to github, this repository has 545 stars and 17contributors. Bottom line, I present to you, if you didn't know about it, Scott Cooper's ngx-toastr.

So, why do I use it? again, simplicity is something that I looked for, but more important this time, I needed a component that satisfied all my use cases from start and matches the UI style without interfering with the layout design. For all those reasons, ngx-toastr met all my requirements and exceeded my expectations.

Here are some of the features available (again, taken from their main page) [2]:

  • Toast Component Injection without being passed ViewContainerRef
  • No use of *ngFor. Fewer dirty checks and higher performance.
  • AoT compilation and lazy loading compatible
  • Component inheritance for custom toasts
  • SystemJS/UMD rollup bundle
  • Animations using Angular's Web Animations API
  • Output toasts to an optional target directive

Then, how do I use it? Apart from following the installation and configuration instructions, I've done nothing. This is an awesome plug-and-play component, but if you prefer, you can customize the UI design simply by following a few extra steps.

Summary

Reaching this point, I've nothing else to say except that both are excellent components that will work great in whatever project you need to work on. And hopefully, this little post makes you want to try them. 

If you have any comment, don't hesitate in contacting me or leaving a comment below. And remember to follow me on twitter to get updated on every new post.