46

CRUD Operations In Angular

 5 years ago
source link: https://www.tuicool.com/articles/hit/2I3AJfv
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

As seen in myprevious blog, it is possible to make CRUD operations in vanilla javascript however, it is a hard decision to make whether to choose vanilla javascript as it can get messier at some point. Moreover, adding event listeners to dynamically added DOM elements is a pain as we saw. It gets even more complicated for large scale projects.

JJVBfiR.png!webEv26num.png!web

Solution is to use modern frameworks such as Angular, React etc. This blog post is based on the same concept to previous example but using Angular.

This blog assumes that you already installed angular-cli on your machine. Once you have it then create a new application using below command.

ng new ngTodo

Wait for few seconds once the project is created, cd into this project. The first thing we need is to create a new component using below command.

ng generate component todo

This will create a folder with the name todo inside src/app folder. This folder consists of todo.component.ts, todo.component.html, todo.component.css and todo.component.spec.ts files.

All of the javascript will be written in .ts file. Actually TypeScript, that is why file extension is .ts. template code goes to todo.component.html file, styles to todo.component.css. todo.component.spec.ts is for tests.

To get started, first thing needs to be done is to add this component inside “app.component.html” file like so:

<app-todo></app-todo>

Now when you run “ng serve” and load the app in browser, todo component will be loaded.

Now its time to head over to todo.component.ts file.

There should be some boilerplate code written by angular-cli. All of our code goes inside TodoComponent class.

import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
constructor() { }
ngOnInit() { }
}

Lets first explain above boilerplate code. First we import Component decorator and OnInit interface from angular core. Below is the definition of decorator.

Decorator marks a class as an Angular component and allows us to set configuration metadata that determines how the component should be processed, instantiated, and used at runtime.

Whereas

Interface is a lifecycle hook that is called after Angular has initialized all data-bound properties of a directive. Define an ngOnInit() method to handle any additional initialization tasks.

Then we are exporting TodoComponent class to make it available for import in rest of the project. For this example we will only need this component to be imported in app.module.ts to initiate the component. Since we created this component using angular-cli so that part is already taken care of. If you look into app.module.ts file you will see the TodoComponent class is imported and added to declarations array. Lets add some code now.

Just like our previous example, add a mockData property to the class like below.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
// mockData array the includes list of objects with items
  mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
constructor() { }
ngOnInit() { }
}

As you can see that we also added the type “any” to mockData . TypeScript brings strictly type functionality to javascript but in this case that really does not matter. If you leave that part from it, it should still be fine.

Lets add some more properties to this class which will be used later.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
// properties to show hide edit form, set updated value and id.
  show: boolean = false;
  value: string;
  id: number;
constructor() {}
ngOnInit() { }
}

Show property is used to show editForm, value property is used to set the value of edit title whereas id is used to assign the id of currently edited item. We will see this later.

Before going into further discussion. Lets add some html template that we are going to use.

<div class="sections">
  <div class="edit-popup" *ngIf="show">
    <input type="text" name="" class="edit-item" value="{{value}}" #item>
    <button class="btn-update" (click)="update(item.value)">Update</button>
  </div>
<input type="text" name="" class="item" #item>
  <button class="btn-add-item" (click)="create(item.value)">Add</button>
<ul>
    <li *ngFor="let item of mockData">
      <span [ngClass]="{'done': item.done}">{{item.title}}</span>
      <button (click)="remove(item.id)">Delete</button>
      <button (click)="edit(item.id, item.title)">Edit</button>
      <button (click)="setTaskComplete(item.id)">Complete</button>
    </li>
  </ul>
</div>

This is where a bunch of differences can be seen. The first thing that is noticeable is “edit-popup”. It has *ngIf conditional directive which shows and hides this piece of html code based on the value of “show” which is either true or false. That is the property that comes from TodoComponent we setup earlier.

Then simply put the value i.e. title using {{}} braces inside input text field. Finally add click event which will call update function and pass the value of input field as argument.

Then ul list which shows all items. As you can see li element has *ngFor which is a repeater directive . It loops through mockData and inside it we access current object and display its title.

[ngClass] directive adds the done class to li item based on the value of done property of the item. If it is true add done class which puts line-trough on li item to indicate this task is achieved.

It also has its buttons which are Delete, Edit and Complete buttons. And each of them has click events which call its respective function and pass current item’s id. In edit function alongside id, title is also passed as argument.

So thats it for the template. Lets head back to TodoComponent. Here we do not need any render function which we had in vanilla javascript. mockData list and *ngFor directive does the job for rendering. So the R part of CRUD is done. Run the angular server using “ng serve” and load the application in your browser and you should have similar result like below:

aIzmYvY.png!webVRVFNnu.png!web

Lets head to create function which is C in CRUD.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [

    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }];
show: boolean = false;
  value: string;
  id: number;
constructor() {}
// Create function to create new item.
  create(item) {
    this.mockData.push({
      id: Date.now(),
      title: item,
      done: false,
      date: new Date()
    });
  }
ngOnInit() { }
}

Create function is triggered when ADD button is clicked from template. This is very easy to understand and follow. First it accesses the mockData array using this keyword and push a new object with appropriate properties i.e. id, title, done and date etc. This will do the job.

NVNBJbe.png!webInMzArf.png!web

Refresh your browser and type “This is new item” and press ADD button similar result like above.

Now lets head to remove/delete function which is D part of CRUD.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
show: boolean = false;
  value: string;
  id: number;
constructor() {}
create(item) {
    this.mockData.push({
      id: Date.now(),
      title: item,
      done: false,
      date: new Date()
    });
  }
// delete/remove function goes here.
  remove(id) {
    this.mockData = this.mockData.filter(item => {
      if (item.id !== id) {
        return item;
      }
    });
  }
ngOnInit() { }
}

Again very simple. Filter through mockData and find the current element using the item’s id that is to be deleted and id of current element from mockData . And return all the items except the one that matches this element.

Refresh your browser and delete the first item from the list. It should be deleted from the screen as below:

6V3mumb.png!webaYVrum6.png!web

For update, again, same as vanilla javascript example , edit is part of two steps. First show edit form and second update the item. First let’s show edit form which is “edit-popup”

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
show: boolean = false;
  value: string;
  id: number;
constructor() {}
create(item) {
    this.mockData.push({
      id: Date.now(),
      title: item,
      done: false,
      date: new Date()
    });
  }
remove(id) {
    this.mockData = this.mockData.filter(item => {
      if (item.id !== id) {
        return item;
      }
    });
  }
// this function does the same as renderEditForm in previous blog.
  edit(id, title) {
    this.show = true;
    this.value = title;
    this.id = id;
  }
ngOnInit() { }
}

Above function simply set some TodoComponent attributes that is set this.show to true which display’s the form. Set the value of this.value to item’s title that is to be updated and set this.id to item’s id. All these attributes can then be accessed in template and we use them accordingly.

Now press the EDIT button for first item and you should be able to view edit form appear at the top of the page:

Z3amaqF.png!webYjaaeyf.png!web

Now its time to write update function that actually performs update operation WHICH is U part of CRUD.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
show: boolean = false;
  value: string;
  id: number;
constructor() {}
create(item) {
    this.mockData.push({
      id: Date.now(),
      title: item,
      done: false,
      date: new Date()
    });
  }
remove(id) {
    this.mockData = this.mockData.filter(item => {
      if (item.id !== id) {
        return item;
      }
    });
  }
edit(id, title) {
    this.show = true;
    this.value = title;
    this.id = id;
  }
// function that performs update 
  update(title) {
    this.mockData.map(item => {
      if (item.id === this.id) {
        item['title'] = title;
      }
    });
this.show = false;
  }
ngOnInit() { }
}

This function get’s title i.e. the value of updated input text field as argument. Then map through mockData and place a check to find the item that needs to be updated based on id. Once found replace the title property with the edited one and set this.show to false to hide edit form.

With this part when you press the UPDATE button, after entering updated title, you should see updated title like this:

uQviymb.png!weba6N32uQ.png!web

Final part is to mark task as done function which is below.

import { Component, OnInit } from '<a href="http://twitter.com/angular/core" data-href="http://twitter.com/angular/core" title="Twitter profile for @angular/core" rel="nofollow noopener" target="_blank">@angular/core</a>';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
mockData: any = [
    {
      id: '1',
      title: 'Buy Milk.',
      done: false,
      date: new Date()
    }, {
      id: '2',
      title: 'Meeting with Ali.',
      done: false,
      date: new Date()
    }, {
      id: '3',
      title: 'Tea break.',
      done: false,
      date: new Date()
    }, {
      id: '4',
      title: 'Go for a run.',
      done: false,
      date: new Date()
    }
  ];
show: boolean = false;
  value: string;
  id: number;
constructor() {}
create(item) {
    this.mockData.push({
      id: Date.now(),
      title: item,
      done: false,
      date: new Date()
    });
  }
remove(id) {
    this.mockData = this.mockData.filter(item => {
      if (item.id !== id) {
        return item;
      }
    });
  }
edit(id, title) {
    this.show = true;
    this.value = title;
    this.id = id;
  }
update(title) {
    this.mockData.map(item => {
      if (item.id === this.id) {
        item['title'] = title;
      }
    });
this.show = false;
  }
setTaskComplete(id) {
    this.mockData.map(item => {
      if (item.id === id) {
        item['done'] = true;
      }
    });
  }
ngOnInit() {
  }
}

This does pretty much the same stuff. map through mockData and find the item to be set as done based on id and set its done property to true.

Finally, add some css in todo.component.css file below.

.done {
  text-decoration: line-through;
}

Above CSS adds line-through to any element that has done class, in this case tasks that are achieved.

After this press a couple of Complete buttons and you should see something similar like this:

RBVvYj3.png!webNnQrmue.png!web

As you can see the difference between this example and the previous one using vanilla javascript. Angular allows us to write easy to understand and maintained and scaled approach which is beneficial in large scale applications. Whereas Vanilla JavaScript does the job but really gets complicated once application grows.

To get all the code written in this example then go ahead and clone below repository.

https://github.com/zafar-saleem/ngTodo


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK