ABP-Book Store Application中文讲解 - Part 3: Creating, Updating and Deleting Books。
本章用于介绍如何新增、编辑和删除Book。
1. 汇总
ABP-Book Store Application中文讲解-汇总-CSDN博客
2. 前一章
ABP-Book Store Application中文讲解 - Part 2: The Book List Page
项目之间的引用关系。
目录
1.1.1 更改add-edit-book.component.html
1.1.2 更改add-edit-book.component.ts (即AddEditBookComponent)
1.1.4 book.component.html增加新增,删除和编辑
1.1.5 book.component.ts中使用AddEditBookComponent
1.2 方法二:将所有业务逻辑放在BookComponent
1. Create a New Book
创建 新增Book的窗体。
此处可以有两种方式:
第一种是单独创建一个component,比如add-edit-book,然后在里面实现所有的业务逻辑,保存和关闭按钮可以通过NgbModal用来显示和关闭dialog。本文重点介绍这一个方法。
第二种是将所有业务逻辑放在BookComponent里面实现,即ABP官方Demo给出的完整代码。
1.1 方法一:单独创建dialog component
右击book文件夹,选择Open in integrated Terminal, 然后输入以下命令敲回车生成AddEditBookComponent。
ng generate component add-edit-book
创建完成,目录结构如下图所示:
1.1.1 更改add-edit-book.component.html
<form [formGroup]="form" (ngSubmit)="save()">
<div class="modal-header">
<h4 class="modal-title">
{{ (book && book.id ? '::EditBook' : '::NewBook') | abpLocalization }}
</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="activeModal.dismiss()"></button>
</div>
<div class="modal-body">
<div class="formGroup mt-2">
<label for="book-name">{{'::Name' | abpLocalization}}</label><span> * </span>
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="formGroup mt-2">
<label for="book-price">{{'::Price' | abpLocalization}}</label><span> * </span>
<input type="number" id="book-price" class="form-control" formControlName="price" formControlName="price" />
</div>
<div class="formGroup mt-2">
<label for="book-type">{{'::Type' | abpLocalization}}</label><span> * </span>
<select class="form-control" id="book-type" formControlName="type">
<option [ngValue]="null">Select a book type</option>
<option [ngValue]="type.value" *ngFor="let type of bookTypes"> {{ '::Enum:BookType.' + type.value |
abpLocalization }}</option>
</select>
</div>
<div class="formGroup mt-2">
<label>{{'::PublishDate' | abpLocalization}}</label><span> * </span>
<input #datepicker="ngbDatepicker" class="form-control" name="datepicker" formControlName="publishDate"
ngbDatepicker (click)="datepicker.toggle()" />
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" (click)="activeModal.dismiss()">{{'::Cancel' |
abpLocalization}}</button>
<button class="btn btn-primary" type="submit" [disabled]="form.invalid">
{{ (book && book.id ? '::Update' :'::Save') | abpLocalization }}
</button>
</div>
</form>
1.1.2 更改add-edit-book.component.ts (即AddEditBookComponent)
注意此处更改了standalone,改为了false
然后引用都需要在book.module.ts中添加对应的引用,具体参看book.module.ts
import { Component, OnInit } from '@angular/core';
import { BookService, BookDto, CreateUpdateBookDto, bookTypeOptions } from '../../proxy/books'; // Import your BookService and BookDto model
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';// added this line
import { ListService } from '@abp/ng.core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
// added this line
@Component({
selector: 'app-add-edit-book',
templateUrl: './add-edit-book.component.html',
styleUrl: './add-edit-book.component.scss',
standalone: false, // 标记为独立组件
providers: [
ListService,
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line
],
})
export class AddEditBookComponent implements OnInit {
public book: BookDto = {} as BookDto; // Input property to receive book data from parent component
form: FormGroup;
bookTypes = bookTypeOptions;
constructor(private bookService: BookService
, private fb: FormBuilder
, public activeModal: NgbActiveModal) { this.buildForm(); } // Inject BookService for adding or updating bo oks
ngOnInit(): void {
this.buildForm();
}
// add buildForm method
buildForm() {
this.form = this.fb.group({
name: [this.book.name, Validators.required],
type: [this.book.type, Validators.required],
publishDate: [this.book.publishDate ? new Date(this.book.publishDate) : null, Validators.required],
price: [this.book.price, Validators.required],
});
}
save() { // Method to save or update a book
if (this.form.invalid) { // Check if the form is invalid
return; // Exit the method if the form is invalid
}
const operation$ = this.book.id
? this.bookService.update(this.book.id, this.form.value)
: this.bookService.create(this.form.value);
operation$.subscribe(() => {
this.form.reset();// reset form values
this.activeModal.close(true);// true used to inform the parent component that the book has been saved/updated
});
}
}
1.1.3 book.module.ts添加引用
完整代码
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { BookRoutingModule } from './book-routing.module';
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; // add this line
import { FormsModule } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';// added this line
import { ListService } from '@abp/ng.core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { AddEditBookComponent } from './add-edit-book/add-edit-book.component';// add this line
@NgModule({
declarations: [
AddEditBookComponent // Import AddEditBookComponent to make it available in this module
],
imports: [
BookRoutingModule,
SharedModule// shared module already export CommonModule, so we don't need to import it again.
, NgbDatepickerModule // add this line
,FormsModule
],
providers: [ListService, NgbActiveModal, // Provide ListService and NgbActiveModal for this module
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line to use native date adapter
],
})
export class BookModule { }
1.1.4 book.component.html增加新增,删除和编辑
新增按钮
编辑和删除按钮
完整代码
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{'::Menu:Books' | abpLocalization}}
</h5>
</div>
<div class="col col-md-6 text-lg-end pt-2">
<button class="btn btn-primary" (click)="createBook()">
<i class="fa fa-plus me-1"></i>
{{'::NewBook' | abpLocalization}}
</button>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
<ngx-datatable-column name="{{'::Name' | abpLocalization}}" prop="name"></ngx-datatable-column>
<ngx-datatable-column name="{{'::Type' | abpLocalization}}" prop="type">
<ng-template let-column="column" let-row="row" ngx-datatable-cell-template>
{{'::Enum:BookType.' + row.type | abpLocalization}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{'::Price' | abpLocalization}}" prop="price">
<ng-template let-column="column" let-row="row" ngx-datatable-cell-template>
<!-- {{row.price | currency:'USD':true}} -->
{{row.price | currency}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{'::PublishDate' | abpLocalization}}" prop="publishDate">
<ng-template let-column="column" let-row="row" ngx-datatable-cell-template>
<!-- {{row.publishDate | date:'dd/MM/yyyy'}} -->
{{row.publishDate | date}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Actions' | abpLocalization" [maxWidth]="150" [sortable]="false">
<ng-template let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" ngbDropdownToggle>
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="editBook(row.id)">
{{ '::Edit' | abpLocalization }}
</button>
<!-- add the Delete button -->
<button ngbDropdownItem (click)="delete(row.id)">
{{ '::Delete' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
1.1.5 book.component.ts中使用AddEditBookComponent
引用
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
import { AddEditBookComponent } from './add-edit-book/add-edit-book.component';
在ctor中添加ConfirmationService和NgbModal
private confirmationService: ConfirmationService, private modalService: NgbModal
constructor(private bookService: BookService, public readonly list: ListService, private confirmationService: ConfirmationService, private modalService: NgbModal) { } // Inject BookService and ListService
新增-利用NgbModal
createBook() {
const modalRef = this.modalService.open(AddEditBookComponent, { size: 'lg' });
modalRef.componentInstance.book = {} as BookDto; // Pass an empty BookDto to the modal
modalRef.result.then((result) => {
if (result) {
this.list.get();
}
});
}
编辑-利用NgbModal
// Add editBook method
editBook(id: string) {
this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
const modalRef = this.modalService.open(AddEditBookComponent, { size: 'lg' });
modalRef.componentInstance.book = book;
modalRef.result.then((result) => {
if (result) {
this.list.get();
}
});
});
}
删除-利用confirmationService
// Add a delete method
delete(id: string) {
this.confirmationService.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
完整代码
import { Component, OnInit } from '@angular/core';
import { ListService, PagedResultDto } from '@abp/ng.core'; // Import ListService and PagedResultDto
import { BookService, BookDto } from '../proxy/books'; // Import your BookService and BookDto model
import { SharedModule } from '../shared/shared.module';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
import { AddEditBookComponent } from './add-edit-book/add-edit-book.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrl: './book.component.scss',
standalone: true, // 标记为独立组件
imports: [SharedModule], // standalone: true导入需要的模块
providers: [ListService], // Provide ListService for this component
})
export class BookComponent implements OnInit {
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>; // Initialize books as an empty PagedResultDto
selectedBook = {} as BookDto; // declare selectedBook
constructor(private bookService: BookService, public readonly list: ListService, private confirmationService: ConfirmationService, private modalService: NgbModal) { } // Inject BookService and ListService
ngOnInit() { // Use ngOnInit to fetch books when the component initializes
this.list.hookToQuery(this.bookService.getList).subscribe((response) => { // Hook to the query and subscribe to the response
this.book = response; // Assign the response to books
});
}
createBook() {
const modalRef = this.modalService.open(AddEditBookComponent, { size: 'lg' });
modalRef.componentInstance.book = {} as BookDto; // Pass an empty BookDto to the modal
modalRef.result.then((result) => {
if (result) {
this.list.get();
}
});
}
// Add editBook method
editBook(id: string) {
this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
const modalRef = this.modalService.open(AddEditBookComponent, { size: 'lg' });
modalRef.componentInstance.book = book;
modalRef.result.then((result) => {
if (result) {
this.list.get();
}
});
});
}
// Add a delete method
delete(id: string) {
this.confirmationService.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
}
1.2 方法二:将所有业务逻辑放在BookComponent
具体参考ABP.IO官网例子: