2017-02-21 17 views
0

Я хочу создать настраиваемый элемент управления, который не содержит никаких входных данных. Всякий раз, когда элемент управления изменяется, я хочу сохранить полную форму.Как вызвать change() в угловой форме с помощью настраиваемого элемента управления без ввода

Наш нынешний подход использует форму, изменил мероприятие, как это:

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

Как вы можете видеть, мы используем «изменить» -Event реагировать на любые изменения в форме. Это прекрасно работает, если у нас есть входы, флажки, ... как элементы управления.

Но наш пользовательский контроль существует только из простого div, на который мы можем нажать. Всякий раз, когда я нажимаю на div, значение элемента управления увеличивается на 1. Но «изменение» - событие формы не запускается. Должен ли я каким-то образом связать свой настраиваемый элемент управления с формой? Или есть какие-то события, которые нужно уволить?

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; 
    } 
} 

Я создал plunker, чтобы продемонстрировать эту проблему: https://plnkr.co/edit/ushMfJfcmIlfP2U1EW6A

Всякий раз, когда вы нажимаете на «Нажмите» модель-значение увеличивается, но нет никакого вывода на консоль, как изменение -event не уволен ... (Существует ссылка console.log, связанная с событием change)

+1

Обратите внимание на выдержки из тегов, которые показывают, когда вы добавляете теги. 'angularjs' для AngularJS 1.x. 'angular2' для Angular 2+. –

+1

Формы HTML5 имеют очень определенный определенный список элементов, которые считаются частью дерева форм; элементы, не входящие в этот список, включая 'div',' span', 'table' и другие, включая пользовательские элементы, не будут обрабатываться как часть формы HTML5. вы можете * сделать это, если ваш компонент использовал 'output', а не' div' для своего шаблона, но это может не работать так, как вы ожидаете. В принципе, это не встроено в спецификацию. – Claies

ответ

0

Спасибо за ваши ответы.

И наконец, я нашел следующее решение этой проблемы: Как упоминалось в комментарии Claies, мой пользовательский компонент не запускает событие изменения. Поэтому форма никогда не знает об изменениях. Это не имеет ничего общего с угловым, но, как сказано, является ожидаемым поведением ввода/формы.

Самым простым решением является стрелять переключающего событие в customcontrol, когда изменение происходит:

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 (..)» в моем пользовательский компонент, то я огонь это событие впоследствии.

Имейте в виду, что для поддержки IE вам необходимо использовать Полигонь Custom-Event-Polyfill! https://www.npmjs.com/package/custom-event-polyfill

0

Вам нужно выпустить событие click из div в родительский. так что вы можете обработать событие.

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 кликов. Замечательная вещь о событии смены формы - это то, что у меня есть только одна точка входа. Так что было бы неплохо, если бы кто-то изменил форму, изменив ценность настраиваемого компонента. – Stefan

+0

@Stefan Я не могу придумать другого решения этой проблемы. по моему мнению, для обнаружения каких-либо изменений в дочернем компоненте, возможное решение было бы eventemitter. :) – amansoni211