2017-02-21 6 views
0

入力を含まないカスタムコントロールを作成したいと思います。コントロールが変更されるたびに、完全なフォームを保存します。入力なしのカスタムコントロールで角型でchange()をトリガする方法

我々の現在のアプローチは、次のようにフォーム変更イベントを使用しています:

<form #demoForm="ngForm" (change)="onChange()"> 
     <custom-input name="someValue" [(ngModel)]="dataModel"> 
     </custom-input> 
</form> 

あなたが見ることができるように、我々は、フォームの変化に反応して「変更」-eventを使用しています。 入力、チェックボックス、...がコントロールである限り、これは問題なく動作します。

私たちのカスタムコントロールは、私たちがクリックできる単純なdivの中にのみ存在します。 divをクリックするたびにコントロールの値が1ずつ増加しますが、フォームの「変更」 - イベントは発生しません。どういうわけか私のカスタムコントロールをフォームにリンクする必要がありますか?または、解雇される必要のあるイベントはありますか?

私は、問題を実証するためのplunker作成しました
import { Component, forwardRef } from '@angular/core'; 
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; 

@Component({ 
    selector: 'custom-input', 
    template: `<div (click)="update()">Click</div>`, 
    providers: [{ 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => CustomInputComponent), 
    multi: true 
}] 
}) 
export class CustomInputComponent implements ControlValueAccessor { 

    private onTouchedCallback:() => void =() => {}; 
    private onChangeCallback: (_: any) => void =() => {}; 

    update(){ 
     this.value++; 
    } 

    get value(): any { 
     return this.innerValue; 
    }; 

    set value(v: any) { 
     console.log("Change to"); 
     if (v !== this.innerValue) { 
      this.innerValue = v; 
      this.onChangeCallback(v); 
     } 
    } 

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

    registerOnChange(fn: any) { 
     this.onChangeCallback = fn; 
    } 

    registerOnTouched(fn: any) { 
     this.onTouchedCallback = fn; 
    } 
} 

:あなたはモデルの値を「クリック」をクリックするたびに増加したが、何も出力がコンソール上に存在しない、変化とされて https://plnkr.co/edit/ushMfJfcmIlfP2U1EW6A

を-eventが実行されません...(changeイベントにリンクされたconsole.logがあります)

+1

タグを追加するときに表示されるタグの抜粋には注意してください。 'angularjs'はAngularJS 1.xです。 'angular2'はAngular 2+です。 –

+1

HTML5フォームには、フォームツリーの一部と見なされる非常に明確な定義済みの要素リストがあります。 'div'、' span'、 'table'などカスタム要素を含むこのリストにない要素は、HTML5形式の一部として扱われません。あなたのコンポーネントがテンプレートの 'div'ではなく' output'を使用していたとしても、あなたが期待するように動作しないかもしれません。基本的に、これは仕様に組み込まれていません。 – Claies

答えて

0

感謝。

最後に、私はこの問題の解決方法を見つけました。 Claiesがコメントで述べたように、私のカスタムコンポーネントは変更イベントを発生させません。それゆえ、フォームはその変更について決して知らない。これには角度を付けることは何もありませんが、入力/フォームの予想される動作と同様です。それだけです

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

public triggerChanged(){ 
    let event = new CustomEvent('change', {bubbles: true}); 
    this.renderer.invokeElementMethod(this.element.nativeElement, 'dispatchEvent', [event]); 
} 

を、私が呼ばれるたび「onControlChange(..)」私のカスタムコンポーネントで、その後私は火災:変更が発生したときに

最も簡単な解決策はcustomcontrolに変更イベントを発生することがありますその後このイベント。

IEをサポートするには、Custom-Event-Polyfillが必要です。 https://www.npmjs.com/package/custom-event-polyfill

0

divのclickイベントを親に送信する必要があります。イベントを処理できるようにします。

Plunker Link

親コンポーネント:

import { Component, forwardRef, Output, EventEmitter } from '@angular/core'; // add output and eventEmitter 
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; 

@Component({ 
selector: 'custom-input', 
template: `<div (click)="update($event)">Click</div>`, 
providers: [{ 
provide: NG_VALUE_ACCESSOR, 
useExisting: forwardRef(() => CustomInputComponent), 
multi: true 
}] 
}) 

export class CustomInputComponent implements ControlValueAccessor { 

    private onTouchedCallback:() => void =() => {}; 
    private onChangeCallback: (_: any) => void =() => {}; 
    @Output() clickEvent = new EventEmitter(); // add this 

    update(event){ 
    this.value++; 
    this.clickEvent.emit(event); // emit the event on click event 
    } 

    get value(): any { 
     return this.innerValue; 
    }; 
} 

子コンポーネント:あなたの返信用

//our root app component 
import {Component} from '@angular/core' 

@Component({ 
    selector: 'demo-app', 
    template: ` 
     <p><span class="boldspan">Model data:</span> {{dataModel}}</p> 
     <form #demoForm="ngForm"> 
      <custom-input name="someValue" 
         [(ngModel)]="dataModel" (clickEvent) = onChange()> // handling emitted event here 
      Write in this wrapper control: 
      </custom-input> 
     </form>` 
}) 
export class AppComponent { 
    dataModel: string = ''; 

    public onChange(){ 
     console.log("onChangeCalled"); 
    } 
} 
+0

これは動作しますが、20個のコントロールを持つフォームでは、20個のclickEvent-registrationで終わります。フォームチェンジイベントのクールなことは、私はエントリーポイントが1つしかないことです。したがって、カスタムコンポーネントの値が変更されたという形をしているのはうれしいことです。 – Stefan

+0

@Stefan私はこの問題に対する他の解決策は考えられません。私によれば、子コンポーネントの変更を検出するためには、イベントエミュレータが可能な解決策になります。 :) – amansoni211

関連する問題