如何让我的 ngModel 在我的 ng-template 中自动工作?
How can i make my ngModel to work automatically in my ng-template?
我有很多带标签的表单组,inputs.I 想制作可重复使用的 ng-template
所以我有
<div class="form-group">
<label class="form-control-label" for="address">Address</label>
<input [disabled]="isTheLoggedInUserAdmin" id="address" class="form-control form-
control-alternative"
[(ngModel)]="sharedService.tempUser.address" name="address" type="text">
</div>
并使用 ng-template 将其转换为
<ng-template [ngTemplateOutlet]="formGroup"
[ngTemplateOutletContext]="{data: {inputId:'address', label:'Address', ngModel:
sharedService.tempUser.address }}"
></ng-template>
<ng-template #formGroup let-data="data">
<div class="form-group">
<label class="form-control-label" [for]="data.inputId">{{data.label}}</label>
<input [disabled]="isTheLoggedInUserAdmin" [id]="data.inputId" class="form-control form-control-
alternative"
[(ngModel)]="sharedService.tempUser.address" [name]="data.inputId" type="text">
</div>
</ng-template>
所以我在这里自动传递 inputId、标签名称,现在 ngModel 是硬编码的,它指向 sharedService.tempUser.address
但是我的 ng-template 需要是动态的,所以在 ng-template 调用中我应该传递参数 like label for example
- tthe argument shpuld point to different ngModel variables in my typescript files
但是当我这样做的时候
<div class="form-group">
<label class="form-control-label" [for]="data.inputId">{{data.label}}</label>
<input [disabled]="isTheLoggedInUserAdmin" [id]="data.inputId" class="form-control form-control-alternative"
[(ngModel)]="data.ngModel" [name]="data.inputId" type="text">
</div>
现在 data.ngModel
是从 ng-template 调用发送的 - 这是 sharedService.tempUser.address
,我从 sharedService.tempUser.address
得到实际值但是 *问题是 ngModel 在这里不起作用`
当我输入内容时它没有更新
我该如何解决这个问题?
您可能想编写 ControlValueAccessor
的实现作为替代。这是创建与 Form API 兼容的可重用组件的 Angular 官方方法。一个最小的例子是这样的:
my-custom-control.component.html
<div class="form-group">
<label class="form-control-label" for="{{data.field}}">{{data.label}}</label>
<input [disabled]="disabled" id="{{data.field}}" class="form-control form-control-alternative"
[value]="value" name="{{data.field}}" type="text"
(change)="onChange($event)" (blur)="onBlur($event)">
</div>
my-custom-control.component.ts
/**
import things....
**/
@Component({
selector: 'MyControl',
templateUrl: './my-custom-control.component.html',
styleUrls: ['./my-custom-control.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyControlComponent),
multi: true
}]
})
export class MyControlComponent implements OnInit, ControlValueAccessor {
@Input() value: any;
@Input() data: { 'field': string, 'label': string } = { field: "default", label: "default" };
@Input() disabled: boolean = false;
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}
propagateChange = (_: any) => { };
propagateTouch = () => { };
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
this.propagateTouch = fn;
}
constructor() {
}
ngOnInit() {
}
// value changed from ui
onChange(event: any){
this.value = event.target.value;
// tell angular that the control value is changed
this.propagateChange(this.value);
}
// received value from form api
writeValue(newFormValue: any) {
this.value = newFormValue;
}
// tell angular that this form control is touched
onBlur(event: any) {
this.propagateTouch();
}
}
之后,您可以像这样重用这个组件:
<!-- With FormGroup -->
<form [formGroup]="myForm">
<MyControl formControlName="address" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'address', label: 'Address' }">
<MyControl formControlName="title" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'title', label: 'Title' }">
<MyControl formControlName="surname" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'surname', label: 'Surname' }">
<!-- other controls... -->
</form>
<!-- Without FormGroup -->
<div>
<MyControl [(ngModel)]="myModel.address" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'address', label: 'Address' }">
<MyControl [(ngModel)]="myModel.title" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'title', label: 'Title' }">
<MyControl [(ngModel)]="myModel.surname" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'surname', label: 'Surname' }">
<!-- other controls... -->
</div>
如果您有模型描述数组,也可以轻松将其写入 ngFor
。
编辑:添加示例 scss 样式。
my-custom-control.component.scss
@import "variable.scss";
:host(.ng-dirty.ng-invalid, .ng-touched.ng-invalid) input {
border-color: $c-alert !important;
border-width: 2px;
border-style: solid;
color: $c-alert;
}
我有很多带标签的表单组,inputs.I 想制作可重复使用的 ng-template
所以我有
<div class="form-group">
<label class="form-control-label" for="address">Address</label>
<input [disabled]="isTheLoggedInUserAdmin" id="address" class="form-control form-
control-alternative"
[(ngModel)]="sharedService.tempUser.address" name="address" type="text">
</div>
并使用 ng-template 将其转换为
<ng-template [ngTemplateOutlet]="formGroup"
[ngTemplateOutletContext]="{data: {inputId:'address', label:'Address', ngModel:
sharedService.tempUser.address }}"
></ng-template>
<ng-template #formGroup let-data="data">
<div class="form-group">
<label class="form-control-label" [for]="data.inputId">{{data.label}}</label>
<input [disabled]="isTheLoggedInUserAdmin" [id]="data.inputId" class="form-control form-control-
alternative"
[(ngModel)]="sharedService.tempUser.address" [name]="data.inputId" type="text">
</div>
</ng-template>
所以我在这里自动传递 inputId、标签名称,现在 ngModel 是硬编码的,它指向 sharedService.tempUser.address
但是我的 ng-template 需要是动态的,所以在 ng-template 调用中我应该传递参数 like label for example
- tthe argument shpuld point to different ngModel variables in my typescript files
但是当我这样做的时候
<div class="form-group">
<label class="form-control-label" [for]="data.inputId">{{data.label}}</label>
<input [disabled]="isTheLoggedInUserAdmin" [id]="data.inputId" class="form-control form-control-alternative"
[(ngModel)]="data.ngModel" [name]="data.inputId" type="text">
</div>
现在 data.ngModel
是从 ng-template 调用发送的 - 这是 sharedService.tempUser.address
,我从 sharedService.tempUser.address
得到实际值但是 *问题是 ngModel 在这里不起作用`
当我输入内容时它没有更新
我该如何解决这个问题?
您可能想编写 ControlValueAccessor
的实现作为替代。这是创建与 Form API 兼容的可重用组件的 Angular 官方方法。一个最小的例子是这样的:
my-custom-control.component.html
<div class="form-group">
<label class="form-control-label" for="{{data.field}}">{{data.label}}</label>
<input [disabled]="disabled" id="{{data.field}}" class="form-control form-control-alternative"
[value]="value" name="{{data.field}}" type="text"
(change)="onChange($event)" (blur)="onBlur($event)">
</div>
my-custom-control.component.ts
/**
import things....
**/
@Component({
selector: 'MyControl',
templateUrl: './my-custom-control.component.html',
styleUrls: ['./my-custom-control.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyControlComponent),
multi: true
}]
})
export class MyControlComponent implements OnInit, ControlValueAccessor {
@Input() value: any;
@Input() data: { 'field': string, 'label': string } = { field: "default", label: "default" };
@Input() disabled: boolean = false;
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}
propagateChange = (_: any) => { };
propagateTouch = () => { };
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
this.propagateTouch = fn;
}
constructor() {
}
ngOnInit() {
}
// value changed from ui
onChange(event: any){
this.value = event.target.value;
// tell angular that the control value is changed
this.propagateChange(this.value);
}
// received value from form api
writeValue(newFormValue: any) {
this.value = newFormValue;
}
// tell angular that this form control is touched
onBlur(event: any) {
this.propagateTouch();
}
}
之后,您可以像这样重用这个组件:
<!-- With FormGroup -->
<form [formGroup]="myForm">
<MyControl formControlName="address" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'address', label: 'Address' }">
<MyControl formControlName="title" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'title', label: 'Title' }">
<MyControl formControlName="surname" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'surname', label: 'Surname' }">
<!-- other controls... -->
</form>
<!-- Without FormGroup -->
<div>
<MyControl [(ngModel)]="myModel.address" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'address', label: 'Address' }">
<MyControl [(ngModel)]="myModel.title" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'title', label: 'Title' }">
<MyControl [(ngModel)]="myModel.surname" [ngModelOptions]="{standalone: true}" [disabled]="isTheLoggedInUserAdmin" [data]="{ field: 'surname', label: 'Surname' }">
<!-- other controls... -->
</div>
如果您有模型描述数组,也可以轻松将其写入 ngFor
。
编辑:添加示例 scss 样式。
my-custom-control.component.scss
@import "variable.scss";
:host(.ng-dirty.ng-invalid, .ng-touched.ng-invalid) input {
border-color: $c-alert !important;
border-width: 2px;
border-style: solid;
color: $c-alert;
}