wake-up-neo.com

Wie kann ich ngModel auf benutzerdefinierten Elementen implementieren? (eigene Combobox)

Mit einem einfachen Eingabeelement kann ich dies tun:

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

Dies funktioniert nicht für meine benutzerdefinierten Elemente:

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

Wie kann ich das umsetzen?

51
maklemenz

Ich denke, dieser Link beantwortet Ihre Frage:

Wir müssen zwei Dinge implementieren, um das zu erreichen:

  • Eine Komponente, die die Logik Ihrer Formularkomponente bereitstellt. Es ist keine Eingabe erforderlich, da dies von ngModel selbst bereitgestellt wird
  • Ein benutzerdefiniertes ControlValueAccessor, das die Brücke zwischen dieser Komponente und ngModel/ngControl implementiert.

Der vorherige Link gibt Ihnen ein vollständiges Beispiel ...

32

Ich habe das ngModel einmal für die Eingabe in meine gemeinsam genutzten Komponenten implementiert und kann es dann sehr einfach erweitern.

Nur zwei Codezeilen:

  1. anbieter: [createCustomInputControlValueAccessor (MyInputComponent)]

  2. erweitert 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.html

<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();
    }
}
2
Shlomi Aharoni