Code snippets for the YouTube video “Angular ASP.NET Core Minimal APIs Tutorial (pt. 2 – front end)”.
app.component.ts ngOnInit
ngOnInit(): void {
this.httpClient.get<Post[]>('https://localhost:7133/posts')
.subscribe(result => {
this.postService.allPosts = result;
console.log(this.postService.allPosts);
})
}
CORS
// 1
builder.Services.AddCors(options =>
{
options.AddPolicy("CORSPolicy",
builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("http://localhost:4200", "https://calm-water-04859b403.azurestaticapps.net");
});
});
// 2
app.UseCors("CORSPolicy");
app.component.html
<div class="container d-flex flex-column min-vh-100 justify-content-center align-items-center">
<h1>Angular ASP.NET Core Minimal APIs Tutorial</h1>
<button class="btn btn-lg btn-dark mt-3">
Create New Post
</button>
<div class="mh-500px w-100 overflow-auto d-inline-block mt-5 shadow">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Title</th>
<th scope="col">Content</th>
<th scope="col">Published</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let post of postService.allPosts; index as i">
<th scope="row">{{ post.id }}</th>
<td>{{ post.title }}</td>
<td>{{ post.content }}</td>
<td>{{ post.published }}</td>
<td>
<button class="btn btn-lg btn-dark me-3">
Update
</button>
<button class="btn btn-lg btn-outline-dark">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
APIEndpoints.ts
<div class="container d-flex flex-column min-vh-100 justify-content-center align-items-center">
<h1>Angular ASP.NET Core Minimal APIs Tutorial</h1>
<button class="btn btn-lg btn-dark mt-3">
Create New Post
</button>
<div class="mh-500px w-100 overflow-auto d-inline-block mt-5 shadow">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Title</th>
<th scope="col">Content</th>
<th scope="col">Published</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let post of postService.allPosts; index as i">
<th scope="row">{{ post.id }}</th>
<td>{{ post.title }}</td>
<td>{{ post.content }}</td>
<td>{{ post.published }}</td>
<td>
<button class="btn btn-lg btn-dark me-3">
Update
</button>
<button class="btn btn-lg btn-outline-dark">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
HttpOptions.ts
import { HttpHeaders } from "@angular/common/http";
const HTTP_OPTIONS = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
}
export default HTTP_OPTIONS;
modal-create-post.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import API_ENDPOINTS from 'src/app/constants/APIEndpoints';
import HTTP_OPTIONS from 'src/app/constants/HttpOptions';
import { PostCreateUpdateDTO } from '../models/post-create-update-dto.model';
import { PostService } from '../services/post.service';
import { Post } from '../models/post.model';
@Component({
selector: 'app-modal-create-post',
templateUrl: './modal-create-post.component.html',
styleUrls: ['./modal-create-post.component.css']
})
export class ModalCreatePostComponent {
form!: FormGroup;
createSuccessful: boolean = false;
createFailed: boolean = false;
constructor(public formBuilder: FormBuilder, private httpClient: HttpClient, public activeModal: NgbActiveModal, private postService: PostService) {
this.form = this.formBuilder.group({
title: ['Example Post Title'],
content: ['Example Post Content'],
published: [true]
});
}
submitForm() {
var postToCreate = {} as PostCreateUpdateDTO;
postToCreate.title = this.form.get('title')!.value;
postToCreate.content = this.form.get('content')!.value;
postToCreate.published = this.form.get('published')!.value;
this.httpClient
.post(API_ENDPOINTS.CREATE_POST, postToCreate, HTTP_OPTIONS)
.subscribe({
next: (createdPostFromServer) => {
this.createSuccessful = true;
this.postService.allPosts.push(createdPostFromServer as Post);
console.log('Successfully created a post! Response from server:');
console.log(createdPostFromServer);
},
error: (error: HttpErrorResponse) => {
this.createFailed = true;
console.log(`Failed to create post! Response from server: "HTTP statuscode: ${error.status}: ${error.error}"`);
},
});
}
}
modal-create-post.component.html
<div class="modal-header">
<h4 class="modal-title">Create New Post</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"></button>
</div>
<form [formGroup]="form" (ngSubmit)="submitForm()">
<div class="modal-body">
<div class="container">
<div class="form-group">
<label for="titleInput">Post Title</label>
<input class="form-control" id="titleInput" placeholder="Post Title" formControlName="title">
</div>
<div class="form-group mt-4">
<label for="contentInput">Post Content</label>
<textarea class="form-control" id="contentInput" placeholder="Post Content" formControlName="content"
rows="8"></textarea>
</div>
<div class="form-check mt-4">
<input class="form-check-input" type="checkbox" checked id="publishedCheckbox" formControlName="published">
<label class="form-check-label" for="publishedCheckbox">
Published
</label>
</div>
</div>
</div>
<div class="modal-footer">
<p class="text-success" *ngIf="createSuccessful">Post created!</p>
<p class="text-danger" *ngIf="createFailed">Failed to create the post. Check the console for details.</p>
<button class="btn btn-lg btn-dark" type="submit" *ngIf="createSuccessful === false">Create</button>
<button type="button" class="btn btn-lg btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
</form>
modal-update-post.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import API_ENDPOINTS from 'src/app/constants/APIEndpoints';
import HTTP_OPTIONS from 'src/app/constants/HttpOptions';
import { PostCreateUpdateDTO } from '../models/post-create-update-dto.model';
import { PostService } from '../services/post.service';
import { Post } from '../models/post.model';
@Component({
selector: 'app-modal-update-post',
templateUrl: './modal-update-post.component.html',
styleUrls: ['./modal-update-post.component.css']
})
export class ModalUpdatePostComponent implements OnInit {
form!: FormGroup;
postToUpdate!: Post;
updateSuccessful: boolean = false;
updateFailed: boolean = false;
constructor(public fb: FormBuilder, private httpClient: HttpClient, public activeModal: NgbActiveModal, private postService: PostService) { }
ngOnInit(): void {
this.form = this.fb.group({
id: [this.postToUpdate.id],
title: [this.postToUpdate.title],
content: [this.postToUpdate.content],
published: [this.postToUpdate.published]
});
this.form.controls['id'].disable();
}
submitForm() {
var postToUpdateDTO = {} as PostCreateUpdateDTO;
postToUpdateDTO.title = this.form.get('title')!.value;
postToUpdateDTO.content = this.form.get('content')!.value;
postToUpdateDTO.published = this.form.get('published')!.value;
this.httpClient
.put(`${API_ENDPOINTS.UPDATE_POST}/${this.postToUpdate.id}`, postToUpdateDTO, HTTP_OPTIONS)
.subscribe({
next: (response) => {
this.updateSuccessful = true;
let updatedPostFromServer: Post = response as Post;
let updatedPostIndex = this.postService.allPosts.findIndex((post => post.id == updatedPostFromServer.id));
this.postService.allPosts[updatedPostIndex].title = updatedPostFromServer.title;
this.postService.allPosts[updatedPostIndex].content = updatedPostFromServer.content;
this.postService.allPosts[updatedPostIndex].published = updatedPostFromServer.published;
console.log('Successfully updated the post! Response from server:');
console.log(response);
},
error: (error: HttpErrorResponse) => {
this.updateFailed = true;
console.log(`Failed to update the post! Response from server: "HTTP statuscode: ${error.status}: ${error.error}"`);
},
});
}
}
modal-update-post.component.html
<div class="modal-header">
<h4 class="modal-title">Updating post titled "{{ postToUpdate.title }}"</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"></button>
</div>
<form [formGroup]="form" (ngSubmit)="submitForm()">
<div class="modal-body">
<div class="container">
<div class="form-group">
<label for="idInput">Post ID</label>
<input type="text" class="form-control" id="idInput" formControlName="id" readonly>
</div>
<div class="form-group mt-4">
<label for="titleInput">Post Title</label>
<input class="form-control" id="titleInput" placeholder="Post Title" formControlName="title">
</div>
<div class="form-group mt-4">
<label for="contentInput">Post Content</label>
<textarea class="form-control" id="contentInput" placeholder="Post Content" formControlName="content"
rows="8"></textarea>
</div>
<div class="form-check mt-4">
<input class="form-check-input" type="checkbox" checked id="publishedCheckbox" formControlName="published">
<label class="form-check-label" for="publishedCheckbox">
Published
</label>
</div>
</div>
</div>
<div class="modal-footer">
<p class="text-success" *ngIf="updateSuccessful">Post updated!</p>
<p class="text-danger" *ngIf="updateFailed">Failed to update the post. Check the console for details.</p>
<button class="btn btn-lg btn-dark" type="submit" *ngIf="updateSuccessful === false">Update</button>
<button type="button" class="btn btn-lg btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
</form>
modal-delete-post-confirm.component.ts
import { Component } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import API_ENDPOINTS from 'src/app/constants/APIEndpoints';
import HTTP_OPTIONS from 'src/app/constants/HttpOptions';
import { Post } from '../models/post.model';
import { PostService } from '../services/post.service';
@Component({
selector: 'app-modal-delete-post-confirm',
templateUrl: './modal-delete-post-confirm.component.html',
styleUrls: ['./modal-delete-post-confirm.component.css']
})
export class ModalDeletePostConfirmComponent {
postToDelete!: Post;
deleteSuccessful: boolean = false;
deleteFailed: boolean = false;
constructor(private httpClient: HttpClient, public activeModal: NgbActiveModal, private postService: PostService) { }
onClickBtnDelete() {
this.httpClient
.delete(`${API_ENDPOINTS.DELETE_POST}/${this.postToDelete.id}`, HTTP_OPTIONS)
.subscribe({
next: (response) => {
this.deleteSuccessful = true;
const index = this.postService.allPosts.indexOf(this.postToDelete);
if (index > -1) {
this.postService.allPosts.splice(index, 1); // 2nd parameter means remove one item only
}
console.log('Successfully deleted the post! Response from server:');
console.log(response);
},
error: (error: HttpErrorResponse) => {
this.deleteFailed = true;
console.log('Failed to delete the post! Error from server:');
console.log(error);
},
});
}
}
modal-delete-post-confirm.component.html
<div class="modal-header">
<h4 class="modal-title">Are you sure you want to delete the post titled "{{ postToDelete.title }}"?</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"></button>
</div>
<div class="modal-body">
<p>A deletion can not be reverted.</p>
</div>
<div class="modal-footer">
<p class="text-success" *ngIf="deleteSuccessful">Post deleted!</p>
<p class="text-danger" *ngIf="deleteFailed">Failed to delete the post. Check the console for details.</p>
<button class="btn btn-lg btn-dark" type="button" *ngIf="deleteSuccessful === false"
(click)="onClickBtnDelete()">Confirm</button>
<button type="button" class="btn btn-lg btn-outline-dark" (click)="activeModal.close('Close click')">{{
deleteSuccessful ? 'Close' : 'Cancel' }}</button>
</div>