Categories
Angular MEA Stack Python

Basic Angular 10 Crud Generator, Powered by Python EVE — Part 2

In this tutorial we’ll create a new Angular 10 Crud app, write the Data Service and Crud Components. I don’t suggest this is the best way to do it

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:

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.

New Angular App

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 cand 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 :

Angular 10 Crud

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

Angular 10 Crud - view
Angular 10 Crud – view
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 :

Angular 10 Crud - view

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

Angular 10 Crud - selector view
Angular 10 Crud – selector view

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 :

Angular 10 Crud - add
Angular 10 Crud – add

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, Injectfrom @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 :

Angular 10 Crud - View
Angular 10 Crud – View
Angular 10 Crud - Edit
Angular 10 Crud – Update

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 :

Angular 10 Crud - Read
Angular 10 Crud – Modal Read
Angular 10 Crud - Detail
Angular 10 Crud – Detail
Angular 10 Crud  - Delete
Angular 10 Crud – Delete

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

Buy me a coffee if this helped you

By rockaru

Self-taught web professional

I started in school, continued as a freelancer and now I’m a self-taught web professional with more than 10 years of experience in the field

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.