Welcome again folks!
This is in continuation of a previous blog where we created Task List crud - POC in Node, Express, mongo and Angular 1.x. We will follow the same back-end and will try to build a new front-end using Angular4.
After adding the dependency add two lines to index.js as:
and soon after the app is defined, add cors to app as:
and start the server by "node index.js" You will get the server running on 8082 with enabled CORS.
This will install the angular-cli tool globally on your system.
This will create a new app under the projects directory. The app name will be task-poc as passed in argument. Once this is done you will get a basic app in place. Let's see into the application whats in there for us:
task-poc
|--- e2e (used for end to end test cases)
|--- node_modules (all the dependencies and build tools)
|--- src (The main app we will be modifying this section)
| |--- app (The app where components needs to be added)
| | |--- app.component.* (a default component js/html/css)
| | |--- app.module.ts (The main app module)
| |--- assests (assest container)
| |--- environments (production/development env)
| |--- index.html (view entry point)
| |--- main.ts (bootstrapping app)
| |--- polyfill.ts (fills the gap between app and browser support)
| |--- styles.css (master styles all themes and vendor css needs to be imported here)
|--- package.json and other config files for ts etc (config files for dependency and development)
To run the app just go inside task-poc folder. I will be now on referring to /task-poc as root and hit ng serve
The application will be served at localhost:4200 and the default component will be displayed as in app.component.*
cdk refers to the component development kit. Once done you will see dependencies added under /node_modules/@angular/material.
Some of the material components works well in presence of hammer.js, so let's just go ahead and add hammer js as a dependency too:
Done with all the dependencies, now its time to use them in application. Let's do it very carefully and in a modular fashion.
Let's add the BrowserAnimationsModule and hammerjs to app.module.ts which helps for animations and material support respectively:
After import we need to pass in dependency as imports dependency component:
Now after the basic dependencies are added, it's time to add the material component dependency. However, we can import material dependency here and add in imports. But to follow a modular approach, we will separate the imports of all material related components in an isolated file. And then use it as a bundled dependency in app.module.ts.
So, let's create a file say app.dependencies.ts under /src/app where we will import and export all the dependencies which can be used in main module.ts. The file will look as:
As we have a bundled dependency in the form of app.dependencies.ts, let's add this to main module in app.module.ts as:
After adding material components and browser support dependencies, it's time to add some styles/icons in the src/index.html as:
While in src/styles.css let's add a default material theme as:
The theme was installed with angular material. You can choose any of the installed theme or add your own custom theme.
Till now if everything was done as mentioned, then your ng serve should be successfully running on localhost:4200.
Let's remove the content of the default app.component.html and place our own routing there. To do so first we will create 3 different components under src/app as:
src/app
|--- tasks
|--- new-task
|--- edit-task
Go to the location src/app in command prompt and do:
A tasks folder will be created inside app/ and it's relevant ts/html/css/spec file as well. Now go inside tasks folder and create 2 new components, new-task and edit-task, as:
This will generate all the necessary files for both components, new-task and edit-task, under respective folders. Let's create a service class so that we have a factory which will consume the REST APIs. Hence, be on the same path of terminal and create a folder called service followed by ng generate service as:
This will generate service class under \service where we will consume REST APIs.
Now, we have all the components in place. Let's add routing and verify the same. To add routing first, we need to remove default html of app/app.component.html and replace it with:
router-outlet is the underlying template for routing here. As we have added routing base, we need to inject few dependencies to app/app.module.ts and also define routes. To do so add the following to app.module.ts as:
Note : Components might be auto added while creation, so just RouterModule needs to be added explicitly
For checking validity of the app to be free from errors, go to the root folder in command prompt and do "ng serve" Check following url's:
Each one of them should load with its respective component.
Well done so far!
Now let's go ahead and modify the tasks component to load the task list by default. Before doing so, we first need to load the httpModule dependency to module app, so that we can use http calls. To do so we need to edit file app.module.ts as:
Now we can use the http module to make server calls. TypeScript is a strictly typed language. Hence, once we have data from the server we need to map it to a dataType. Instead of using <any> dataType let's create a class Task which will have the relevant properties defined in it. To do so go to path src/app/tasks and do:
This will generate an empty class file Task under tasks\ modify it to:
This means, Task is an object which will have these four properties, so now we have a new type called Task.
Let's, first create service for all calls. Hence, modify the file app\tasks\service\tasks.service.ts as:
Here, server calls are resolved as Observables instead of the previously used Promises. Observable resolves to the dataType provided in argument. You can see Task[ ], Task and <any> are used. It can be any particular dataType as String, Boolean, etc. or even a custom class like Task.
Having done the data gathering part, it's time to render it on html view. Hence, do the required changes to app/tasks/tasks.component.html:
Notable things here include :
Note how model binding is done using [(ngModel)] and click events using (click)="fn()"
new-task.component.ts:
As we have already gone through the concepts of providers and using services in list view section,
I think much of code here now is self explanatory
Although, much of the code is derived from the new task component still we will focus on one thing specifically:
If all goes well, you will get the development build inside /dist folder. Don't be surprised as Angular converts all the bundle in just five files. All the styles wrapped and bundled size would also be highly optimized other than for vendor.bundle.
Let's try production build to do so run:
Now, check the size of /dist folder and number of files. You cannot be more happy than ever as a developer experiencing this :).
Thank you guys. I hope you have enjoyed the post and it was a helpful session. Reminding you again to see the code in action visit here and for source code at github
Please don't forget to comment, like and share this article.
Happy coding! :)
This is in continuation of a previous blog where we created Task List crud - POC in Node, Express, mongo and Angular 1.x. We will follow the same back-end and will try to build a new front-end using Angular4.
Pre-requisite :
- People who have gone through PART1 know the dependency which was mentioned, rest who are starting from here please go through the pre-requisite of PART1 session.
- You need to have angular-cli installed. We will use it to scaffold our application and for development and production builds as well.
What are we going to build?
We'll be building the same Task Crud application as we did in previous session, but with upgraded version of Angular and Material design. The source code for the application can be found at github and to see the app in action visit the DEMO.
Getting started:
To get started we will require a back-end enabled with REST APIs. Let's use the same old Task Server from previous session. You can download the source code and run server with mongo DB up.
Just a minor change in index.js. We shall enable CORS as we will be running our angular development on different PORT. To do so go into the root folder of the download source and install cors dependency as npm.
Just a minor change in index.js. We shall enable CORS as we will be running our angular development on different PORT. To do so go into the root folder of the download source and install cors dependency as npm.
D:\projects\task-crud > npm install cors --save
After adding the dependency add two lines to index.js as:
var cors = require('cors')
and soon after the app is defined, add cors to app as:
app.use(cors())
and start the server by "node index.js" You will get the server running on 8082 with enabled CORS.
Getting started with Angular4:
Prior to Angular2/4 it was highly preferred to write code in Javascript, ES5, ES6. Although, it served the purpose but maintainability was an issue in long run. Thanks to the Angular folks they came up with this idea of web components and strict mode. Soon the preference shifted to Typescript as the primary language for developing the angular apps. Enabled strict mode and its robust nature of language made application maintainable in the long run.
Scaffolding a bare app:
Angular-cli to the rescue, we don't need to worry much about that, just install the cli tool. If you have node and npm installed then just hit:
C:\ > npm install -g @angular/cli
This will install the angular-cli tool globally on your system.
Create new app:
Once you're done with the cli tool, it's time to create our app. Go to the project work-space location in command prompt and do:
D:\projects > ng new task-poc
This will create a new app under the projects directory. The app name will be task-poc as passed in argument. Once this is done you will get a basic app in place. Let's see into the application whats in there for us:
task-poc
|--- e2e (used for end to end test cases)
|--- node_modules (all the dependencies and build tools)
|--- src (The main app we will be modifying this section)
| |--- app (The app where components needs to be added)
| | |--- app.component.* (a default component js/html/css)
| | |--- app.module.ts (The main app module)
| |--- assests (assest container)
| |--- environments (production/development env)
| |--- index.html (view entry point)
| |--- main.ts (bootstrapping app)
| |--- polyfill.ts (fills the gap between app and browser support)
| |--- styles.css (master styles all themes and vendor css needs to be imported here)
|--- package.json and other config files for ts etc (config files for dependency and development)
To run the app just go inside task-poc folder. I will be now on referring to /task-poc as root and hit ng serve
D:\projects > cd task-poc
D:\projects\task-poc > ng serve
D:\projects\task-poc > ng serve
The application will be served at localhost:4200 and the default component will be displayed as in app.component.*
Add Material dependency:
To add material first we need to add it as a dependency of npm:
D:\projects\task-poc > npm install --save @angular/material
D:\projects\task-poc > npm install --save @angular/cdk
D:\projects\task-poc > npm install --save @angular/cdk
cdk refers to the component development kit. Once done you will see dependencies added under /node_modules/@angular/material.
Some of the material components works well in presence of hammer.js, so let's just go ahead and add hammer js as a dependency too:
D:\projects\task-poc > npm install --save hammerjs
Done with all the dependencies, now its time to use them in application. Let's do it very carefully and in a modular fashion.
Let's add the BrowserAnimationsModule and hammerjs to app.module.ts which helps for animations and material support respectively:
import 'hammerjs';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
After import we need to pass in dependency as imports dependency component:
imports: [
BrowserModule,
BrowserAnimationsModule
]
Now after the basic dependencies are added, it's time to add the material component dependency. However, we can import material dependency here and add in imports. But to follow a modular approach, we will separate the imports of all material related components in an isolated file. And then use it as a bundled dependency in app.module.ts.
So, let's create a file say app.dependencies.ts under /src/app where we will import and export all the dependencies which can be used in main module.ts. The file will look as:
//main core module
import { NgModule } from '@angular/core';
//importing all required material components <you can import more also>
import {MdInputModule, MdButtonModule, MdCheckboxModule, MdCardModule, MdDatepickerModule, MdNativeDateModule, MdIconModule} from '@angular/material';
//importing forms module required for binding data to models
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
],
imports: [
MdInputModule,
MdButtonModule,
MdCheckboxModule,
MdCardModule,
MdDatepickerModule,
MdNativeDateModule,
FormsModule,
MdIconModule
],
exports:[
MdInputModule,
MdButtonModule,
MdCheckboxModule,
MdCardModule,
MdDatepickerModule,
MdNativeDateModule,
FormsModule,
MdIconModule
],
providers: [],
bootstrap: []
})
export class DependencyModule {}
As we have a bundled dependency in the form of app.dependencies.ts, let's add this to main module in app.module.ts as:
//importing the DependencyModule
import { DependencyModule } from './app.dependencies';
//adding it to imports
imports: [
BrowserModule,
BrowserAnimationsModule,
DependencyModule
]
After adding material components and browser support dependencies, it's time to add some styles/icons in the src/index.html as:
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
While in src/styles.css let's add a default material theme as:
@import '../node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
The theme was installed with angular material. You can choose any of the installed theme or add your own custom theme.
Till now if everything was done as mentioned, then your ng serve should be successfully running on localhost:4200.
Let's remove the content of the default app.component.html and place our own routing there. To do so first we will create 3 different components under src/app as:
src/app
|--- tasks
|--- new-task
|--- edit-task
Go to the location src/app in command prompt and do:
D:\projects\task-poc\src\app > ng generate component tasks
A tasks folder will be created inside app/ and it's relevant ts/html/css/spec file as well. Now go inside tasks folder and create 2 new components, new-task and edit-task, as:
D:\projects\task-poc\src\app\tasks > ng generate component new-task
D:\projects\task-poc\src\app\tasks > ng generate component edit-task
D:\projects\task-poc\src\app\tasks > ng generate component edit-task
This will generate all the necessary files for both components, new-task and edit-task, under respective folders. Let's create a service class so that we have a factory which will consume the REST APIs. Hence, be on the same path of terminal and create a folder called service followed by ng generate service as:
D:\projects\task-poc\src\app\tasks > mkdir service
D:\projects\task-poc\src\app\tasks\service > ng generate service tasks
D:\projects\task-poc\src\app\tasks\service > ng generate service tasks
This will generate service class under \service where we will consume REST APIs.
Now, we have all the components in place. Let's add routing and verify the same. To add routing first, we need to remove default html of app/app.component.html and replace it with:
<div class='container'>
<router-outlet></router-outlet>
</div>
router-outlet is the underlying template for routing here. As we have added routing base, we need to inject few dependencies to app/app.module.ts and also define routes. To do so add the following to app.module.ts as:
Note : Components might be auto added while creation, so just RouterModule needs to be added explicitly
//Add all the route imports and Router from angular
import { TasksComponent } from './tasks/tasks.component';
import { NewTaskComponent } from './tasks/new-task/new-task.component';
import { EditTaskComponent } from './tasks/edit-task/edit-task.component';
import { RouterModule } from '@angular/router';
//define route
const routes = [
{ path: '', redirectTo: '/tasks', pathMatch: 'full' },
{ path: 'tasks', component: TasksComponent },
{ path: 'tasks/new', component: NewTaskComponent },
{ path: 'tasks/:id', component: EditTaskComponent }
];
//add specific declarations and imports
declarations: [
AppComponent,
TasksComponent,
NewTaskComponent,
EditTaskComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
DependencyModule,
RouterModule.forRoot(routes)
]
For checking validity of the app to be free from errors, go to the root folder in command prompt and do "ng serve" Check following url's:
- localhost:4200 will resolve to http://localhost:4200/tasks,
- http://localhost:4200/tasks/new
- http://localhost:4200/tasks/123456
Each one of them should load with its respective component.
Well done so far!
Now let's go ahead and modify the tasks component to load the task list by default. Before doing so, we first need to load the httpModule dependency to module app, so that we can use http calls. To do so we need to edit file app.module.ts as:
//import the HTTPModule
import { HttpModule } from '@angular/http';
//add it in imports
imports: [
BrowserModule,
HttpModule,
BrowserAnimationsModule,
DependencyModule,
RouterModule.forRoot(routes)
]
Now we can use the http module to make server calls. TypeScript is a strictly typed language. Hence, once we have data from the server we need to map it to a dataType. Instead of using <any> dataType let's create a class Task which will have the relevant properties defined in it. To do so go to path src/app/tasks and do:
D:\projects\task-poc\src\app\tasks > ng generate class task
This will generate an empty class file Task under tasks\ modify it to:
export class Task {
_id: string;
title: string;
desc: string;
taskdt: string;
}
This means, Task is an object which will have these four properties, so now we have a new type called Task.
Let's, first create service for all calls. Hence, modify the file app\tasks\service\tasks.service.ts as:
import { Injectable } from '@angular/core';
//import http and response
import { Http, Response } from '@angular/http';
//Observable for resolving server calls
import { Observable } from 'rxjs';
//Task Class to map the data
import { Task } from '../task';
@Injectable()
export class TasksService {
constructor(private http: Http) { }
//base url
private baseURL = "http://localhost:8082"
private tasksURL = "/task";
//return response data object as json
extractTasks(res: Response) {
return res.json().data;
}
//returns response object as json
extractResponse(res: Response) {
return res.json();
}
//handle server errors
handleError (error: any) {
let errMsg = error.message || 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
//gets all Task return type is array of type Task
getTasks(): Observable<Task[]> {
return this.http.get(this.baseURL + this.tasksURL).map(this.extractTasks).catch(this.handleError);
}
//creates a Task return type is Object
saveTask(task: Task): Observable<any>{
delete task._id;
return this.http.post(this.baseURL + this.tasksURL,task).map(this.extractResponse).catch(this.handleError);
}
//gets a single Task with given id return type of Task
getTask(id: String): Observable<Task>{
return this.http.get(this.baseURL + this.tasksURL + "/" + id).map(this.extractTasks).catch(this.handleError);
}
//updates a task with given id return type Object
editTask(id: String, task: Task): Observable<any>{
delete task._id;
return this.http.put(this.baseURL + this.tasksURL + "/" + id,task).map(this.extractResponse).catch(this.handleError);
}
//deletes a task with given id return type Object
deleteTask(id: String): Observable<any>{
return this.http.delete(this.baseURL + this.tasksURL + "/" + id).map(this.extractResponse).catch(this.handleError);
}
}
Here, server calls are resolved as Observables instead of the previously used Promises. Observable resolves to the dataType provided in argument. You can see Task[ ], Task and <any> are used. It can be any particular dataType as String, Boolean, etc. or even a custom class like Task.
List View
It is responsible for loading data from server and displaying in table. The service layer created above will serve the data.
At first let's modify code for app/tasks/tasks.component.ts - the controller file for list view as:
This will load our tasks. Notice, here we are using subscribe instead of the legacy .then syntax for resolving promises, because as said earlier observables are being used and subscribe is the technique used for resolving observables.At first let's modify code for app/tasks/tasks.component.ts - the controller file for list view as:
//import all required modules service
import { Component, OnInit } from '@angular/core';
import { Task } from './task';
import { TasksService } from './service/tasks.service';
@Component({
selector: 'app-tasks',
templateUrl: './tasks.component.html',
styleUrls: ['./tasks.component.css'],
providers: [TasksService] //pass the provider
})
export class TasksComponent implements OnInit {
tasks: Task[]; //define a variable tasks of type Task array
//initialize service in constructor
constructor(private service: TasksService) {
}
//on init hook
ngOnInit() {
this.tasks = [];
this.loadTasks();
}
loadTasks(){
//Call the service
this.service.getTasks().subscribe((tasks) =>{
this.tasks = tasks;
console.log(this.tasks);
}
);
}
}
Having done the data gathering part, it's time to render it on html view. Hence, do the required changes to app/tasks/tasks.component.html:
<div>
<div *ngIf="tasks.length>0; then table_display else info_display"></div>
<ng-template #table_display>
<md-card>
<div> Total Tasks : <span class="counter">{{tasks.length}}</span> <button class="pull-right" (click)="navigateNew()" md-raised-button color="primary">Add more Tasks</button></div>
<div style="clear: both"></div>
<hr/>
<table class="full-width">
<thead>
<tr>
<th>No.</th>
<th>Title</th>
<th>Description</th>
<th>Date</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let items of tasks;index as i">
<td>{{i+1}}</td>
<td>{{items.title}}</td>
<td>{{items.desc}}</td>
<td>{{items.taskdt | date: 'MM/dd/yyyy'}}</td>
<td> <a [routerLink]="['/tasks', items._id]"><md-icon color="accent" class="icon-td">mode_edit</md-icon></a></td>
<td><md-icon color="warn" class="icon-td" (click)="deleteTask(items._id)">delete_forever</md-icon></td>
</tr>
</tbody>
</table>
<hr/>
</md-card>
</ng-template>
<ng-template #info_display>
<md-card>
<div class="text-center"> No records found click <a [routerLink]="['/tasks', '/new']"> here </a> to insert Tasks.</div>
</md-card>
</ng-template>
<router-outlet></router-outlet>
</div>
Notable things here include :
- If else statement in view - Introduced in Angular4 recently.
- ngFor been used instead of ng-for with defined index.
- routerLink is used instead of ng-href, see how we are passing path and arguments as array.
The template also contains functionality for delete. To enable links and delete functionality we need to add some code to tasks.component.ts
Superb! the listing of Tasks is done. If server is running on 8082 and angular serve on 4200, you will now be able to see the list.
//import router module
import {Router} from '@angular/router';
//adding route in constructor
constructor(private service: TasksService, private router: Router) {
}
//add delete function
deleteTask(id: String){
if(!confirm("This data will be lost permanently. Are you sure you want to delete this data ?"))
return;
this.service.deleteTask(id).subscribe((data) =>{
alert("Data Deleted");
this.loadTasks();
},(err) =>{
alert("Server Error")
}
);
}
//manually route change
navigateNew(){
this.router.navigate(['/tasks/new']);
}
Superb! the listing of Tasks is done. If server is running on 8082 and angular serve on 4200, you will now be able to see the list.
Add Task view:
Having done with list task, we will now focus on adding a task. It requires a form to be implemented in new-task/new-task.component.html and its relevant controller in /new-task.component.ts as follows:
new-task.component.html:
<md-card class="task-form">
<form>
<div>
<md-input-container class="full-width">
<input [(ngModel)]="task.title" mdInput placeholder="Task title" name="title">
</md-input-container>
</div>
<div>
<md-input-container class="full-width">
<textarea [(ngModel)]="task.desc" mdInput placeholder="Task description" name="desc"> </textarea>
</md-input-container>
</div>
<div>
<md-input-container class="full-width">
<input mdInput (focus)="picker.open()" [(ngModel)]="task.taskdt" [mdDatepicker]="picker" placeholder="Task Date" name="taskdt">
<button mdPrefix [mdDatepickerToggle]="picker"></button>
</md-input-container>
<md-datepicker #picker></md-datepicker>
</div>
<div>
<button (click)="saveTask(false)" color="primary" md-raised-button>Save</button>
<button (click)="saveTask(true)" color="accent" md-raised-button>Save and Add More</button>
<button (click)="resetForm()" color="warn" md-raised-button>Reset</button>
<button (click)="cancelForm()" md-raised-button>Cancel</button>
</div>
</form>
</md-card>
Note how model binding is done using [(ngModel)] and click events using (click)="fn()"
new-task.component.ts:
import { Component, OnInit } from '@angular/core';
import { Task } from '../task';
import { TasksService } from '../service/tasks.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-new-task',
templateUrl: './new-task.component.html',
styleUrls: ['./new-task.component.css'],
providers: [TasksService]
})
export class NewTaskComponent implements OnInit {
task : Task;
constructor(private service: TasksService, private router: Router) {
}
ngOnInit() {
this.task = new Task();
}
saveTask(addMore: Boolean) {
this.service.saveTask(this.task).subscribe((data) =>{
this.task = new Task();
alert("Task Saved");
if(!addMore){
this.router.navigate(['/tasks']);
}
},(err) =>{
alert("Server Error")
}
);
}
resetForm(){
this.task = new Task();
}
cancelForm(){
this.router.navigate(['/tasks']);
}
}
As we have already gone through the concepts of providers and using services in list view section,
I think much of code here now is self explanatory
Edit Task view:
It comes in picture when the user clicks on edit section in list view. We will reuse the form from new-task.component.html. Additionally, we will have to code for edit purpose and to load data initially in edit-tasks.component.ts.
edit-task.component.ts:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Task } from '../task';
import { TasksService } from '../service/tasks.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-edit-task',
templateUrl: '../new-task/new-task.component.html',
styleUrls: ['../new-task/new-task.component.css'],
providers: [TasksService]
})
export class EditTaskComponent implements OnInit {
task: Task;
taskID: String;
constructor(private service: TasksService,private route: ActivatedRoute,private router: Router) {
this.task = new Task();
this.taskID = "";
}
getTask(id : String){
this.service.getTask(id).subscribe((data) =>{
this.task = data;
}
);
}
saveTask(addMore: Boolean) {
this.service.editTask(this.taskID,this.task).subscribe((data) =>{
alert("Data modified")
if(!addMore){
this.router.navigate(['/tasks']);
}else{
this.router.navigate(['/tasks/new']);
}
},(err) =>{
alert("Server Error")
}
);
}
ngOnInit() {
this.route.params.subscribe(params => {
if (params['id']) {
this.taskID = params['id']
this.getTask(this.taskID);
}
});
}
resetForm(){
this.task = new Task();
}
cancelForm(){
this.router.navigate(['/tasks']);
}
}
Although, much of the code is derived from the new task component still we will focus on one thing specifically:
- import of ActivatedRoute so that we can get path param, observe the injection in constructor and the usage inside ngOnInit function.
Awesome! ☺
You did a fabulous job! Now we are completely done with angular4 app Task POC. From now you can create your own cool apps in angular4 and rock it.
You did a fabulous job! Now we are completely done with angular4 app Task POC. From now you can create your own cool apps in angular4 and rock it.
Before wrapping things up, I want to give few ideas regarding the build of angular-
Go to the root of the application and hit ng build like this:
D:\projects\task-poc > ng build
Let's try production build to do so run:
D:\projects\task-poc > ng build --target=production
Now, check the size of /dist folder and number of files. You cannot be more happy than ever as a developer experiencing this :).
Thank you guys. I hope you have enjoyed the post and it was a helpful session. Reminding you again to see the code in action visit here and for source code at github
Please don't forget to comment, like and share this article.
Happy coding! :)
Comments
Post a Comment