Angular2: Custom toaster / notification service using Angular2 Material Snackbar Component

Standard

Since toasters/notifications are essential component for any connected web application, we have couple of toasters component available in market for angular2, I am using Angular Material Snackbar component.

Usage

Since toasters/notifications are used throughout the application, so its better to define as unified service and then consume it throughout application by injecting service in various controllers.

Pre-Step:

  • Install Angular Material components
npm install --save @angular/material
  • Import the Angular Material NgModule in src/app/app.module.ts
import { MaterialModule } from '@angular/material';
// other imports 
@NgModule({
  imports: [MaterialModule],
  ...
})
export class PizzaPartyAppModule { }
  • Some of the components like md-slide-toggle, md-slider, mdTooltip rely on HammerJS for gestures
npm install --save hammerjs

After installing, import HammerJS on your app’s module. src/app/app.module.ts

import 'hammerjs';
  • If your project is using SystemJS for module loading, you will need to add @angular/material to the SystemJS configuration:
System.config({
  // existing configuration options
  map: {
    ...,
    '@angular/material': 'npm:@angular/material/bundles/material.umd.js'
  }
});

Reference

Step 1 : Create angular material toaster service IN toaster.service.ts:

import { Injectable } from '@angular/core';
import { MdSnackBar } from '@angular/material';

@Injectable()
export class ToasterService {

    constructor(private snackBar: MdSnackBar) {
    }

    showToaster(msg: string) {
        this.snackBar.open(msg, null, {
            duration: 3000,
        });
    }
}

A snack-bar can contain either a string message or a given component.

// Simple message.
let snackBarRef = snackBar.open('Message archived');

// Simple message with an action.
let snackBarRef = snackBar.open('Message archived', 'Undo');

// Load the given component into the snack-bar.
let snackBarRef = snackbar.openFromComponent(MessageArchivedComponent);

Step 2: Register toaster service to main module IN app.module.ts:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { MaterialModule } from '@angular/material';
import 'node_modules/hammerjs/hammer.js';

import { AppComponent } from './app.component';
import { CustomComponent } from './custom.component';
import { ToasterService } from './shared/service/toaster.service';

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,

        //ui module
        MaterialModule.forRoot()
    ],
    declarations: [
        AppComponent,
        CustomComponent 
    ],
    providers: [
        ToasterService
    ],
    bootstrap: [
        AppComponent
    ],
    schemas: [
        CUSTOM_ELEMENTS_SCHEMA
    ]
})

export class AppModule {
}

Step 3: Inject toaster service in controller, let say custom.component.ts:

import { Component, OnInit } from '@angular/core';
import { ToasterService } from '../toaster.service';

@Component({
    selector: 'search-movie',
    templateUrl: '../custom.component.html'
})

export class CustomComponent implements OnInit {

    constructor(
        private toasterService: ToasterService) {
    }

    ngOnInit() {
        this.toasterService.showToaster('Hello World');
    }
}

Output:

 

 

Advertisements

Angular2: Using custom loader / spinner as service in Angular 2 application

Standard

Since loaders/spinners are essential component for any connected web application, we have couple of spinner component available in market for angular2. For spinner’s css, I am using Absolute Center CSS Overlay Spinner By MattIn4D

Usage

Since spinner is used throughout the application, so its better to define it once in index.html and then try to enable/disable through component code. I am also using BehaviorSubject object in service, which is way more awesome and better then observable in many cases, Behavior Subject is a special type of observable so you can subscribe to messages like any other observable. In plain words the variable controlling enabling and disabling the spinner in index.html can be set and observed in service using BehaviorSubject object.

Step 1 : Copy spinner css IN app.component.css file:

.tootlbar-icon {
  padding: 0 14px;
}

.tootlbar-spacer {
  flex: 1 1 auto;
}

/* Absolute Center Spinner */
.loading {
  position: fixed;
  z-index: 999;
  height: 2em;
  width: 2em;
  overflow: show;
  margin: auto;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}

/* Transparent Overlay */
.loading:before {
  content: '';
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.3);
}

/* :not(:required) hides these rules from IE9 and below */
.loading:not(:required) {
  /* hide "loading..." text */
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
  background-color: transparent;
  border: 0;
}

.loading:not(:required):after {
  content: '';
  display: block;
  font-size: 10px;
  width: 1em;
  height: 1em;
  margin-top: -0.5em;
  -webkit-animation: spinner 1500ms infinite linear;
  -moz-animation: spinner 1500ms infinite linear;
  -ms-animation: spinner 1500ms infinite linear;
  -o-animation: spinner 1500ms infinite linear;
  animation: spinner 1500ms infinite linear;
  border-radius: 0.5em;
  -webkit-box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
  box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0, rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
}

/* Animation */

@-webkit-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-moz-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-o-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

Step 2 : Create angular material spinner service IN loader.service.ts:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class LoaderService {
    public status: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

    display(value: boolean) {
        this.status.next(value);
    }
}

Step 3: Register loader service to main module IN app.module.ts:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { MaterialModule } from '@angular/material';
import 'node_modules/hammerjs/hammer.js';

import { AppComponent } from './app.component';
import { CustomComponent } from './custom.component';
import { LoaderService } from './shared/service/loader.service';

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,

        //ui module
        MaterialModule.forRoot()
    ],
    declarations: [
        AppComponent,
        CustomComponent 
    ],
    providers: [
        LoaderService
    ],
    bootstrap: [
        AppComponent
    ],
    schemas: [
        CUSTOM_ELEMENTS_SCHEMA
    ]
})

export class AppModule {
}

Step 4 : Register spinner html inside router-outlet to have its impact on all components IN app.component.html

<router-outlet>
    <span*ngIf="showLoader" class="loading"></span>
</router-outlet>
*wordpress text editor has issue with div tag, you can replace span with tag

Step 5: Inject toaster service inside app.component.ts to show or hide loader

import { Component, OnInit } from '@angular/core';

import { LoaderService } from './shared/service/loader.service';

@Component({
    selector: 'my-app',
    templateUrl: './app/app.component.html',
    styleUrls: ['./app/app.component.css']
})

export class AppComponent implements OnInit {
    showLoader: boolean;

    constructor(
        private loaderService: LoaderService) {
    }

    ngOnInit() {
        this.loaderService.status.subscribe((val: boolean) => {
            this.showLoader = val;
        });
    }
}

Step 6: Consume loader service in controller custom.component.ts:

Just pass ‘true’ in order to display the loader and ‘false’ in order to hide the loader

import { Component, OnInit } from '@angular/core';
import { LoaderService } from '../loader.service';

@Component({
    selector: 'search-movie',
    templateUrl: '../custom.component.html'
})

export class CustomComponent implements OnInit {

    constructor(
        private loaderService: LoaderService) {
    }

    ngOnInit() {
        //http call starts
        this.loaderService.display(true);
        //http call ends
        this.loaderService.display(false);
    }
}

Output:

 

Angular2: Resolve TS5023 Build:Unknown compiler option ‘typeRoots’ and ‘types’ error in Visual Studio

Standard

I installed fresh copy of Visual Studio 2015 update 3 on my secondary machine and try to execute Angular2 project integrated with ASP.NET CORE and came across an issue

TS5023 Build:Unknown compiler option 'typeRoots'
TS5023 Build:Unknown compiler option 'types'

Solution 1:

In VS2015 go to:

Tools -> Options -> Projects and Solutions -> External Web Tools.

uncheck anything that starts with $(VSINSTALLDIR)

Solution 2 (recommended):

Before trying any other option, I just updated Typescript version installed for VS2015 from 2.0.3 to 2.2.0 and this resolve compiler option error, Upgrade to latest version of Typescript by installing executable from MS Official Download link.

Angular2 in ASP.NET MVC Nuget Package

Standard

To install Angular2 Template for MVC & WebAPI, run the following command in the Package Manager Console

Install-Package Angular2-Template-for-MVC-and-WebAPI

This Nuget Package will help you to integrate Angular2 JS framework into ASP.NET MVC or WebAPI applications

Package includes ASP.NET MVC compatible tsconfig.json, typings.json, systemjs.config.js, package.json files. Package also includes client side JS libraries reference and configuration for Angular2, @angular/common, @angular/compiler, @angular/core, @angular/forms, @angular/http, @angular/platform-browser, core-js, lodash, rxjs, systemjs, zone.js. Package also contains sample SPA template implemented according to Angular2 Best Design Guidelines.

File Type INFO:

  1. File1: Package.json file
    package.json identifies npm package dependencies for the project.
    

    2. File2: tsconfig.json file

    This file defines how the TypeScript compiler generates JavaScript from the project’s files.
    

    3. File3: typings.json file

    This file provides additional definition files for libraries that the TypeScript compiler doesn’t natively recognize.
    

    Required Step: Install package.json file

    Open CMD and redirect to your application folder and Using npm from the command line, install the packages listed in package.json with the command:

      > npm install --save --save-dev
    

    wait for the installation to complete

    4. File4: systemjs.config.js file This file provides information to a module loader about where to find application modules, and registers all the necessary packages.

Project Usage:

  1. Folder name “App” in Scripts folder

    2. Application module file (App/app.module.ts)

    Angular itself is split into separate Angular Modules. This makes it possible for you to keep payload size small by only importing the parts of Angular that your application needs.Every Angular application has at least one module: the root module, named AppModule here.

    3. Component & add it to your application (App/app.component.ts)

    Every Angular application has at least one component: the root component, named AppComponent here.Components are the basic building blocks of Angular applications. A component controls a portion of the screen—a view—through its associated template.

    4. Start up file (App/main.ts)

    Now we need to tell Angular to start up your application.

    5. Index.cshtml in View Folders contain angular 2 directive

     <my-app>Loading...</my-app>
    

    6. _Layout.cshtml contain angular2 script reference and system.js startup configuration

     http://../../node_modules/core-js/client/shim.min.js
     http://../../node_modules/zone.js/dist/zone.js
     http://../../node_modules/reflect-metadata/Reflect.js
     http://../../node_modules/systemjs/dist/system.src.js
    
     <!-- 2. Configure SystemJS -->
     http://../../systemjs.config.js
     
         System.import('../../Scripts/App/main').catch(function (err) {
             console.error(err);
         });
     
    

Angular2: Using Speech Recognition of Web Speech API in Angular2

Standard

Speech Recognition functionality of the Web Speech API in Angular2 application

Speech Recognition

Speech recognition involves receiving speech through a device’s microphone, which is then checked by a speech recognition service against a list of grammar (basically, the vocabulary you want to have recognised in a particular app.) When a word or phrase is successfully recognised, it is returned as a result (or list of results) as a text string, and further actions can be initiated as a result.

The Web Speech API has a main controller interface for this — SpeechRecognition — plus a number of closely-related interfaces for representing grammar, results, etc. Generally, the default speech recognition system available on the device will be used for the speech recognition — most modern OSes have a speech recognition system for issuing voice commands. Think about Dictation on Mac OS X, Siri on iOS, Cortana on Windows 10, Android Speech, etc.


Chrome support

As mentioned earlier, Chrome currently supports speech recognition with prefixed properties, therefore at the start of our code we include these lines to feed the right objects to Chrome, and non-prefix browsers, like Firefox:

var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
var SpeechGrammarList = SpeechGrammarList || webkitSpeechGrammarList
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent  

Properties

  • SpeechRecognition.lang: Sets the language of the recognition. Setting this is good practice, and therefore recommended.
  • SpeechRecognition.interimResults: Defines whether the speech recognition system should return interim results, or just final results. Final results are good enough for this simple demo.
  • SpeechRecognition.maxAlternatives: Sets the number of alternative potential matches that should be returned per result.
          recognition.continuous = false;
          recognition.lang = 'en-US';
          recognition.interimResults = false;
          recognition.maxAlternatives = 1;
    

Event handlers

  • SpeechRecognition.onaudiostartFired when the user agent has started to capture audio.
  • SpeechRecognition.onaudioendFired when the user agent has finished capturing audio.
  • SpeechRecognition.onendFired when the speech recognition service has disconnected.
  • SpeechRecognition.onerrorFired when a speech recognition error occurs.
  • SpeechRecognition.onnomatchFired when the speech recognition service returns a final result with no significant recognition. This may involve some degree of recognition, which doesn’t meet or exceed the confidence threshold.
  • SpeechRecognition.onresultFired when the speech recognition service returns a result — a word or phrase has been positively recognized and this has been communicated back to the app.
  • SpeechRecognition.onstartFired when the speech recognition service has begun listening to incoming audio with intent to recognize grammars associated with the current SpeechRecognition.

Method

  • SpeechRecognition.abort()Stops the speech recognition service from listening to incoming audio, and doesn’t attempt to return a SpeechRecognitionResult.
  • SpeechRecognition.start()Starts the speech recognition service listening to incoming audio with intent to recognize grammars associated with the current SpeechRecognition.
  • SpeechRecognition.stop()Stops the speech recognition service from listening to incoming audio, and attempts to return a SpeechRecognitionResult using the audio captured so far.

Starting the speech recognition

recognition.start();

Receiving and handling results

recognition.onresult = function(event) {
  var last = event.results.length - 1;
  console.log(event.results[last][0].transcript);
  console.log('Confidence: ' + event.results[0][0].confidence);
}

The SpeechRecognitionEvent.results property returns a SpeechRecognitionResultList object containing SpeechRecognitionResult objects. It has a getter so it can be accessed like an array — so the [last] returns the SpeechRecognitionResult at the last position. Each SpeechRecognitionResult object contains SpeechRecognitionAlternative objects that contain individual recognised words. These also have getters so they can be accessed like arrays — the [0] therefore returns the SpeechRecognitionAlternative at position 0

Stopping the speech recognition

recognition.stop(); 

Handling error in the speech recognition

SpeechRecognition.onerror handles cases where there is an actual error with the recognition successfully — the SpeechRecognitionError.error property contains the actual error returned:

recognition.onerror = function(event) {
  console.log(event.error);
}

Web Speech API in Angular2

See extended DEMO on Github

Angular2 Service using Web Speech API

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import * as _ from "lodash";

interface IWindow extends Window {
    webkitSpeechRecognition: any;
    SpeechRecognition: any;
}

@Injectable()
export class SpeechRecognitionService {
    speechRecognition: any;

    constructor(private zone: NgZone) {
    }

    record(): Observable<string> {

        return Observable.create(observer => {
            const { webkitSpeechRecognition }: IWindow = <IWindow>window;
            this.speechRecognition = new webkitSpeechRecognition();
            //this.speechRecognition = SpeechRecognition;
            this.speechRecognition.continuous = true;
            //this.speechRecognition.interimResults = true;
            this.speechRecognition.lang = 'en-us';
            this.speechRecognition.maxAlternatives = 1;

            this.speechRecognition.onresult = speech => {
                let term: string = "";
                if (speech.results) {
                    var result = speech.results[speech.resultIndex];
                    var transcript = result[0].transcript;
                    if (result.isFinal) {
                        if (result[0].confidence < 0.3) {
                            console.log("Unrecognized result - Please try again");
                        }
                        else {
                            term = _.trim(transcript);
                            console.log("Did you said? -> " + term + " , If not then say something else...");
                        }
                    }
                }
                this.zone.run(() => {
                    observer.next(term);
                });
            };

            this.speechRecognition.onerror = error => {
                observer.error(error);
            };

            this.speechRecognition.onend = () => {
                observer.complete();
            };

            this.speechRecognition.start();
            console.log("Say something - We are listening !!!");
        });
    }

    DestroySpeechObject() {
        if (this.speechRecognition)
            this.speechRecognition.stop();
    }

}

Component using above service

import { Component, OnInit, OnDestroy} from '@angular/core';
import { SpeechRecognitionService } from './speech-recognition.service';

@Component({
    selector: 'my-app',
    templateUrl: './App/app.component.html'
})

export class AppComponent implements OnInit, OnDestroy {
    showSearchButton: boolean;
    speechData: string;

    constructor(private speechRecognitionService: SpeechRecognitionService) {
        this.showSearchButton = true;
        this.speechData = "";
    }

    ngOnInit() {
        console.log("hello")
    }

    ngOnDestroy() {
        this.speechRecognitionService.DestroySpeechObject();
    }

    activateSpeechSearchMovie(): void {
        this.showSearchButton = false;

        this.speechRecognitionService.record()
            .subscribe(
            //listener
            (value) => {
                this.speechData = value;
                console.log(value);
            },
            //errror
            (err) => {
                console.log(err);
                if (err.error == "no-speech") {
                    console.log("--restatring service--");
                    this.activateSpeechSearchMovie();
                }
            },
            //completion
            () => {
                this.showSearchButton = true;
                console.log("--complete--");
                this.activateSpeechSearchMovie();
            });
    }

}

Usage

Before using project Install dependencies by typing below command in CMD:

npm install --save --save-dev

Output

Initial State:

screenshot_19

Example1:

screenshot_20

Example2:

screenshot_21

Reference

Text Reference.

API Reference

Angular2: Error – Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’.

Standard

In order to implement two way binding in Angular2 application, you have to use [(ngModel)] binding in html code, but in case if you have receive below error:

“Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’.”

screenshot_18

Solution:

You need to import the FormsModule package in your Angular module

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,
        FormsModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [
    ],
    bootstrap: [
        AppComponent
    ]
})

export class AppModule {
}

Angular2: Error in firefox – EXCEPTION: SyntaxError: JSON.parse: unexpected character of the JSON data

Standard

While working with webservices in Angular2 using promises or observable, if you have receive below issue in Firefox browser, it is most likely, you need to set accept header in http get/post request

“EXCEPTION: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data”

Solution:

You need to append Accept headers to your get request in order for Firefox to render the json that comes back.

In the headers object, the Content-Type specifies that the body represents JSON. The headers object is used to configure the options object. The options object is a new instance of RequestOptions, a class that allows you to specify certain settings when instantiating a request. In this way, headers is one of the RequestOptions.

In the return statement, options is the third argument of the post method, as shown above.

    ngOnInit() {
        let headers = new Headers();
        headers.append('Accept', 'q=0.8;application/json;q=0.9');
        return this.http.get(this.url, { headers: headers } )
                   .map(data => console.log(data.json()))
                   .subscribe(err => console.log(err));
    }