首頁 web前端 js教程 在Angular19中有關自訂表單控制項使用

在Angular19中有關自訂表單控制項使用

Jun 08, 2018 pm 04:23 PM
angular

這篇文章主要介紹了Angular19 自訂表單控制項的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

1 需求

當開發者需要一個特定的表單控制項時就需要自己開發一個和預設提供的表單控制項用法相似的控制項來作為表單控制項;自訂的表單控制項必須考慮模型與檢視之間的資料怎麼進行互動

2 官方文檔-> 點擊前往

##Angular為開發者提供了ControlValueAccessor介面來輔助開發者建立自訂的表單控件,開發者只需要在自訂表單控制項類別中實作ControlValueAccessor介面中的方法就可以實作模型和檢視之間的資料交互

interface ControlValueAccessor { 
 writeValue(obj: any): void
 registerOnChange(fn: any): void
 registerOnTouched(fn: any): void
 setDisabledState(isDisabled: boolean)?: void
}
登入後複製

2.1 writeValue

writeValue(obj: any): void
登入後複製

該方法用於將值寫入到自訂表單控制項中的元素;

這個參數值(obj)是使用這個自訂表單控制項的元件透過範本表單或響應式表單的資料綁定傳過來的;

在自訂表單控制項的類別中只需要將這個值(obj)賦值給一個成員變數即可,自訂表單控制項的視圖就會透過屬性綁定顯示出來這個值

2.2 registerOnChange

registerOnChange(fn: any): void
登入後複製

自訂表單控制項的資料變更時會觸發registerOnChange方法,該方用於如何處理自訂表單控制項資料的變更;

registerOnChange方法接收的參數(fn)其實是一種方法,該方法負責處理變更的資料

當自定義控制項資料變更時就會自動呼叫fn執行的方法,但是通常的做法是自訂一個方法propagateChange 讓自訂的方法指向fn,這樣當資料變更時只需要呼叫propagateChange 就可以對變更的資料進行處理

2.3 registerOnTouched

registerOnTouched(fn: any): void
登入後複製

表單控制項被觸摸時會觸發registerOnTouched方法,具體細節待更新......2018-1-31 11:18:33

2.4 setDisabledState

setDisabledState(isDisabled: boolean)?: void
登入後複製

#待更新......2018-1-31 11:19:30

#3 程式設計步驟

3.1 建立自訂表單控制項元件

<p>
 <h4>当前计数为:{{countNumber}}</h4>
 <br />
 <p>
 <button md-icon-button (click)="onIncrease()">
  <span>增加</span>
  <md-icon>add</md-icon>
 </button>
 <span style="margin-left: 30px;"></span>
 <button md-icon-button (click)="onDecrease()">
  <span>减少</span>
  <md-icon>remove</md-icon>
 </button>
 </p>
</p>
登入後複製
登入後複製

HTML

import { Component, OnInit } from &#39;@angular/core&#39;;
import { ControlValueAccessor } from &#39;@angular/forms&#39;;
@Component({
 selector: &#39;app-counter&#39;,
 templateUrl: &#39;./counter.component.html&#39;,
 styleUrls: [&#39;./counter.component.scss&#39;]
})
export class CounterComponent implements OnInit {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
}
登入後複製

3

.1.1功能描述

點選增加按鈕時目前計數會增加1,點選減少按鈕時目前計數會剪下1

## 

3.1. 2 直接在其他元件中使用時會報錯誤

 

#錯誤訊息如下:

## 

錯誤訊息是說我們我們使用的元件還不是一個表單控制項

#3.2 如何讓元件變成表單元件

3.2.1 實作ControlValueAccessor 介面

 

export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}
登入後複製

3.2.2 指定依賴資訊providers

import { Component, OnInit, forwardRef } from &#39;@angular/core&#39;;
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from &#39;@angular/forms&#39;;
@Component({
 selector: &#39;app-counter&#39;,
 templateUrl: &#39;./counter.component.html&#39;,
 styleUrls: [&#39;./counter.component.scss&#39;],
 providers: [
 {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CounterComponent),
  multi: true
 }
 ]
})
export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}
登入後複製

3.2.3 待修復bug

#雖然可以正常運行,但是表單控制項中的元素接受不到使用表單控制項那個元件中表單模型傳過來的數據,表單控制項變化的資料也無法回傳到使用表單控制項那個元件中的表單模型中去;簡而言之,就是模型和視圖之間無法進行資料交互

3.3實習那模型和試圖的資料互動

3.3.1 模型到視圖

重構自訂表單控制項類別中的writeValue 方法

#技巧01:writeValue 方法中的參數是使用自訂表單控制項的那個元件透過表單的資料綁定傳進來的

 

3.3.2 視圖到模型

》自訂一個方法來處理自訂表單控制項中的變更資料

propagateChange = (_: any) => {};
登入後複製

》重構自訂表單控制項類別中的registerOnChange 方法

 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 this.propagateChange = fn;
 }
登入後複製

》在資料變更的地方呼叫那個自訂的方法

 

#3.4 自訂表單控制項元件程式碼總結

<p>
 <h4>当前计数为:{{countNumber}}</h4>
 <br />
 <p>
 <button md-icon-button (click)="onIncrease()">
  <span>增加</span>
  <md-icon>add</md-icon>
 </button>
 <span style="margin-left: 30px;"></span>
 <button md-icon-button (click)="onDecrease()">
  <span>减少</span>
  <md-icon>remove</md-icon>
 </button>
 </p>
</p>
登入後複製
登入後複製

# HTML

import { Component, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
 selector: 'app-counter',
 templateUrl: './counter.component.html',
 styleUrls: ['./counter.component.scss'],
 providers: [
 {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CounterComponent),
  multi: true
 }
 ]
})
export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 propagateChange = (_: any) => {};
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 this.propagateChange(this.countNumber);
 }
 onDecrease() {
 this.countNumber--;
 this.propagateChange(this.countNumber);
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 this.countNumber = obj;
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 /**fn其实是一个函数,当视图中的数据改变时就会调用fn指向的这个函数,从而达到将数据传播到模型的目的 */
 this.propagateChange = fn; // 将fn的指向赋值给this.propagateChange,在需要将改变的数据传到模型时只需要调用this.propagateChange方法即可
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}
登入後複製

3.5 使用自訂表單控制項的那個元件的程式碼總結

技巧01:如果自定义表单控件和使用自定义表单控件的组件都在不在同一个模块时需要对自定义表单控件对应组件进行导出和导入操作

<p class="panel panel-primary">
 <p class="panel-heading">面板模板</p>
 <p class="panel-body">
 <h3>面板测试内容</h3>
 </p>
 <p class="panel-footer">2018-1-22 10:22:20</p>
</p>

<p class="panel-primary">
 <p class="panel-heading">自定义提取表单控件</p>
 <p class="panel-body">
 <form #myForm=ngForm>
  <app-counter name="counter" [(ngModel)]="countNumber">
  </app-counter>
 </form>
 <h6>绿线上是自定义提取的表单控件显示的内容</h6>
 <hr style="border: solid green 2px" />
 <h6>绿线下是使用自定义表单控件时表单的实时数据</h6>
 <h3>表单控件的值为:{{myForm.value | json}}</h3>
 </p>
 <p class="panel-footer">2018-1-31 10:09:17</p>
</p>

<p class="panel-primary">
 <p class="panel-heading">提取表单控件</p>
 <p class="panel-body">
 <form #form="ngForm">
  <p>outerCounterValue value: {{outerCounterValue}}</p>
  <app-exe-counter name="counter" [(ngModel)]="outerCounterValue"></app-exe-counter>
  <br />
  <button md-raised-button type="submit">Submit</button>
  <br />
  <p>
  {{form.value | json}}
  </p>
 </form>
 </p>
 <p class="panel-footer">2018-1-27 21:51:45</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">ngIf指令测试</p>
 <p class="panel-body">
 <button md-rasied-button (click)="onChangeNgifValue()">改变ngif变量</button>
 <br />
 <p *ngIf="ngif; else ngifTrue" >
  <h4 style="background-color: red; color: white" >ngif变量的值为true</h4>
 </p>
 <ng-template #ngifTrue>
  <h4 style="background-color: black; color: white">ngif变量的值为false</h4>
 </ng-template>
 </p>
 <p class="panel-footer">2018-1-27 16:58:17</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">RXJS使用</p>
 <p class="panel-body">
 <h4>测试内容</h4>
 </p>
 <p class="panel-footer">2018-1-23 21:14:49</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">自定义验证器</p>
 <p class="panel-body">
 <form (ngSubmit)="onTestLogin()" [formGroup]="loginForm">
  <md-input-container>
  <input mdInput placeholder="请输入登录名" formControlName="username" />
  </md-input-container>
  <br />
  <md-input-container>
  <input mdInput placeholder="请输入密码" formControlName="userpwd" />
  </md-input-container>
  <br />
  <button type="submit" md-raised-button>登陆</button>
 </form>
 </p>
 <p class="panel-footer">2018-1-23 11:06:01</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">响应式表单</p>
 <p class="panel-body">
 <form [formGroup]="testForm">
  <md-input-container>
  <input mdInput type="text" placeholder="请输入邮箱" formControlName="email" />
  <span mdSuffix>@163.com</span> 
  </md-input-container>
  <br />
  <md-input-container>
  <input mdInput type="password" placeholder="请输入密码" formControlName="password" />
  </md-input-container>
 </form>
 <hr />
 <p>
  <h2>表单整体信息如下:</h2>
  <h4>表单数据有效性:{{testForm.valid}}</h4>
  <h4>表单数据为:{{testForm.value | json}}</h4>
  <h4>获取单个或多个FormControl:{{testForm.controls[&#39;email&#39;] }}</h4>
  <hr />
  <h2>email输入框的信息如下:</h2>
  <h4>有效性:{{testForm.get(&#39;email&#39;).valid}}</h4>
  <h4>email输入框的错误信息为:{{testForm.get(&#39;email&#39;).errors | json}}</h4>
  <h4>required验证结果:{{testForm.hasError(&#39;required&#39;, &#39;email&#39;) | json}}</h4>
  <h4>minLength验证结果:{{ testForm.hasError(&#39;minLength&#39;, &#39;email&#39;) | json }}</h4>
  <h4>hello:{{ testForm.controls[&#39;email&#39;].errors | json }}</h4>
  <hr />
  <h2>password输入框啊的信息如下:</h2>
  <h4>有效性:{{testForm.get(&#39;password&#39;).valid}}</h4>
  <h4>password输入框的错误信息为:{{testForm.get(&#39;password&#39;).errors | json }}</h4>
  <h4>required验证结果:{{testForm.hasError(&#39;required&#39;, &#39;password&#39;) | json}}</h4>
 </p>
 <p>
  <button nd-rasied-button (click)="onTestClick()">获取数据</button>
  <h4>data变量:{{data}}</h4>
 </p>
 </p>
 <p class="panel-footer">2018-1-22 15:58:43</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">利用响应式编程实现表单元素双向绑定</p>
 <p class="panel-body">
 <md-input-container>
  <input mdInput placeholder="请输入姓名(响应式双向绑定):" [formControl]="name"/>
 </md-input-container>
 <p>
  姓名为:{{name.value}}
 </p>
 </p>
 <p class="panel-footer">2018-1-22 11:12:35</p>
</p> -->

<p class="panel panel-primary">
 <p class="panel-heading">模板表单</p>
 <p class="panel-body">
 <md-input-container>
  <input mdInput placeholder="随便输入点内容" #a="ngModel" [(ngModel)]="desc" name="desc" />
  <button type="button" md-icon-button mdSuffix (click)="onTestNgModelClick()">
  <md-icon>done</md-icon>
  </button>
 </md-input-container>
 <p>
  <h3>名为desc的表单控件的值为:{{ a.value }}</h3>
 </p>
 </p>
 <p class="panel-footer">2018-1-22 10:19:31</p>
</p>

<p class="panel panel-primary">
 <p class="panel-heading">md-chekbox的使用</p>
 <p calss="panel-body">
 <p>
  <md-checkbox #testCheckbox color="primary" checked="true">测试</md-checkbox>
 </p>
 <p *ngIf="testCheckbox.checked">
  <h2>测试checkbox被选中啦</h2>
 </p>
 </p>
 <p class="panel-footer">2018-1-18 14:02:20</p>
</p> 

<p class="panel panel-primary">
 <p class="panel-heading">md-tooltip的使用</p>
 <p class="panel-body">
 <span md-tooltip="重庆火锅">鼠标放上去</span>
 </p>
 <p class="panel-footer">2018-1-18 14:26:58</p>
</p>


<p class="panel panel-primary">
 <p class="panel-heading">md-select的使用</p>
 <p class="panel-body">
 <md-select placeholder="请选择目标列表" class="fill-width" style="height: 40px;">
  <md-option *ngFor="let taskList of taskLists" [value]="taskList.name">{{taskList.name}}</md-option>
 </md-select>
 </p>
 <p class="panel-footer">2018-1-18 14:26:58</p>
</p> 

<p class="panel panel-primary">
 <p class="panel-heading">ngNonBindable指令的使用</p>
 <p class="panel-body">
 <h3>描述</h3>
 <p>使用了ngNonBindable的标签,会将该标签里面的元素内容全部都看做时纯文本</p>
 <h3>例子</h3>
 <p>
  <span>{{taskLists | json }}</span>
  <span ngNonBindable>← 这是{{taskLists | json }}渲染的内容</span>
 </p>
 </p>
 <p class="panel-footer">2018-1-19 09:34:26</p>
</p>
登入後複製

HTML

import { Component, OnInit, HostListener, Inject} from &#39;@angular/core&#39;;
import { FormControl, FormGroup, FormBuilder, Validators } from &#39;@angular/forms&#39;;
import { Http } from &#39;@angular/http&#39;;
import { QuoteService } from &#39;../../service/quote.service&#39;;
@Component({
 selector: &#39;app-test01&#39;,
 templateUrl: &#39;./test01.component.html&#39;,
 styleUrls: [&#39;./test01.component.scss&#39;]
})
export class Test01Component implements OnInit {
 countNumber: number = 9;
 outerCounterValue: number = 5; 
 ngif = true;
 loginForm: FormGroup;
 testForm: FormGroup;
 data: any;
 name: FormControl = new FormControl();
 desc: string = &#39;hello boy&#39;;
 taskLists = [
 {label: 1, name: &#39;进行中&#39;},
 {label: 2, name: &#39;已完成&#39;}
 ];
 constructor(
 private formBuilder: FormBuilder,
 private http: Http,
 @Inject(&#39;BASE_CONFIG&#39;) private baseConfig,
 private quoteService: QuoteService
 ) {}
 ngOnInit() {
 this.testForm = new FormGroup({
  email: new FormControl(&#39;&#39;, [Validators.required, Validators.minLength(4)], []),
  password: new FormControl(&#39;&#39;, [Validators.required], [])
 });
 this.name.valueChanges
 .debounceTime(500)
 .subscribe(value => alert(value));
 this.loginForm = this.formBuilder.group({
  username: [&#39;&#39;, [Validators.required, Validators.minLength(4), this.myValidator], []],
  userpwd: [&#39;&#39;, [Validators.required, Validators.minLength(6)], []]
 });
 this.quoteService.test()
 .subscribe(resp => console.log(resp));
 }
 onChangeNgifValue() {
 if (this.ngif == false) {
  this.ngif = true;
 } else {
  this.ngif = false;
 }
 }
 @HostListener(&#39;keyup.enter&#39;)
 onTestNgModelClick() {
 alert(&#39;提交&#39;);
 }
 onTestClick() {
 // this.data = this.testForm.get(&#39;email&#39;).value;
 // console.log(this.testForm.getError);
 console.log(this.testForm.controls[&#39;email&#39;]);
 }
 onTestLogin() {
 console.log(this.loginForm.value);
 if (this.loginForm.valid) {
  console.log(&#39;登陆数据合法&#39;);
 } else {
  console.log(&#39;登陆数据不合法&#39;);
  console.log(this.loginForm.controls[&#39;username&#39;].errors);
  console.log(this.loginForm.get(&#39;userpwd&#39;).errors);
 }
 }
 myValidator(fc: FormControl): {[key: string]: any} {
 const valid = fc.value === &#39;admin&#39;;
 return valid ? null : {myValidator: {requiredUsername: &#39;admin&#39;, actualUsername: fc.value}};
 }
}
登入後複製

3.6 初始化效果展示

 

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JavaScript中Object基础内部方法图(图文教程)

在webpack中如何使用ECharts?

vue如何制作自动建站项目(详细教程)

以上是在Angular19中有關自訂表單控制項使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1249
24
聊聊Angular中的元資料(Metadata)和裝飾器(Decorator) 聊聊Angular中的元資料(Metadata)和裝飾器(Decorator) Feb 28, 2022 am 11:10 AM

這篇文章繼續Angular的學習,帶大家了解Angular中的元數據和裝飾器,簡單了解一下他們的用法,希望對大家有幫助!

如何在Ubuntu 24.04上安裝Angular 如何在Ubuntu 24.04上安裝Angular Mar 23, 2024 pm 12:20 PM

Angular.js是一種可自由存取的JavaScript平台,用於建立動態應用程式。它允許您透過擴展HTML的語法作為模板語言,以快速、清晰地表示應用程式的各個方面。 Angular.js提供了一系列工具,可協助您編寫、更新和測試程式碼。此外,它還提供了許多功能,如路由和表單管理。本指南將討論在Ubuntu24上安裝Angular的方法。首先,您需要安裝Node.js。 Node.js是一個基於ChromeV8引擎的JavaScript運行環境,可讓您在伺服器端執行JavaScript程式碼。要在Ub

淺析angular中怎麼使用monaco-editor 淺析angular中怎麼使用monaco-editor Oct 17, 2022 pm 08:04 PM

angular中怎麼使用monaco-editor?以下這篇文章記錄下最近的一次業務中用到的 m​​onaco-editor 在 angular 中的使用,希望對大家有幫助!

一文探究Angular中的服務端渲染(SSR) 一文探究Angular中的服務端渲染(SSR) Dec 27, 2022 pm 07:24 PM

你知道 Angular Universal 嗎?可以幫助網站提供更好的 SEO 支援哦!

Angular + NG-ZORRO快速開發一個後台系統 Angular + NG-ZORRO快速開發一個後台系統 Apr 21, 2022 am 10:45 AM

這篇文章跟大家分享一個Angular實戰,了解一下angualr 結合 ng-zorro 如何快速開發一個後台系統,希望對大家有幫助!

如何使用PHP和Angular進行前端開發 如何使用PHP和Angular進行前端開發 May 11, 2023 pm 04:04 PM

隨著網路的快速發展,前端開發技術也不斷改進與迭代。 PHP和Angular是兩種廣泛應用於前端開發的技術。 PHP是一種伺服器端腳本語言,可以處理表單、產生動態頁面和管理存取權限等任務。而Angular是一種JavaScript的框架,可以用來開發單一頁面應用程式和建構元件化的網頁應用程式。本篇文章將介紹如何使用PHP和Angular進行前端開發,以及如何將它們

angular學習之詳解狀態管理器NgRx angular學習之詳解狀態管理器NgRx May 25, 2022 am 11:01 AM

這篇文章帶大家深入了解angular的狀態管理器NgRx,介紹一下NgRx的使用方法,希望對大家有幫助!

使用Angular和Node進行基於令牌的身份驗證 使用Angular和Node進行基於令牌的身份驗證 Sep 01, 2023 pm 02:01 PM

身份驗證是任何網路應用程式中最重要的部分之一。本教程討論基於令牌的身份驗證系統以及它們與傳統登入系統的差異。在本教程結束時,您將看到一個用Angular和Node.js編寫的完整工作演示。傳統身份驗證系統在繼續基於令牌的身份驗證系統之前,讓我們先來看看傳統的身份驗證系統。使用者在登入表單中提供使用者名稱和密碼,然後點擊登入。發出請求後,透過查詢資料庫在後端驗證使用者。如果請求有效,則使用從資料庫中獲取的使用者資訊建立會話,然後在回應頭中傳回會話訊息,以便將會話ID儲存在瀏覽器中。提供用於存取應用程式中受

See all articles