[NetCore] Asp.net Core with Angular 6-CUD

這篇繼續透過Angular 呼叫 webapi完成資料Create、Delete、Update

修改WEB API controller,新增CRU

[HttpDelete]
       [Route("delete/{id}")]
       public async Task<int> DeleteAsync(long id)
       {
           return await _eventLogService.RemoveEventLogAsync(new[] { new EventLog { Id = id } });
       }
 
       [HttpPost]
        [Route("create")]
        public async Task<int> CreateAsync([FromBody]EventLogRequest request)
        {
           return await _eventLogService.CreateEventLogAsync(
                        new[] { new EventLog
                                {
                                    Id=request.Id,
                                    EventID=request.EventID,
                                    Message=request.Message,
                                    CreatedTime= DateTime.Parse(request.CreatedTime),
                                    LogLevel="Test",
                                    Exception=string.Empty
                                }
                        });
        }
 
        [HttpPut]
        [Route("update")]
        public async Task<int> UpdateAsync([FromBody]EventLogRequest request)
        {
           return await _eventLogService.UpdateEventLogAsync(
                         new[] { new EventLog
                                   {
                                       Id=request.Id,
                                       EventID=request.EventID,
                                       Message=request.Message,
                                       CreatedTime= DateTime.Parse(request.CreatedTime),
                                       LogLevel="Test",
                                       Exception=string.Empty
                                   } }
                         );
        }

 

修改eventlog.service.ts,新增CUD

Note:因為我把rxjs upgrade到6.2.2,所以catcherror也需改寫

import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable, Subject, empty , throwError, of } from 'rxjs';
import { map, filter, switchMap, catchError } from 'rxjs/operators';

@Injectable()
export class EventlogService {
  myAppUrl: string = "";  
  constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    this.myAppUrl = baseUrl;  
  }

  getEventLogs() {
    return this._http.get(this.myAppUrl + "api/eventlog/all")
      .pipe(     
      //map((response: Response) => response.json())
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
      ); 
  }
 
  getEventLogsById(id: number) {
    return this._http.get(this.myAppUrl + "api/eventlog/" + id)
      .pipe(      
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
      ); 
  }

  deleteEventLog(id: number) {
    return this._http.delete(this.myAppUrl + "api/eventlog/delete/" + id)
      .pipe(
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
      ); 
  }

  createEventLog(eventlog) {
    return this._http.post(this.myAppUrl + "api/eventlog/create/", eventlog)
      .pipe(
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
      ); 
  }

  updateEventLog(eventlog) {
    return this._http.put(this.myAppUrl + "api/eventlog/update", eventlog)
      .pipe(
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
      ); 
  }

  errorHandler(error: Response) {
    console.log(error);
    return Observable.throw(error);
  }  

}

 

修改eventlog.component.ts,新增delete function

delete(id: number) {
    var ans = confirm("Do you want to delete eventLog with Id: " + id);
  if (ans) {
    this._eventLogService.deleteEventLog(id).subscribe((result) => {
      console.log(result);
      this.getEventLogs();
    })
  }
}

 

新增eventlogAdd component,用來處理新增和更新

ng g c eventlogAdd

因為表單中會有一個日期控制項,我打算使用ng-bootstrap,所以先安裝該libary

npm install --save @ng-bootstrap/ng-bootstrap

note:我安裝完後,順便更新相關cli和rxjs

ng update @angular/cli
npm ls -g --depth=1
npm update rxjs@6.2.2
npm uninstall -g rxjs
npm install -g rxjs@6.2.2

 

修改app.module.ts

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

修改font CDN

@import url('https://fonts.googleapis.com/css?family=Ubuntu');
@import url('https://use.fontawesome.com/releases/v5.4.1/css/all.css');

Note: Font Awesome's Free CDNfontawesome.com

 

修改eventlog-add.component.ts

import { Component, OnInit, Inject } from '@angular/core';
import { NgForm, FormBuilder, FormGroup, Validators, FormControl, ReactiveFormsModule } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Time, DatePipe  } from '@angular/common';
import { NgbDateStruct, NgbCalendar, NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
import { EventlogComponent } from '../eventlog/eventlog.component';
import { EventlogService } from '../service/eventlog.service'


@Component({
  selector: 'app-eventlog-add',
  templateUrl: './eventlog-add.component.html',
  styleUrls: ['./eventlog-add.component.css']
})
export class EventlogAddComponent implements OnInit {
  eventLogForm: FormGroup; // 宣告eventLogForm as FormGroup 
  title: string = "Create";
  id: number;
  datePipe = new DatePipe('en-US');
  modelDate; // ngbDatepicker

  constructor(private _fb: FormBuilder, private _avRoute: ActivatedRoute,
    private _eventLogService: EventlogService, private _router: Router,
    private _calendar: NgbCalendar) {
    if (this._avRoute.snapshot.params["id"]) {
      this.id = this._avRoute.snapshot.params["id"];      
    }

    this.eventLogForm = this._fb.group({
      id: 0, // 建立名為id,預設值0的formControl
      eventID: ['', [Validators.required]], // Validators.required 必須值
      message: ['', [Validators.required]],
      createdTime: ['', [Validators.required]]
    })  
  }

  ngOnInit() {    
    if (this.id > 0) {
      this.title = "Edit";
      this._eventLogService.getEventLogsById(this.id)        
        .subscribe((result) =>
        {
          console.log(result[0]);// 只取第一個object
          let dateParts = this.datePipe.transform(result[0].createdTime.substring(0, 10), 'M-d-y').split('-');
          this.eventLogForm.controls["id"].setValue(result[0].id);
          this.eventLogForm.controls["eventID"].setValue(result[0].eventID);
          this.eventLogForm.controls["message"].setValue(result[0].message);          
          let currentDate: NgbDateStruct = {
            year: parseInt(dateParts[2]),
            month: parseInt(dateParts[0]),
            day: parseInt(dateParts[1])
          }; // date format                
          this.modelDate = currentDate;        
          //this.eventLogForm.setValue(result[0])
        });     
    } else {
      this.eventLogForm.controls["id"].setValue('');     
    }
    this.eventLogForm.controls["id"].disable();
  }

  save() {
    if (!this.eventLogForm.valid) {
      return;
    }
    let currentDate= this.modelDate.year.toString() + "-" + this.modelDate.month.toString() + "-" + this.modelDate.day.toString();
    this.eventLogForm.controls["createdTime"].setValue(currentDate); 
    if (this.title == "Create") {
      this._eventLogService.createEventLog(this.eventLogForm.value)
        .subscribe((result) => {
          console.log(result);
          this._router.navigate(['/eventlog']);
        });
    }
    else if (this.title == "Edit") {
      this._eventLogService.updateEventLog(this.eventLogForm.getRawValue()) // get value from each control
        .subscribe((result) => {
          console.log(result);
          this._router.navigate(['/eventlog']); // go back to index
        });
    }
  }

  cancel() {
    this._router.navigate(['/eventlog']);
  }

}

 

修改template

<h3>EventLog {{title}}</h3>
<hr />
<!--
    novalidate屬性,是為了要防止瀏覽器自己執行native驗證
    [formGroup]="eventLogForm"是將template內的form元件關連controller中所建立的formGroup
    #formDir="ngForm",產生一個ngForm實體
-->
<form [formGroup]="eventLogForm" (ngSubmit)="save()" #formDir="ngForm" novalidate>
  <div class="form-group row">
    <label class="control-label col-md-12" for="Id">Id</label>
    <div class="col-md-4">
      <!--formControlName="id", 將input與formGroup下為Id的formControl建立關連 -->
      <input class="form-control" type="text" formControlName="id">
    </div>
  </div>
  <div class="form-group row">
    <label class="control-label col-md-12" for="EventID">EventID</label>
    <div class="col-md-4">
      <input class="form-control" type="text" formControlName="eventID" placeholder="required">
    </div>
    <!-- 按下submitted如有錯誤才顯示-->
    <span class="text-danger" *ngIf="eventLogForm.hasError('required', 'eventID') && formDir.submitted">
      EventID is required
    </span>
  </div>
  <div class="form-group row">
    <label class="control-label col-md-12" for="Message">Message</label>
    <div class="col-md-4">
      <input class="form-control" type="text" formControlName="message" placeholder="required">
    </div>
    <span class="text-danger" *ngIf="eventLogForm.hasError('required', 'message') && formDir.submitted">
      Message is required
    </span>
  </div>
  <div class="form-group row">
    <label class="control-label col-md-12" for="CreatedTime">CreatedTime</label>
    <div class="col-md-4">
      <!--[(ngModel)]="modelDate" data雙向binding-->
      <input class="form-control" type="text" placeholder="yyyy-mm-dd" formControlName="createdTime" data-val="true"
             ngbDatepicker #d="ngbDatepicker" [(ngModel)]="modelDate">
      <button class="btn" (click)="d.toggle()" type="button">
        <i class="far fa-calendar-alt"></i>
      </button>
    </div>
      <span class="text-danger" *ngIf="eventLogForm.hasError('required', 'createdTime') && formDir.submitted">
        CreatedTime is required
      </span>
  </div>  
  <div class="form-group">
    <!-- eventLogForm.valid 驗證都通過才enable -->
    <button type="submit" [disabled]="!eventLogForm.valid" class="btn btn-default">Save</button>
    <button class="btn" (click)="cancel()">Cancel</button>
  </div>
</form>

 

結果-Create

結果-Edit

結果-Delete

 

 

下一篇我們再來看看如何實現Paging

參考

Angular 6 Forms Tutorial Example From Scratch

Angular 6 - Reactive Forms Validation Example

Reactive Forms with Angular

Reactive Forms in Angular: Dynamically Creating Form Fields With FormArray

Angular 6 Date format MM/dd/yyyy in reactive form

Angular Tips: Formatting Dates with a Custom Date Pipe (dd/MM/yyyy)

rxjs

RxJS 6 Changes - Overview

RxJS 6: What's new and what has changed?

Angular 6 RxJS 6 Tutorial & Example

RxJs Error Handling: Complete Practical Guide

Bug with Angular-Cli 6 : "Unknown option: '--extractCss'"

ng-bootstrap

Angular Datepicker – Exploring Bootstrap (Part 3)

Timepicker

DatePipe

NgbDatePicker - How to bind longDate string to [ngModel]?

formatDate

introduce Angular Form

FormGroup

Reactive Forms