Tuesday, 11 October 2016

Angular 2 - Polymorphic Component Container using ContentChildren


As I do a deep dive into Angular 2 I've been finding some amazing features, one which really stands out being the Decorator ContentChildren. ContentChildren allows a component to access it's children components which are placed between it's selector. An example of such a setup is as follows:


<parent>
    <child></child>
    <child></child>
</parent>

now inside of the parent's component it can define the following:

@ContentChildren(ChildComponent) editors: QueryList<ChildComponent>;

ngAfterViewInit() {
    let myChildComponents = this.editors.toArray();
}


NOTE: you cannot access the child components inside of ngOnInit as the child components have not become available yet. ContentChildren and QueryList are both found inside of @angular/core.

The benefit of ContentChildren over the traditional AngularJs's transclude is that the child component need not know about the parent component. This is great because a common design pattern is top down (example a tab component).

The real hidden gem here though is creating a system where you can have an abstract base class for your child components. Through doing so you can achieve a polymorphic system which lets you combine multiple like components with a base class.

Lets say for example, you have a dropdown of question types that a user can choose to answer with. You could either couple all of the editors and have them hard coded into the component that produces this part of your website, OR you could have a container ccomponent which accepts any number of different editors which are just placed in and magically work! I much prefer magic, so lets have a look at the markup that could achieve this

<question-editor>
    <foo-editor></foo-editor>
    <bar-editor></bar-editor>
</question-editor>

the contents of question-editor don't matter yet, so lets have a think of what information we would require from each of our editors (foo and bar). first we would need to be able to hide then when they are in-active, then get some sort of human friendly name and finally get the value that the form has extracted from the user. this contract could be forfilled with the following abstract class (using abstract class over interface as interfaces are compile time only, and I need something injectable!)

export abstract class BaseEditor {
  constructor(private privateEditorName: string, public isSelected: boolean = false) {}
  get editorName(): string {
    return this.privateEditorName;
  }
  public value: string;
}  

as you can see, this base class exposes a getter for the editorName, the value and also isSelected (used to toggle visibility)

A class would then implement this base class like so

import { Component, forwardRef } from '@angular/core';
import { BaseEditor } from 'app/editor/base-editor.ts';

@Component({
  selector: 'bar-editor',
  template: `
  <div style="color: blue" *ngIf="isSelected">
    <p>bar editor</p>
    <input [(ngModel)]="value">
  </div>
  `,
  providers: [{provide: BaseEditor, useExisting: forwardRef(() => BarEditorComponent)}]
})
export class BarEditorComponent extends BaseEditor { 
  constructor() {
    super('bar editor', false)
  }
} 

as this editor is a test editor, there is no complicated editor logic inside of the component, but theoretically in a real world situation there would be. What makes this editor unique to the foo editor is that it allows the user to enter an answer via an input field which we can see inside of the template.

The other thing to notice here, is that we are providing the angular DI system an implementation of the BaseEditor through use of the ExistingProvider provider (as seen inside of @Component's providers array). This provider basically tells angular, if somebody asks about BaseEditor, I'm your man! As we are defining this provide at the component level, we don't have to worry about breaking the DI every time we define a new editor either as the provide is scoped to this component and under.

next we have a look at the question-editor

import { Component, OnInit, AfterViewInit, ContentChildren, QueryList, Output, EventEmitter } from '@angular/core'
import { BaseEditor } from 'app/editor/base-editor.ts';

@Component({
    templateUrl: 'app/editor/editor.component.html', // unfortunatly need full uri 
    selector: 'question-editor'
})
export class EditorComponent implements OnInit, AfterViewInit {
    @Output() formValueChange: EventEmitter<string> = new EventEmitter<string>();
    @ContentChildren(BaseEditor) editors: QueryList<BaseEditor>;

    onQuestionChange(newQuestion: string) {
        // reset editors
        this.hideAllEditors();
        let editorFilter = this.editors.filter(editor => editor.editorName === newQuestion);
        let editor = editorFilter[0];

        if(editor == null) {
            throw new Error(`Cannot find question editor for: ${newQuestion}`)
        }

        editor.isSelected = true;
    }
    
    onClickSubmit() {
      let currentEditor = this.editors.filter(editor => editor.isSelected)[0];
      console.log(`submitting: ${currentEditor.value}`);
      this.formValueChange.emit(currentEditor.value);
    } 

    private hideAllEditors(): void {
        this.editors.forEach(editor => {
            editor.isSelected = false;
        })
    }
}

the part to take note of is the @ContentChildren. As you can see, we request all children of this component which have the type of BaseEditor. Both FooEditor and BarEditor have setup their DI to point all requests for BaseEditor to themselves, so as we scan over the components, each editor is picked upa as a BaseEditor and placed inside the array for editors. The remainder of the code in the component are used to hide, display and gather input from the editors.

The html for this component is as follows:

<<div>
    <select (change)="onQuestionChange($event.target.value)">
        <option *ngFor="let editor of editors" [value]="editor.editorName">{{ editor.editorName }}</option>
    </select>
</div>
<div>
    <ng-content></ng-content>
</div>
<div>
  <button (click)="onClickSubmit()">submit</button>
</div>

as you can see, we are using our list of editors to create options for our select, then displaying it inside of our component via ng-content.

In summary: @ContentChildren is an amazing new tool for every angular developers utility belt. It allows for creating top down architectures and with some DI wizardry, it also allows for polymorphic designs to be created!

Working example over here on Plunker 

Thursday, 18 February 2016

Getting MVC 6 and .Net Core running on Ubuntu in 2016



I thought I would make my first blog post in a while on something I have been learning recently, that is .Net Core, more specifically on Ubuntu 14.

First things first, open a terminal! Personally I run all these commands under the root user, so I will be using 'sudo su' so that I don't have to enter sudo every time I need super user privileges (so if you don't you will need sudo in front of almost all of the commands). I have also found that sometimes the permisions between the root user and the local user can cause issues if you don't install everything against ONE user. If you use 'sudo su' you will have to use the root account for everything you install through apt-get, but you will still have to run the packages you install via npm under your account as root won't have access (this is important for Yeoman)

Installing .Net Core

The following will walk you through the preperation of your system

Installing DNVM


The next step is to enter some commands that will allow us to download and install DNVM. DNVM stands for Dot Net Version Manager and is the tool used to set and manage the .net run-times on your machine. For more information check out the aspnet documentation on DNVM.


      ~$ sudo su
      ~$ apt-get install unzip curl
      ~$ curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_BRANCH=dev sh && source ~/.dnx/dnvm/dnvm.sh

After doing the above commands you can test that the installation worked by typing 'dnvm'

















If you do not see the above once you have entered the above commands then look for error messages and or try to enter the command 'source ~/.dnx/dnvm/dnvm.sh'. This should run automatically though. If you would like to find out more about the dnvm you can also type 'dnvm -h' to bring up the help.

Installing DNX and Core CLR

The following commands will download the prerequisites of the dnx and then install the Core CLR. The core CLR is the new open source implementation of .net which has been built from the ground up to be used to build .net apps cross platform and has been cloud optimised. It is light weight and highly uncoupled. Unlike .net 4 and mono, it is installed per app rather than per system, this per app design is great as it will allow devs in the future to install new apps to their servers without having to upgrade all their old apps and without the system admins input!


      ~$ apt-get install libunwind8 gettext libssl-dev libcurl4-openssl-dev zlib1g libicu-dev uuid-dev
      ~$ dnvm upgrade -r coreclr

The first line installs the prerequisites and the second instructs the dnvm to either install the latest coreclr or to update to the latest, you MUST include '-r coreclr' as it instructs the dnvm you don't want to upgrade the default mono clr. It is at ths time that you could also install mono, but I have chosen not too as this blog post is about the core clr.

To verify that you have the core clr installed and to check what runtime is active, type 'dnvm list'



Two things to note:
  1. Active: shows you which run time is currently in use.
  2. Alias: When you upgrade the default alias is automatically added, if you have multiple run times you can utilize the 'dnvm use' command with '-p' to switch the active run time and to remove the current default alias and set it to the newly selected one.

Installing Kestrel requirements

When we eventually create a MVC 6 website, we will need somthing to run it! So I have opted to use the default web server that .net core is provided, Kestral.

To run Kestral, we will need to install libuv, a multi-platform asynchronous IO library!

      ~$ apt-get install make automake libtool curl
      ~$ curl -sSL https://github.com/libuv/libuv/archive/v1.8.0.tar.gz | sudo tar zxfv - -C /usr/local/src
      ~$ cd /usr/local/src/libuv-1.8.0
      ~$ sh autogen.sh
      ~$ ./configure
      ~$ make
      ~$ make install
      ~$ rm -rf /usr/local/src/libuv-1.8.0 && cd ~/
      ~$ ldconfig

The above installs libtool and curl, then downloads the libuv source, configures it, compiles it and finally installs it. ldconfig is used to update the ld.so.cache so that dlopen can load it.

Congratulations! You now have a working .net environment on your system! What's next? Actually making something!

MVC 6 with YeoMan scaffolding!

To use YeoMan to scaffold the default project that we have all grown to love from Visual Studio, we first will need to install a few things, namely node, npm, yo and generator-aspnet!

Installing Node.js and NPM

installing node is simple enough, there are just a few apt-get to run and your good!

      ~$ apt-get install nodejs
      ~$ apt-get install npm
      ~$ ln -s /usr/bin/nodejs /usr/bin/node

What it does is fairly self explanitory, install the nodejs and npm, then add a symbolic link for node so we can use node in the terminal. From here we can enter 'node -v' and 'npm -v' to confirm installation.


Updating NodeJs

The next is optional, but if your system already has nodejs installed making sure you have the latest version of nodejs is a good idea!

      ~$ npm cache clean -f
      ~$ npm install -g n
      ~$ n stable

This will clean out the npm cache and the next line installs the n package (node helper) globally (-g). From there we run n stable to tell the node helper to update to the latest stable release. You could also enter a specific version you want to use instead of stable. Next when you type you will find your node is up to date!

Installing YeoMan and the aspnet generators

Almost on the home stretch now! All that is left is to install YeoMan and the aspnet generators

      ~$ npm install -g yo
      ~$ npm install -g generator-aspnet

This will install YeoMan and the aspnet YeoMan Generators globally.

Scaffolding the MVC Starter Template

All that is left now is to actually run the YeoMan aspnet gernerator! Today we will be creating the default MVC Web Template that you make when you choose the default authentication in Visual Studio.

First type 'yo aspnet' into the console. You will be presented with an error! Oh no! Don't worry, if you see this there is a good chance it is because you are still under the root account and you just need to type 'exit' to go back to your users session. I don't know why 'yo' won't work for me under the root account, but the fix is easy enough. Try again and this time you will be presented with the following (after choosing to contribute your data or not):

From here you can use your arrow keys to navigate the menu, choose Web Application.
Then choose a nice name (I will be using 'HelloMvcUbuntu').

All that is left to do is follow the instructions it leaves you. If you ran the installation under the root (sudo su) account you will need to login to the super user account again (type 'sudo su')

      ~$ cd "HelloMvcUbuntu"
      ~$ dnu restore 
      ~$ dnu build (optional, build will also happen when it's run)
      ~$ dnx web

this will move you into the newly created directory and restore all of the nuget packages that are required as documented inside of project.json. If you want to have a look around the directory either use 'ls' and 'cd' OR you can use 'xdg-open .' to open the current directory in the Ubuntu file explorer.

If you want to be able to run 'dnu build' you will need to make a modification to project.json. Inside of the frameworks you will see there is 'dnx451' which is actually only available on windows, so you can either remove it or add mono in there if you have it installed.

After running all of those commands congrats! your website running in aspnet is now running on http://localhost:5000.


Just as a heads up, in the next release candidate (rc2) and all the future versions the two commands dnu and dnx are merging into the single tool command 'dotnet' so instead of the above commands you would use:

      ~$ cd "HelloMvcUbuntu"
      ~$ dotnet restore 
      ~$ dotnet build (optional, build will also happen when it's run)
      ~$ dotnet web

I hope this helps somebody out there, if you have any questions or feedback please feel free to leave them in the comments bellow.

References: