使用 ngx-bootstrap 在 Angular 中执行 CRUD 操作(使用 TypeScript)






2.33/5 (8投票s)
在本文中,我们将主要介绍如何使用 ngx-bootstrap 在 Angular 中实现 CRUD(创建、读取、更新和删除)操作,并使用 Asp.Net Core Web API 创建的 API。
引言
Angular 是一个 开源的客户端 JavaScript 框架,用于 SPA 应用程序的端到端开发。如今,学习 Angular 的热潮日渐高涨,每个人都想学习 Angular。在学习 Angular 的过程中,首先想到的是“如何创建第一个 Angular 应用”,其次是“如何创建一个具有 CRUD 功能实现的应用程序”。这样才能理解 Angular 的端到端功能。如果您想学习如何创建 Angular 应用并实现 CRUD 操作,那么您来对地方了。
在本文中,我们将主要介绍如何使用 ngx-bootstrap 在 Angular 中实现 CRUD(创建、读取、更新和删除) 操作,并使用 Asp.Net Core Web API 创建的 API。如果您可以通过本文学习 如何使用 Entity Framework 创建 Asp.Net Core Web API。
创建 Angular CLI 项目
让我们开始使用 CLI 创建一个 新的 Angular 应用程序 [撰写本文时,我们使用的是 Angular 6]。
- 打开 Visual Studio Code 并打开终端窗口,按 Ctrl+`
- 执行命令 ng new AngularCRUDExample --routing 然后按 Enter 键
- 执行命令 ng serve --open 来运行您的项目。
- 使用 Ctrl+C 停止正在运行的项目。
- 执行命令 npm install bootstrap@3 --save 安装 bootstrap。
- 执行命令 npm install glyphicons --save 安装 glyphicons。
- 执行命令 npm install ngx-bootstrap --save 安装 ngx-bootstrap,它提供了 Modal、Tabs 等模块。
CRUD 操作实现
现在,让我们进入下一步,在任何其他实现之前先创建一个服务,我们将在此服务中定义所有 CRUD 操作函数。所以,首先创建一个名为“Services”的文件夹,然后从终端窗口移至此文件夹路径,并执行以下命令来创建一个名为“BlogService”的服务。
ng generate service Blog
现在将创建 CRUD 操作所需的所有方法。
- 首先,让我们从 @angular/common/http 导入 HttpClient 和 HttpHeaders [不要忘记在 AppModule 中导入 HttpClientModule]。
- 由于我们将使用运行在 IIS 上的实时 API,首先让我们为 API 服务配置基本 URL。
- 然后创建 CRUD 操作所需的方法列表,例如
- getCategoryList(): 获取可用类别列表。
- getPostList(): 获取可用博客文章列表。
- addPost(): 用于添加新帖子
- deletePost(): 用于删除现有帖子
- updatePost(): 用于更新现有帖子
- getPost(): 获取单个帖子详细信息
- changePostId(): 这是一个特殊方法,用于在更新现有帖子时获取帖子 ID。
- 不要忘记添加带有 Content-Type 的头。
blog.service.ts
import { Injectable } from "@angular/core"; import { HttpClient, HttpHeaders } from "@angular/common/http"; import { BehaviorSubject } from "rxjs"; @Injectable() export class BlogService{ private readonly baseURL: string; postIdSource = new BehaviorSubject<number>(0); postIdData: any; constructor(private http: HttpClient){ this.baseURL ="https://:44314/api/post/"; this.postIdData= this.postIdSource.asObservable(); } getCategoryList(){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.get(this.baseURL + "getcategories", { headers: header}) } getPostList(){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.get(this.baseURL + "getposts", { headers: header}) } addPost(post: any){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.post(this.baseURL + "addpost", post, { headers: header}) } deletePost(postId: number){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.post(this.baseURL + "deletepost?postId="+postId, { headers: header}) } updatePost(post: any){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.post(this.baseURL + "updatepost", post, { headers: header}) } getPost(postId: number){ let header = new HttpHeaders(); header.append('Content-Type', 'applications/json'); return this.http.get(this.baseURL + "getpost?postId="+ postId, { headers: header}) } changePostId(postId: number){ this.postIdSource.next(postId); } }
这样,我们的服务就准备好了。这意味着我们可以继续进行后续实现而不会中断。所以,让我们首先在 Angular.json 中配置 bootstrap 和 glyphicons ,如下所示。
angular.json
"styles": [ "node_modules/bootstrap/dist/css/bootstrap.css", "src/styles.css" ], "scripts": [ "node_modules/glyphicons/glyphicons.js" ]
现在创建一个名为“components”的新文件夹,并在终端窗口中切换到此文件夹,然后执行以下命令来创建三个新组件。
- ng generate component AddNewPost
- ng generate component EditPost
- ng generate component DeletePost
执行完这三个命令后,我们的 AppModule 将如下所示。在这里,我们想确认几件事情。
- 导入 FormsModule, ReactiveFormsModule 以使用表单相关功能。
- 导入 HttpClientModule 以访问 API 并执行数据库操作。
- 导入 ModalModule, BsModalService 以创建模态弹出窗口。
- 导入 BlogService 以访问我们上面已定义的 CRUD 函数。
- 将上述组件添加到 EntryComponents 部分,以便我们可以将这些组件用作弹出窗口。
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { HttpClientModule } from '@angular/common/http'; import { ModalModule, BsModalService } from 'ngx-bootstrap/modal'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BlogService } from 'src/app/services/blog.service'; import { AddNewPostComponent } from './components/add-new-post/add-new-post.component'; import { EditPostComponent } from './components/edit-post/edit-post.component'; import { DeletePostComponent } from './components/delete-post/delete-post.component'; @NgModule({ declarations: [ AppComponent, AddNewPostComponent, EditPostComponent, DeletePostComponent ], imports: [ BrowserModule, FormsModule, ReactiveFormsModule, AppRoutingModule, HttpClientModule, ModalModule.forRoot() ], providers: [BlogService, BsModalService], bootstrap: [AppComponent], entryComponents:[AddNewPostComponent, DeletePostComponent, EditPostComponent] }) export class AppModule { }
让我们打开 app.component.html 并创建一个列表来显示可用帖子。我们将使用表格和 \*ngFor 指令来创建列表。我们使用 Bootstrap CSS 类来实现外观和感觉,并使用 glyphicon 来实现图标。此表还将包含两个按钮,用于编辑 帖子和删除 帖子。除此之外,我们还在顶部保留一个按钮,它将打开一个对话框,我们可以在其中添加新帖子。
app.component.html
<router-outlet></router-outlet> <div class="container"> <div class="row"> <div class="col-md-6" style="text-align:center;"> <h3>CRUD Operation in Angular with TypeScript</h3> </div> </div> <div class="row"> <div class="col-md-8"> <span (click)="addNewPost()" class="btn btn-primary btn-xs">Add New Post</span> <br /><br /> <div class="table-responsive"> <table id="mytable" class="table table-bordred table-striped"> <thead> <th>Post Id</th> <th>Title</th> <th>Description</th> <th>Category</th> <th>Create Date</th> <th>Edit</th> <th>Delete</th> </thead> <tbody> <tr *ngFor="let item of postList"> <td>{{item.postId}}</td> <td>{{item.title}}</td> <td>{{item.description}}</td> <td>{{item.categoryName}}</td> <td>{{item.createdDate | date}}</td> <td><span class="btn btn-primary btn-xs" (click)="editPost(item.postId)"> <span class="glyphicon glyphicon-pencil"></span></span></td> <td><span class="btn btn-danger btn-xs" (click)="deletePost(item.postId, item.title)"> <span class="glyphicon glyphicon-trash"></span></span></td> </tr> </tbody> </table> </div> </div> </div> </div>
现在,我们已经设计了 app.component.html 页面,其中将列出数据以及添加、更新、删除按钮。但现在是时候为这些按钮添加实际功能了。所以,转到 AppComponent 以添加功能来打开对话框窗口,以便在每个按钮点击时执行CRUD 操作的实际实现。但在这里,您可以看到我们在每次按钮点击时都会打开模态弹出窗口。
- 在页面初始化时,我们将使用 getPosts() 函数从服务中获取可用帖子的列表,该列表将使用 *ngFor 指令绑定到“app.component.html”表格。
- AddNewPost() 函数将打开一个模态弹出窗口,我们可以在其中添加新帖子,一旦添加新记录,我们的列表将更新。
- DeletePost() 函数将打开一个模态弹出窗口,我们将在此窗口中发送帖子的 PostId 和 Title,并删除单个帖子。
- EditPost() 函数将打开一个模态弹出窗口,我们将使用 Rxjs 发送 PostId 来更新该特定帖子。
app.component.ts
import { Component } from '@angular/core'; import { BlogService } from 'src/app/services/blog.service'; import { BsModalService, BsModalRef } from "ngx-bootstrap/modal"; import { AddNewPostComponent } from './components/add-new-post/add-new-post.component'; import { DeletePostComponent } from './components/delete-post/delete-post.component'; import { EditPostComponent } from './components/edit-post/edit-post.component'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'AngularCRUDExample'; postList: any[] = []; bsModalRef: BsModalRef; constructor(private blogService: BlogService, private bsModalService: BsModalService) { this.getPosts(); } getPosts() { this.blogService.getPostList().subscribe(data => { Object.assign(this.postList, data); }, error => { console.log("Error while getting posts ", error); }); } addNewPost() { this.bsModalRef = this.bsModalService.show(AddNewPostComponent); this.bsModalRef.content.event.subscribe(result => { if (result == 'OK') { this.getPosts(); } }); } deletePost(postId: number, title: string) { this.bsModalRef = this.bsModalService.show(DeletePostComponent); this.bsModalRef.content.postId = postId; this.bsModalRef.content.title = title; this.bsModalRef.content.event.subscribe(result => { console.log("deleted", result); if (result == 'OK') { setTimeout(() => { this.postList=[]; this.getPosts(); }, 5000); } }); } editPost(postId: number) { this.blogService.changePostId(postId); this.bsModalRef = this.bsModalService.show(EditPostComponent); this.bsModalRef.content.event.subscribe(result => { if (result == 'OK') { setTimeout(() => { this.getPosts(); }, 5000); } }); } }
现在,让我们使用 ng serve 命令运行应用程序,看看迄今为止的进展。哇……看起来不错,并显示了数据库中的记录列表。
上面我们完成了从数据库显示记录,现在我们将向数据库添加一条新记录。所以,让我们转到 add-new-post.component.html 并替换为以下代码。在这里,您可以看到我们正在创建一个响应式表单,其中包含添加数据所需的控件,以及两个按钮:提交和关闭。此表单有两种不同类型的控件,一种是下拉列表,另一种是文本框。
add-new-post.component.html
<div role="document"> <div> <form class="form-horizontal" id="add-form" [formGroup]="addNewPostForm" (ngSubmit)="onPostFormSubmit()"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="onClose()"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="add-modal-label">Add Post</h4> </div> <div class="modal-body"> <div class="form-group"> <label class="col-sm-2 control-label">Cateogry</label> <div class="col-sm-10"> <select formControlName="category"> <option [value]="null">Select Category</option> <option *ngFor="let item of categories" [value]="item.id">{{item.name}}</option> </select> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Title</label> <div class="col-sm-10"> <input type="text" class="form-control" formControlName="title" /> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Description</label> <div class="col-sm-10"> <textarea class="form-control" formControlName="description"></textarea> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal" (click)="onClose()">Close</button> <button type="submit" class="btn btn-primary">Submit</button> </div> </form> </div> </div>
现在,让我们转到 AddNewPostComponent 进行实际的添加逻辑实现。首先,我们将导入所需的模块类,然后在构造函数中创建响应式表单,并设置控件的默认值。然后获取类别列表,它将绑定到下拉列表。还有一个名为 onPostFormSubmit() 的方法,我们将使用表单实例获取所有控件的值,如 Title, Description, Category Id ,并将其传递给服务以添加新记录。这里我们还定义了一个名为 onClose() 的函数,它将关闭模态弹出窗口。
add-new-post.component.ts
import { Component, OnInit, EventEmitter } from '@angular/core'; import { FormBuilder, FormGroup, FormControl } from '@angular/forms'; import { BlogService } from 'src/app/services/blog.service'; import { BsModalRef } from 'ngx-bootstrap/modal'; @Component({ selector: 'app-add-new-post', templateUrl: './add-new-post.component.html', styleUrls: ['./add-new-post.component.css'] }) export class AddNewPostComponent implements OnInit { addNewPostForm: FormGroup; categories: any[] = []; event: EventEmitter<any>=new EventEmitter(); constructor(private builder: FormBuilder, private blogService: BlogService, private bsModalRef: BsModalRef) { this.addNewPostForm = this.builder.group({ category: new FormControl(null, []), title: new FormControl('', []), description: new FormControl('', []) }); this.blogService.getCategoryList().subscribe(data => { Object.assign(this.categories, data); }, error => { console.log('Error while gettig category data.'); }); } onPostFormSubmit(){ let postData = { 'Title': this.addNewPostForm.get('title').value, 'Description': this.addNewPostForm.get('description').value, 'CategoryId': this.addNewPostForm.get('category').value, }; this.blogService.addPost(postData).subscribe(data=>{ console.log(data); if(data!=null && data>0){ this.event.emit('OK'); this.bsModalRef.hide(); } }); } onClose(){ this.bsModalRef.hide(); } ngOnInit() { } }
现在,让我们再次使用 ng serve 命令运行应用程序,看看迄今为止的进展。这次点击主页面上的“添加新帖子”按钮,它将打开一个模态弹出窗口,如下图所示。现在从下拉列表中选择类别,在文本框中填写标题和描述值,然后点击提交按钮。它会将值保存在数据库中,并返回到主页面,数据已更新。
现在是时候为帖子添加编辑功能了,当我们点击表格中特定记录的编辑 图标时,我们可以编辑现有帖子。所以,让我们转到 edit-post.component.html 并替换为以下代码。在这里,您可以看到我们正在创建一个响应式表单,用于编辑现有记录,其中包含所需的控件以及更新和关闭两个按钮。让我们先创建这个表单,然后实现编辑现有记录的逻辑。
edit-post.component.html
<div role="document"> <div> <form class="form-horizontal" id="add-form" [formGroup]="editPostForm" (ngSubmit)="onPostEditFormSubmit()"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="onClose()"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="add-modal-label">Edit Post</h4> </div> <div class="modal-body"> <div class="form-group"> <label class="col-sm-2 control-label">Cateogry</label> <div class="col-sm-10"> <select formControlName="category"> <option [value]="null">Select Category</option> <option *ngFor="let item of categories" [value]="item.id">{{item.name}}</option> </select> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Title</label> <div class="col-sm-10"> <input type="text" class="form-control" formControlName="title" /> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Descriptio</label> <div class="col-sm-10"> <textarea class="form-control" formControlName="description"></textarea> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal" (click)="onClose()">Close</button> <button type="submit" class="btn btn-primary">Update</button> </div> </form> </div> </div>
现在转到 EditPostComponent 并在构造函数中使用响应式表单方法创建带有默认值的表单。然后获取类别列表并绑定下拉列表。除此之外,我们还有可用的 Post Id,我们将使用它来更新数据。所以,首先让我们获取该特定 Post Id 的现有数据并将其绑定到控件的当前数据。
this.editPostForm.controls['category'].setValue(this.postData.categoryId); this.editPostForm.controls['title'].setValue(this.postData.title); this.editPostForm.controls['description'].setValue(this.postData.description);
一旦实际值设置完毕,我们就可以修改该值。修改现有值并点击更新 按钮后,它将调用 onPostEditFormSubmit() 函数,该函数负责从表单收集更新后的值,并通过 BlogService 的 EditPost 函数更新到数据库。
edit-post.component.ts
import { Component, OnInit, Input, EventEmitter } from '@angular/core'; import { FormGroup, FormBuilder, FormControl } from '@angular/forms'; import { BlogService } from 'src/app/services/blog.service'; import { BsModalRef } from 'ngx-bootstrap/modal'; @Component({ selector: 'app-edit-post', templateUrl: './edit-post.component.html', styleUrls: ['./edit-post.component.css'] }) export class EditPostComponent implements OnInit { editPostForm: FormGroup; categories: any[] = []; postId: number; postData: any; event: EventEmitter<any> = new EventEmitter(); constructor(private builder: FormBuilder, private blogService: BlogService, private bsModalRef: BsModalRef) { this.editPostForm = this.builder.group({ category: new FormControl(null, []), title: new FormControl('', []), description: new FormControl('', []) }); this.blogService.getCategoryList().subscribe(data => { Object.assign(this.categories, data); }, error => { console.log('Error while gettig category data.'); }); this.blogService.postIdData.subscribe(data => { this.postId = data; if (this.postId !== undefined) { this.blogService.getPost(this.postId).subscribe(data => { this.postData = data; if (this.editPostForm!=null && this.postData!=null) { this.editPostForm.controls['category'].setValue(this.postData.categoryId); this.editPostForm.controls['title'].setValue(this.postData.title); this.editPostForm.controls['description'].setValue(this.postData.description); } }, error => { console.log("Error while gettig post details") }); } }); } onPostEditFormSubmit() { let postData = { 'PostId': this.postId, 'Title': this.editPostForm.get('title').value, 'Description': this.editPostForm.get('description').value, 'CategoryId': this.editPostForm.get('category').value, }; this.blogService.updatePost(postData).subscribe(data => { this.event.emit('OK'); this.bsModalRef.hide(); }); } onClose() { this.bsModalRef.hide(); } ngOnInit() { } }
现在,让我们测试编辑功能。所以,首先使用 ng serve 命令运行应用程序,然后从列表中点击任意特定记录的编辑图标。它将打开一个编辑模态弹出窗口,如下图所示。所以,用新值更改实际值,然后点击更新按钮。它将用新数据更新您的现有记录,并反映到列表中,同时显示更新后的数据。
到目前为止,我们已经完成了添加 和编辑 功能。现在是时候为帖子添加删除功能 了,当我们点击表格中特定记录的删除图标时,我们可以删除现有帖子。所以,让我们转到 delete-post.component.html 并替换为以下代码。在这里,您可以看到我们只有两个按钮:删除和关闭。除此之外,在顶部,我们将显示帖子的标题以确认您正在删除正确的帖子。
delete-post.component.html
<div role="document"> <div> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="onClose()"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="add-modal-label">Delete Post</h4> </div> <div class="modal-body"> <div class="form-group"> <label class="col-sm-2 control-label">Are you sure to delete following post?</label> <div class="col-sm-10"> <h3 style="color:blue;">{{title}}</h3> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label"></label> <div class="col-sm-10"> <button type="button" class="btn btn-default" data-dismiss="modal" (click)="onClose()">Close</button> <button type="submit" class="btn btn-primary" (click)="deletePost(postId)" style="margin:5px;">Delete</button> </div> </div> </div> </div> </div>
好的,我们已经设计了删除现有帖子的页面。所以,让我们转到 DeletePostComponent 并实现删除帖子功能。点击按钮时,我们将调用 BlogService 中的 deletePost() 函数,该函数以 Post Id 作为参数。一旦您的帖子被删除,模态弹出窗口将隐藏,您的列表将更新。
delete-post.component.ts
import { Component, OnInit, EventEmitter } from '@angular/core'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { BlogService } from 'src/app/services/blog.service'; @Component({ selector: 'app-delete-post', templateUrl: './delete-post.component.html', styleUrls: ['./delete-post.component.css'] }) export class DeletePostComponent implements OnInit { postId: number; title: string; event: EventEmitter<any> = new EventEmitter(); constructor(private bsModalRef: BsModalRef, private blogService: BlogService) { } deletePost(postId: number) { this.blogService.deletePost(postId).subscribe(); this.event.emit('OK'); this.bsModalRef.hide(); } onClose() { this.bsModalRef.hide(); } ngOnInit() { } }
所以,最后让我们测试删除功能。首先,使用 ng serve 命令运行项目,然后从帖子列表中点击删除 图标。它将打开一个模态弹出窗口,如下图所示。一旦您点击删除按钮,它将删除记录并返回到主页面,您可以在其中看到帖子列表。
结论
今天,我们已经了解了如何创建一个 Angular 项目,并向其中添加 bootstrap 和 ngx-bootstrap。此外,我们还学习了如何在 Angular 应用中执行 CRUD 操作。
希望这篇文章能帮助到您。请通过评论留下您的反馈,这有助于我改进下一篇文章。如果您有任何疑问,请在评论区提问。如果您喜欢这篇文章,请与您的朋友分享。谢谢!