angular 指令渲染_[Angular 组件库 NG-ZORRO 基础入门] - 待办事项 + 双向绑定

2023-11-03

前言回顾

这几天我们已经完成了 TODO 待办事项 的一些基本功能,涉及多个组件的使用方式,今天我们将 TODO 待办事项 的一些组件独立出来维护,介绍一些组件设计的小方法后,我们将对这个项目里涉及的组件进行一一讲解,有助于大家更加深刻地理解 NG-ZORRO 的常用组件。

看一下我们目前的项目情况:

待办事项

菜单目录

todo
├── task-detail
│   ├── task-detail.component.html
│   ├── task-detail.component.less
│   └── task-detail.component.ts
├── todo.component.html
├── todo.component.less
└── todo.component.ts

我们看到,待办事项 项目文件结构如图,我们现在只将 task 详情抽离出来,看一下 todo.component.html 里渲染待办任务列表的代码,这里显示逻辑全部写在该 component 里面,对于后续维护十分困难:

<div class="task-container">
  <div class="task-todo">
    <nz-table [nzData]="listOfTodoTasks" [nzNoResult]="noResultTpl" [nzFrontPagination]="false" [nzShowPagination]="false" [nzWidthConfig]="tableWidthConfig">
      <tbody>
        <tr *ngFor="let task of listOfTodoTasks">
          <td
            nzShowCheckbox
            (nzCheckedChange)="checkTask(task)"
          ></td>
          <td>{{task.name}}</td>
          <td>
            <i class="more-actions" nz-icon nzType="ellipsis" nz-dropdown [nzDropdownMenu]="actions" nzPlacement="bottomRight" nzTrigger="click" (click)="setActivatedTask(task)"></i>
          </td>
        </tr>
      </tbody>
    </nz-table>
  </div>
</div>

列表组件

那么我们想剥离列表部分,作为一个独立模块来维护该怎么做呢?

创建组件

很简单,让我们先创建一个组件 task-list,然后看下我们新的项目结构:

$ cd ng-zorro-ironman2020
$ ng g c components/demos/todo/task-list --skip-import

看一下新目录结构

todo
├── task-detail
│   ├── task-detail.component.html
│   ├── task-detail.component.less
│   └── task-detail.component.ts
├── task-list
│   ├── task-list.component.html
│   ├── task-list.component.less
│   └── task-list.component.ts
├── todo.component.html
├── todo.component.less
└── todo.component.ts

组件设计

我们把列表相关的代码全部迁移至 TaskListComponent,这时我们面临一个问题,如何渲染待办任务数据并和 TodoComponent 内的数据同步。

我们先来第一种设计方案(stackblitz 在线代码演示):

@Component({
  selector       : 'app-task-list',
  templateUrl    : './task-list.component.html',
  styleUrls      : [ './task-list.component.less' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TaskListComponent implements OnInit, ControlValueAccessor {
  @Input() listOfTasks: ITask[] = [];
  constructor() {}
  ngOnInit() {}
}

task-list.component.html 使用方式为:

<app-task-list [listOfTasks]="listOfTodoTasks"></app-task-list>

todo.component.ts 新增任务方法仍然不变:

addTask(): void {
  if (this.createForm.valid) {
    const newTask = {
      ...this.createForm.getRawValue(),
      id: new Date().getTime()
    };
    this.listOfTodoTasks = this.listOfTodoTasks.concat([ newTask ]);
    // reset after adding new task
    this.createForm.get('name').reset();
  }
}

我们接受一个 ITask 类型的数组,然后渲染需要的数据,咋一看并没有什么问题,但是当尝试去新增一个新数据的时候出现了问题,我们看一下:

发现问题了吗?我们在 TaskListComponent 组件中完成的任务又被添加回来了,原因很简单,就是 TodoComponentlistOfTodoTasks 数据和 TaskListComponentlistOfTasks 数据不是同步的,我们可以通过 双向绑定 的方法来实现数据同步(对于通过 API 方式请求数据渲染的场景可以通过 Rxjs 的 Subject 去订阅重新渲染,我们暂时不对这种情况深入讨论)。

双向绑定

了解双向绑定

对于上面的例子,如果我们要以 双向绑定 模式来使用的话,该怎么写呢?

<app-task-list [(ngModel)]="listOfTodoTasks"></app-task-list>

那么到底什么是 ngModel 呢?看一下 官方介绍,当然,要想使用 ngModel,别忘了引入 FormsModule

它可以接受一个领域模型作为可选的 Input。如果使用 [] 语法来单向绑定到 ngModel,那么在组件类中修改领域模型将会更新视图中的值。 如果使用 [()] 语法来双向绑定到 ngModel,那么视图中值的变化会随时同步回组件类中的领域模型。

如何在自定义组件中实现双向绑定

在官方文档 模板语法 一节中,专门提到了 ngModel 的实现过程。

ngModel 输入属性会设置该元素的值,并通过 ngModelChange 的输出属性来监听元素值的变化。
各种元素都有很多特有的处理细节,因此 NgModel 指令只支持实现了ControlValueAccessor的元素, 它们能让元素适配本协议。 输入框正是其中之一。 Angular 为所有的基础 HTML 表单都提供了值访问器(Value accessor),表单一章展示了如何绑定它们。
你不能把 [(ngModel)] 用到非表单类的原生元素或第三方自定义组件上,除非写一个合适的值访问器,这种技巧超出了本章的范围。
你自己写的 Angular 组件不需要值访问器,因为你可以让值和事件的属性名适应 Angular 基本的双向绑定语法,而不使用 NgModel。 前面看过的 sizer就是使用这种技巧的例子。

文档中提到“NgModel 指令只支持实现了ControlValueAccessor的元素”,很显然我们的组件需要继承 ControlValueAccessor,看到以下定义,我们只需要继承需要的功能,注册 NG_VALUE_ACCESSOR 即可实现。

interface ControlValueAccessor {
  writeValue(obj: any): void
  registerOnChange(fn: any): void
  registerOnTouched(fn: any): void
  setDisabledState(isDisabled: boolean)?: void
}

开始改造

让我们改造一下 TaskListComponent,打开 task-list.component.ts,重写如下代码:

import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-task-list',
  templateUrl: './task-list.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  // register NG_VALUE_ACCESSOR to support ngModel
  providers      : [
    {
      provide    : NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TaskListComponent),
      multi      : true
    }
  ]
})
export class TaskListComponent implements OnInit {
  // 部分代码已省略
  listOfTasks: ITask[] = [];
  constructor(
    private cdr: ChangeDetectorRef,
  ) {}
  ngOnInit() {}

  checkTask(task: ITask): void {
    this.listOfTasks = this.listOfTasks.filter(v => v.id !== task.id);
    // ngModelChange事件,同步数据
    this.onChange(this.listOfTasks);
  }

  /**
   * Update ngModel -> update listOfSelectedValue
   */
  onChange: (value: ITask[]) => void = () => [];
  onTouched: () => void = () => null;

  writeValue(tasks: ITask[]): void {
    if (tasks) {
      this.listOfTasks = [ ...tasks ];
      // markForCheck to render table data
      this.cdr.markForCheck();
    }
  }

  registerOnChange(fn: (value: ITask[]) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }
}

这样,一个支持 ngModel 双向绑定的组件已经完成了,我们再来看看 这个例子 ,现在已经能正常渲染数据了:

总结 & 预告

今天我们介绍了如何通过 implements ControlValueAccessor来实现自定义组件的双向绑定,这对于一些表单业务场景有很大的作用,能够保证我们同一份数据在多组件模块下的同步问题。

之前在 待办事项 项目中,很多组件都是使用了最简单常用的使用方式和属性,我们在接下来几天会对这个项目中涉及的组件进行专项解读,帮助大家更容易地理解怎么使用这些组件。

相关资源

  • iThelp 地址:
[Angular 元件庫 NG-ZORRO 基礎入門] Day 06 - 待辦事項 + 雙向繫結 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天​ithelp.ithome.com.tw
  • github 代码:
simplejason/ng-zorro-ironman2020​github.com
  • stackblitz 在线示例:
angular-s3c1qh-qplzgm - StackBlitz​stackblitz.com
  • ngModel:
Angular - NgModel​angular.cn
  • ControlValueAccessor:
Angular - ControlValueAccessor​angular.cn
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

angular 指令渲染_[Angular 组件库 NG-ZORRO 基础入门] - 待办事项 + 双向绑定 的相关文章

  • CSS揭秘学习笔记(背景与边框)

    背景与边框 1 半透明边框 我们的预期是给box容器设置一个白色背景以及一个半透明的边框 但是box的背景色会从它的半透明边框上面透上来 默认情况下 背景会延伸到边框所在的区域
  • STM32 memset卡死

    MDK官方给的文档里面 memset应该按照memset void length value 的顺序 不能用C语言中的顺序menset void value length 的顺序
  • selenium页面元素定位、操作

    1 打开 关闭浏览器 2 打开URL链接 3 定位单个页面元素 3 1 通过ID定位 3 2 通过name定位 3 3 通过classname定位 3 4 通过CSS定位 3 5 通过链接的文本信息定位 3 6 通过XPath定位 3 6
  • C++String 和 char类型的区别和用法辨析

    众所周知 C 中有两种类型类型的字符串 一种是STL的string容器 另一种是char类型的数组 一 基本区别 要说最基本的区别 就是string可以包含多个字符 char类型只有1个字符 且分别用双引号和单引号 string temp1
  • 门电路OD门

    漏极开路输出的门电路 OD门 为了满足输出电平的变换 输出大负载电流 以及实现 线与 功能 将CMOS门电路的输出级做成漏极开路的形式 称为漏极开路输出的门电路 简称OD Open Drain Output 门 1 结构和符号 图为OD输出
  • 使用jquery加载子页面

    官方解释说明 用法 selector load URL data callback 必需的 URL 参数规定您希望加载的 URL 可选的 data 参数规定与请求一同发送的查询字符串键 值对集合 可选的 callback 参数是 load
  • 【NLP】第 6 章:XGBoost 超参数

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 【鸿蒙应用ArkTS开发系列】- 常量类定义和使用

    本篇为入门基础知识介绍 作为代码学习记录使用 请选择性阅读 一 常量类定义 在ArkTS中 定一个常量很简单 具体如下 export const TAB HOME INDEX number 1 export const TAB HOME N
  • Qt学习——控件Widgets

    Qt的控件可以在设计窗口左边部分看到 各个控件的使用 可以直接拖动至Dialog中即可 将界面布置完成后 再在源文件中编写对应的代码 下面通过一个综合的使用 熟悉一下常用控件 1 首先将一个QLabel 一个QLineEdit 两个QPus
  • 使用CURL来获取COOKIE的方法

    php curl lib 中 设置一个Cookie文件 cookeFilePath 在初始化以后和执行访问页面以前调用 curl setopt c CURLOPT COOKIEFILE cookieFilePath curl setopt
  • 奇奇怪怪的电脑小知识

    1 关闭键盘右上角最右边的灯 不知道怎么把这个灯点亮了 关闭的话 FN win 或者按ScrollLock键盘 后续再补充别的吧
  • AIGC:文生图模型Stable Diffusion

    1 Stable Diffusion介绍 Stable Diffusion 是由CompVis Stability AI和LAION共同开发的一个文本转图像模型 它通过LAION 5B子集大量的 512x512 图文模型进行训练 我们只要简
  • Opencv交通标志识别

    文章目录 前言 效果预览 数据集下载地址 训练模型 模型预测 项目结构及源码下载 前言 本文使用的数据集包含43种交通标志 使用opencv以及卷积神经网络训练模型 识别交通标志 使用pyqt5制作交通标志识别GUI的界面 效果预览 如视频
  • python读取pdf并写入excel_Python读取pdf表格写入excel代码方法

    本篇文章小编给大家分享一下Python读取pdf表格写入excel代码方法 文章代码介绍的很详细 小编觉得挺不错的 现在分享给大家供大家参考 有需要的小伙伴们可以来看看 避免CV大法 pdf 文件的表格的数据可以复制 但是这是一项非常繁琐的
  • Numpy学习笔记——常用函数

    3 1 文件读写 3 2 动手实践 读写文件 savetxt 将数组保存到文件中 i2 np eye 2 print i2 np savetxt eye txt i2 3 3 CSV 文件 3 4 动手实践 读入CSV 文件 NumPy中的
  • 心电监护仪、呼吸机、超声电机

    目录 一 心电监护仪原理和使用步骤详解 什么是心电监护仪 心电监护仪原理 1 系统基本组成 2 便携式远程心电监护仪结构及原理 3 便携式心电监测仪结构及原理 心电监护仪使用步骤 二 便携式心电监护仪设计 1 系统总体设计 2 系统硬件设计
  • vm虚拟服务器经常网卡丢失,Vmware虚拟机中Ubuntu系统找不到网卡的问题解决

    Vmware上新建出的Ubuntu可以使用 问题就是找不到网卡了 提示 No such device eth0 解决过程不写了 反正耗掉了我好几个小时 原因是Vmware保存的硬件配置文件 vmx里记录了网卡的MAC地址 而Ubuntu也会
  • 江东子弟今犹在,不见霸王卷土来-------重启编程记录征程之序

    炮炮是个爱看书的孩子 喜欢网文 喜欢小说 不yy 不种马 记得看历史小说的时候总有那么几个人 又惋惜 又不忍 一个是三国吕奉先 赤兔马 方天戟 勇武过人 器宇轩昂 另一个就是江东楚霸王 乌骓马 破城戟 力拔山兮 铁骨柔情 历史对与错不予评说
  • Java学习笔记12——StringBuilder

    StringBuilder 为什么要用StringBuilder String与StringBuilder的区别 StringBuilder的构造方法 StringBuilder的添加和反转 添加append 反转reverse Strin

随机推荐

  • 【Nginx配置】反向代理、负载均衡、解决跨域、文件大小限制、缓存限制、超时响应限制

    话不多说直接上配置 worker processes 1 线程打开2个 有一个是主线程 运行很稳定 events worker connections 1024 工作进程的最大连接数量 反向代理设置 upstream server list
  • ORACLE之case when用法

    Oracle中case when的用法 case when 表达式是一个通用条件的表达式 可以在表达式有效的任何位置使用 用法如下 CASE WHEN condition THEN result WHEN condition THEN re
  • ajax回调函数demo,window_让回调函数 showResponse 也带上参数的代码,function demo(){ var url="ajaxdemo.asp"; - phpStudy...

    让回调函数 showResponse 也带上参数的代码 function demo var url ajaxdemo asp var paras var myAjax new Ajax Request url method post par
  • 计算机毕业设计Node.js+Vue流浪动物救助网站(程序+源码+LW+部署)

    该项目含有源码 文档 程序 数据库 配套开发软件 软件安装教程 欢迎交流 项目运行 环境配置 Node js Vscode Mysql5 7 HBuilderX Navicat11 Vue Express 项目技术 Express框架 No
  • js控制伪元素属性更改

    首先 先简单说一下伪元素都有哪些 伪元素有六个 分别是 after before first line first letter selection backdrop 其中 after和 before是网站用的比较多的 有些场景我们想要通过
  • 嵌入式Linux Qt5 (C++)开发栏目概述

    本栏目开始介绍Linux系统下的Qt C 程序开发 资源是以嵌入式为切入点 现在Linux系统下的Qt C 程序开发好像就是应用于嵌入式 那就跟着一起学习Linux系统下的Qt C 程序开发知识 再扩展一下嵌入式的知识吧 我这里默认已经熟悉
  • LeetCode:动态规划中的股票问题【来和我一起用Python炒股吧~】

    股票问题是动态规划里面非常非常经典的问题了 本文列举了8道经典题目 都给出了详细的分析 可以发现这些题目的思路都是一致的 只是细节不同而已 赶快刷起来 quad PS 本文是参考代码随想录做的一些笔记 完整版本请戳链接 非常好的教程 121
  • 9月计算机二级考后须知 & 下次考试通知

    哈喽 小伙伴们大家好啊 2022年9月计算机等级考试已接近尾声 提前祝参加考试的同学都能顺利上岸 再次预祝参加9月考试的同学锦鲤附体 都是过儿 考完试后 这几件事你还得知道 目录 02 下次考试情况 03 备考12月二级 刷题软件 公众h
  • C++网络编程-高性能服务器编程

    目录 5 linux网络编程基础api 5 1 socket地址api 主机字节序和网络字节序 通用socket地址 专用socket地址 ip转换函数 5 2 创建socket 5 3 命名socket 5 4 监听socket 5 5
  • Eclipse中使用Mybatis自动生成

    插件的安装 Help gt Eclipse Marketpalce 搜索mybatis 选择如下图的插件 一路安装 重启idea 配置文件的生成 new gt file gt other 搜索mybatis 选择如下图文件 运行文件 自动生
  • 【华为OD】

    一 题目描述 某公司研发了一款高性能 AI 处理器 每台物理设备具备 8 颗 AI 处理器 编号分别为 0 1 2 3 4 5 6 7 编号 0 3 的处理器处于同一个链路中 编号 4 7 的处理器处于另外一个链路中 不通链路中的处理器不能
  • 分页---Vue+.net+bootstrap实现

    通过学习Vue 的确觉的Vue的双向绑定使用起来十分方便 因此研究了一下列表显示时分页的实现 这里我使用了bootstrap的样式 所以在页面中引用bootstrap的样式文件 后台提数据源使用 net的 数据库访问使用EF 如果库中存有大
  • SvelteKit 1.0 - 建立个人博客,显示您的 DEV 帖子

    这篇文章的目的是提供最新版本的 SvelteKit 的简要介绍 我们将构建一个开发人员组合和博客网站 从您的 RSS 提要和 GitHub API 中获取数据 内容 SvelteKit 简介 我们要建造什么 让我们开始吧 步骤 0 先决条件
  • seaborn 超全用就完事了

    seaborn Seaborn 01 图控制 01 Seaborn 02 颜色板控制 02 Seaborn 03 数据分布图 03 Seaborn 04 Jointplot两变量图 04 Seaborn 05 Pairplot多变量图 05
  • 大一同学快要期末考试的Python专业课复习 第一章

    第一章 Ptthon 简介 1 1 Python 概述 1 2 搭建 Python 开发环境 1 3 第一个 Python 程序 1 3 1 在IDLE 中编写 Hello World 程序 1 3 2 运行 Python 程序 1 4 P
  • SpringBoot定时任务及分布式锁

    目录 目录 目录 前言 一 定时任务 二 Cron表达式 用短横线 表示时间段 用L表示最后 L是单词Last 最后的 的首字母 Scheduled常用参数的差异 三 分布式锁 分布式锁 项目目中的问题及解决办法 分布式锁的实现 前言 需求
  • 编写测试分析

    编写测试分析的目的 在方向上明确要测什么 怎么测 以及达到什么样质量标准 按照从主到次 从上到下 梳理系统思路 明确测试点 便于对需求的了解和分析 通过编写软件测试分析可间接整理出需求设计的缺陷 提前了解整体测试任务 预测测试风险 测试分析
  • vue项目发布后,webpack源码F12能查看

    正常情况下 webpack 打包的 vue 项目 发布后在浏览器中F12可以直接查看到前端源码 解决这个问题 在 config js 文件中找到 productionSourceMap true 改为 false 如果没有效果 增加 Sou
  • YOLO的训练数据和标注方法是怎样的?如何准备和处理数据集?

    YOLO You Only Look Once 是一种高效的实时目标检测算法 它在训练过程中需要准备适当的数据集和相应的标注 本文将介绍YOLO算法的训练数据和标注方法 以及如何准备和处理数据集 为读者提供一个全面的指南 YOLO的训练数据
  • angular 指令渲染_[Angular 组件库 NG-ZORRO 基础入门] - 待办事项 + 双向绑定

    前言回顾 这几天我们已经完成了 TODO 待办事项 的一些基本功能 涉及多个组件的使用方式 今天我们将 TODO 待办事项 的一些组件独立出来维护 介绍一些组件设计的小方法后 我们将对这个项目里涉及的组件进行一一讲解 有助于大家更加深刻地理