自定义表单输入未检测到更改

时间:2018-01-22 16:09:27

标签: angular angular4-forms

我有一个Angular 4的自定义表单输入。我无法在单击此元素上的嵌入式下拉列表时传播更改。如果我使用最后一个选项“添加自定义”然后手动键入值,我只能进行更改。一旦我这样做并将焦点放在元素上,更改就会按预期工作。

这是我设置的一个简单示例。当我向此组件添加更多详细信息(如您单击以选择的下拉列表)时,更改不会流回到父控制器。 注意,模型总是正确更新,但我没有触发更改功能。

Link to simple input exapmple

我不确定为什么“SetKnownCoin”函数不会传播更改。我错过了什么吗?

import { Component, Input, forwardRef, ElementRef, Renderer } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Coin2 } from '../../../models/config';

@Component({
    selector: 'input-coin',
    template:
        `
        <div class="input-coin col-xs-12">
            <div class="input-coin-symbol col-xs-6">
                <div class="dropdown">
                    <input type="text" class="form-control dropdown-toggle" placeholder="Symbol"  [(ngModel)]="value" [maxlength]="5" 
                    (change)="update()" 
                    [disabled]="isDisabled" (click)="getSymbol()" data-toggle="dropdown" > 
                    <ul class="dropdown-menu">
                        <li *ngFor="let c of coins" (click)="setKnownCoin(c)">{{c.symbol}} - {{c.name}}</li>
                        <li role="separator" class="divider"></li>
                        <li (click)="setCustom()">Add Custom</li>
                    </ul>
                </div>
            </div>
            <div class="input-coin-name col-xs-6"> {{coinName}}</div>
        </div>    
        `,
    styles: [
        `
                .defaultLabel{
                    color:#848484;
                }
                .input-coin {
                    width: 100%;
                    height: 34px;
                    display: block;       
                }
                .input-coin, .input-coin-symbol{
                    padding-left:0;
                }
                .input-coin-symbol > .dropdown > ul {
                    padding-top:0;
                    margin-top:0;
                    border-color: #66afe9;
                }
                .input-coin > .input-coin-symbol > .dropdown > ul > li {
                    padding: 4px 2px 4px 12px;
                }
                .input-coin > .input-coin-symbol > .dropdown > ul > li.divider {
                    padding-top: 0;
                    padding-bottom: 0;
                }
                .input-coin > .input-coin-symbol > .dropdown > ul > li:hover {
                    background-color:#D8D8D8;
                }
                .input-coin > .input-coin-name {
                    padding: 6px 12px 6px 2px;
                }
                `
    ],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => InputCoinComponent),
            multi: true
        },
    ]
})
export class InputCoinComponent implements ControlValueAccessor {
    @Input('value') value: string = "";

    propagateChange = (_: any) => { };
    propagateTouch = (_: any) => { };
    isDisabled: boolean = false;
    coinName: string = "";
    coins: Coin2[];

    constructor(private elRef: ElementRef, private renderer: Renderer) { }

    writeValue(value: any): void {
        if (value) {
            this.value = value;
        }
    }

    registerOnChange(fn: (_: any) => void): void {
        this.propagateChange = fn;
    }
    registerOnTouched(fn: () => void): void {
        this.propagateTouch = fn;
    }

    update() {
        this.value = this.value.toUpperCase();
        this.propagateChange(this.value);
    }

    onTouch(event: any) {
        this.value = this.value.toUpperCase();
        this.propagateTouch(event);
    }

    setDisabledState(isDisabled: boolean): void {
        this.isDisabled = isDisabled;
    }

    getSymbol() {
        var coins: Coin2[] = [{ symbol: 'USD', name: 'US Dollar' }, { symbol: 'BTC', name: 'Bitcoin' }, { symbol: 'ETH', name: 'Ethereum' },
        { symbol: 'XRP', name: 'Ripple' }, { symbol: 'ADA', name: 'Cardano' }];
        this.coins = coins;
    }

    setKnownCoin(c: any) {
        this.value = c.symbol;
        this.coinName = c.name;
        this.propagateChange(this.value);
    
    }

    setCustom() {
        this.value = "";
        this.coinName = "";
        this.propagateChange(this.value);
        this.renderer.invokeElementMethod(this.elRef.nativeElement.querySelector('input'), 'focus', []);
    }


}

我对这个组件的使用:

<input-coin type="text"  id="coin" name="coin"  [(ngModel)]="manualEntry.coin"  #coin="ngModel"  (change)="test($event)" required></input-coin>

1 个答案:

答案 0 :(得分:0)

显然,如果我使用(ngModelChange)而不是(change),则此代码 效果很好。

(change)是一个DOM事件,而(ngModelChange)是一个Angular形式的更改事件(与您的数据结构有关)。