尝试使用在模板驱动窗体上实现ControlValueAccessor的Angular 4自定义组件
我正在使用Angular 4.3.6和typescript版本2.20。我已经创建了一个Angular 4自定义组件,它实现了ControlValueAccessor,并希望在我的一个模板驱动表单上使用它,但当我尝试此操作时,自定义组件的writeValue和registerOnChange事件不会触发。我以前创建过一个自定义组件,它们在被动表单上工作得很好,所以我想知道是否有可能在模板驱动的表单上使用实现ControlValueAccessor的自定义组件。这可能吗?如果是,我做错了什么?(我编辑了这篇文章,因为我现在对这个问题有了更清晰的认识。)下面是我的代码:尝试使用在模板驱动窗体上实现ControlValueAccessor的Angular 4自定义组件,angular,angular-components,angular-reactive-forms,angular-template,angular-forms,Angular,Angular Components,Angular Reactive Forms,Angular Template,Angular Forms,我正在使用Angular 4.3.6和typescript版本2.20。我已经创建了一个Angular 4自定义组件,它实现了ControlValueAccessor,并希望在我的一个模板驱动表单上使用它,但当我尝试此操作时,自定义组件的writeValue和registerOnChange事件不会触发。我以前创建过一个自定义组件,它们在被动表单上工作得很好,所以我想知道是否有可能在模板驱动的表单上使用实现ControlValueAccessor的自定义组件。这可能吗?如果是,我做错了什么?(我
import { Component, OnInit, ViewChild, OnDestroy, Output, EventEmitter, Input, forwardRef } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { DomSanitizer } from '@angular/platform-browser'
import { CommonService } from '../../services/common.service';
import { ConfigLayoutService } from './config-layout.service';
@Component({
selector: 'config-layout',
template: '<div>
<ul class="clean-list">
<li>
<ul class="clean-list" style="height:175px; overflow:auto">
<li *ngFor="let configlayout of data; trackBy: trackByLayouts | filter:[{Disabled: false}]">
<label class="input-control radio small-check" style="margin-right:5px!important">
<input type="radio" [value]="configlayout" name="cl" [(ngModel)]="value" (ngModelChange)="layoutChanged($event)" />
<span class="check"></span>
<span class="caption" title="{{configlayout.Description}}">{{configlayout.Name}}</span>
</label>
</li>
</ul>
</li>
<li [title]="value.Description" *ngIf="showImage" [style]="liBackgroundImageStyle">
</li>
</ul>
</div>',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ConfigLayoutComponent),
multi: true
},
ConfigLayoutService
]
})
export class ConfigLayoutComponent implements OnInit, OnDestroy, ControlValueAccessor
{
@Output() itemChanged: EventEmitter<ConfigLayoutComponent> = new EventEmitter<ConfigLayoutComponent>();
@Input() public data: any[];
@Input('IsCabinet') _IsCabinet: boolean = false;
//Placeholders for the callbacks which are later provided
//by the Control Value Accessor
private onTouchedCallback: () => {};
private onChangeCallback: (_: any) => {};
@Input() get value(): any
{
return this.configLayoutService.configLayoutValue;
}
set value(val: any)
{
this.configLayoutService.configLayoutValue = val;
if (this.onChangeCallback)
{
this.onChangeCallback(val);
}
}
constructor(private sanitizer: DomSanitizer, private commonService: CommonService, private configLayoutService: ConfigLayoutService)
{
}
ngOnInit(): void
{
if (!this.value)
{
this.configLayoutService.configLayoutValue = {};
}
}
ngOnChanges(inputs: any): void
{
if (this.value)
{
if (this.onChangeCallback)
{
this.onChangeCallback(this.value);
}
}
}
writeValue(value: any): void
{
if (value)
{
this.value = value;
}
}
registerOnChange(fn: any): void
{
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void
{
this.onTouchedCallback = fn;
}
ngOnDestroy()
{
this.value = undefined;
}
get imgFileName(): any
{
let name: string = "";
if (this.value != null)
{
name = this.value.ImageFileName;
}
return name;
}
get liBackgroundImageStyle(): any
{
let style: any = this.sanitizer.bypassSecurityTrustStyle("width:348px;height:211px;margin-top:5px!important;border-top: grey 1px solid; background: url(CoreIVCli/src/layoutimages/" + this.imgFileName + ") no-repeat;");
return style;
}
get showImage(): boolean
{
let show: boolean = false;
if (this.value != null)
{
show = this.value.ImageFileName != null;
}
return show;
}
layoutChanged(config: any)
{
this.itemChanged.emit(config);
}
get configLabel(): string
{
let label: string = "Rack";
if (this._IsCabinet)
{
label = "Cabinet";
}
return label;
}
trackByLayouts(index: number, config: any)
{
return config.Id;
}
}
import{Component,OnInit,ViewChild,OnDestroy,Output,EventEmitter,Input,forwardRef}来自“@angular/core”;
从“@angular/forms”导入{ControlValueAccessor,NG_VALUE_ACCESSOR};
从“@angular/platform browser”导入{domsanizer}
从“../../services/common.service”导入{CommonService};
从“./config layout.service”导入{ConfigLayoutService};
@组成部分({
选择器:“配置布局”,
模板:'
-
-
{{configlayout.Name}
-
',
供应商:[
{
提供:NG_值访问器,
useExisting:forwardRef(()=>ConfigLayoutComponent),
多:真的
},
ConfigLayoutService
]
})
导出类ConfigLayoutComponent实现OnInit、OnDestroy、ControlValueAccessor
{
@Output()itemChanged:EventEmitter=新的EventEmitter();
@Input()公共数据:任意[];
@输入('IsCabinet')\u IsCabinet:boolean=false;
//稍后提供的回调的占位符
//通过控制值访问器
私有onTouchedCallback:()=>{};
私有onChangeCallback:((_quo:any)=>{};
@输入()获取值():任意
{
返回this.configLayoutService.configLayoutValue;
}
设定值(val:any)
{
this.configLayoutService.configLayoutValue=val;
if(this.onChangeCallback)
{
这个.onChangeCallback(val);
}
}
构造函数(专用清理器:DOMSANTIZER,专用commonService:commonService,专用configLayoutService:configLayoutService)
{
}
ngOnInit():void
{
如果(!this.value)
{
this.configLayoutService.configLayoutValue={};
}
}
ngOnChanges(输入:任意):无效
{
if(该值)
{
if(this.onChangeCallback)
{
this.onChangeCallback(this.value);
}
}
}
writeValue(值:任意):无效
{
如果(值)
{
这个值=值;
}
}
注册变更(fn:任何):无效
{
this.onChangeCallback=fn;
}
注册人(fn:任何):无效
{
this.onTouchedCallback=fn;
}
恩贡德斯特罗()
{
this.value=未定义;
}
获取imgFileName():任意
{
let name:string=“”;
如果(this.value!=null)
{
name=this.value.ImageFileName;
}
返回名称;
}
get-liBackgroundImageStyle():任意
{
let style:any=this.sanitizer.bypassSecurityTrustStyle(“宽度:348px;高度:211px;页边顶部:5px!重要;边框顶部:灰色1px实心;背景:url(CoreIVCli/src/layoutimages/“+this.imgFileName+”)无重复;”;
回归风格;
}
获取showImage():布尔值
{
让我们看看:布尔=假;
如果(this.value!=null)
{
show=this.value.ImageFileName!=null;
}
回归演出;
}
layoutChanged(配置:任意)
{
this.itemChanged.emit(配置);
}
获取configLabel():字符串
{
let标签:string=“Rack”;
如果(这是一个数据库)
{
label=“机柜”;
}
退货标签;
}
trackByLayouts(索引:number,配置:any)
{
返回config.Id;
}
}
请提供帮助。为什么在组件中使用ControlValueAccessor?这样我的组件就可以绑定到ngModel,所以当单击单选按钮时,组件的值将通过ngModel使用所选单选按钮的值进行更新。ControlValueAccessor主要是Angular forms API和DOM中本机元素之间的桥梁。我认为使用ControlValueAccess不是一个好主意