Angular 9教程:如何构建Angular 9 CRUD应用程序

Angular 9为构建丰富的客户端Web应用程序提供了基础,该应用程序专门研究数据绑定。 Angular具有受Web组件启发的组件体系结构。 Angular中的所有内容都是很小的组成部分。这样,Angle变得越来越模块化,在大型企业级应用程序中易于处理。借助Angular,您甚至可以使用其路由模块构建本机应用程序,单页应用程序。

Angular 9教程

内容概述

  • 1 Angular 9教程
  • 2 Angular 9体系结构
  • Angular 9的3个新功能
  • 4我们将在Angular 9教程中介绍什么
  • 5 Angular 9教程工作流程
  • 6角9 CRUD
  • 7步骤1:设置Angular CLI v9
  • 8步骤2:初始化新的Angular 9 CRUD项目
  • 9步骤3:安装Bootstrap 4 CSS框架
  • 10步骤4:创建Angular组件
  • 11步骤5:创建Angular 9路由
  • 12步骤6:配置“角度路由进度指示器”。
  • 13步骤7:添加Angular路由器事件。
  • 14步骤8:添加Bootstrap 4 HTML表单
  • 15步骤9:创建Angular 9表单验证
  • 16步骤10:添加和配置HttpClientModule
  • 17步骤11:创建TypeScript模型文件。
  • 18步骤12:创建Angular 9服务文件
  • 19步骤13:将表单值提交到节点服务器
  • 20步骤14:在Node中创建一个后端API
  • 21步骤15:创建路线和模型文件。
  • 22#步骤16:将数据保存在MongoDB数据库中
  • 23#步骤17:Angular 9显示数据
  • 24#步骤18:Angular 9编辑和更新数据
  • 25#步骤19:角度9删除表格数据。

Angular源代码是用TypeScript编写的。如果您是TypeScript的新手,请在此博客中查看TypeScript示例指南。 TypeScript是Javascript的超集。

TypeScript的优点

  1. TypeScript使用ES2015或ES6类。
  2. TypeScript使用模块。因此,我们可以导入或导出任何模块。
  3. TypeScript具有强类型;这意味着,如果您为特定变量定义类型,则无法将不同类型分配给该变量。它是一种强类型语言,而不是松散耦合的语言。
  4. TypeScript具有函数签名。
  5. 我们可以在TypeScript文件中编写Javascript代码。因此,不必使用强类型代码。但是在大型Web应用程序中,强类型键入是有益的,并且可以节省大量时间。

Angular 9体系结构

角度框架基于组件。角度应用程序是第一个父组件的自举,很像HTML DOM树(从HTML元素开始然后从那里分支)。

Angular在组件树模型上运行。 Angular通过引导调用加载第一个组件后,它将在该组件的HTML视图中查找并查看是否有任何嵌套的组件。如果是这样,那么Angular会找到匹配项并在其上运行适当的组件代码。对树下的每个组件重复此过程。

Angular中的组件用于呈现HTML的一部分并为该部分提供功能。它通过Component类执行此操作,您可以在其中定义组件的应用程序逻辑。

Angular 9指令

Angular指令提供了可以传输DOM的功能。

Angular中有两种类型的指令

  1. 结构性
  2. 属性

结构指令通过更改DOM中的HTML元素来修改布局。

属性指令更改现有DOM元素的行为或外观。

您可以将指令应用于现有的DOM元素。

就像组件一样,该指令使用Angular将使用的选择器进行配置以查找匹配项并应用该指令。您可以通过不同方式应用指令。

您可以在与选择器匹配的元素上写一个属性,也可以使用模板语法添加指令和赋值语句。

除了创建指令外,Angular还提供了一些现成的指令,可通过基于某些表达式的有条件渲染的组件来处理标准Web应用程序构造,从而循环出要渲染的项目。

Angular 9数据绑定

Angular不仅仅是通过组件呈现标记模板的引擎。 Angular的优势之一是易于将数据绑定到视图以及在这些视图中使用数据。

在视图模板中显示数据的最流行方式是通过插值,即您在组件属性周围使用花括号集合来告诉Angular渲染该属性的内容。

您还可以使用内置的Angular指令和创建的指令来帮助显示数据。

指令使您可以通过客户端强大的应用程序向视图添加逻辑,类似于在服务器端的逻辑。

Angular中的模板语法非常合理,在处理视图中的数据时,您可以完成很多工作。

我们可以将click事件连接到DOM元素,这些元素会更改您在其他位置显示的数据,Angular将以可视方式控制该数据的更新。

模板语法有很多组件。除了内插和内置指令外,该语法还具有构造和模式,例如模板表达式和语句,属性,属性,类和样式绑定的绑定语法,事件绑定和模板表达式运算符。

Angular 9依赖注入

依赖注入或DI是控制反转的概念,简称IoC,您在其中构造代码的方式是为模块提供其他模块,它需要完成一些工作,而不是使模块退出并获得其他模块本身。

DI(依赖注入)使您可以编写更易于进行单元测试和使用的解耦代码。在Angular环境中,这将使您能够编写这些模块化组件甚至应用程序中的服务,并告诉Angular您要使用什么以及要在哪里使用它们。

Angular将控制这些实例的构造实例,并在需要时将其发送到您的代码中。您使用依赖注入的最常见地方是在类构造函数中。因此,您编写的指令,组件,管道和服务的构造函数可以利用Angular进行依赖注入的方式。

您可以在TypeScript的一些帮助下在构造函数参数上声明类型,并且Angular将对其进行解释,并确保构造函数运行时收到该类型的实例。

您还可以通过组件元数据,属性,指令和提供程序之类的东西来利用DI。

您甚至可以在Angular应用的引导阶段进行一些依赖注入,在应用启动时设置依赖图,并通过应用的各个方面进行传递。 DI的功能之一是能够在应用程序代码的任何阶段替换依赖项。

Angular 9服务

Angular中的服务更多是预定模式。在Angular框架中没有什么不寻常的地方,它将某些代码定义为服务。

服务意味着我们引用了我们编写的JavaScript类或函数来封装一些逻辑作为应用程序的服务。

编写组件时,最好为这些组件设计类,以使类逻辑仅包含往返于视图的数据以及向视图添加功能。

因此,如果您不将业务逻辑放入组件和指令中,那么您将其放在哪里?答案是服务。

您可以编写JavaScript类来处理从API或外部数据源中查找记录并将其作为对象返回的情况。这将是一项服务。然后使用Angular的DI,您可以指定您的Angular组件将要使用您的服务,并且可以从组件逻辑中向服务中请求数据库记录并将其提供给视图模板。

您编写的这些服务还可以利用DI,因此您可以在一些TypeScript的帮助下创建构造函数并指定参数类型,并且Angular将为您的服务实例提供适当的依赖项。

您编写的服务中没有任何东西可以为它们提供任何Angular类型的服务。它们只是普通的旧JavaScript逻辑代码。借助DI的强大功能,他们可以使用其他代码,而无需知道该代码是特定于Angular的代码。

因此,当您在应用程序代码中利用编写服务时,您将获得编写JavaScript逻辑的好处,而JavaScript逻辑绝不会与Angular框架耦合。这是Angular的优点之一。

Angular 9路由

Angular开箱即用地提供了一个路由器模块。它支持配置到组件的路径路径,路径参数,因此您可以在URL中包含变量,该指令用于指定被路由的组件将在其中显示模板的位置,创建子路径,所有导航拦截。

它还处理历史记录状态,修改浏览器默认情况下的处理方式,更改浏览器默认情况下的处理方式,以便用户执行的来回操作,以便用户执行的来回操作将导致Angular路由更改这将导致角度路线更改。

使用路由器可以使您的应用熟悉用户已经习惯的标准客户端-服务器网站体验。用户已经习惯了它。但它也为您提供了一种通过一组配置指令和链接,配置指令和链接而不是一堆条件逻辑脚本来加载不同组件的方法。

Angular 9 HttpClient

Angular框架使用XMLHttpRequest接口或fetch()API通过REST API与后端服务器进行通信。

Angular HttpClient使用XMLHttpRequest接口,该接口同时支持现代和旧版浏览器。

Angular HttpClient可从@ angular / common / http包中获得,并具有简化的API接口和强大的功能,例如键入请求,易于测试,响应对象,请求,响应拦截器,具有RxJS Observables的反应式API和简化的错误处理。

因此,这些是Angular的主要组件架构。让我们谈谈Angular 9的最新功能。

Angular 9的新功能

默认常春藤

现在,随着Angular 9的发布,Ivy渲染器是默认的Angular编译器,因此您无需在tsconfig文件中编写任何新内容即可享受Ivy。

如果在旧项目中使用了Angular 8,您会记得Ivy渲染器已经可用,但是您需要选择使用它。例如,您必须转到tsconfig.json文件,并将下面的行添加到其中。

"angularCompilerOptions": {    "enableIvy": true  }

ModuleWithProviders支持

此新功能主要供图书馆创建者使用。如果您在Angular 9之前使用过ModuleWithProviders,那么您可能会或可能不会一直在积极使用它。尽管如此,在此版本中,您始终必须使用通用的ModuleWithProviders 输入以显示您的模块类型。

以下代码是一个旧的声明。

@NgModule({ ...}) export class MyModule { static forRoot(config: SomeConfig): ModuleWithProviders {  
   return {  
         ngModule: SomeModule,  
         providers: [{ provide: SomeConfig, useValue: config }]  
   };  
 }  
}

现在,它们应类似于以下代码。

@NgModule({ ...})  
export class MyModule {  
  static forRoot(config: SomeConfig): ModuleWithProviders<**SomeModule**>  
{  
   return {  
         ngModule: SomeModule,  
         providers: [{ provide: SomeConfig, useValue: config }]  
   };  
 }  
}

如果您不知道如何将旧的角度项目迁移到Angular 9,请查看Angular 9项目更新指南。

核心中的依赖注入更改

对于依赖项注入,新版本的Angular也进行了一些改进。这不是一个重大更改,但是已经为依赖项注入的providerIn值部分添加了一些支持。

请参阅以下代码。

@Injectable({    providedIn: 'platform'  })  class MyService {...}

服务人员更新

在此最新版本的Angular中,对于服务工作者,服务工作者资产组配置中已弃用的版本文件选项已被删除。现在,看起来像这样。

"assetGroups": [  
  {  
    "name": "test",  
    "resources": {  
      "files": [  
        "/**/*.txt"  
      ]  
    }  
  }  
]

Angular i18n的改进

Angular是一个长期支持国际化的JavaScript MVC框架。使用Angular CLI,您可以生成有助于创建翻译器文件的标准代码,以便可以用多种语言发布您的angular应用程序。 Angular团队在Ivy上进一步重构了此过程,以使其更易于添加编译时内联。

我们将在Angular 9教程中介绍什么

  1. 如何安装Angular CLI 9
  2. 如何使用Angular CLI创建Angular 9项目,
  3. 如何创建Angular组件,它们之间的路由和导航。
  4. 如何创建和注入Angular服务。
  5. 如何使用HttpClient将HTTP GET,POST请求发送到服务器。
  6. 如何设置node.js Web服务器。
  7. 如何安装和配置Express Web框架。
  8. 如何创建快速路线和模型。

Angular 9教程工作流程

让我们为此Angular 9教程创建两个单独的项目。一个用于Angular前端,另一个用于Node.js后端。这意味着一个用于前端,一个用于后端。

我们将使用node和mongodb创建一个后端API,用于处理从数据库中保存,修改和删除表单值,并且前端将使用该API。例如,它显示来自后端的数据并将数据发布到节点服务器并将值存储在数据库中。

对于本教程,我使用以下技术堆栈。我已经用当前最新版本对其进行了描述。您的未来可能会有所不同。

  1. 节点v13.3.0
  2. NPM v6.13.7
  3. AngularCLI v9.0.3
  4. MongoDB Shell版本v3.6.3
  5. MongoDB版本v3.6.3
  6. Mac OS卡塔利娜

在这个博客中,我已经简短地编写了Angular 8教程,Angular 7 CRUD和Angular 6 CRUD教程。现在,Angular社区发布了下一个版本,即Angular 9。

因此,在此MEAN Stack教程中,我们将看到Angular Routing,Angular Forms,并且在后端,我们使用Node.js和Express.js来控制数据并将数据存储在服务器端。我们将使用MongoDB作为DBMS。

角9 CRUD

在这个Angular 9 Crud示例中,我们将创建Namaste Trump的Angular应用程序,该应用程序实现CRUD操作。

在2020年2月24日这一天,唐纳德·特朗普抵达印度。因此,我们将创建一个简单的Crud应用,该应用可以添加,编辑,更新和删除王牌的家庭成员。

该应用程序将使用REST API,该API从节点存储和获取所需的数据,表达Web API,使用POST请求存储网络数据,放置大小写更改,以及删除数据。

因此,我们将学习如何使用HTTPClient模块,使用Angular Form,使用路由和导航来访问REST API,以及如何创建一个简单的Calendar。还将看到如何使用Angular 9应用程序中的REST API服务器发送GET请求和处理HTTP响应 HttpClient 用于获取和使用JSON数据。

让我们开始Angular 9教程来构建一个Crud应用程序。

步骤1:设定Angular CLI v9

如果您以前没有安装过Angular CLI,请遵循以下命令。

// For Mac and Linux

sudo npm install -g @angular/cli

// For Windows

Open CMD in Administrator mode and hit the following command.

npm install -g @angular/cli

现在,运行以下命令以检查Angular CLI版本。

ng version

设置Angular CLI v9

在下一步中,我们初始化新的angular9crud项目。

步骤2:初始化新的Angular 9 CRUD项目

键入以下命令以创建新的Angular 9项目。

ng new angular9crud

CLI会问您两个问题,例如是否要添加Angular路由?键入y为是,第二个问题是您想使用哪种样式表格式?选择CSS。您可以根据自己的要求选择任何人。

这将指示CLI自动在我们的项目中设置路线,因此我们只需为角度组件添加路线即可在应用程序中实现导航。

您可以在src >> app目录中检查一个名为app-routing.module.ts的文件。

接下来,导航到您的项目目录,并使用以下命令运行本地开发服务器。

ng serve --open
➜  angular9crud git:(master) ng serve --open
0% compiling
Compiling @angular/core : es2015 as esm2015

Compiling @angular/common : es2015 as esm2015

Compiling @angular/platform-browser : es2015 as esm2015

Compiling @angular/platform-browser-dynamic : es2015 as esm2015

Compiling @angular/router : es2015 as esm2015

chunk {main} main.js, main.js.map (main) 60.6 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 140 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 9.72 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 2.97 MB [initial] [rendered]
Date: 2020-02-24T04:43:10.082Z - Hash: 7aef88a18f3aab2ca218 - Time: 22469ms
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
: Compiled successfully.

Date: 2020-02-24T04:43:11.341Z - Hash: 7aef88a18f3aab2ca218
5 unchanged chunks

Time: 857ms
: Compiled successfully.

使用“ –open”参数将在默认浏览器中自动打开此Angular 9应用程序。

默认URL是:http:// localhost:4200

Angular 9教程

您应该使开发服务器保持运行状态,并启动新的命令行界面以运行后续步骤的CLI命令。

步骤3:安装Bootstrap 4 CSS框架

接下来,使用以下命令安装Bootstrap 4 CSS库。这不是必需的步骤,您也可以选择CSS框架。例如,大多数人将使用Angular Material组件。

➜  angular9crud git:(master) ✗ npm install bootstrap --save

> fsevents@1.2.11 install /Users/krunal/Desktop/code/angular/angular9crud/node_modules/watchpack/node_modules/fsevents
> node-gyp rebuild

  SOLINK_MODULE(target) Release/.node
  CXX(target) Release/obj.target/fse/fsevents.o
  SOLINK_MODULE(target) Release/fse.node

> fsevents@1.2.11 install /Users/krunal/Desktop/code/angular/angular9crud/node_modules/webpack-dev-server/node_modules/fsevents
> node-gyp rebuild

  SOLINK_MODULE(target) Release/.node
  CXX(target) Release/obj.target/fse/fsevents.o
  SOLINK_MODULE(target) Release/fse.node
npm WARN bootstrap@4.4.1 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.
npm WARN bootstrap@4.4.1 requires a peer of popper.js@^1.16.0 but none is installed. You must install peer dependencies yourself.

+ bootstrap@4.4.1
added 139 packages from 33 contributors, updated 1 package and audited 15251 packages in 24.033s

33 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

现在,将bootstrap css文件添加到angular.json文件中。

"styles": [
   "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
 ],

步骤4:创建Angular组件

我们将创建三个Angular组件。

ng g c member-add --skipTests=true
ng g c member-get --skipTests=true
ng g c member-edit --skipTests=true

查看输出。

➜  angular9crud git:(master) ✗ ng g c member-add --skipTests=true
CREATE src/app/member-add/member-add.component.css (0 bytes)
CREATE src/app/member-add/member-add.component.html (25 bytes)
CREATE src/app/member-add/member-add.component.ts (290 bytes)
UPDATE src/app/app.module.ts (489 bytes)
➜  angular9crud git:(master) ✗ ng g c member-get --skipTests=true
CREATE src/app/member-get/member-get.component.css (0 bytes)
CREATE src/app/member-get/member-get.component.html (25 bytes)
CREATE src/app/member-get/member-get.component.ts (290 bytes)
UPDATE src/app/app.module.ts (585 bytes)
➜  angular9crud git:(master) ✗ ng g c member-edit --skipTests=true
CREATE src/app/member-edit/member-edit.component.css (0 bytes)
CREATE src/app/member-edit/member-edit.component.html (26 bytes)
CREATE src/app/member-edit/member-edit.component.ts (294 bytes)
UPDATE src/app/app.module.ts (685 bytes)
➜  angular9crud git:(master) ✗

对于此演示,我们不需要测试文件。因此,我们不会创建它。

这三个组件都将自动注册到app.module.ts文件中。这些组件将自动注册到app.module.ts。接下来,打开并编辑`src / app / app-routing.module.ts`,然后添加这些导入。

步骤5:创建Angular 9路由

将所有新创建的角度分量导入app-routing.module.ts文件中。

// app-routing.module.ts

import { MemberAddComponent } from './member-add/member-add.component';
import { MemberEditComponent } from './member-edit/member-edit.component';
import { MemberGetComponent } from './member-get/member-get.component';

将这些数组添加到包含上述组件路由的现有路由常数中。

// app-routing.module.ts

const routes: Routes = [
  {
    path: 'member/create',
    component: MemberAddComponent
  },
  {
    path: 'edit/:id',
    component: MemberEditComponent
  },
  {
    path: 'members',
    component: MemberGetComponent
  }
];

因此,最终的app-routing.module.ts文件如下所示。

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MemberAddComponent } from './member-add/member-add.component';
import { MemberEditComponent } from './member-edit/member-edit.component';
import { MemberGetComponent } from './member-get/member-get.component';

const routes: Routes = [
  {
    path: 'member/create',
    component: MemberAddComponent
  },
  {
    path: 'edit/:id',
    component: MemberEditComponent
  },
  {
    path: 'members',
    component: MemberGetComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

打开并编辑“ src / app / app.component.html”,您将看到现有的路由器出口。

接下来,修改此HTML页面以适合CRUD页面。

将以下代码写入app.component.html文件中。



转到浏览器,然后单击两个链接。您可以看到我们可以基于导航看到不同的组件。

步骤6:配置Angular路由进度指示器。

键入以下命令以安装ng2-slim-loading-bar库。

npm install ng2-slim-loading-bar --save

如果安装ng2-slim-loading-bar库,则它与Angular 9不兼容。

如果我们想弥补Angular 9和第三方软件包之间的差距,我们需要安装以下库。这就对了。

npm install rxjs-compat --save

现在,在app.module.ts文件中导入一个SlimLoadingBarModule。

// app.module.ts

import { SlimLoadingBarModule } from 'ng2-slim-loading-bar';

imports: [
    ...
    SlimLoadingBarModule
],

下一步是,将库随附的样式导入src >> styles.css文件中。

@import "../node_modules/ng2-slim-loading-bar/style.css";

步骤7:添加Angular路由器事件。

Angular RouterModule为我们提供了以下事件。

  1. NavigationStart
  2. 导航结束
  3. NavigationError
  4. 导航取消
  5. 路由器
  6. 事件

现在,将以下代码添加到app.component.ts文件中。

// app.component.ts

import { Component } from '@angular/core';
import { SlimLoadingBarService } from 'ng2-slim-loading-bar';
import {
  NavigationCancel,
  Event,
  NavigationEnd,
  NavigationError,
  NavigationStart,
  Router
} from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular9tutorial';
  constructor(private loadingBar: SlimLoadingBarService, private router: Router) {
    this.router.events.subscribe((event: Event) => {
      this.navigationInterceptor(event);
    });
  }
  private navigationInterceptor(event: Event): void {
    if (event instanceof NavigationStart) {
      this.loadingBar.start();
    }
    if (event instanceof NavigationEnd) {
      this.loadingBar.complete();
    }
    if (event instanceof NavigationCancel) {
      this.loadingBar.stop();
    }
    if (event instanceof NavigationError) {
      this.loadingBar.stop();
    }
  }
}

在上面的代码中,我们告诉Angular应用程序,当我们从一个组件导航到另一个组件时,我们想要显示路由器进度指示器。

当用户单击另一个链接时,角度进度指示器开始显示,并且当导航完成时,它将停止显示指示器。就像一个加载程序,它告诉用户某种进程正在进行中。

因此,在导航不同路线时,我们可以为用户提供最佳的用户体验。

在代码内部,发生的事情是它拦截了路由事件并将加载栏组件添加到加载路线,以便我们每次更改路线时都可以看到路线指示。

最后一步是显示路由指示器。

因此,我们需要在页面顶部的app.component.html文件内插入ng2-slim-loading-bar指令。





现在,去终端查看是否有任何错误,如果没有错误,然后去应用程序并更改路线,您会看到现在我们可以在更改不同角度时看到路由指示器路线。

步骤8:添加Bootstrap 4 HTML表单

在add-member.component.html文件中添加以下HTML代码。


保存文件并转到:http:// localhost:4200 / member / create

如何构建Angular 9 CRUD应用

步骤9:创建Angular 9表单验证

网络应用通常要做两件事之一,要么向用户显示数据,要么向用户收集数据。我们通过Web应用程序收集数据的方式是使用Web表单和更具体的表单元素。

当我们在Web应用程序中构建表单时,我们将其设计为执行一组标准的事情,以收集数据,了解用户何时更改数据,验证数据以及向用户显示错误的方式进行处理。

由于表单是Web应用程序的标准组件,因此Angular有专门的部分可帮助您处理表单。

Angular表单提供了内置的数据验证器以及创建自己的数据验证器的能力。可以在用户更改输入值时运行验证的异步验证器。它还将表单字段盘点到一个对象结构中,以便在提交时易于使用。

在Angular中有两种传统的方法来构建表单。

  1. 模板驱动:大多数表单逻辑是在模板标记中设计的。
  2. 模型驱动:大多数形式逻辑在组件类中构建。

总体而言,Angular内置的表单支持涵盖了广泛的输入收集方案。

我们将使用ReactiveFormsModule方法。现在,如果您是Angular Form Validation的新手,请在此博客上查看我的文章Angular Form Validation Example Tutorial。

下一步是在app.module.ts文件中导入ReactiveFormsModule。它附带了Angular项目。

// app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

imports: [
    ...
    ReactiveFormsModule
],

现在,我们需要对app.component.ts文件进行编码。请记住,这不是模板驱动的形式。因此我们需要将代码插入app.component.ts文件中。

首先,我们需要从@ angular / forms模块导入FormGroup,FormBuilder,Validators模块。

此外,创建构造函数并实例化FormBuilder。

因此,请在member-add.component.ts文件中编写以下代码。

// member-add.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-member-add',
  templateUrl: './member-add.component.html',
  styleUrls: ['./member-add.component.css']
})
export class MemberAddComponent implements OnInit {
  angForm: FormGroup;
  constructor(private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      MemberName: ['', Validators.required],
      MemberBio: ['', Validators.required],
      MemberAge: ['', Validators.required]
    });
  }

  ngOnInit(): void {
  }

}

我们已经使用表单构建器来处理所有验证。因此,在构造函数中,我们使用特定字段的所有验证规则创建一个表单。在我们的示例中,有三个表单字段。

如果输入文本为空,则会给我们一个错误,我们需要向用户显示该错误。

现在,在member-add.component.html文件中编写以下代码。


Member Name is required.
Member Bio is required.
Member Age is required.

转到浏览器,尝试不在任何输入框中填充任何值,然后它将显示错误。

创建Angular 9表单验证

步骤10:添加并配置HttpClientModule

大多数前端应用程序通过HTTP协议与后端服务进行通信。现代浏览器支持两种主要的用于发出HTTP请求的API:XMLHttpRequest和fetch API。

@ angular / common / http模块中的HttpClient为Angular应用程序提供了简化的客户端HTTP API,该API位于浏览器公开的XMLHttpRequest接口上。

HttpClient的其他好处包括请求,可测试性功能,键入的请求,响应对象,响应拦截,Observables API和平滑的错误处理。

现在,将HttpClientModule导入app.module.ts文件中。

// app.module.ts

import { HttpClientModule } from '@angular/common/http';

imports: [
   ...
    HttpClientModule
 ],

步骤11:创建TypeScript模型文件。

在src >> app目录中,创建一个名为Member.ts的文件并添加以下代码。

// Member.ts

export default class Member {
  MemberName: string;
  MemberBio: string;
  MemberAge: number;
}

步骤12:创建Angular 9服务文件

REST API的全部访问权限(POST,GET,PUT,DELETE)将放入Angular 9服务。 Observable发出的来自REST API的响应,可以订阅和读取组件。

点击以下命令以生成服务文件。

服务文件的主要用途是我们将所有AJAX(网络请求)代码添加到该文件中。

因此,它处理后端服务器,并从后端服务器发送和检索数据。

ng g service member --skipTests=true

因此,您所需的member.service.ts文件如下所示。

// member.service.ts

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

@Injectable({
  providedIn: 'root'
})
export class MemberService {

  constructor() { }
}

现在,将member.service.ts文件导入到app.module.ts文件中。

// app.module.ts

import { MemberService } from './member.service';

providers: [ MemberService ],

步骤13:将表单值提交到节点服务器

现在,我们将带有数据的HTTP POST请求发送到Node.js服务器,并将数据存储到MongoDB数据库中。

将以下代码写入member.service.ts文件中。

// member.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class MemberService {

  uri = 'http://localhost:4000/members';

  constructor(private http: HttpClient) { }

  addMember(MemberName, MemberBio, MemberAge) {
    const obj = {
      MemberName,
      MemberBio,
      MemberAge
    };
    console.log(obj);
    this.http.post(`${this.uri}/add`, obj)
      .subscribe(res => console.log('Done'));
  }
}

我们已经定义了后端服务API URL,但是还没有创建任何后端,但是我们将在以下几个步骤中完成它。

现在,在member-add.component.ts文件内添加addMember函数。

因此,请将以下代码写入member-add.component.ts文件中。

// member-add.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { MemberService } from '../member.service';

@Component({
  selector: 'app-member-add',
  templateUrl: './member-add.component.html',
  styleUrls: ['./member-add.component.css']
})
export class MemberAddComponent implements OnInit {
  angForm: FormGroup;
  constructor(private fb: FormBuilder, private ms: MemberService, private router: Router, ) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      MemberName: ['', Validators.required],
      MemberBio: ['', Validators.required],
      MemberAge: ['', Validators.required]
    });
  }

  addMember(MemberName, MemberBio, MemberAge) {
    this.ms.addMember(MemberName, MemberBio, MemberAge);
    this.router.navigate(['members']);
  }

  ngOnInit(): void {
  }

}

在上面的代码中,我所做的就是导入了member.service.ts文件。然后我们定义了addMember方法。

当用户单击“创建成员”按钮时将调用该方法,流程将在此处转移。我们在addMember函数中获取MemberName,MemberBio和MemberAge数据。

在该函数内部,我们将调用member.service.ts文件的addMember()函数,并随同传递三个参数。

因此,从member.service.ts文件将调用API并将成员保存在服务器上。现在,我们需要配置后端API。

到目前为止,我们已经达到了Angular 9 CRUD示例的一半。

在angular 8教程的下半部分,我们将讨论Node,Express,MongoDB,API和其他内容,因为本教程是Angular 9 CRUD Full Stack示例。

现在,我们需要将click事件添加到“添加成员按钮”。因此,将以下代码添加到member-add.component.html文件中。

因此,如果前端没有错误,我们可以提交一个表单,它将调用组件的addMember()函数。从那里,我们将调用一个角度服务,该服务将向Node.js服务器发送一个HTTP Post请求。

步骤14:在Node中创建一个后端API

在角度根文件夹内,创建一个名为API的文件夹,然后进入该文件夹。请记住,这将是与Angular前端项目完全不同的项目。

因此其node_modules文件夹与Angular项目不同。

打开API目录中的终端并点击以下命令。它将使用NPM生成package.json文件。我不想一个接一个地指定每个选项。所以我们用-y标志输入以下命令。

npm init -y

安装以下特定于节点的模块。

npm install express body-parser cors mongoose --save

如果您不想每次都重新启动节点服务器,则可以安装nodemon服务器。它的作用是,当我更改server.js文件时,它将自动重新启动node.js服务器。

npm install nodemon --save-dev

我们还安装了一个主体解析器模块,以解析来自传入Http请求的数据。

因为角度和节点应用程序都在不同的端口上运行,所以我们安装了CORS模块。

浏览器将不允许进行“跨请求来源”攻击;这就是为什么我们需要安装CORS模块以在后端服务器上接收适当的请求的原因。

我们安装了Mongoose模块,因为它为MongoDB数据库提供了ORM。

现在,在API文件夹中,创建一个名为server.js文件的文件。

在该文件中添加以下代码。

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose');

    const app = express();
    let port = process.env.PORT || 4000;

    const server = app.listen(function(){
        console.log('Listening on port ' + port);
    });

下一步是将MongoDB数据库与我们的Node Express应用程序连接。

如果您以前尚未在计算机中安装过MongoDB数据库,请先安装它,然后使用以下命令启动MongoDB服务器。

mongod

现在,我已经连接到数据库了。

在API项目文件夹中创建一个名为DB.js的文件。

在DB.js文件中编写以下代码。

// DB.js

module.exports = {
  DB: 'mongodb://localhost:27017/ng9crud'
};

在server.js文件中导入一个DB.js文件,并使用Mongoose库与MongoDB建立数据库连接。我们还可以使用Mongoose ORM使用Mongoose将数据保存在数据库中。

在server.js文件中编写以下代码,以将我们的MongoDB数据库连接到Node.js服务器。

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');

mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useUnifiedTopology: true, useNewUrlParser: true }).then(
    () => { console.log('Database is connected') },
    err => { console.log('Can not connect to the database' + err) }
);

const app = express();
app.use(bodyParser.json());
app.use(cors());
const port = process.env.PORT || 4000;

const server = app.listen(port, function () {
    console.log('Listening on port ' + port);
});

保存上面的server.js文件并启动nodemon服务器。

nodemon server

因此,现在,您在我们的计算机上运行着三台服务器。

  1. Angular开发服务器。
  2. Nodemon服务器。
  3. MongoDB服务器。

请记住,所有三台服务器都运行良好,没有任何错误。否则,我们的应用程序将无法运行。

步骤15:创建路线和模型文件。

下一步,我们需要在API文件夹内创建两个文件夹,称为“路由和模型”。

在模型文件夹中,创建一个名为Member.js的模型。

// Member.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define collection and schema for Member
let Member = new Schema({
  MemberName: {
    type: String
  },
  MemberBio: {
    type: String
  },
  MemberAge: {
    type: Number
  }
},{
    collection: 'Member'
});

module.exports = mongoose.model('Member', Member);

因此,我们已经为Member集合定义了架构。我们有三个字段,分别称为MemberName,MemberBio,MemberAge。

在routes文件夹中,创建一个名为member.route.js的文件。

将CRUD代码写在member.route.js文件中。

// member.route.js

const express = require('express');
const app = express();
const memberRoutes = express.Router();

// Require Member model in our routes module
let Member = require('../models/Member');

// Defined store route
memberRoutes.route('/add').post(function (req, res) {
  let member = new Member(req.body);
  member.save()
    .then(member => {
      res.status(200).json({ 'Member': 'Member has been added successfully' });
    })
    .catch(err => {
      res.status(400).send("unable to save to database");
    });
});

// Defined get data(index or listing) route
memberRoutes.route('/').get(function (req, res) {
  Member.find(function (err, members) {
    if (err) {
      console.log(err);
    }
    else {
      res.json(members);
    }
  });
});

// Defined edit route
memberRoutes.route('/edit/:id').get(function (req, res) {
  let id = req.params.id;
  Member.findById(id, function (err, member) {
    res.json(member);
  });
});

//  Defined update route
memberRoutes.route('/update/:id').post(function (req, res) {
  Member.findById(req.params.id, function (err, member) {
    if (!member)
      res.status(404).send("Record not found");
    else {
      member.MemberName = req.body.MemberName;
      member.MemberBio = req.body.MemberBio;
      member.MemberAge = req.body.MemberAge;

      member.save().then(member => {
        res.json('Update complete');
      })
        .catch(err => {
          res.status(400).send("unable to update the database");
        });
    }
  });
});

// Defined delete | remove | destroy route
memberRoutes.route('/delete/:id').get(function (req, res) {
  Member.findByIdAndRemove({ _id: req.params.id }, function (err, member) {
    if (err) res.json(err);
    else res.json('Successfully removed');
  });
});

module.exports = memberRoutes;

在这里,我们使用了猫鼬模型来保存,更新和删除数据库中的数据。 Mongoose是在MongoDB数据库中使用的ORM。它将在后端处理所有CRUD任务。现在,我们在路由文件上设置了所有CRUD操作功能。最后一件事是我们需要在server.js文件中导入。

请记住,server.js文件是我们后端节点应用程序的起点。因此,每个模块都必须包含在server.js文件中。

因此,我们最终的server.js文件如下所示。

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');
memberRoute = require('./routes/member.route');

mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useUnifiedTopology: true, useNewUrlParser: true }).then(
    () => { console.log('Database is connected') },
    err => { console.log('Can not connect to the database' + err) }
);


const app = express();
app.use(bodyParser.json());
app.use(cors());
app.use('/members', memberRoute);

const port = process.env.PORT || 4000;

const server = app.listen(port, function () {
    console.log('Listening on port ' + port);
});

现在,转到终端并启动节点服务器(如果尚未启动)。

nodemon server
[nodemon] 2.0.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node server.js`
Listening on port 4000
Database is connected

#Step 16:将数据保存在MongoDB数据库中

如果所有服务器都已启动并正在运行,则可以转到浏览器并填写表单数据并添加成员。如果成功,您可以在屏幕上看到类似的内容。

有时,如果您在浏览器上运行adblocker,则它将无法正常工作。因此,请关闭adblocker,然后重试此示例。

MongoDB数据库

#步骤17:Angular 9显示数据

我们可以使用Angular ngfor指令迭代后端数据并以表格格式显示数据。

在member-get.component.html文件中,编写以下代码。


Member Name Member Bio Member Age Actions
{{ member.MemberName }} {{ member.MemberBio }} {{ member.MemberAge }} Edit Delete

现在,在member.service.ts文件中,我们需要编写从MongoDB数据库中获取成员数据并将其显示在Angular应用程序中的函数。

// member.service.ts

getMembers() {
    return this
      .http
      .get(`${this.uri}`);
  }

在上面的getMembers()函数中,我们已将HTTP GET请求发送到Node.js服务器并从数据库中获取数据。

现在,我们需要在member-get.component.ts文件中包含member.service.ts文件和Member.ts文件。

将以下代码写入member-get.component.ts文件中。

// member-get.component.ts

import { Component, OnInit } from '@angular/core';
import Member from '../Member';
import { MemberService } from '../member.service';

@Component({
  selector: 'app-member-get',
  templateUrl: './member-get.component.html',
  styleUrls: ['./member-get.component.css']
})
export class MemberGetComponent implements OnInit {

  members: Member[];
  constructor(private ms: MemberService) { }

  ngOnInit() {
    this.ms
      .getMembers()
      .subscribe((data: Member[]) => {
        this.members = data;
      });
  }

}

保存文件,然后转到浏览器并切换到以下URL:http:// localhost:4200 / members。您可以看到成员列表。角9 CRUD

#Step 18:Angular 9编辑和更新数据

现在,我们需要使用_id明智地从MongoDB数据库中获取数据并将其显示在member-edit.component.html文件中。

为此,当member-edit.component.html加载时,我们向节点服务器发送AJAX请求,并使用_id和数据将其获取的特定行提取到HTML表单内的相应字段中。

因此,首先,将以下代码添加到member-edit.component.ts文件中。

// member-edit.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { MemberService } from '../member.service';

@Component({
  selector: 'app-member-edit',
  templateUrl: './member-edit.component.html',
  styleUrls: ['./member-edit.component.css']
})
export class MemberEditComponent implements OnInit {
  angForm: FormGroup;
  member: any = {};

  constructor(private route: ActivatedRoute, private router: Router, private ms: MemberService, private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      MemberName: ['', Validators.required],
      MemberBio: ['', Validators.required],
      MemberAge: ['', Validators.required]
    });
  }


  ngOnInit(): void {
    this.route.params.subscribe(params => {
      this.ms.editMember(params[`id`]).subscribe(res => {
        this.member = res;
      });
    });
  }
}

在这里,当member-edit component.ts呈现时,它将调用ngOnInit()函数并将HTTP请求发送到节点服务器,并从_id获取数据以显示在member-edit component.html文件中。

现在,在member.service.ts文件中,我们需要对editMember()函数进行编码以发送HTTP请求。

// member.service.ts

editMember(id) {
    return this
            .http
            .get(`${this.uri}/edit/${id}`);
    }

现在,我们需要在member-edit.component.html文件中添加表单代码。


Member Name is required.
Member Bio is required.
Member Age is required.

保存文件并转到列表页面,然后单击“编辑”按钮,您将看到成员编辑组件,其中包含该行中数据库中填充的表单字段。

现在,让我们根据其_id将数据更新到数据库中。

Inside the member.service.ts file, we need to write a function that updates the form fields data.请参阅以下代码。

// member.service.ts

updateMember(MemberName, MemberBio, MemberAge, id) {
    const obj = {
      MemberName,
      MemberBio,
      MemberAge
    };
    this
      .http
      .post(`${this.uri}/update/${id}`, obj)
      .subscribe(res => console.log('Done'));
  }

Okay, now write the updateMember() function inside member-edit.component.ts file.

// edit-member.component.ts

updateMember(MemberName, MemberBio, MemberAge) {
    this.route.params.subscribe(params => {
      this.ms.updateMember(MemberName, MemberBio, MemberAge, params.id);
      this.router.navigate(['members']);
    });
  }

In the above method, we get the form values from the HTML form and sends the PUT request to a backend server with the updated values, and at the server-side, the update function will grab the values and update the values inside the MongoDB database.

Save the file, and you can update the data into the Database.

#Step 19: Angular 9 Delete form data.

I have already written the edit and update service functions to make API calls.

So up until now, we have completed the Create, Read, Update task of this Angular 9 Tutorial CRUD post.

Now, take a look at how to Delete or remove the data from the Database.

Now, we have to define the click event on the delete button inside the member-get.component.html file.请参阅以下代码。


 
      
          {{ member.MemberName }}
          {{ member.MemberBio }}
          {{ member.MemberAge }}
          Edit
         Delete
      
  

Now, write the deleteMember() function inside the member-get.component.ts file.