Contents
Hi there, today we will be developing an Angular 17 CRUD app using a REST API. The four basic operations in any programming are CRUD. CRUD is an acronym for CREATE, READ, UPDATE, DELETE.
Angular is a popular open-source front-end web application framework primarily maintained by Google and a community of developers. It’s used for building dynamic, single-page web applications (SPAs) and provides tools and architecture to streamline the development process. Angular enables developers to create rich, interactive, and responsive user interfaces.
In this tutorial, we will be using the REST API available that is made by Binaryboxtus. you can check it out here.
Prerequisite:
- ^18.13.0 || ^20.9.0
- @angular/cli
Step 1: Create An Angular 17 Project
First, select a folder that you want the Angular 17 project to be created then execute this command on Terminal or CMD :
ng new angular-crud-app --routing --no-standalone
Step 2: Install packages
After creating a fresh angular project, go to the Angular 17 project folder and install these packages:
- bootstrap – a package of bootstrap framework
- sweetalert2 – a package for pop-up boxes
- axios – a promised-based HTTP library that is used to request to a server or API.
npm i bootstrap
npm i sweetalert2
npm i axios
After installing the packages. import the bootstrap in style.css.
src\styles.css
/* You can add global styles to this file, and also import other style files */
@import "~bootstrap/dist/css/bootstrap.css";
Step 3: Configure Application Environment
After installing the packages, we will now generate the app environment. We will declare the API base URL and API Key. Run the command below:
ng generate environments
You can get the API_KEY here. Click the “Reveal Key” button and copy the API key.
After running the command this will generate files for the environment. let’s add value to the environment.
environment.development.ts
export const environment = {
production: false,
apiUrl: 'https://mock-api.binaryboxtuts.com/',
apiKey: 'insert_api_key_here'
};
After configuring the environment, let’s configure the axios on main.ts.
src\main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import axios from 'axios';
import { environment } from './environments/environment.development';
axios.defaults.baseURL = environment.apiUrl
axios.interceptors.request.use(function (config) {
config.headers['X-Binarybox-Api-Key'] = environment.apiKey
return config;
});
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Step 4: Create Components
We will now create the components. run the command below:
ng generate component project/index
ng generate component project/create
ng generate component project/show
ng generate component project/edit
after running these commands it will create folders with files in them. We will now update the code on it.
src\app\project\create\create.component.ts
import { Component } from '@angular/core';
import { ProjectService } from '../project.service';
import Swal from 'sweetalert2'
@Component({
selector: 'app-create',
templateUrl: './create.component.html',
styleUrls: ['./create.component.css']
})
export class CreateComponent {
name:string = ''
description:string = ''
isSaving:boolean = false
constructor(public projectService: ProjectService) {}
handleSave(){
this.isSaving = true
this.projectService.create({name:this.name, description:this.description})
.then(({data}) => {
this.isSaving = false
Swal.fire({
icon: 'success',
title: 'Project saved successfully!',
showConfirmButton: false,
timer: 1500
})
this.name = ""
this.description = ""
return data
}).catch(error => {
this.isSaving = false
Swal.fire({
icon: 'error',
title: 'An Error Occured!',
showConfirmButton: false,
timer: 1500
})
return error
})
}
}
src\app\project\create\create.component.html
<h2 class="text-center mt-5 mb-3">Create New Project</h2>
<div class="card">
<div class="card-header">
<a routerLink="/project/index"
class="btn btn-outline-info float-right"
>View All Projects
</a>
</div>
<div class="card-body">
<form >
<div class="form-group">
<label html="name">Name</label>
<input
[(ngModel)]="name"
type="text"
class="form-control"
id="name"
name="name"/>
</div>
<div class="form-group">
<label html="description">Description</label>
<textarea
[(ngModel)]="description"
class="form-control"
id="description"
rows="3"
name="description"></textarea>
</div>
<button
[disabled]="isSaving"
(click)="handleSave()"
type="button"
class="btn btn-outline-primary mt-3">
Save Project
</button>
</form>
</div>
</div>
src\app\project\edit\edit.component.ts
import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../project.service';
import { ActivatedRoute } from '@angular/router';
import Swal from 'sweetalert2'
import { Project } from '../project';
@Component({
selector: 'app-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.css']
})
export class EditComponent implements OnInit {
project:Project
isSaving:boolean = false
constructor(public projectService: ProjectService, private route: ActivatedRoute) {
this.project = {
id:this.route.snapshot.params['id'],
name: '',
description: ''
}
}
ngOnInit(): void {
this.projectService.show(this.route.snapshot.params['id']).then(({data}) => {
this.project = data
}).catch(error => {return error})
}
handleSave(){
this.isSaving = true
this.projectService.update(this.project)
.then(({data}) => {
this.isSaving = false
Swal.fire({
icon: 'success',
title: 'Project saved successfully!',
showConfirmButton: false,
timer: 1500
})
return data
}).catch(error => {
this.isSaving = false
Swal.fire({
icon: 'error',
title: 'An Error Occured!',
showConfirmButton: false,
timer: 1500
})
return error
})
}
}
src\app\project\edit\edit.component.html
<h2 class="text-center mt-5 mb-3">Edit Project</h2>
<div class="card">
<div class="card-header">
<a routerLink="/project/index"
class="btn btn-outline-info float-right"
>View All Projects
</a>
</div>
<div class="card-body">
<form >
<div class="form-group">
<label html="name">Name</label>
<input
[(ngModel)]="project.name"
type="text"
class="form-control"
id="name"
name="name"/>
</div>
<div class="form-group">
<label html="description">Description</label>
<textarea
[(ngModel)]="project.description"
class="form-control"
id="description"
rows="3"
name="description"></textarea>
</div>
<button
[disabled]="isSaving"
(click)="handleSave()"
type="button"
class="btn btn-outline-primary mt-3">
Save Project
</button>
</form>
</div>
</div>
src\app\project\index\index.component.ts
import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../project.service';
import { Project } from '../project';
import Swal from 'sweetalert2'
@Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.css']
})
export class IndexComponent implements OnInit{
projects: Project[] = [];
constructor(public projectService: ProjectService) { }
ngOnInit(): void {
this.fetchProjectList()
}
fetchProjectList(){
this.projectService.getAll().then(({data}) => {
this.projects = data;
}).catch(error => {return error})
}
handleDelete(id:number){
Swal.fire({
title: 'Are you sure?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then(result =>{
if (result.isConfirmed) {
this.projectService.delete(id)
.then( response => {
Swal.fire({
icon: 'success',
title: 'Project deleted successfully!',
showConfirmButton: false,
timer: 1500
})
this.fetchProjectList()
return response
}).catch(error => {
Swal.fire({
icon: 'error',
title: 'An Error Occured!',
showConfirmButton: false,
timer: 1500
})
return error
})
}
})
}
}
src\app\project\index\index.component.html
<div class="container">
<h2 class="text-center mt-5 mb-3">Project Manager</h2>
<div class="card">
<div class="card-header">
<a routerLink="/project/create"
class="btn btn-outline-primary float-right"
>Create New Project
</a>
</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th width="240px">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let project of projects" >
<td>{{ project.name }}</td>
<td>{{ project.description }}</td>
<td>
<a [routerLink]="['/project', project.id, 'show']" class="btn btn-outline-info mx-1">Show</a>
<a [routerLink]="['/project', project.id, 'edit']" class="btn btn-outline-success mx-1">Edit</a>
<button
(click)="handleDelete(project.id)"
class="btn btn-outline-danger mx-1">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
src\app\project\show\show.component.ts
import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../project.service';
import { ActivatedRoute } from '@angular/router';
import { Project } from '../project';
@Component({
selector: 'app-show',
templateUrl: './show.component.html',
styleUrls: ['./show.component.css']
})
export class ShowComponent implements OnInit {
project:Project
constructor(public projectService: ProjectService, private route: ActivatedRoute) {
this.project = {
id:this.route.snapshot.params['id'],
name: '',
description: ''
}
}
ngOnInit(): void {
this.projectService.show(this.route.snapshot.params['id']).then(({data}) => {
this.project = data
}).catch(error => {return error})
}
}
src\app\project\show\show.component.html
<h2 class="text-center mt-5 mb-3">Show Project</h2>
<div class="card">
<div class="card-header">
<a routerLink="/project/index"
class="btn btn-outline-info float-right"
>View All Projects
</a>
</div>
<div class="card-body">
<b className="text-muted">Name:</b>
<p>{{project.name}}</p>
<b className="text-muted">Description:</b>
<p>{{project.description}}</p>
</div>
</div>
Step 5: Create Module and Routing
After creating the component we will then create a module and routing. Run the command below:
ng generate module project --routing
now we will update the code of the module and routing.
src\app\project\project.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProjectRoutingModule } from './project-routing.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IndexComponent } from './index/index.component';
import { CreateComponent } from './create/create.component';
import { EditComponent } from './edit/edit.component';
import { ShowComponent } from './show/show.component';
@NgModule({
declarations: [
IndexComponent,
CreateComponent,
EditComponent,
ShowComponent
],
imports: [
CommonModule,
ProjectRoutingModule,
FormsModule,
ReactiveFormsModule
]
})
export class ProjectModule { }
src\app\project\project-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { IndexComponent } from './index/index.component';
import { CreateComponent } from './create/create.component';
import { EditComponent } from './edit/edit.component';
import { ShowComponent } from './show/show.component';
const routes: Routes = [
{ path: '', redirectTo: 'project/index', pathMatch: 'full'},
{ path: 'project', redirectTo: 'project/index', pathMatch: 'full'},
{ path: 'project/index', component: IndexComponent },
{ path: 'project/:id/show', component: ShowComponent },
{ path: 'project/create', component: CreateComponent },
{ path: 'project/:id/edit', component: EditComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProjectRoutingModule { }
Step 6: Create Services and Interface
We will now create the services and interface
ng generate service project/project
ng generate interface project/project
Let’s update the code of services and interface.
src\app\project\project.service.ts
import { Injectable } from '@angular/core';
import axios from 'axios';
import { Project } from './project';
@Injectable({
providedIn: 'root'
})
export class ProjectService {
getAll (): Promise<any>{
return axios.get('/api/projects')
}
delete (id:number): Promise<any>{
return axios.delete('/api/projects/' + id)
}
create(data:any): Promise<any>{
let payload = {
name: data.name,
description: data.description
}
return axios.post('/api/projects', payload)
}
show (id:number): Promise<any>{
return axios.get('/api/projects/' + id)
}
update(data:Project): Promise<any>{
let payload = {
name: data.name,
description: data.description
}
return axios.patch('/api/projects/' + data.id, payload)
}
}
src\app\project\project.ts
export interface Project {
id: number;
name: string;
description: string;
}
Step 7: Update the AppModule and AppComponent
After finishing the step above we will now update the app module and app component:
src\app\app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ProjectModule } from './project/project.module';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
ProjectModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
src\app\app.component.html
<div class="container">
<router-outlet></router-outlet>
</div>
Step 8: Run the app
We’re all done, what is left is to run the app.
ng serve
Open this URL:
http://localhost:4200/
Screenshots:
Index Page
Create Page
Edit Page
Show Page