如何通过没有输入的自定义控件以角度形式触发change()

时间:2017-02-21 15:58:02

标签: javascript forms angular

我确实想要创建一个不包含任何输入的自定义控件。每当控件改变时,我都想保存完整的表单。

我们当前的方法使用像这样的形式更改事件:

library(shiny)
library(ggplot2)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel( 
      uiOutput("Cylselectui"),
      submitButton("Apply changes")
    ),
    mainPanel(
     plotOutput("Carsplot") 
    )
  )
)


server <- function(input, output) {
  output$Carsplot <- renderPlot({
    plotdata <- subset(mtcars, cyl %in% input$Cylselection) #Filter based on cyl

    ggplot(plotdata, aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
      geom_point()
  })

  output$Cylselectui <- renderUI({ #Create the cyl selectize ui based on the values of cyl that are in the data
    selectizeInput(
      'Cylselection', 'Select by Cylinder', 
      choices = sort(unique(mtcars$cyl)),
      selected = sort(unique(mtcars$cyl)),
      multiple = TRUE
    )
  })
}

shinyApp(ui = ui, server = server)

正如您所看到的,我们使用&#34;更改&#34; -event来对表单中的任何更改做出反应。 只要我们有输入,复选框,......作为控件,这样就可以正常工作。

但是我们的自定义控件只存在于我们可以单击的简单div中。每当我点击div时,控件的值都会增加1.但是不会触发表单的&#34;更改&#34; -event。我是否必须以某种方式将我的自定义控件链接到表单?或者是否有任何需要解雇的事件?

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

我已经创建了一个用于演示问题的plunker: https://plnkr.co/edit/ushMfJfcmIlfP2U1EW6A

每当您点击&#34;点击&#34;模型值增加,但控制台上没有输出,因为更改事件未被触发...(有一个与更改事件链接的console.log)

4 个答案:

答案 0 :(得分:5)

感谢您的回复。

最后我找到了以下解决这个问题的方法: 正如评论中提到的Claies一样,我的自定义组件不会触发更改事件。因此,表格永远不会知道这种变化。这与angular没什么关系,但正如所说的是输入/表单的预期行为。

最简单的解决方案是在发生更改时触发customcontrol中的change-event:

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

public triggerChanged(){
    let event = new CustomEvent('change', {bubbles: true});
    this.renderer.invokeElementMethod(this.element.nativeElement, 'dispatchEvent', [event]);
}
只要我打电话给#34; onControlChange(..)&#34;那就是它。在我的自定义组件中,然后我随后触发此事件。

请注意,您需要Custom-Event-Polyfill来支持IE! https://www.npmjs.com/package/custom-event-polyfill

答案 1 :(得分:1)

感谢Stefan向我指出正确的方向。

不幸的是,不赞成使用Renderer(具有invokeElementMethod())或赞成Renderer2(不具有该方法)

所以以下内容对我有用

this.elementRef.nativeElement.dispatchEvent(new CustomEvent('change', { bubbles: true }));

答案 2 :(得分: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");
    }
}

答案 3 :(得分:0)

当您调用change onChange回调(在ControlValueAccessor函数中传递的回调)时,似乎没有在表单上触发registerOnChange事件,但总体上可以观察到valueChanges形式)。

代替:

 ...
 <form (change)="onChange()">
 ...

您可以尝试使用:

this.form.valueChanges
  .subscribe((formValues) => {
    ...
  });

当然,您必须在组件中获得正确的表格参考。