Angular study notes

The main reference of this series of notes:
Angular learning video
Angular official document
Angular series of notes
Thank you very much!

Table of contents

1. Introduction to Angular

Angular is a development platform built on TypeScript. it includes:

  • A component-based framework for building scalable web applications
  • A set of well-integrated libraries covering a wide range of functionality, including routing, form management, client-server communication, and more
  • A set of development tools to help you develop, build, test and update your code

Angular is an open source web front-end framework developed by Google. It was born in 2009, created by Misko Hevery and others, and later acquired by Google. It is an excellent front-end JS framework, which has been used in many products of Google.

According to the statistics of the number of projects, angular (1.x, 2.x, 4.x, 5.x, 6.x, 7.x, 8.x, 9.x) is currently the most widely used framework on the Internet.

Angular is based on TypeScript and react, and vue is more suitable for medium and large enterprise-level projects than Angular.

2. Build Angular environment, create Angular project, run Angular project

2.1. Environment construction

  • Download and install NodeJs
  • Install Angular CLI
npm install -g @angular/cli

ng --version //校验安装成功与否

Related configuration can refer to the following link: https://blog.csdn.net/weixin_43938259/article/details/104792233

2.2. Create an Angular project

  • The command line enters the folder where the project is to be created
  • New Project
ng new angularDemo
//或者这样,跳过下载依赖包,后续再下载
ng new angularDemo --skip-install
cd angularDemo
cnpm install

In the middle, it will prompt whether to create an editor with routing and style, select as needed

2.3. Run the project

Enter the following command in the terminal to run the project

cd angularDemo

ng serve --open
//或者这样
ng serve --o
//或者这样
ng serve

3.Angular directory structure analysis

3.1. Directory structure analysis

- node_modules  第三方依赖包存放目录
- e2e  端到端的测试目录 用来做自动测试的
- src  应用源代码目录
|- app 包含定义应用逻辑和数据的组件文件
    |- app.component.ts 为应用的根组件定义逻辑,名为 AppComponent。当你向应用中添加组件和服务时,与这个根组件相关联的视图就会成为视图树的根。
    |- app.component.html 定义与根组件 AppComponent 关联的 HTML 模板。
    |- app.component.css 为根组件 AppComponent 定义了基本的 CSS 样式表。
    |- app.component.spec.ts 为根组件 AppComponent 定义了一个单元测试。
    |- app.module.ts 为应用的根组件定义逻辑,名为 AppComponent。定义了名为 AppModule 的根模块,它会告诉 Angular 如何组装应用。这里最初只声明一个 AppComponent。当你向应用中添加更多组件时,它们也必须在这里声明。
|- assets目录 资源目录,存储静态资源的 比如图片
|- environments 目录环境配置。Angular是支持多环境开发的,我们可以在不同的环境下(开发环境,测试环境,生产环境)共用一套代码,主要用来配置环境的
|- index.html 整个应用的根html,程序启动就是访问这个页面
|- main.ts 整个项目的入口点,Angular通过这个文件来启动项目
|- polyfills.ts 主要是用来导入一些必要库,为了让Angular能正常运行在老版本下
|- styles.css 主要是放一些全局的样式
|- tsconfig.app.json TypeScript编译器的配置,添加第三方依赖的时候会修改这个文件
|- tsconfig.spec.json 不用管
|- test.ts 也是自动化测试用的
|- typings.d.ts不用管
- .angular-cli.json   Angular命令行工具的配置文件。后期可能会去修改它,引一些其他的第三方的包
比如jquery等
- karma.conf.js karma是单元测试的执行器,karma.conf.js是karma的配置文件
- package.json
这是一个标准的npm工具的配置文件,这个文件里面列出了该应用程序所使用的第三方依赖包。实际上我们在新建项目的时候,等了半天就是在下载第三方依赖包。下载完成后会放在node_modules这个目录中,后期我们可能会修改这个文件。
- protractor.conf.js 也是一个做自动化测试的配置文件
- README.md 说明文件
- tslint.json 是tslint的配置文件,用来定义TypeScript代码质量检查的规则,不用管它

3.2.app.module.ts Analysis

app.module.ts
insert image description here

4. Angular components and templates inside components

4.1. Creating and using components

// 1.创建组件 ng g component 目录名/组件名
ng g component components/header
// 2.使用组件 <app-header></app-header>

Component ts file analysis

import {
    
     Component, OnInit } from "@angular/core"; /*引入 angular 核心*/
@Component({
    
    
  selector: "app-header" /*使用这个组件的名称*/,
  templateUrl: "./header.component.html" /*html 模板*/,
  styleUrls: ["./header.component.css"] /*css 样式*/,
})
export class HeaderComponent implements OnInit {
    
    
  /*实现接口*/
  constructor() {
    
    
    /*构造函数*/
  }
  ngOnInit() {
    
    
    /*初始化加载的生命周期函数*/
  }
}

4.2. Angular binding data

  1. There are several ways to declare attributes in component ts files
    :
/*
public     共有 *(默认)  可以在这个类里面使用、也可以在类外面使用
protected  保护类型      他只有在当前类和它的子类里面可以访问
private    私有          只有在当前类才可以访问这个属性
*/
public title:string = 'this is a title'
  1. Data Text Binding - { {}}

<h1>{
   
   {title}}</h1>
<div>1+1={
   
   {1+1}}<!--还可以运算--></div>
  1. bind HTML

this.h = "<h2>这是一个 h2 用[innerHTML]来解析</h2>";
<div [innerHTML]="h"></div>

4.3. Binding properties

<div [id]="id" [title]="msg">调试工具看看我的属性</div>

4.4. Data loop *ngFor

<!--普通循环-->
<ul>
  <li *ngFor="let item of list">
     {
   
   {item}}
  </li>
</ul>
<!-- 循环的时候设置 key -->
<ul>
  <li *ngFor="let item of list;let i = index;">
     {
   
   {item}} --{
   
   {i}}
  </li>
</ul>
<!-- template 循环数据 -->
<ul>
  <li template="ngFor let item of list">
     {
   
   {item}}
  </li>
</ul>

4.5. Conditional judgment ngIf

<!-- 常用 -->
<p *ngIf="flag">这是 ngIF 判断是否显示</p>

<p template="ngIf flag">这是 ngIF 判断是否显示</p>

4.6.ngSwitch

<ul [ngSwitch]="score">
  <li *ngSwitchCase="1">已支付</li>
  <li *ngSwitchCase="2">订单已经确认</li>
  <li *ngSwitchCase="3">已发货</li>
  <li *ngSwitchDefault>无效</li>
</ul>

4.7. Execution event (click)

<button class="button" (click)="getData()">点击按钮触发事件</button>

<button class="button" (click)="setData()">点击按钮设置数据</button>
getData(){
    
     /*自定义方法获取数据*/
  //获取
  alert(this.msg);
  }

setData(){
    
    
  //设置值
  this.msg='这是设置的值';
}

keyboard events

<input type="text" (keyup)="keyUpFn($event)" />
keyUpFn(e){
    
    
   console.log(e)
}
// e可能会报错,因为现阶段版本要求加上类型了,改成这样keyUpFn(e:any){...}

4.8. Two-way data binding (important)

  1. app.module.ts imports FormsModule
...
import {
    
     FormsModule } from '@angular/forms';

...
imports: [
   BrowserModule,
   FormsModule
],
  1. used in the component
<!-- 需要在组件中声明inputValue -->
<input type="text" [(ngModel)]="inputValue" /> {
   
   {inputValue}}

4.9.[ngClass] 、[ngStyle]

<!-- 'xxx':xx 类名:布尔值-->
<div [ngClass]="{
     
     'red': true, 'blue': false}">这是一个 div</div>

public flag=false;
<div [ngClass]="{
     
     'red': flag, 'blue': !flag}">这是一个 div</div>

public arr = [1, 3, 4, 5, 6];
<ul>
  <li *ngFor="let item of arr, let i = index">
    <span [ngClass]="{
     
     'red': i==0}">{
   
   {item}}</span>
  </li>
</ul>
<div [ngStyle]="{
     
     'background-color':'green'}">你好 ngStyle</div>
public attr='red';

<div [ngStyle]="{
     
     'background-color':attr}">你好 ngStyle</div>

4.10. Pipeline

<p>{
   
   {today | date:'yyyy-MM-dd HH:mm:ss' }}</p>
public today=new Date();

Other pipelines: http://bbs.itying.com/topic/5bf519657e9f5911d41f2a34

4.11. Example: Angular forms

Realize the effect:
insert image description here

Specific implementation: https://www.bilibili.com/video/BV1X4411472m?p=5

See angularDemo4

5. Services in Angular and custom services

5.1. Services in Angular

  1. Reasons for Angular to introduce services
    In Angular applications, many functions need to share data and business logic, such as: HTTP requests, form validation, logging, etc. If these functions are implemented in components, the code will be lengthy and difficult to maintain and test. To solve this problem, Angular provides the concept of service.

By using services, we can extract the common code in the application, encapsulate it into an injectable class, and share it in the whole application. Doing so helps improve code reusability, maintainability, and testability. It also allows components to focus more on displaying data and handling user interaction.

  1. Definition of service
    A service is an injectable class in Angular, which is usually used to implement a specific function, such as: HTTP request, form validation, logging, etc. Services contain some properties and methods that can be called by other components or services. The service is defined as follows:
  • Create a plain Typescript class.
  • Add the @Injectable() decorator to the class to indicate that the class can be injected into other components or services. This decorator tells the Angular dependency injection system that this class is a service.
  • Define properties and methods in the service class. These properties and methods can be used to store data, manipulate data, or perform certain tasks.
import {
    
     Injectable } from "@angular/core";

/* @Injectable() 服务
注意,这个新的服务导入了 Angular 的 Injectable 符号,并且给这个服务类添加了 @Injectable() 装饰器。 它把这个类标记为依赖注入系统的参与者之一。 
@Injectable() 装饰器会接受该服务的元数据对象,就像 @Component() 对组件类的作用一样。
*/

/* 默认情况下,Angular CLI 命令 ng generate service 会通过给 @Injectable() 装饰器添加 providedIn: 'root' 元数据的形式,用根注入器将你的服务注册成为提供者。 */
@Injectable({
    
    
  providedIn: "root",
})
export class MyService {
    
    
  private data: any;

  getData() {
    
    
    return this.data;
  }

  setData(data: any) {
    
    
    this.data = data;
  }
}

The above code defines a service class named MyService, which contains a private property named data, and two public methods: getData and setData. This service can be injected into other components or services in the application.

  1. Benefits of service
  • Improves code reusability: Services make code reusable more easily because they can be injected and used throughout the application.
  • Reduce code coupling: Through services, we can separate business logic from components, making components more focused on displaying data and handling user interactions. Doing so reduces the coupling between code, making the application easier to maintain and test.
  • Ease of testing: Since services can be shared across the application, we can more easily write unit and integration tests to ensure the stability and correctness of our application.
    Better modular management: services can help us better manage the various modules of the application, making the code easier to expand and maintain.
  1. use of services
  • Create the service
    First, create a service in the Angular application. A service can be spawned by running the following command:
ng generate service my-service

This will create a service called "my-service" in the project and register it in the app.module.ts file.

  • Injecting a service
    To use a service, it needs to be injected into a component or other service. Inject the service using the constructor:
// 引入
import {
    
     MyService } from '../myservice.service';

// 注入服务
constructor(private myService: MyService) {
    
     }
  • Adding the method
    Now that the service has been injected, it is ready to be used in the component. For example, if you have a method called "getData" in your "my-service" service, you can call that method in your component:
getData(){
    
    
   this.data = this.myService.getData()
}

PS: Generally, the getData() method is called in the ngOnInit() method instead of in the constructor.
Keep the constructor simple and only do minimal initialization operations, such as assigning the parameters of the constructor to attributes. The constructor should not do anything. It certainly shouldn't be calling a function to make an HTTP request to a remote service (such as a real data service).
Instead, choose to call getData() in the ngOnInit lifecycle hook, and then Angular will call ngOnInit() at an appropriate time after constructing an instance of the component.

5.2. Example: TodoList and search history cache data function

  • proposed service
  1. storage.service.ts
import {
    
     Injectable } from "@angular/core";

@Injectable({
    
    
  providedIn: "root",
})
export class StorageService {
    
    
  constructor() {
    
    }

  set(key: string, value: any) {
    
    
    localStorage.setItem(key, JSON.stringify(value));
  }
  get(key: string) {
    
    
    return JSON.parse(localStorage.getItem(key) || "");
  }

  remove(key: string) {
    
    
    localStorage.removeItem(key);
  }
}
  1. app.module.ts
import {
    
     NgModule } from "@angular/core";
import {
    
     BrowserModule } from "@angular/platform-browser";

import {
    
     FormsModule } from "@angular/forms";

import {
    
     AppComponent } from "./app.component";
import {
    
     SearchComponent } from "./components/search/search.component";
import {
    
     TodolistComponent } from "./components/todolist/todolist.component";

//引入并且配置服务
import {
    
     StorageService } from "./services/storage.service";

FormsModule;
NgModule;
@NgModule({
    
    
  declarations: [AppComponent, SearchComponent, TodolistComponent],
  imports: [BrowserModule, FormsModule],
  providers: [StorageService],
  bootstrap: [AppComponent],
})
export class AppModule {
    
    }
  1. app.component.html
<app-todolist></app-todolist>
  • Example 1: TodoList
    insert image description here
  1. todolist.component.html
<h2>todoList</h2>
<div class="todolist">
  <input
    id="todoInput"
    type="text"
    [(ngModel)]="keyword"
    (keyup)="doAdd($event)"
  />
  <hr />

  <h3>待办事项</h3>
  <ul>
    <li *ngFor="let item of todolist,let key = index" [hidden]="item.status==1">
      <input
        type="checkbox"
        [(ngModel)]="item.status"
        (change)="checkBoxChange()"
      />{
   
   {item.title}} <button (click)="deleteTodo(key)">X</button>
    </li>
  </ul>
  <h3>已完成事项</h3>
  <ul>
    <li *ngFor="let item of todolist,let key = index" [hidden]="item.status==0">
      <input type="checkbox" [(ngModel)]="item.status" />{
   
   {item.title}}
      <button (click)="deleteTodo(key)">X</button>
    </li>
  </ul>
</div>
  1. todolist.component.scss
h2 {
  text-align: center;
}
.todolist {
  width: 400px;
  margin: 20px auto;
  #todoInput {
    margin-bottom: 20px;
    width: 300px;
    height: 32px;
  }

  li {
    line-height: 60px;
  }
}
  1. todolist.component.ts
/*
1、ng g service services/storage
2、app.module.ts 里面引入创建的服务 并且声明import { storageService } from './services/storage.serviceproviders:[storageService]
3、在用到的组件里面
//引入服务
import { storageService ] from '../../services/storage. service';
//初始化
constructor(public storage:StorageService){
    console.log(storage);
}
*/

import {
    
     Component } from "@angular/core";
//引入服务
import {
    
     StorageService } from "src/app/services/storage.service";

@Component({
    
    
  selector: "app-todolist",
  templateUrl: "./todolist.component.html",
  styleUrls: ["./todolist.component.scss"],
})
export class TodolistComponent {
    
    
  public keyword: string = "";
  public todolist: any[] = [];

  //服务注入
  constructor(public storage: StorageService) {
    
    
    console.log(storage);
  }
  ngOnInit() {
    
    
    //服务使用
    var todolist = this.storage.get("todolist");
    if (todolist) {
    
    
      this.todolist = todolist;
    }
  }
  doAdd(e: any) {
    
    
    if (e.keyCode == 13) {
    
    
      // console.log(this.keyword)
      if (this.keyword !== "") {
    
    
        if (!this.todoListHasKeyword(this.todolist, this.keyword)) {
    
    
          this.todolist.push({
    
     title: this.keyword, status: false });
          //******数据持久化******
          this.storage.set("todolist", this.todolist);
        } else {
    
    
          alert("数据已经存在!");
        }
        this.keyword = "";
      }
    }
  }
  deleteTodo(key: any) {
    
    
    this.todolist.splice(key, 1);
    //******数据持久化******
    this.storage.set("todolist", this.todolist);
  }
  todoListHasKeyword(todolist: any[], keyword: any) {
    
    
    let flag: boolean = false;
    todolist.forEach((item) => {
    
    
      if (item.title == keyword) flag = true;
    });
    return flag;
  }
  //监听多选框变化事件
  checkBoxChange() {
    
    
    console.log("change");
    this.storage.set("todolist", this.todolist);
  }
}
  • Example 2: Search history cache
    insert image description here
  1. search.component.html
<div class="search">
  <input type="text" [(ngModel)]="keyword" />
  <button (click)="doSearch()">搜索</button>
  <hr />
  <ul>
    <li *ngFor="let item of historyList,let key = index">
      {
   
   {item}}
      <button (click)="deleteHistory(key)">x</button>
    </li>
  </ul>
</div>

2.search.component.scss

.search {
  width: 400px;
  margin: 20px auto;
  input {
    margin-bottom: 20px;
    width: 300px;
    height: 32px;
  }

  button {
    height: 32px;
    width: 80px;
  }

  li {
    button {
      width: 20px;
      height: 20px;
      border-radius: 50%;
    }
  }
}
  1. search.component.ts
import {
    
     Component } from "@angular/core";
//引入服务
import {
    
     StorageService } from "src/app/services/storage.service";

@Component({
    
    
  selector: "app-search",
  templateUrl: "./search.component.html",
  styleUrls: ["./search.component.scss"],
})
export class SearchComponent {
    
    
  public keyword: string = "";
  public historyList: string[] = [];
  constructor(public storage: StorageService) {
    
    
    console.log(storage);
  }
  ngOnInit() {
    
    
    //页面刷新会出发这个生命周期函数
    var searchList = this.storage.get("searchList");
    if (searchList) {
    
    
      this.historyList = searchList;
    }
  }

  doSearch() {
    
    
    // console.log(this.keyword)
    if (this.keyword !== "") {
    
    
      // let index = this.historyList.indexOf(this.keyword)
      // if(index != -1) this.historyList.splice(index,1)
      // this.historyList.unshift(this.keyword)

      if (this.historyList.indexOf(this.keyword) == -1) {
    
    
        this.historyList.push(this.keyword);
        //数据持久化
        this.storage.set("searchList", this.historyList);
        //重置keyword
        this.keyword = "";
      }
    }
  }
  deleteHistory(key: number) {
    
    
    // console.log(key)
    this.historyList.splice(key, 1);
    //数据持久化
    this.storage.set("searchList", this.historyList);
  }
}

6. Dom operation in Angular and @ViewChild and Angular perform css3 animation

6.1. DOM manipulation in Angular

  1. Native JS
ngAfterViewInit(){
    
    
    let oBox1:any = document.getElementById('box1')
    console.log(oBox1.innerHTML)
    oBox1.style.color='blue'
  }
  1. ViewChild
// ViewChild获取DOM节点

// 1.模板中给dom起名字  #xxx
<div #myBox>
    我是一个Dom节点
</div>

// 2.在业务逻辑里面引入ViewChild并获取节点
import {
    
     ViewChild } from '@angular/core';
// 写在类里面,获取dom节点
@ViewChild('myBox') mybox:any;

// 3.ngAfterViewInit生命周期函数获取Dom

//使用节点
console.log(this.mybox.nativeElement)
this.mybox.nativeElement.style.width = '100px'
this.mybox.nativeElement.style.height = '50px'
this.mybox.nativeElement.style.background = 'red'
console.log(this.mybox.nativeElement.innerHTML);

for example:

<app-header #header></app-header>
<hr />

<div #myBox>我是一个Dom节点</div>
<button (click)="getChildRun()">获取子组件的方法</button>
//引入ViewChild
import {
    
     Component, ViewChild } from "@angular/core";

@Component({
    
    
  selector: "app-news",
  templateUrl: "./news.component.html",
  styleUrls: ["./news.component.scss"],
})
export class NewsComponent {
    
    
  // 获取dom节点
  @ViewChild("myBox") mybox: any;
  // 获取一个组件
  @ViewChild("header") header: any;

  constructor() {
    
    }
  ngOnInit(): void {
    
    }
  ngAfterViewInit(): void {
    
    
    console.log(this.mybox.nativeElement);
    this.mybox.nativeElement.style.width = "100px";
    this.mybox.nativeElement.style.height = "50px";
    this.mybox.nativeElement.style.background = "red";
    console.log(this.mybox.nativeElement.innerHTML);

    // //调用子组件的方法
    // this.header.run()
  }
  getChildRun() {
    
    
    this.header.run();
  }
}

6.2. In the parent-child component, the method of calling the child component through ViewChild

  1. Call the subcomponent to define a name for the subcomponent
<app-footer #footerChild></app-footer>
  1. Introducing ViewChild
import {
    
     Component, OnInit, ViewChild } from "@angular/core";
  1. ViewChild is associated with the subcomponent just now
@ViewChild('footerChild') footer;
  1. call child component
run(){
    
    
   this.footer.footerRun();
}

6.3. Example: Angular executes css3 animation

transition.module.ts

import {
    
     Component } from "@angular/core";

@Component({
    
    
  selector: "app-transition",
  templateUrl: "./transition.component.html",
  styleUrls: ["./transition.component.scss"],
})
export class TransitionComponent {
    
    
  showAside() {
    
    
    //原生js获取节点
    var asideDom: any = document.getElementById("aside");
    asideDom.style.transform = "translate(0,0)";
  }
  hideAside() {
    
    
    //原生js获取节点
    var asideDom: any = document.getElementById("aside");
    asideDom.style.transform = "translate(100%,0)";
  }
}

7. Parent-child components and communication between components in Angular

7.1. Parent components pass values ​​to child components

7.1.1.@input

Parent components can not only pass simple data to child components, but also pass their own methods and the entire parent component to child components.

  1. When the parent component calls the child component, the data is passed in
<app-header [msg]="msg"></app-header>
  1. The subcomponent imports the Input module
import {
    
     Component, OnInit, Input } from "@angular/core";

3. @Input in the child component receives data from the parent component

export class HeaderComponent implements OnInit {
    
    
  // Input
  @Input() msg: string;

  constructor() {
    
    }
  ngOnInit() {
    
    }
}
  1. Use the data of the parent component in the child component
<h2>这是头部组件--{
   
   {msg}}</h2>

7.1.2.@ViewChild

  1. Call the subcomponent to define a name for the subcomponent
<app-footer #footerChild></app-footer>
  1. Introducing ViewChild
import {
    
     Component, OnInit, ViewChild } from "@angular/core";
  1. ViewChild is associated with the subcomponent just now
@ViewChild('footerChild') footer;
  1. call child component
run(){
    
    
   this.footer.footerRun();
}

7.2. The child component triggers the method of the parent component through @Output

  1. Subcomponents introduce Output and EventEmitter
import {
    
     Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
  1. Instantiate EventEmitter in subcomponent
@Output() private outer=new EventEmitter<string>();
/*用 EventEmitter 和 output 装饰器配合使用 <string>指定类型变量*/
  1. Subcomponents broadcast data through the EventEmitter object outer instance
sendParent(){
    
    
  this.outer.emit('msg from child')
}
  1. When the parent component calls the child component, define the receiving event, outer is the EventEmitter object outer of the child component
<app-header (outer)="runParent($event)"></app-header>
  1. When the parent component receives the data, it will call its own runParent, and at this time, the data of the child component can be obtained
//接收子组件传递过来的数据
runParent(msg:string){
    
    
   alert(msg);
}

7.3. Non-parent-child component communication

  1. public service
  2. Localstorage (recommended)
  3. Cookie

8. Angular life cycle

Lifecycle functions in Angular
official documentation: https://www.angular.cn/guide/lifecycle-hooks

Generally speaking, the life cycle function is a series of methods that will be triggered when the component is created, updated, and destroyed.

When Angular uses the constructor to create a new component or directive, it will call these lifecycle hook methods at a specific moment in the following order.
insert image description here
insert image description here
insert image description here

9. Rxjs Asynchronous Data Flow Programming - Rxjs Quick Start Tutorial

9.1. Introduction to Rxjs

RxJS is the JavaScript implementation of the ReactiveX library. It is a powerful library for asynchronous and event-driven programming using observables. It provides a powerful and easy-to-use way to work with asynchronous data streams, sequences of events, and reactive programming.

RxJS helps developers easily handle asynchronous code, events, and stream-based data while keeping the code clean and readable. One of the main advantages of RxJS is that it takes a functional reactive programming (FRP) approach, which means that data flow can be processed using chained calls and composed operations.

The most commonly used concepts in RxJS are Observable, Observer and Subscription. Observable represents an observable object, that is, a data source, that can emit multiple values ​​or an error or completion signal. Observer is just a listener for processing values ​​received from Observable, which can be a callback function or an object with next, error, complete methods. Subscription represents the execution of Observable, and the execution of Observable can be cancelled.

In addition to the above concepts, RxJS also provides many operators for processing data in Observable streams, such as map, filter, reduce, merge, etc. By using these operators, the RxJS data flow can be transformed into any form the developer needs.

RxJS is suitable for a variety of scenarios, including web applications, mobile applications, and server-side applications. By using RxJS, developers can easily create efficient, readable and maintainable code and handle asynchronous tasks, events and streaming data.

Advantages of RXJS
Asynchronous programming: RXJS provides a powerful asynchronous programming solution that makes handling asynchronous events easier and more intuitive.
Reactive Programming: RXJS provides a reactive programming paradigm that allows us to easily create data flow based applications.
Composability: RXJS' operators are highly composable, and they can be easily combined to create complex data flows.
Rich operators: RXJS has rich operators, including map, filter, reduce, scan, etc. These operators greatly simplify the process of data conversion and filtering.

RXJS usage scenarios
RXJS is widely used in JavaScript, especially in web development. Here are some scenarios:
Handling Asynchronous Requests: By using Observable objects, we can easily handle asynchronous requests and get the data when the request is completed.
Handling user input: By creating a data stream, we can listen for user input events and then process them accordingly.
Handling UI events: Similarly, we can also listen to DOM events and perform corresponding operations according to the type of the event.
Handling WebSocket connections: Using RXJS can easily handle WebSocket connections to achieve real-time communication.

Overall, RXJS provides a flexible, composable, and extensible asynchronous programming solution that can be used in many scenarios.

9.2. The process of using RXJS

RxJS is a stream processing library that allows you to process streams of data in a declarative and reactive manner. Here are some basic steps to use RxJS:

  • Install RxJS
    You can use npm or yarn to install RxJS. For example, installing via npm can use the following command:
npm install rxjs
  • Introducing RxJS modules
    Introduce RxJS modules where RxJS is required. For example, if you want to use Observable, you can import it like this:
import {
    
     Observable } from "rxjs";
  • Creating an Observable
    Use the Observable.create() method to create an Observable object. For example, you can create a simple Observable that will emit some value and then complete:
const observable = new Observable((observer) => {
    
    
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
});
  • Subscribing to an Observable
    Use the Observable.subscribe() method to subscribe to an Observable and define handlers to handle the values ​​emitted by the Observable. For example, a callback function could be defined to print each value emitted by an Observable:
observable.subscribe((value) => console.log(value));
  • Handling Observable
    can use operators (such as map, filter, etc.) to process the emitted value. For example, each value can be doubled using the map operator:
observable
  .pipe(map((value) => value * 2))
  .subscribe((value) => console.log(value));

The above are some basic steps of RxJS. Of course, RxJS has many more features and operators available, depending on your needs.

9.3. Current common asynchronous programming methods

  • Callback
//1、回调函数解决异步传参问题
getCallBackData(cb: any) {
    
    
   setTimeout(() => {
    
    
   var data = '张三--Callback';
   // return data;
   cb(data);
   }, 1000);
}
// callback获取异步数据
let callbackData = this.request.getCallBackData((data: any) => {
    
    
  console.log("callback:" + data);
});
  • Event listening/publishing and subscribing

  • Promise

getPromiseData() {
    
    
    return new Promise((resolve, reject) => {
    
    
      setTimeout(() => {
    
    
        var data = '张三--Promise';
        // return data;
        resolve(data);
      }, 3000);
    });
  }
// promise获取异步数据
let promiseData = this.request.getPromiseData();

promiseData.then((data) => {
    
    
  console.log(data);
});
// console.log(promiseData);
  • Rxjs
getRxjsData() {
    
    
    return new Observable<any>((observer) => {
    
    
      setTimeout(() => {
    
    
        var data = '张三--Rxjs';
        // return data;
        observer.next(data);
        // observer.error('失败返回这个')
      }, 3000);
    });
  }
// Rxjs
let rxjsData = this.request.getRxjsData();
rxjsData.subscribe((data: any) => {
    
    
  console.log(data);
});

From the above list, we can see that the basic usage of RxJS and Promise is very similar, except for some keywords. Promise uses then()and resolve(), while RxJS uses next()and subscribe().

From the above example, we feel that the usage of Promise and RxJS is basically similar. 其实Rxjs相比Promise 要强大很多. For example, Rxjs can be withdrawn midway, Rxjs can emit multiple values, Rxjs provides a variety of tool functions, and so on.

9.4. Several applications of Rxjs different from Promise

9.4.1. Rxjs unsubscribe Unsubscribe

Once the Promise is created, the action cannot be undone. Observable is different, the action can be withdrawn midway through the unsbscribe() method, and Observable has done intelligent processing internally.
Actions cannot be undone once the Promise is created:

let promise = new Promise((resolve) => {
    
    
  setTimeout(() => {
    
    
    resolve("---promise timeout---");
  }, 2000);
});

promise.then((value) => console.log(value));

Rxjs can withdraw the subscribe action through unsubscribe():

let stream = new Observable((observer) => {
    
    
  let timeout = setTimeout(() => {
    
    
    clearTimeout(timeout);
    observer.next("observable timeout");
  }, 2000);
});

let disposable = stream.subscribe((value) => console.log(value));
setTimeout(() => {
    
    
  //取消执行
  disposable.unsubscribe();
}, 1000);

9.4.2. Rxjs executes multiple times after subscription

If we want to execute the method in asynchronously multiple times, such as the following code.

Promise cannot do this. For Promise, the final result is either resole (cash out) or reject (rejection), and both of them can only be triggered once. If the resolve method is called multiple times on the same Promise object, an exception will be thrown.
Unlike Observable, it can continuously trigger the next value, as the name of the next() method implies.

//多次执行
getPromiseIntervalData() {
    
    
   return new Promise((resolve, reject) => {
    
    
   setInterval(() => {
    
    
      var data = '张三--Promise--interval';
      // return data;
      resolve(data);
   }, 3000);
   });
}

//promise多次执行
let promiseIntervalData = this.request.getPromiseIntervalData()
promiseIntervalData.then((data)=>{
    
    //只会执行一次
   console.log(data);
})
getRxjsIntervalData() {
    
    
    return new Observable<any>((observer) => {
    
    
      setInterval(() => {
    
    
        var data = '张三--Rxjs--interval';
        // return data;
        observer.next(data);
        // observer.error('失败返回这个')
      }, 3000);
    });
  }


//rxjs多次执行
let rxjsIntervalData = this.request.getRxjsIntervalData()
rxjsIntervalData.subscribe((data)=>{
    
    //可以多次执行
console.log(data);
})

9.5. Use Rxjs tool function map filter before Angualr6.x

Note: After Angular6 uses the previous rxjs method, the rxjs-compat module must be installed to use the map and filter methods.

After angular6, the official use is the new feature of RXJS6, so the official has given a way to temporarily delay the need to modify the rsjx code.

// 下载包
npm install rxjs-compat

// 引入rxjs
import {
    
    Observable} from 'rxjs';
import 'rxjs/Rx';

//使用
let stream= new Observable<any>(observer => {
    
    
  let count = 0;
  setInterval(() => {
    
    
      observer.next(count++);
   }, 1000);
});

// filter
stream.filter(val=>val%2==0).subscribe(value => console.log("filter>"+value));

// map
stream.map(value => {
    
    
        return value * value
  }).subscribe(value => console.log("map>"+value));

The map() operator maps each value emitted by an Observable 映射to another value as a 新的Observable返回. This allows you to perform certain transformations on the values ​​emitted by the Observable, such as multiplying numbers by 2, converting strings to uppercase letters, and so on.

Similar to map(), filter() is also an operator for 过滤Observable发出的数据. 它基于给定的条件,只发出符合条件的值. For example, if we have an Observable that contains a sequence of numbers from 1 to 10, and we only want to filter out even numbers, we can use the filter() operator to do so.

9.6. Delayed execution of Rxjs

RxJS provides several ways to delay execution. Here are a few of them:

  • delay()Operator: Delays the emission of Observable events for a period of time before emitting them. For example, of(1, 2, 3).pipe(delay(1000)) emits the three values ​​1, 2, 3 after 1 second.
  • timer()Operator: emits a value after a specified time, which can be used in conjunction with other operators. For example, timer(1000).pipe(map(() => 'hello')) emits the string 'hello' after 1 second.
  • debounceTime()and throttleTime() operators: used for anti-shake and throttling respectively. debounceTime() waits for a period of time after the Observable emits a value before emitting the value. If a new value is emitted during the waiting period, the timer will restart. throttleTime() only emits the first value within a period of time, ignoring subsequent values, and does not allow the next value to pass until the time is up.
  • delayWhen()Operator: Delays the emission event of Observable for a period of time, but this period of time is determined by an Observable. For example, of(1, 2, 3).pipe(delayWhen(() => timer(1000))) emits the three values ​​1, 2, 3 in sequence after 1 second.

In addition to the above operators, there are operators such as timeout(), etc. that can also implement delayed execution. delayWhen()When using, you need to choose the appropriate operator according to the actual needs.

import {
    
     Observable, fromEvent } from "rxjs";
import {
    
     map, filter, throttleTime } from "rxjs/operators";

var button = document.querySelector("button");
fromEvent(button, "click")
  .pipe(throttleTime(1000))
  .subscribe(() => console.log(`Clicked`));

10. Data interaction in Angular (get jsonp post)

10.1. Angular get request data

1. Introduce and inject HttpClientModule in app.module.ts

import {
    
     HttpClientModule } from "@angular/common/http";
imports: [BrowserModule, HttpClientModule];

2. Introduce HttpClient where it is used and declare it in the constructor

import {
    
     HttpClient } from "@angular/common/http";
constructor(public http:HttpClient) {
    
     }

3. Get request data

var api = "http://a.itying.com/api/productlist";
this.http.get(api).subscribe((response) => {
    
    
  console.log(response);
});

10.2. Angular post submit data

After Angular5.x, get, post and interact with the server use the HttpClientModule module.

1. Introduce and inject HttpClientModule in app.module.ts

import {
    
     HttpClientModule } from "@angular/common/http";
imports: [BrowserModule, HttpClientModule];

2. Introduce HttpClient and HttpHeaders where they are used and declare HttpClient in the constructor

import {
    
     HttpClient, HttpHeaders } from "@angular/common/http";
constructor(public http:HttpClient) {
    
     }

3. post submit data

const httpOptions = {
    
    
  headers: new HttpHeaders({
    
     "Content-Type": "application/json" }),
};
var api = "http://127.0.0.1:3000/doLogin";
this.http
  .post(api, {
    
     username: "张三", age: "20" }, httpOptions)
  .subscribe((response) => {
    
    
    console.log(response);
  });

10.3. Angular Jsonp request data

1. Introduce HttpClientModule and HttpClientJsonpModule in app.module.ts and inject them

import {
    
     HttpClientModule, HttpClientJsonpModule } from "@angular/common/http";
imports: [BrowserModule, HttpClientModule, HttpClientJsonpModule];

2. Introduce HttpClient where it is used and declare it in the constructor

import {
    
     HttpClient } from "@angular/common/http";
constructor(public http:HttpClient) {
    
     }

3. jsonp request data

var api = "http://a.itying.com/api/productlist";
this.http.jsonp(api, "callback").subscribe((response) => {
    
    
  console.log(response);
});

10.4. Use the third-party module axios to request data in Angular

1. Install axios

npm install axios --save

2. Introduce axios where it is used

import axios from "axios";

3. Look at the documentation and use

axios
  .get("/user?ID=12345")
  .then(function (response) {
    
    
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    
    
    // handle error
    console.log(error);
  })
  .then(function () {
    
    
    // always executed
  });

11. Routing in Angular

11.1. Introduction to Routing in Angular

Routing in Angular can be used to implement navigation between different components. It allows users to navigate to different pages or views within an application without refreshing the entire page.

11.2. Routing usage in Angular

Here are the steps on how to use routing to navigate in Angular:

  1. Install the Angular routing module

You need to install the @angular/router module, which can be done through the npm package manager. Run the following command in a terminal window:

npm install @angular/router --save
  1. Import RouterModule and Routes in app.module.ts

Open the app.module.ts file and import RouterModule and Routes:

import {
    
     RouterModule, Routes } from "@angular/router";

Generally, when we create a new angular project, we will choose whether to add a route. If we enter y, it will automatically import the package of the second step for us, so usually steps 1 and 2 can be omitted.

  1. Create an array of routes

In app-routing.module.ts (this file is automatically generated when you choose to create routes when creating the project) (app.module.ts), create a routes array that will define all the routes in your application. Examples are as follows:

const routes: Routes = [
  {
    
     path: "", component: HomeComponent },
  {
    
     path: "about", component: AboutComponent },
  {
    
     path: "contact", component: ContactComponent },
  {
    
     path: "**", redirectTo: "" }, //找不到页面时就重定向
];

In this example, we define three routes: home page (/), about page (/about) and contact page (/contact).

  1. Add routing to NgModule

In the NgModule metadata of app-routing.module.ts (app.module.ts), add the route to the imports array:

@NgModule({
    
    
  declarations: [AppComponent, HomeComponent, AboutComponent, ContactComponent],
  imports: [BrowserModule, RouterModule.forRoot(routes)],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {
    
    }

This step can usually be omitted, it has been generated when the project is created

  1. Add router-outlet to the template

Add a router-outlet tag to the AppComponent template, this will be the routing container for all components in your application:

<router-outlet></router-outlet>
  1. Create navigation links

In any component of your application, you can use the routerLink directive to create navigation links. For example, in a menu component, you can create the following links:

<!-- 快捷键 ng-router-link -->
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
<a routerLink="/contact">Contact</a>
  1. trigger navigation

When the user clicks on one of the navigation links, Angular automatically navigates to the corresponding route. If you want to navigate programmatically, you can inject the Router service and use the navigate() method to do so:

import {
    
     Router } from '@angular/router';

constructor(private router: Router) {
    
    }

goToAboutPage() {
    
    
  this.router.navigate(['/about']);
}

That's the basic steps of how to use routing for navigation in Angular.

11.3. Dynamic Routing

11.3.1. Basic use of dynamic routing

1. Configure dynamic routing

const routes: Routes = [
  {
    
     path: "home", component: HomeComponent },
  {
    
     path: "news", component: NewsComponent },
  // /:id 接收动态参数
  {
    
     path: "newscontent/:id", component: NewscontentComponent },
  {
    
    
    path: "",
    redirectTo: "/home",
    pathMatch: "full",
  },
];

2. Jump to pass value (if you don't understand the reason, watch the video to understand better)

<a [routerLink]="[ '/newscontent/',aid]">跳转到详情</a>
<a [routerLink]="/newscontent/{
    
    {aid}}">跳转到详情</a>

3. Get the value of dynamic routing

import {
    
     ActivatedRoute } from "@angular/router";
constructor( private route: ActivatedRoute) {
    
    
}

ngOnInit() {
    
    
  console.log(this.route.params);
  this.route.params.subscribe(data=>this.id=data.id);
}

11.3.2. JS jump of dynamic routing

  1. introduce
import {
    
     Router } from "@angular/router";

2. Initialization

export class HomeComponent implements OnInit {
    
    
  constructor(private router: Router) {
    
    }
  ngOnInit() {
    
    }
  goNews() {
    
    
    // this.router.navigate(['/news', hero.id]);
    this.router.navigate(["/news"]);
  }
}

3. Routing jump

this.router.navigate(["/news", hero.id]);

11.4. Routing get pass value js jump

  1. Introducing NavigationExtras
import {
    
     Router, NavigationExtras } from "@angular/router";
  1. Define a goNewsContent method to execute the jump, and use NavigationExtras to configure the parameters.
goNewsContent(){
    
    
  let navigationExtras: NavigationExtras = {
    
    
      queryParams: {
    
     'session_id': '123' },
      fragment: 'anchor'
  };
  this.router.navigate(['/news'],navigationExtras);
}
  1. get get pass value
constructor(private route: ActivatedRoute) {
    
    
   console.log(this.route.queryParams);
}

11.5. Parent-child routing

  1. Create component import component
import {
    
     NewsaddComponent } from "./components/newsadd/newsadd.component";
import {
    
     NewslistComponent } from "./components/newslist/newslist.component";
  1. configure routing
{
    
    
  path: 'news',
  component:NewsComponent,
  children: [
  {
    
    
     path:'newslist',
     component:NewslistComponent
},
{
    
    
   path:'newsadd',
   component:NewsaddComponent
}]}
  1. Define router-outlet in the parent component
<router-outlet></router-outlet>
// js跳转路由
/*
---------动态路由----------
1.引入声明模块
import { Router } from '@angular/router';
constructor(public router:Router){}
2.跳转
this.router.navigate(['/productcontent', '1234'])


//跳转并进行get传值
let queryParams:NavigationExtras = {
      queryParams:{aid:111}
    }
this.router.navigate(['/news'],queryParams)

-----------get传值-----------
1.引入声明模块
import { Router,NavigationExtras } from '@angular/router';
constructor(public router:Router){}

2.跳转

//跳转并进行get传值
let queryParams:NavigationExtras = {
  queryParams:{aid:111}
}

12. Custom modules in Angular

12.1. Angular built-in modules

Angular is a JavaScript framework, and its core modules include:

  • @angular/core: This is one of the most important modules, which defines the various core components and services required by an Angular application.

    Including: Component, Directive, Pipe, Service, etc.

  • @angular/common: This module provides many common Angular features, such as date formatting, number formatting, internationalization support, etc.

    Including: CommonModule, NgIf, NgForOf, DecimalPipe, etc.

In addition, Angular has several other commonly used modules:

  • @angular/forms: This module provides functions such as form building, validation, and interaction.

    Including: FormsModule、ReactiveFormsModule、FormControl etc.

  • @angular/platform-browser: This module allows you to run Angular applications in the browser and provides basic functions such as DOM and HTTP.

    Including: BrowserModule, platformBrowserDynamic, HttpClient, etc.

By introducing these modules, we can develop Angular applications more conveniently.

12.2. Angular custom module

When our project is relatively small, we don't need to customize the module. But when our project is very large, it is not particularly appropriate to mount all components into the root module. So at this time we can customize modules to organize our projects. And the lazy loading of routes can be realized through Angular custom modules.
insert image description here

12.2.1. Use of angular custom modules

  1. Create modules from the command line
// 新建模块
ng g module module/user

// 模块中新建组件
ng g component module/user //这一步执行完后就会和app的内容差不多
ng g component module/user --routing //还可以加上路由

ng g component module/user/components/profile

//模块中新建服务
ng g service module/user/services/common
  1. app.module.ts imports custom modules
// 引入自定义模块
import {
    
     UserModule } from './modules/user/user.module';
...

imports: [
    ...
    UserModule,
    ...
  ],
  1. Call the module in html
<h2>调用用户模块</h2>
<app-user></app-user>

Generally, we can only call the root component of the custom module. If we want to call the subcomponent of the custom module externally, such as ProfileComponent, we need to export it in the custom module (user.module.ts).
exports:[UserComponent, ProfileComponent],//暴露组件,让其他模块里面可以使用暴露的组件

12.2.2. Angular custom module implements lazy loading

Lazy loading - does not introduce the corresponding components, but jumps to the corresponding interface through routing

  1. app.module.ts does not import components in custom modules
import {
    
     NgModule } from "@angular/core";
import {
    
     BrowserModule } from "@angular/platform-browser";

import {
    
     AppRoutingModule } from "./app-routing.module";
import {
    
     AppComponent } from "./app.component";

@NgModule({
    
    
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {
    
    }
  1. app.module.html
<header>
  <a [routerLink]="[ '/user' ]">用户模块</a>
  <a [routerLink]="[ '/product' ]">产品模块</a>
  <a [routerLink]="[ '/article' ]">文章模块</a>
</header>

<router-outlet></router-outlet>
  1. app-routing.module.ts
import {
    
     NgModule } from "@angular/core";
import {
    
     RouterModule, Routes } from "@angular/router";

// 懒加载---并没有引入相应组件,而是通过路由去跳转到相应界面
const routes: Routes = [
  {
    
    
    path: "user",
    loadChildren: () =>
      import("./module/user/user.module").then((x) => x.UserModule),
  },
  {
    
    
    path: "product",
    loadChildren: () =>
      import("./module/product/product.module").then((x) => x.ProductModule),
  },
  {
    
    
    path: "article",
    loadChildren: () =>
      import("./module/article/article.module").then((x) => x.ArticleModule),
  },
  {
    
     path: "**", redirectTo: "user" },
];

@NgModule({
    
    
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {
    
    }
  1. user-routing.module.ts
import {
    
     NgModule } from "@angular/core";
import {
    
     RouterModule, Routes } from "@angular/router";
import {
    
     ProfileComponent } from "./components/profile/profile.component";
import {
    
     AddressComponent } from "./components/address/address.component";

import {
    
     UserComponent } from "./user.component";
//第一个path!!!
const routes: Routes = [
  {
    
     path: "", component: UserComponent },
  {
    
     path: "profile", component: ProfileComponent },
  {
    
     path: "address", component: AddressComponent },
];

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

Guess you like

Origin blog.csdn.net/m0_43416592/article/details/130710821