Saturday, April 01, 2017

This is how birds enjoy water ...





This is how much the sunbirds in my garden enjoy even with the little water you share with them this summer. They are pretty cool :)

Musings on Nature around Gandhkosh

Some of shots of nature taken around DSK Gandhkosh, my work home over a period of few months. Hope you like it :)

















Friday, February 24, 2017

A "Generic Component" in Angular 2

I am generally a lazy person. Especially so when it comes to writing some UI code (although I can have endless comments and critiques on someone else's UI and UX ;-)) . I find it repetitive. And any form of repetitive behaviour is ripe for automation. One such activity which I recently encountered in a project I was doing was creating forms - a lot of them - with Angular 2 front end. I remember in good old MS Access days these were just a click away - although I disliked it, this is what I did in my first paying job in summer break of my school.
I am not sure we have something equivalent here - more so when Angular is so rapidly changing and keeps breaking every other month.

However, it is rather easy to write a "generic component" that can be simply configured using a JSON and you can have a new form without writing any of the usual code. This has two main advantages: 1) You have a single place to fix when Angular changes something in its structure 2) You have a super reusable form engine which can be configured on the fly, allowing you to do cool things like storing form info in a backend service, and automatically update the Angular 2 app on the fly.

To start off, you will need to define a JSON which can be used to construct the UI on the fly.

this.componentJSON = {};
this.componentJSON['title'] = "Trials";

this.componentJSON['formItems'] = [
 { "type": "text", "id": "trial", "name": "Trial Name", "description": "Name of trial", "theValue": "", "param_name": "trial_name" },
 { "type": "text", "id": "sponsorer", "name": "Sponsorer", "description": "Sponsorer of the trial", "theValue": "", "param_name": "sponsorer_name" },
 { "type": "button", "id": "submit", "name": "Submit", "description": "Submit the form", "api_call": this.createTrial },
];


The above JSON is intended to create a simple form with a title, two text fields and a button. The api_call parameter of the button is a Service object used to make an API call.  This JSON should be used in any parent component that intends to use this component, typically being initialised in ngOnInit() method.

Next we define generic.component.ts and generic.component.html as follows

import { Component, OnInit, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';

@Component({
   moduleId: module.id,
   selector: 'generic-cmp',
   templateUrl: 'generic.component.html'
})
export class GenericComponent implements OnInit {

   @Input()
   componentJSON: any;

   constructor() { }

   ngOnInit() {
   }

   callAPI(item: any) {
     item.api_call.api_call(this.processInput(this.componentJSON)).subscribe((res:any) => {      
if (res.status == 0) {
        alert(res.result.message);  
} else {
        alert(res.error.error_message);  
}
     });
   }

   processInput(componentJSON: any) {
     var formItems = componentJSON['formItems'];

     var params: any;
     params = {};
     for(var frmItm in formItems) {
if (formItems[frmItm].type != 'button') {
        params[formItems[frmItm].param_name] = formItems[frmItm].theValue;
}
     }

     return params;
   }
}













The trick as always is to generalise the JSON and then the generic component generator above to take care of different input forms as well as adding validations. The callAPI function above for instance, basically generalises an API call, where as the processInput method creates the parameter payload for API call from the JSON we created earlier. Advantage again being that simply changing the JSON pretty much re-creates the whole of the HTML. Creating a different form just requires one to define a new JSON.

Since this component needs to be used in multiple places it would be wise to declare the directives associated with this component in a shared.module.ts file:

import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { BrowserModule } from '@angular/platform-browser';

import { NameListService } from './name-list/index';
import { GenericComponent } from './generic-component/generic.component';

@NgModule({
    imports: [CommonModule, RouterModule, FormsModule],
    declarations: [GenericComponent],
    exports: [CommonModule, FormsModule, RouterModule, BrowserModule, GenericComponent],    
})

export class SharedModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [NameListService]
        };
    }
}


Now a third component can embed this reusable, configurable component as using:



Thats it! You should have a fairly reusable forms module, that you can fully configure using the JSON, without the need to keep writing the HTML and related Component code every time. 

A similar pattern may also be used for creating a generic service call. This is again useful as you code can remain independent of the changes that may occur in basic underlying syntax of say actually calling the HTTP post method. 

Wednesday, January 04, 2017

My tech wish list - 2017

1. MacBook with inbuilt cellular connectivity
2. iPhone with no ports - not even lightning - with wireless charging. For a truly courageous furture.
3. If I can just use my phone for every thing - where is that elusive Surface Phone ?
4. On demand apps on iOS - so that I can save on my precious local storage
5. Driver less cars - where are they ?
6. Super personalised medicines
7. AI assistant for myself - without a cloud connected device
8. Battery that lasts for 1 month on 15 min charge and doesn't explode.