In this tutorial we’ll create a new Angular 10 Crud app, write the Data Service and Crud Components. Next we’ll create the Form Service to consume the structure API and generate CRUD modals.
Disclaimer
I don’t suggest this is the best way to do it, this is the simplest way to do it. Feel free to show me the right way 🙂
I like modals.
Prerequisites:
- First part of this tutorial
- Node.js — download
- I will be using Visual Studio Code — download, but you are welcome to use anything you like
- We’ll be using npm to install the Angular CLI:
npm install -g @angular/cli
Creating the Angular 10 Crud App
Run the CLI command ng new
and provide whatever name you like, select No for Angular routing and SCSS for stylesheet format
ng new my-pets
To run the app you need to navigate to the workspace folder and run the command ng serve -o
,the -o
option automatically opens your browser to http://localhost:4200/
.
cd my-pets
ng serve -o
If everything was successful, you should see a page similar to the following.

Install Angular Material
To set up your Angular Material project, use the following command :
ng add @angular/material
Create the Data Service
Generate a new service using the command ng g s
and the name of the service:
ng g s data
In data.service.ts
import HttpClient from @angular/common/http
and pass it into constructor
Let’s initialize a new constant with the dogs api endpoint url:
private url = 'http://localhost:5000/dogs
'
And add methods for Create, Read, Update and Delete:
Read Component and Service
Generate a new component using the command ng g c
and the name of the component:
ng g c read
And a new service in the read folder:
ng g s read/read
I told you I like modals so in order to use the Angular Material Dialog, we will first need to import MatDialogModule
in app.module.ts
Let’s start with read.service.ts
:
It is not recommended to import components in services. It will be changed in next parts. We also need to import MatDialog
from @angular/material/dialog
and pass it into constructor
We need to add the open method, which will be called to open the ReadComponent
:
open() {
this.dialog.open(ReadComponent)
}
In read.component.ts
the first thing we need is to import the Data Service and pass it to the constructor:
import {DataService} from '../data.service' constructor( public dataService:DataService ) {}
We need to declare an Array to keep the data, let’s name it items
, and then we create the loadData
method and call it on ngOnInit()
:
items:Array=[] ngOnInit() { this.loadData() } loadData(){ this.dataService.getAll().subscribe(data=> this.items = data["_items"]) }
Inside read.component.html
we need to create a table to display data from the dogs api endpoint:
<h2 mat-dialog-title>View Dogs</h2> <mat-dialog-content> <table> <thead> <tr> <td>Name</td> <td>Description</td> </tr> </thead> <tbody> <tr *ngFor="let item of items"> <td>{{ item.name }}</td> <td>{{ item.description }}</td> </tr> </tbody> </table> </mat-dialog-content> <mat-dialog-actions> <button mat-button color="primary" matDialogClose>Close</button> </mat-dialog-actions>
To test it, we need to import ReadService
inside app.components.ts
, pass it tot the constructor and write the open method:
import { ReadService } from './read/read.service' constructor( private readService:ReadService ){} read(){ this.readService.open() }
Open app.component.html
delete the content and add the following button:
<button (click)="read()">Open Dogs</button>
Let’s try it ng-serve -o
:

If we open the javascript console and click the button we will see the following error, but the modal works:

Access to XMLHttpRequest at 'http://localhost:5000/dogs' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The easiest way I found around this error is to add a proxy:
In my-pets
folder create a new file proxy.conf.json
with the following content:
Add it as a parameter to the start
script, open package.json
and change it like this “start”: “ng serve — proxy-config proxy.conf.json”
Last step is to change the url
variable in data.service.ts
:
private url = 'api/dogs
'
From now we need to run the app with npm start
command
And if everything works we should see the test data from Part 1 :

The read component can also be displayed using it’s selector <app-read></app-read>
:

Create Component and Service
Generate a new component:
ng g c create
And a new service in the create folder:
ng g s create/create
Open create.service.ts
, the only difference between ReadService and this one is that we need to import the CreateComponent and pass it to the MatDialog:
Like in ReadComponent, in create.component.ts
we need to import DataService
and pass it to the constructor. We also need MatDialogRef
from ‘@angular/material/dialog’
and pass it to the constructor, FormGroup
and FormControl
from @angular/forms
;
import { DataService } from '../data.service' import { FormGroup, FormControl } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; constructor( public dataService:DataService, private dialogRef: MatDialogRef<CreateComponent> ) {}
In order to use the FormGroup and FormControl, we will first need to import FormsModule
and ReactiveFormsModule
in app.module.ts
import { FormsModule,ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ ... ReactiveFormsModule, FormsModule ],
Back to read.component.ts
We need to declare a new FormGroup
variable to keep the data, let’s name it myFormGroup
, and then we create the loadForm
method and call it on ngOnInit()
:
myFormGroup: FormGroup ngOnInit() { this.loadForm() } loadForm() { const group = {} group["name"] = new FormControl('') group["description"] = new FormControl('') this.myFormGroup = new FormGroup(group) }
Let’s create the save
method. We will send a FormData object to the api.
First we need to create it and only add to it if the form was filled
save() {
const formData = new FormData()
if (!this.myFormGroup.get("name").untouched) {
formData.append("name", this.myFormGroup.get("name").value)
}
if (!this.myFormGroup.get("description").untouched) {
formData.append("description",
this.myFormGroup.get("description").value)
}
this.dataService.add(formData).subscribe(data => {
console.log(data)
this.dialogRef.close("close");
})
}
Inside create.component.html
:
<h2 mat-dialog-title>Add Dog</h2> <mat-dialog-content> <form [formGroup]="myFormGroup"> <mat-form-field> <mat-label>Nume</mat-label> <input matInput formControlName="name"> </mat-form-field> <mat-form-field> <mat-label>Description</mat-label> <input matInput formControlName="description"> </mat-form-field> </form> </mat-dialog-content> <mat-dialog-actions> <button mat-raised-button color="accent" (click)="save()">Save</button> <button mat-button type="button" color="primary" matDialogClose>Close</button> </mat-dialog-actions>
Before we test it we need to import the following modules from @angular/material
:
import {MatFormFieldModule} from ‘@angular/material/form-field’ import {MatInputModule} from ‘@angular/material/input’ import {MatButtonModule} from ‘@angular/material/button’; @NgModule({ ... imports: [ ... MatFormFieldModule, MatInputModule, MatButtonModule ], ... })
To test it, we need to import CreateService
inside app.components.ts, pass it tot the constructor and write the create method:
import { ReadService } from './read/read.service' import { CreateService } from './create/create.service' constructor( private readService:ReadService private createService:CreateService ){} read(){ this.readService.open() } create(){ this.createService.open() }
Open app.component.html
and add the following button:
<button (click)="create()">Add Dog</button>
We can also add the create method to our ReadComponent, like we did in app.component.ts
, import the CreateService in read.component.ts
, pass it to the constructor and write the create method, then we can open read.component.html
and add the create button
Let’s try it npm start
:

Here are the final Create Component files:
Update Component and Service
Generate a new component:
ng g c update
And a new service in the update folder:
ng g s update/update
This time in update.service.ts
we need to import the UpdateComponent and pass it to the MatDialog. We also need to pass the item we want to edit, for this we need to import MatDialogConfig
from @angular/material/dialog
Inside the update
method we need a new MatDialogConfig object to pass data to the component
Like in CreateComponent, in update.component.ts
we need to import FormGroup
and FormControl
from @angular/forms
, DataService
,MatDialogRef
from ‘@angular/material/dialog’
and pass them to the constructor. We also need, Inject
from @angular/core
,and MAT_DIALOG_DATA
from ‘@angular/material/dialog’
import { Component, OnInit, Inject } from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog' import { FormGroup, FormControl } from '@angular/forms'; import {DataService} from '../data.service' constructor( public dataService:DataService, private dialogRef: MatDialogRef<UpdateComponent>, @Inject(MAT_DIALOG_DATA) data ) {}
We need to declare a new FormGroup
variable to keep the form data, let’s name it myFormGroup
, and a variable item
to keep the item.
In constructor we will inject MAT_DIALOG_DATA as data:
constructor(
public dataService:DataService,
private dialogRef: MatDialogRef<UpdateComponent>,
@Inject(MAT_DIALOG_DATA) data
) {
this.item = data.item
}
And then we can create the loadForm
method and call it on ngOnInit()
:
myFormGroup: FormGroup ngOnInit() { this.loadForm() } loadForm() { const group = {} group["name"] = new FormControl(this.item.name) group["description"] = new FormControl(this.item.description) this.myFormGroup = new FormGroup(group) }
We can use the same save
method from CreateService
save() {
const formData = new FormData()
if (!this.myFormGroup.get("name").untouched) {
formData.append("name", this.myFormGroup.get("name").value)
}
if (!this.myFormGroup.get("description").untouched) {
formData.append("description",
this.myFormGroup.get("description").value)
}
this.dataService.add(formData).subscribe(data => {
console.log(data)
this.dialogRef.close("close");
})
}
And the same template from Create Component:
<h2 mat-dialog-title>Edit {{item.name}}</h2> <mat-dialog-content> <form [formGroup]="myFormGroup"> <mat-form-field> <mat-label>Nume</mat-label> <input matInput formControlName="name"> </mat-form-field> <mat-form-field> <mat-label>Description</mat-label> <input matInput formControlName="description"> </mat-form-field> </form> </mat-dialog-content> <mat-dialog-actions> <button mat-raised-button color="accent" (click)="save()">Save</button> <button mat-button type="button" color="primary" matDialogClose>Close</button> </mat-dialog-actions>
We need to update our Read Component, in read.component.ts
import the Update Service, pass it to the constructor and write the update method:
... import { UpdateService } from '../update/update.service' constructor( ... public updateService: UpdateService, ) {} update(item){ this.updateService.open(item) }
In read.component.html
we need to add the update button :
<thead> <tr> <td>Name</td> <td>Description</td> <td colspan="2">Actions</td> </tr> </thead> <tr *ngFor="let item of items"> <td><a (click)="details(item)">{{ item.name }}</a></td> <td><a (click)="details(item)">{{ item.description }}</a></td> <td><button mat-button color="primary" type="button" (click)="update(item)">Update</button></td> </tr>
Let’s try it npm start
:


Here are the final Update Component files:
Delete and Detail Components and Services
You can skip the delete component and add the delete
method to the Read Component, but I usually like an extra step before a delete operation
Generate the new components:
ng g c delete
ng g c detail
And the new services:
ng g s delete/delete
ng g s detail/detail
The only difference between these services and the Update Service is the imported component: DeleteComponent
for the Delete Service and DetailComponent
for the Detail Service:
For both components we will use the update template and in *.component.ts
we need to change the loadForm
method like this:
loadForm() {
const group = {}
group["name"] = new FormControl(
{value: this.item.name, disabled: true}
)
group["description"] = new FormControl(
{value: this.item.description, disabled: true}
)
this.myFormGroup = new FormGroup(group)
}
We need to add the delete
method to delete.component.ts
:
delete(){
this.dataService.delete(this.item._id).subscribe(data=>{
console.log(data)
this.dialogRef.close("close")
})
}
Now we need to update our Read Component to use the new components:
In read.component.ts
import the Delete and Detail Services, pass them to the constructor and write the methods:
... import { DetailService } from '../detail/detail.service' import { DeleteService } from '../delete/delete.service' constructor( ... public detailService: DetailService, public deleteService: DeleteService, ) {} detail(item){ this.detailService.open(item) } delete(item){ this.deleteService.open(item) }
In read.component.html
add the new buttons:
<td><button mat-button color="primary" type="button" (click)="detail(item)">View</button></td> <td><button mat-button color="warn" type="button" (click)="delete(item)">Delete</button></td>
Let’s try it npm start
:



Here are the final Read Component files:
Conclusion
In this tutorial, we saw how to create a simple Angular 10 CRUD App using Python EVE Framework.
In the next part we will create the Form Service for our Angular 10 CRUD generator.
Source code: GitHub