Monday, 2 May 2016

Angular Js - Lesson 10 - Chat application using Angular Js 2 and RxJs part 1

Making a chat app using Angular Js 2 and RxJs

The screenshot for this app is here.

The cod for this app is also available at Github here. If you have purchased the book and downloaded the zip code of the source code that comes with the book then go to the directory code/rxjs/chat by changing to the directory as shown in step 1 below and do the following:
  1. cd code/rxjs/chat
  2. npm install
  3. nom run go
  4. Open chrome or firefox and in the address bar type http://localhot:8080
  5. Play with the application by clicking the unread messages available and chat with the bots.
Three top level components have been used to build this application. They are given below:
  1. ChatNavBar -  This component is displayed at the top of the screen in the browser and shows among other things the number of unread messages. Note that when you click an unread thread and load its messages in the ChatWindow the number of unread messages decrease.
  2. ChatThreads - The number of chat threads are shown in the ChatNavBar but the actual chat threads are here and each row represents one chat thread. Once you click on a chat thread the messages in that chat thread will be loaded in the component ChatWindow. The ChatThread component listens for the most recent list of threads from the ThreadService.
  3. ChatWindow - The window that had a box for typing and that you used to type your message as well as read the previous messages if any. The ChatWindow component subscribes for the most recent list of messages.
The components subscribe to the streams maintained by the services  and then render according to the most recent values.

The app has three models given below:
  1. Thread - This model stores a collection of messages as well as some data about the conversation in a thread. Each thread has a unique id. Moreover, a thread has a name, a source for the avatar avatarSrc shown to represent that thread and the lastMessage which sotres the last message in this thread.
  2. Message - One Message is stored here. To identify a message uniquely a message has an id. It has a time sentAt. A boolean isRead showing if the message has been read or not. A string variable text which has the text of the message. Moreover, a Message has an author and a thread to which it belongs.
  3. User - A human being chatting with a bot in the app is a user. A user has an id, a name and and avatarSrc.
Each model has a corresponding service. In this app a singleton objet has been used to provide a service. The singleton object not only provide streams of data that our app can subscribe to but also provide operations to add new data or modify existing data. The services used in this app are given below:
  1. UserService
  2. MessageService
  3. ThreadService
The services maintain streams and these streams emit models. An example of a model in this app is a Message. The MessageService maintains a stream that emits Messages. The UserService maintains a stream that emits the current user. Moreover, it provides a method setCurrentUser that emits the current user from the currentUser stream.

We will build this app in the following three stages.
  1. Implement our three models namely Thread, Message and User.
  2. Create services UserService, MessageService and ThreadService which manage streams.
  3. Implement the three components namely ChatNavBar, ChatThreads and ChatWindow.

Implementing the Models

Implementation of the Model User:

User
export class User{
    id: string;
    /* We are using typescript shorthand in the constructor below.
    Whenever a new instance is created, that instance get two public properties apart from the        property id.
    The values of the arguments to the constructor are assigned to those public properties that together with
    the property id make an instance of the class USer.
     */
    constructor(public name: string, public avatarSrc: string){
        this.id = uuid();
    }
}//class User ends here.

Implementation of the Model Thread:

Thread
export class Thread{
    id: string;
    name: string;
    avatarSrc: string;
    lastMessage: Message;
    /*
        The reference lastMessage points to the last Message in a thread in order to display this last message  in the preview of this thread to the user.
    */
 
    constructor(id?: string, name?: string, avatarSrc?: string){
        this.id = id || uuid();
        this.name = name;
        this.avatarSrc = avatarSrc;
    }
}//class Thread ends here.

Implementation of the Model Message:

Message
export class Message
    id: string;
    text: string;
    author: string;
    isRead: boolean;
    sentAt: Date;
    thread: Thread;
 
    constructor(obj?: any){
        this.id = (obj && obj.id) || uuid();
        this.text = (obj && obj.text) || null;
        this.author = (obj && obj.author) || null;
        this.isRead = (obj && obj.isRead) || false;
        this.sentAt = (obj && obj.sentAt) || new Date();
        this.thread = (obj && obj.thread) || null;
    }
}//class Message ends here.
    /* We can call the contructor above without any arguments or with some of the arguments to make a new instance of class Message. In this way we can create a new instance with whatever data we have available. Moreover, we don't have to worry about the order of the arguments or if some arguments are missing. For example, we can create a new instance like this.
let message = new Message({
    text: "Hi Mr. xyz. How are you today?"
});*/


Implementing the Services

Implementation of the Service UserService:

We will make the UserService class injectable so that it could be used as a dependency to the other components in the app. The job of the UserService is to provide a place where the app can learn about the current user and notify the rest of the app in case the current user changes. 

UserService
import { Injectable, bind } from 'angular2/core';
import { Subject, BehaviorSubject } from 'rxjs';
import { User } from '../models';

@Injectable()
export class UserService{
     /*
          In the line below we set up a stream which will be used to manage the current user.
          A subject can be thought of as a "read/write" stream.
    */
    currentUser: Subject<User> = new BehaviorSubject<User>(null);
 
    public setCurrentUser(newUser: User): void{
            /* We use the next method on a Subject (read/write stream) to push a new value to the      stream.
           */
        this.currentUser.next(newUser);
    }
}//class UserService ends here.

export var userServiceInjectables: Array<any> = [bind(UserService).toClass(UserService)];


Messages are published immediately to the stream and therefore there is a chance that a new subscriber misses the latest value of the stream. To overcome this we use the constructor of BehaviorSubject to create a new instance because BehaviorSubject stores the last value in a special property. Due to this special property a subscriber to the stream will receive the latest value. Any part of the application that subscribes to the UserService.currentUser stream will immediately come to know who the current user is.

So how to do we set a new user. There are two ways to do it.
One way is to create a new user and add the user directly to the stream like this.

  1. let user = new User('Alex', 'imageSource');
    userService = new UserService();
    userService.subscribe(
       (user) => {
           console.log('New user is: ', user.name);
    }
    );
    userService.currentUser.next(user);
    The next method will pust the new value i.e., user into the stream. 
  2. Another way to update the current user is to create a helper method to do the job.
 Here is how we can do it.  
public setCurrentUser(user: User) : void {
     this.currentUser.next(user);
}

This second technique is better as implementation of the currentUser is decoupled from the implementation of the stream. In the second technique we wrap the method next in the helper method setCurrentUser and this gives us room to change the implementation of the UserService class without breaking our clients that subscribe to the UserService class. Maintainability is important in large projects and decoupling is part and parcel of writing maintainable code.

Implementation of the Service MessagesService:

In row two of the following table the code for MessagesService has been commented extensively to explain the code. Row 3 of the same table has the same code but without comments for quick reference. 

MessagesService

import {Injectable, bind} from 'angular2/core';
import {Subject, Observable} from 'rxjs';
import {User, Thread, Message} from '../models';

let initialMessages: Message[] = [];

interface IMessagesOperation extends Function {
  /* Accepts a list of messges actually an array of objects of type Message.
     Returns an array of objects of type Message.
   */
  (messages: Message[]): Message[];
}

@Injectable()
export class MessagesService {
  // a stream that publishes new messages only once
  /* Subject can be thought of as a read/write stream. */
  newMessages: Subject<Message> = new Subject<Message>();

  // `messages` is a stream that emits an array of the most up to date messages
  messages: Observable<Message[]>;

  /* updates is a stream which is a stream of functions. Any function that is put
  on the stream updates will change the list of current messages stored in
  'messages'. Any function that is put on the updates stream should accept a
  list of Message objects and return a list of Message objects.
  `updates` receives _operations_ to be applied to our `messages`. It's a way
   we can perform changes on *all* messages (that are currently stored in `messages`)
   */
  updates: Subject<any> = new Subject<any>();

  /* action streams - the create stream is a regular stream. The term 'action stream'
     is meant to describe its role in our service.  
  */
  create: Subject<Message> = new Subject<Message>();
  markThreadAsRead: Subject<any> = new Subject<any>();

  constructor() {
    /***************************************************************************/
    this.messages = this.updates
      // watch the updates and accumulate operations on the messages
      /* The scan runs the function for each element in the incoming stream
      and accumulates a value. scan will emit a value for each intermediate
      result and doesn't wait for the stream to complete before emitting a
      result.
      */
      .scan((messages: Message[], /* The messages we are acuumulating in this pass */
             operation: IMessagesOperation) => { /* The new operation to apply in this pass. */
               return operation(messages); /* Returning the new Message[]. */
             },
            initialMessages)
      /*
         Make sure we can share the most recent list of messages across anyone who's interested
         in subscribing and cache the last known list of messages.
       */
      .publishReplay(1)
      .refCount(); /* refCount makes it easier to use the return value of publishReplay
      by managing when the ovservable will emit values. */
      /***************************************************************************/
      /*
          Next in our constructor we configure the create stream.
          The create stream takes a Message object and then puts an operation (the
          inner function) on the 'updates' stream to add the Message object to the
          list of messages. The map operator works on streams and it runs the inner
          function once for each item (Message object) in the stream create and
          emits the return value of the function. In this case we are saying "for each
          Message we receive as input, return an IMessagesOperation that adds this Message
          to the list 'messages'. In other words we can say that the create stream
          will emit a function for each Message and that function accpts the Message
          and adds it to our list of messages. That is for each item that gets added
          to 'create' stream (by using 'next') the stream 'create' emits a concat
          operation function.
          Next we subscribe 'this.updates' to listen to the stream 'create' which
          means tht it will receive each operation (in this case the concat operation)
          that is created. That is we are subscribing the 'updates' stream to listen to
          'create' stream which means that when 'create' receives a message it will
          emit an IMessagesOperation that will be received by the 'updates' stream
          and then the Message will be added to messages: Message[].
       */
    this.create
      .map( function(message: Message): IMessagesOperation {
        return (messages: Message[]) => {
          return messages.concat(message);
        };
      })
      .subscribe(this.updates);
/***************************************************************************/
    this.newMessages
      .subscribe(this.create);
 /*
   The 'create' stream is subscribing to the newMessages stream which is a stream
   that publishes new messages only once. Now our flow is complete. We get
   individual messages from the stream newMessages and we can get the most
   up-to-date list from the stream 'messages'.
 */
/***************************************************************************/
    /* The stream`markThreadAsRead` takes a Thread and
       then puts an operation on the `updates` stream to mark the Messages as read.
       The map operator works on the stream markThreadAsRead and for each thread in
       this stream it runs the function () once for each item/thread and
       emits the return value of the function.
    */
    this.markThreadAsRead
      .map( (thread: Thread) => {
        /* In this pass get all the messages in the list (Message[]). */
        return (messages: Message[]) => {
          /* In this pass get one message from the list of messages (Message[]). */
          return messages.map( (message: Message) => {
            /* Get the thread for this message and then get the id of the thread.
               Then compare it to the id of the thread 'thread' passed to the
               mapfunction to check if it has been read. Each message has a
               property isRead. Set that to true and false accordingly.
            */
            // note that we're manipulating `message` directly here. Mutability
            // can be confusing and there are lots of reasons why you might want
            // to, say, copy the Message object or some other 'immutable' here
            if (message.thread.id === thread.id) {
              message.isRead = true;
            }
            return message;
          });
        };
      })
      /*
         The stream 'updates' will subscribe to the message returned by
         this.markThreadAsRead.map() and this will set the property isRead of this messges
         to true or false accordingly.
      */
      .subscribe(this.updates);

  }
/************************************************************************/
  // an imperative function call to this action stream
  addMessage(message: Message): void {
    this.newMessages.next(message);
  }

  messagesForThreadUser(thread: Thread, user: User): Observable<Message> {
    return this.newMessages
      .filter((message: Message) => {
               // belongs to this thread
        return (message.thread.id === thread.id) &&
               // and isn't authored by this user
               (message.author.id !== user.id);/* Return all message of other users. */
      });
  }
}

export var messagesServiceInjectables: Array<any> = [
  bind(MessagesService).toClass(MessagesService)
];
/*Here is the code for this service without comments and explanation. */

import {Injectable, bind} from 'angular2/core';
import {Subject, Observable} from 'rxjs';
import {User, Thread, Message} from '../models';

let initialMessages: Message[] = [];

interface IMessagesOperation extends Function {
  (messages: Message[]): Message[];
}

@Injectable()
export class MessagesService {

  newMessages: Subject<Message> = new Subject<Message>();
  messages: Observable<Message[]>;
  updates: Subject<any> = new Subject<any>();
  create: Subject<Message> = new Subject<Message>();
  markThreadAsRead: Subject<any> = new Subject<any>();

  constructor() {
    this.messages = this.updates
      .scan((messages: Message[],
             operation: IMessagesOperation) => {
               return operation(messages);
             },
            initialMessages).publishReplay(1).refCount();
    this.create
      .map( function(message: Message): IMessagesOperation {
        return (messages: Message[]) => {
          return messages.concat(message);
        };
      }).subscribe(this.updates);

    this.newMessages.subscribe(this.create);
    this.markThreadAsRead
      .map( (thread: Thread) => {
        return (messages: Message[]) => {
          return messages.map( (message: Message) => {
            if (message.thread.id === thread.id) {
              message.isRead = true;
            }
            return message;
          });
        };
      }).subscribe(this.updates);
  }
  addMessage(message: Message): void {
    this.newMessages.next(message);
  }
  messagesForThreadUser(thread: Thread, user: User): Observable<Message> {
    return this.newMessages
      .filter((message: Message) => {
        return (message.thread.id === thread.id) &&
               (message.author.id !== user.id);
      });
  }
}
export var messagesServiceInjectables: Array<any> = [
  bind(MessagesService).toClass(MessagesService)
];


Implementation of the Service ThreadsService:

In row two of the following table the code for ThreadsService has been commented extensively to explain the code. Row 3 of the same table has the same code but without comments for quick reference.

Four streams have been used in the ThreadsService.

  1. threads - This is a stream that maps the current set of Threads.
  2. orderedThreads - This stream keeps the list of Threads in chronological order i.e., newest first.
  3. currentThread - This stream is for the currently selected Thread.
  4. currentThreadMessages - This stream is the list of Messages for the currently selected Thread.

More explanation in the comments in the code for ThreadsService below.

ThreadsService
import {Injectable, bind} from 'angular2/core';
import {Subject, BehaviorSubject, Observable} from 'rxjs';
import {Thread, Message} from '../models';
import {MessagesService} from './MessagesService';
import * as _ from 'underscore';

@Injectable()
export class ThreadsService {

  /* threads is a stream (Observable) that has the most up-to-date list of threads.
     This stream will emit a map(an object). The object has a key and value as shown below:
     key is of type string [key: string] which is the id of a Thread
     value is an object of type Thread which is the thread associated with the given id.
  */
  threads: Observable<{ [key: string]: Thread }>;

  // `orderedThreads` contains a newest-first chronological list of threads
  orderedThreads: Observable<Thread[]>;

  // `currentThread` contains the currently selected thread
  currentThread: Subject<Thread> =
    new BehaviorSubject<Thread>(new Thread());

  /* `currentThreadMessages` contains the set of messages for the currently selected thread. */
  currentThreadMessages: Observable<Message[]>;

  constructor(public messagesService: MessagesService) {
    /* In the service MessagesService, each time a new Message is created, the stream
       messages will emit an array of the current Messages . Here, we are goin to
       look at each Message and return a unique list of the Threads.
    */
    this.threads = messagesService.messages
      /* The map operator works on streams and it runs the inner
          function once for each item in the stream 'messages' and
          emits the return value of the function.
      */
      .map( (messages: Message[]) => {
        /*
        Each time i.e, in each pass of operator map we will create a
        new list of 'threads'. The reason for this is because we might delete
        some messages down the line (e.g., leave the conversation). Because we
        are recalculating the list of threads each time, we naturally will
        delete a thread that has no messages.
         */
        let threads: {[key: string]: Thread} = {};
        /*
            Store the message's thread in our accumulator `threads`. Each time we will
            create a new list of threads. The reason for this that the user might leave
            the converstation and, therefore, messages of such a user might have been
            deleted. Since we are recalculating the list of threads in each pass of the
            oerpator map, lists with no messages will be deleted as we start from a message
            and get its thread and then id of that Thread threads[message.thread.id].
        */
        messages.map((message: Message) => {
          /* In each pass of the operator map do the following:
            1. Get a Messge from the stream.
            2. Get the Thread to which the message belong.
            3. Get the id of that Thread.
            4. Check if the key already exists then we retain the value otherwise we assign the Thread of step 3 to the key.
            This can also be written like the following:
            if(!threads[message.thread.id]) {
              threads[message.thread.id] = message.thread;
            }
          */
          threads[message.thread.id] = threads[message.thread.id] ||
            message.thread;
/*****************************************************************************/
/*
   On the webpage we show threads and in the preview of each thread we also show
   the text of the last message (the most recent message) in that thread. To do
   that we have to sore the most recent message for each Thread by comparing the
   property sentAt of all Messages in a particular thread.
*/
          // Cache the most recent message for each thread
          let messagesThread: Thread = threads[message.thread.id];
          if (!messagesThread.lastMessage ||
              messagesThread.lastMessage.sentAt < message.sentAt) {
            messagesThread.lastMessage = message;
          }
        });
 /*****************************************************************************/
        return threads;
      });
/*****************************************************************************/
/* `this.orderedThreads` contains a newest-first chronological list of threads. */
    this.orderedThreads = this.threads
    /* this.threads is a stream (Observable) that has the most up-to-date list of threads.
       This stream will emit a map(an object). threads: Observable<{ [key: string]: Thread }>;
    */
      .map(
         ( threadGroups: { [key: string]: Thread } ) => {
        let threads: Thread[] = _.values(threadGroups);
        return _.sortBy(threads, (t: Thread) => t.lastMessage.sentAt).reverse();
      });
/*****************************************************************************/
    this.currentThreadMessages = this.currentThread
      .combineLatest(messagesService.messages,
                     (currentThread: Thread, messages: Message[]) => {
        if (currentThread && messages.length > 0) {
          return _.chain(messages)
            .filter((message: Message) =>
                    (message.thread.id === currentThread.id))
            .map((message: Message) => {
              message.isRead = true;
              return message; })
            .value();
        } else {
          return [];
        }
      });
/*****************************************************************************/
/*
      /* The stream`markThreadAsRead` takes a Thread as argument and
       then puts an operation on the `updates` stream to mark the Messages as read.
       The map operator works on the stream markThreadAsRead and for each thread in
       this stream it runs the function () once for each item/thread and
       emits the return value of the function.
       In the code line below we are connecting the stream markThreadAsRead to
       the stream currentThread so that markThreadAsRead can gets its argument of
       type Thread and mark all its messages as read.
*/
    this.currentThread.subscribe(this.messagesService.markThreadAsRead);
  }//constructor ends here.
/*****************************************************************************/
  setCurrentThread(newThread: Thread): void {
    this.currentThread.next(newThread);
  }
/*****************************************************************************/
}//class ThreadsService ends here.

export var threadsServiceInjectables: Array<any> = [
  bind(ThreadsService).toClass(ThreadsService)
];

/*Here is the code for this service without comments and explanation. */

import {Injectable, bind} from 'angular2/core';
import {Subject, BehaviorSubject, Observable} from 'rxjs';
import {Thread, Message} from '../models';
import {MessagesService} from './MessagesService';
import * as _ from 'underscore';

@Injectable()
export class ThreadsService {

  threads: Observable<{ [key: string]: Thread }>;
  orderedThreads: Observable<Thread[]>;
  currentThread: Subject<Thread> = new BehaviorSubject<Thread>(new Thread());
  currentThreadMessages: Observable<Message[]>;

  constructor(public messagesService: MessagesService) {
    this.threads = messagesService.messages.map(
     (messages: Message[]) => {
        let threads: {[key: string]: Thread} = {};
        messages.map((message: Message) => {
          threads[message.thread.id] = threads[message.thread.id] || message.thread;

          let messagesThread: Thread = threads[message.thread.id];
          if (!messagesThread.lastMessage ||
              messagesThread.lastMessage.sentAt < message.sentAt) {
            messagesThread.lastMessage = message;
          }
        });

        return threads;
      });

    this.orderedThreads = this.threads.map(
         ( threadGroups: { [key: string]: Thread } ) => {
        let threads: Thread[] = _.values(threadGroups);
        return _.sortBy(threads, (t: Thread) => t.lastMessage.sentAt).reverse();
      });

    this.currentThreadMessages = this.currentThread
      .combineLatest(messagesService.messages,
                     (currentThread: Thread, messages: Message[]) => {
        if (currentThread && messages.length > 0) {
          return _.chain(messages)
            .filter((message: Message) =>
                    (message.thread.id === currentThread.id))
            .map((message: Message) => {
              message.isRead = true;
              return message; })
            .value();
        } else {
          return [];
        }
      });

    this.currentThread.subscribe(this.messagesService.markThreadAsRead);
  }//constructor ends here.

  setCurrentThread(newThread: Thread): void {
    this.currentThread.next(newThread);
  }

}//class ThreadsService ends here.

export var threadsServiceInjectables: Array<any> = [
  bind(ThreadsService).toClass(ThreadsService)
];


Implementation of the Service xxxxxService:

In row two of the following table the code for xxxxService has been commented extensively to explain the code. Row 3 of the same table has the same code but without comments for quick reference. 




Sunday, 1 May 2016

Angular Js - Lesson 9 - Forms_7 - two way data binding with ngModel

Angular Js 2 - ngModel - Two way data binding


Angular 2 is built to generally have one-way data flow i.e., top-down. However, in forms, it is easier to use a two-way data binding.



import { Component } from 'angular2/core';
import {
  CORE_DIRECTIVES,
  FORM_DIRECTIVES,
  FormBuilder,
  ControlGroup,
  Validators
} from 'angular2/common';


@Component({
  selector: 'demo-form-ng-model',
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
  <div class="ui raised segment">
    <h2 class="ui header">Demo Form: with ng-model</h2>
    <div class="ui info message">
      The product name is: {{productName}}
    </div>
    <form [ngFormModel]="myForm"
          (ngSubmit)="onSubmit(myForm.value)"
          class="ui form">
      <div class="field">
        <label for="productNameInput">Product Name</label>
        <input type="text"
               id="productNameInput"
               placeholder="Product Name"
               <!--
                   we’re still using ngFormControl to specify that this input
                    should be bound to the Control on our form. We do this
                    because ngModel is only binding the input to the instance
                    variable productName - the Control is completely separate. But because
                    we still want to validate this value and submit it as part
                    of the form, we keep the ngFormControl directive.
               -->
               [ngFormControl]="myForm.find('productName')"
               <!--
                   we’re using both the input [] brackets and the output ()
                   parenthesis. It’s an indication of the two-way bind.
               -->
               [(ngModel)]="productName">
      </div>
      <div *ngIf="!myForm.valid"
        class="ui error message">Form is invalid</div>
      <button type="submit" class="ui button">Submit</button>
    </form>
  </div>
  `
})


export class DemoFormNgModel {
  myForm: ControlGroup;
  productName: string;
  constructor(fb: FormBuilder) {
    this.myForm = fb.group({
      'productName':  ['', Validators.required]
    });
  }
  onSubmit(value: string): void {
    console.log('you submitted value: ', value);
  }
}

//---------------------------------------------------------------------------------------------------------

Angular Js - Lesson 9 - Forms_6-EventEmitter and Observable


Angular Js 2 - Forms - EventEmitter, Observable -
 Observing changes in a control or changes in the form.




import { Component } from 'angular2/core';
import {
  ControlGroup,
  AbstractControl,
  FormBuilder,
  Validators,
  CORE_DIRECTIVES,
  FORM_DIRECTIVES
} from 'angular2/common';

@Component({
  selector: 'demo-form-with-events',
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
    <div class="ui raised segement">
      <h2 class="ui header"></h2>
      <form [ngFormModel]="myForm"
            (ngSubmit)="onSubmit(myForm.value)"
            class="ui form">
        <div class="field"
             [class.error]="sku.touched && !sku.valid">
          <label for="skuInput">SKU</label>
          <input type="text"
                 class="form-control"
                 id="skuInput"
                 placeholder="SKU"
                 [ngFormControl]="sku">
            <div *ngIf="!sku.valid" class="ui error message">SKU is invalid.</div>
            <div *ngIf="sku.hasError('required')" class="ui error message">SKU is required.</div>
        </div>
       
        <div *ngIf="!myForm.valid" class="ui error message">Form is invalid.</div>
       
        <button type="submit" class="ui button">Submit</div>
      </form>
    </div>
  `
})
export class DemoFormWithEvents{
  myForm: ControlGroup;
  sku: AbstractControl;
 
  constructor(fb: FormBuilder){
    this.myForm = fb.group({
      'sku': ['', Validators.required]
    });
    this.sku = this.myForm.controls['sku'];
   
    /* Both Control and ControlGroup have an EventEmitter that we can use to observe changes.
    EventEmitter is an observable which means that it conforms to a defined specification for
    watching for changes. An Observable is an object that can send multiple values to a
    consumer. An Observable has (must have) a subscribe method which accepts a generator and can send it
    any number of values.
    let subscription = observable.subscribe(generator);
    generator is a required argument and it must be an object. Subscribe must return a subscription
    object and this object must have an unsubscribe method. A call to the unsubscribe method
    should free all references to the generator held by the Observable.
    */
    /* We get access to the EventEmitter for the control sku by calling this.sku.valueChanges */
    /* Observing the change event for the control sku */
    this.sku.valueChanges.subscribe(
      (value: string) => {
        console.log('sku value changed to: ', value);
      }
    );
   
    /* Observing the change event for the changes on the form. */
    this.myForm.valueChanges.subscribe(
      (form: any) => {
        console.log('form changed to: ', form);
      }
    );
  }//constructor ends here.
  onSubmit(form: any): void {
    console.log('You submitted value:', form.sku);
  }
}//class DemoFormWithEvents ends here.

Saturday, 30 April 2016

Angular Js - Lesson 9 - Forms_5 - customizing validators


Instance variable version of customized validated Control 



import { Component } from 'angular2/core';
import {
  ControlGroup,
  AbstractControl,
  FormBuilder,
  Validators,
  Control,
  CORE_DIRECTIVES,
  FORM_DIRECTIVES
} from 'angular2/common';

@Component({
  selector: 'demo-form-with-custom-validations',
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
    <div class="ui raised segment">
      <h2 class="ui header">Demo Form: with custom validation</h2>
      <form [ngFormModel]="myForm"
            (ngSubmit)="onSubmit(myForm.value)"
            class="ui form">
        <div class="field"
             [class.error]="sku.touched && !sku.valid">
          <label for="skuInput">SKU</label>
          <input type="text"
                  id="skuInput"
                  placeholder="SKU"
                  [ngFormControl]="sku"]>
          <div *ngIf="!sku.valid" class="ui error message">SKU is invalid.</div>
          <div *ngIf="sku.hasError('required')" class="ui error message">
            SKU is required.
          </div>
          <div *ngIf="sku.hasError('invalidSku')" class="ui error message">
            SKU must begin with <tt>123</tt>
          </div>
        </div>
        <div *ngIf="!myForm.valid">
          Form is invalid.
        </div>
        <button type="submit" class="ui button">Submit</button>
      </form>
    </div>
  `
})
export class DemoFormWithCustomValidation{
  myForm: ControlGroup;
  sku: AbstractControl;
 
  /* Adding multiple validators to a single field requires using
  Validators.compose which takes an array of validators wrapping
  all of the validators and assigning it to a control. The control
  is not valid untill all the validations in the array are valid. */
  constructor(fb: FormBuilder){
    this.myForm = fb.group({
      'sku': ['', Validators.compose([
        Validators.required,
        skuValidator
      ])]
    });
   
    this.sku = this.myForm.controls['sku'];
  }//constructor ends here.
 
  onsubmit(value: string): void{
    console.log('You submitted value: ', value);
  }
}//class DemoFormWithCustomValidation ends here.

/* Custom validation. We are customizing validation using the  function
skuValidator given below. We want the sku to begin with numbers 123
so we will make sure in the funciton below that the sku begins with numbers.
 The function returns a StringMap<string, boolean> where the key is
 "error code" and the value is "true" if the validator fails.
 */
function skuValidator(control: Control): {[s: string]: boolean}{
  if(!control.value.match(/^123/)){
    return {invalidSku: true};
  }
}

Angular Js - Lesson 9 - Forms_4 - validators

Non-instance variable version of validated Control code

Creating an instance variable for every input tag on a form is verbose. In the code below we do not use sku: AbstractControl as we did in the previous example as we are not creating instance for an input tag in our form here. Since we are not exposing the sku control as an instance variable we have to get a reference to sku using myForm.find or ngFormControl directive. The method .find allows us to look up a child control by path so we can use it like this. myForm.find('sku').touched. Another way to get a reference to sku is via the ngForm export of the ngFormControl directive. ngFormControl exports itself as ngForm so we can use this export by using the #reference syntax like this. 
#sku = ngForm
But it should be kept in mind that sku is now an instance of ngFormControl directive
 and that sku is not a control. To get a reference to the control we do as sku.control as shown in the following line.
!sku.control.valid which checks if the related input control is valid. Similarly ku.control.touched checks if the related input control has been made dirty. 

Note that local references that we create using the #reference syntax are only available to sibling and children elements but not parents. The following code will not work because the <div class="field" is a parent of the input element that declares the reference.
<div class="field" [class.error]="!sku.control.valid && sku.control.touched">

Here is the complete code.

import { Component } from 'angular2/core';
import {
  ControlGroup,
  FormBuilder,
  Validators,
  CORE_DIRECTIVES,
  FORM_DIRECTIVES
} from 'angular2/common';

@Component({
  selector: 'demo-form-with-validations-shorthand',
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
    <div class="ui raised segment">
      <h2 class="ui header">Demo Form: with validations (shorthand)</h2>
      <form [ngFormModel]="myForm"
            (ngSubmit)="onSubmit(myForm.value)"
            class="ui form">
        <div class="field"
              [class.error]="myForm.find('sku').touched && !myForm.find('sku').valid">
          <label for="skuInput">
            SKU
          </label>
          <input type="text"
                 id="skuInput"
                 placeholder="SKU"
                 #sku="ngForm"
                 [ngFormControl]="myForm.controls['sku']">
            <div *ngIf="!sku.control.valid"
                 class="ui error message">
              SKU is invalid.
            </div>
            <div *ngIf="sku.control.hasError('required')"
                  class="ui error message">
              SKU is required.
            </div>    
        </div>
        <div *ngIf="!myForm.valid"
              class="ui error message">
          Form is invalid.
        </div>
        
        <button type="submit" class="ui button">
          Submit
        </button>
      </form>    
    </div>
  `
})
export class DemoFormValidationsShorthand{
  myForm: ControlGroup;
  
  constructor(fb: FormBuilder){
    this.myForm = fb.group({
      'sku': ['', Validators.required]
    });
  }//constructor ends here.
  
  onSubmit(value: any){
    console.log('You submitted value: ', value.sku);
  }
}//class DemoFormValidationsShorthand ends here.

Friday, 29 April 2016

Angular Js - Lesson 9 - Forms_3 - validators

Validators in Angular Js 2



/*
Validators to validate the form controls.
Using FormBuilder in this example.
We are using just one input field in this form.
Explicitly setting the sku Contorl as an instance variable in the controller. This is the
most flexible way to deal with individual controls in the view as we set up an instance
variable for each control in the class in which we define this component.
 */
import { Component } from 'angular2/core';
import {
  ControlGroup,
  AbstractControl,
  FormBuilder,
  Validators,
  FORM_DIRECTIVES,
  CORE_DIRECTIVES
} from 'angular2/common';

@Component({
  selector: 'demo-form-with-validations-explicit',
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
    <div class:"ui raised segement">
      <h2 class:"ui header">Demo Form: with validations (explicit)</h2>
     
      <form [ngFormModel]="myForm"
            (ngSubmit)="onSubmit(myForm.value)"
            class="ui form">
            <!--
              We are using Semantic UI CSS Framework's CSS class .error which means
              if we add the class error to the <div class="field"> it will show the
              input tag with a red border.
              .touched below means  that we only want to show the error if the user
              has tried editing the form. .valid below means that the control is
              invalid now.
            -->
        <div class="field"
             [class.error]="sku.touched && !sku.valid">
          <label for="skuInput">SKU</label>
          <input type="text"
                 id="skuInput"
                 placeholder="sku"
                 [ngFormControl]="sku">
            <div *ngIf="!sku.valid" class="ui error message">
              SKU is invalid.
            </div>
            <div *ngIf="sku.hasError('required')" class="ui error message">
              SKU is required.
            </div>
        </div>
            <div *ngIf="!myForm.valid" class="ui error message">
              Form is invalid.
            </div>
           
            <button type="submit" class="ui button">Submit</button>    
     </form>
    </div>
  `
})

export class DemoFormWithValidationsExplicit{
  myForm: ControlGroup;
  /* There are two ways we can access the validation value in the view:
  1. We can explicitly assign the Control sku to an instance variable of the class and
  this gives easy access to the Control in the view. This is what we are doing in
  this example. The kickback of this method is that we have to creat n number of
  instance variable for n controls.
  Another way is to lookup the Control sku from myForm in the view. This requires
  less work in the Component definiton class but is slightly more verbose in the view.
   */
  sku: AbstractControl;
  /* During injection an instance of FormBuilder will be created and we assign that
  instance to the local variable fb in the arguments to the constructor. */
  constructor(fb: FormBuilder){
    /* We create a ControlGroup by calling method fb.group() which takes an object
    of key-value pairs that specify the controls in this group. */
    this.myForm = fb.group({
      /* We are using FormBuilder therefore, we will using the following syntax.
      Otherwise to assign a validator to a Control object we can simply pass the validator
      to the constructor of that control as given below:
      let control = new Control('sku', Validators.required);
       */
      'sku': ['', Validators.required]
    });
    this.sku = this.myForm.controls['sku'];
  }//constructor ends here.
 
  onSubmit(value: string): void{
    console.log('You submitted value: ', value);
  }
 
}//class DemoFormWithValidationsExplicit ends here.


Thursday, 28 April 2016

Angular Js - Lesson 9 - Forms_1

Angular Js Forms - part 1




Here is the code for the form above.

import { Component } from 'angular2/core';
import { FORM_DIRECTIVES } from 'angular2/common';
/* FORM_DIRECTIVES is a constant that Angular provides for us as a shorthand
to several driectives that are all useful in a form.
FORM_DIRECTIVES includes:
ngControl
ngControlGroup
ngForm
ngModel
....... and many more.
By injecting FORM_DIRECTIVES we can use any of the directives in that list in our view template. */

@Component({
  selector: 'demo-form-sku',
  directives: [FORM_DIRECTIVES],
  /* Since we have injected FORM_DIRECTIVES, therefore, that makes
  ngForm available to our view and will get attached to any
  element that matches their selector. In the template below
  bgForm directive gets automatically attached to the <form> tag
  in the view. This happens behid the scenes.
  */
  /* ngForm gives us two important pieces of functionalities:
  (a). A ControlGroup named ngForm.
  (b). An output (ngSubmit) which we use in our form to call the
  method onSubmit(f.value)
  */
  /* SKU is an abbreviation for Stock Keeping Unit. */
  template: `
  <div class="ui raised segment">
    <h2 class="ui header">Demo Form: Sku</h2>
    <form #f="ngForm"
          (ngSubmit)="onSubmit(f.value)"
          class="ui form">

      <div class="field">
        <label for="skuInput">SKU</label>
        <input type="text"
               id="skuInput"
               placeholder="SKU"
               ngControl="sku">
      </div>

      <button type="submit" class="ui button">Submit</button>
    </form>
  </div>
  `
})
export class DemoFormSku {
  onSubmit(form: any): void {
    console.log('you submitted value:', form);
  }
}