Snippets Angular ASP.NET Core Tutorial Part 2

Published on 2022-06-01 by Ruben Heeren


Code Snippets Snippets for the tutorial Angular ASP.NET Core Minimal APIs Tutorial (pt. 2 - front end).

Video

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

import { isDevMode } from '@angular/core';

const SERVER_BASE_URL_DEVELOPMENT = 'https://localhost:7133';
const SERVER_BASE_URL_PRODUCTION = 'https://aspnetcorereacttutorial-aspnetserver.azurewebsites.net';

const BASE_ENDPOINTS = {
  GET_ALL_POSTS: 'posts',
  GET_POST_BY_ID: 'posts',
  CREATE_POST: 'posts',
  UPDATE_POST: 'posts',
  DELETE_POST: 'posts'
};

const DEVELOPMENT_ENDPOINTS = {
  GET_ALL_POSTS: `${SERVER_BASE_URL_DEVELOPMENT}/${BASE_ENDPOINTS.GET_ALL_POSTS}`,
  /**
  * Append /{id}. Example: \`${API_ENDPOINTS.GET_POST_BY_ID}/1\`
  */
  GET_POST_BY_ID: `${SERVER_BASE_URL_DEVELOPMENT}/${BASE_ENDPOINTS.GET_POST_BY_ID}`,
  /**
  * Send the post to create as an object of type PostCreateUpdateDTO in the HTTP body.
  */
  CREATE_POST: `${SERVER_BASE_URL_DEVELOPMENT}/${BASE_ENDPOINTS.CREATE_POST}`,
  /**
  * Append /{id}. Example: \`${API_ENDPOINTS.UPDATE_POST}/1\`.
  * Send the post to update as an object of type PostCreateUpdateDTO in the HTTP body.
  */
  UPDATE_POST: `${SERVER_BASE_URL_DEVELOPMENT}/${BASE_ENDPOINTS.UPDATE_POST}`,
  /**
  * Append /{id}. Example: \`${API_ENDPOINTS.DELETE_POST}/1\`
  */
  DELETE_POST: `${SERVER_BASE_URL_DEVELOPMENT}/${BASE_ENDPOINTS.DELETE_POST}`
};

const PRODUCTION_ENDPOINTS = {
  GET_ALL_POSTS: `${SERVER_BASE_URL_PRODUCTION}/${BASE_ENDPOINTS.GET_ALL_POSTS}`,
  GET_POST_BY_ID: `${SERVER_BASE_URL_PRODUCTION}/${BASE_ENDPOINTS.GET_POST_BY_ID}`,
  CREATE_POST: `${SERVER_BASE_URL_PRODUCTION}/${BASE_ENDPOINTS.CREATE_POST}`,
  UPDATE_POST: `${SERVER_BASE_URL_PRODUCTION}/${BASE_ENDPOINTS.UPDATE_POST}`,
  DELETE_POST: `${SERVER_BASE_URL_PRODUCTION}/${BASE_ENDPOINTS.DELETE_POST}`
};

const ENDPOINTS_TO_EXPORT = isDevMode() ? DEVELOPMENT_ENDPOINTS : PRODUCTION_ENDPOINTS;

export default ENDPOINTS_TO_EXPORT;

HttpOptions.ts

import { HttpHeaders } from "@angular/common/http";

const HTTP_OPTIONS = {
    headers: new HttpHeaders({'Content-Type': 'application/json'})
  }

export default HTTP_OPTIONS;
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}"`);
        },
      });
  }
}
<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>
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}"`);
        },
      });
  }
}
<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>
Back to blog