sourcetip

사용자 지정 요소에 ngModel을 구현하는 방법은 무엇입니까?

fileupload 2023. 9. 5. 20:44
반응형

사용자 지정 요소에 ngModel을 구현하는 방법은 무엇입니까?

단순한 경우input내가 할 수 있는 요소:

<input [(ngModel)]="name" /> {{ name }}

사용자 지정 요소에는 적합하지 않습니다.

<my-selfmade-combobox [(ngModel)]="name" values="getValues()" required></my-selfmade-combobox>

어떻게 구현할 수 있습니까?

[(ngModel)]="item"의 줄임말입니다.[ngModel]="item" (ngModelChange)="item = $event"

즉, 예를 들어 2방향 바인딩 속성을 구성 요소에 추가하려는 경우

<app-my-control [(myProp)]="value"></app-my-control>

구성 요소에서 필요한 것은 추가하기만 하면 됩니다.

@Input()
myProp: string;

// Output prop name must be Input prop name + 'Change'
// Use in your component to write an updated value back out to the parent
@Output()
myPropChange = new EventEmitter<string>();

@Input쓰기를 처리하고 부모에게 새 값을 다시 쓰기 위해, 그냥 전화하세요.this.myPropChange.emit("Awesome")값이 변경될 때마다 배출물이 업데이트되도록 하려면 해당 속성의 설정기에 배출물을 넣을 수 있습니다.

작동 방식/이유에 대한 자세한 설명은 여기를 참조하십시오.


이름을 사용하려는 경우ngModel(왜냐하면 요소에 결합하는 추가 명령어가 있기 때문입니다.)ngModel) 또는 이는 다음을 위한 것입니다.FormControl구성요소가 아닌 요소(AKA, 사용을 위한ngForm), 그러면 당신은 그것을 가지고 놀 필요가 있을 것입니다.ControlValueAccessor자신만의 제품을 만들기 위한 자세한 설명FormControl그리고 그것이 작동하는 이유는 여기에서 읽을 수 있습니다.

정말 필요하다면,[(ngModel)](지원)ngForm,와는 달리[(myProp)]접근), 이 링크가 귀하의 질문에 답할 것이라고 생각합니다.

이를 위해 다음 두 가지를 구현해야 합니다.

  • 양식 구성 요소의 논리를 제공하는 구성 요소입니다.ngModel 자체에서 제공하기 때문에 입력이 필요하지 않습니다.
  • 관습ControlValueAccessor이 구성 요소와 이 구성 요소 사이의 브리지를 구현할 것입니다.ngModel/ngControl

이전 링크는 전체 샘플을 제공합니다.

다음을 구현했습니다.ngModel공유 구성요소에 한 번만 입력하면 매우 간단하게 확장할 수 있습니다.

코드 두 줄만:

  1. providers: [createCustomInputControlValueAccessor(MyInputComponent)]

  2. extends InputComponent

my-input.component.ts

import { Component, Input } from '@angular/core';
import { InputComponent, createCustomInputControlValueAccessor } from '../../../shared/components/input.component';
@Component({
   selector: 'my-input',
   templateUrl: './my-input-component.component.html',
   styleUrls: ['./my-input-component.scss'],
   providers: [createCustomInputControlValueAccessor(MyInputComponent)]
})
export class MyInputComponent extends InputComponent {
    @Input() model: string;
}

my-input.component.sys

<div class="my-input">
    <input [(ngModel)]="model">
</div>

input.component.ts

import { Component, forwardRef, ViewChild, ElementRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
export function createCustomInputControlValueAccessor(extendedInputComponent: any) {
    return {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => extendedInputComponent),
        multi: true
    };
}

@Component({
    template: ''
})
export class InputComponent implements ControlValueAccessor, OnInit {
    @ViewChild('input') inputRef: ElementRef;

    // The internal data model
    public innerValue: any = '';

    // Placeholders for the callbacks which are later provided
    // by the Control Value Accessor
    private onChangeCallback: any;

    // implements ControlValueAccessor interface
    writeValue(value: any) {
        if (value !== this.innerValue) {
            this.innerValue = value;
        }
    }
    // implements ControlValueAccessor interface
    registerOnChange(fn: any) {
        this.onChangeCallback = fn;
    }

    // implements ControlValueAccessor interface - not used, used for touch input
    registerOnTouched() { }

    // change events from the textarea
    private onChange() {
        const input = <HTMLInputElement>this.inputRef.nativeElement;
        // get value from text area
        const newValue = input.value;

        // update the form
        this.onChangeCallback(newValue);
    }
    ngOnInit() {
        const inputElement = <HTMLInputElement>this.inputRef.nativeElement;
        inputElement.onchange = () => this.onChange();
        inputElement.onkeyup = () => this.onChange();
    }
}

1단계: 추가providers아래 속성:

@Component({
    selector: 'my-cool-element',
    templateUrl: './MyCool.component.html',
    styleUrls: ['./MyCool.component.css'],
    providers: [{   // <================================================ ADD THIS
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => MyCoolComponent),
        multi: true
    }]
})

2단계: 구현ControlValueAccessor:

    export class MyCoolComponent implements ControlValueAccessor {
    
      private _value: string;
      // Whatever name for this (myValue) you choose here, use it in the .html file.
      public get myValue(): string { return this._value }
      public set myValue(v: string) {
        if (v !== this._value) {     
          this._value = v;
          this.onChange(v);
        }
      }
    
      constructor() {}
    
      onChange = (_) => { };
      onTouched = () => { };
    
      writeValue(value: any): void {    
        this.myValue = value;
      }
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
      registerOnTouched(fn: any): void {
        this.onTouched = fn;
      }
      setDisabledState?(isDisabled: boolean): void {
        throw new Error("Method not implemented.");
      }
    
    }

3단계: html에서 원하는 컨트롤을 바인딩합니다.myValue:


    <my-cool-element [(value)]="myValue">
              <!-- ..... -->
     </my-cool-element>

사용자 정의 양방향 바인딩을 직접 구현할 수 있습니다.각도 10의 경우 공식 예제 SizerComponent를 참조하십시오. 여기서[(size)]똑같이 행동합니다.[(ngModel)]:

<app-sizer [(size)]="fontSizePx"></app-sizer>

언급URL : https://stackoverflow.com/questions/35149535/how-to-implement-ngmodel-on-custom-elements

반응형