如何让我的 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;
}