角2自定义表单输入 [英] Angular 2 custom form input

查看:428
本文介绍了角2自定义表单输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何创建自定义组件,它会工作就像本地<输入> 标记?我想我的自定义表单控件能够支持ngControl,ngForm,[(ngModel)。

How can I create custom component which would work just like native <input> tag? I want to make my custom form control be able to support ngControl, ngForm, [(ngModel)].

据我了解,我需要实现一些接口,使我自己的形式控制工作就像原生之一。

As I understand, I need to implement some interfaces to make my own form control work just like native one.

此外,恍如ngForm指令结合只为&LT;输入&GT; 标签,这是正确的?我该如何处理呢?

Also, seems like ngForm directive binds only for <input> tag, is this right? How can i deal with that?

让我解释为什么我需要这个的。我想换几个输入元素,使它们能够作为一个单一的输入一起工作。是否有其他的方式来处理呢?
再来一次:我想使这个控制,就像原生之一。验证,ngForm,ngModel双向绑定等。任何想法?

Let me explain why I need this at all. I want to wrap several input elements to make them able to work together as one single input. Is there other way to deal with that? One more time: I want to make this control just like native one. Validation, ngForm, ngModel two way binding and other. Any ideas?

PS:我用的打字稿

PS:对不起,我英文不好:/

ps: Sorry for bad English :/

推荐答案

在事实上,有两件事情来实现:

In fact, there are two things to implement:


  • 提供表单组件的逻辑组件。它不会因为它会通过 ngModel 提供一个输入本身

  • 自定义 ControlValueAccessor ​​将实现这个组件和 ngModel / ngControl之间的桥梁

  • A component that provides the logic of your form component. It doesn't an input since it will be provided by ngModel itself
  • A custom ControlValueAccessor that will implement the bridge between this component and ngModel / ngControl

让我们一起来样本。我想要实现管理的标签列表对于一个公司的组件。该组件将允许添加和删除标签。我想添加一个验证,以确保标签列表不是空的。如下所述,我会在我的组件定义它:

Let's take a sample. I want to implement a component that manages a list of tags for a company. The component will allow to add and remove tags. I want to add a validation to ensure that the tags list isn't empty. I will define it in my component as described below:

(...)
import {TagsComponent} from './app.tags.ngform';
import {TagsValueAccessor} from './app.tags.ngform.accessor';

function notEmpty(control) {
  if(control.value == null || control.value.length===0) {
    return {
      notEmpty: true
    }
  }

  return null;
}

@Component({
  selector: 'company-details',
  directives: [ FormFieldComponent, TagsComponent, TagsValueAccessor ],
  template: `
    <form [ngFormModel]="companyForm">
      Name: <input [(ngModel)]="company.name"
         [ngFormControl]="companyForm.controls.name"/>
      Tags: <tags [(ngModel)]="company.tags" 
         [ngFormControl]="companyForm.controls.tags"></tags>
    </form>
  `
})
export class DetailsComponent implements OnInit {
  constructor(_builder:FormBuilder) {
    this.company = new Company('companyid',
            'some name', [ 'tag1', 'tag2' ]);
    this.companyForm = _builder.group({
       name: ['', Validators.required],
       tags: ['', notEmpty]
    });
  }
}

TagsComponent 组件定义逻辑添加和删除在标签元素列表。

The TagsComponent component defines the logic to add and remove elements in the tags list.

@Component({
  selector: 'tags',
  template: `
    <div *ngIf="tags">
      <span *ngFor="#tag of tags" style="font-size:14px"
         class="label label-default" (click)="removeTag(tag)">
        {{label}} <span class="glyphicon glyphicon-remove"
                        aria-  hidden="true"></span>
      </span>
      <span>&nbsp;|&nbsp;</span>
      <span style="display:inline-block;">
        <input [(ngModel)]="tagToAdd"
           style="width: 50px; font-size: 14px;" class="custom"/>
        <em class="glyphicon glyphicon-ok" aria-hidden="true" 
            (click)="addTag(tagToAdd)"></em>
      </span>
    </div>
  `
})
export class TagsComponent {
  @Output()
  tagsChange: EventEmitter;

  constructor() {
    this.tagsChange = new EventEmitter();
  }

  setValue(value) {
    this.tags = value;
  }

  removeLabel(tag:string) {
    var index = this.tags.indexOf(tag, 0);
    if (index != undefined) {
      this.tags.splice(index, 1);
      this.tagsChange.emit(this.tags);
    }
  }

  addLabel(label:string) {
    this.tags.push(this.tagToAdd);
    this.tagsChange.emit(this.tags);
    this.tagToAdd = '';
  }
}

正如你所看到的,有这部分没有输入但的setValue 一(名字并不重要)。我们用它更高,才能从 ngModel 值到组件。该组件定义一个事件通知时,组件的状态(标记表)被更新。

As you can see, there is no input in this component but a setValue one (the name isn't important here). We use it later to provide the value from the ngModel to the component. This component define an event to notify when the state of the component (the tags list) is updated.

现在让我们来实现这个组件之间的链接 ngModel / ngControl 。这相当于实现了 ControlValueAccessor ​​接口的指令。提供者必须对 NG_VALUE_ACCESSOR 标记此值访问定义(不要​​忘了使用 forwardRef 自指令后所定义)。

Let's implement now the link between this component and ngModel / ngControl. This corresponds to a directive that implements the ControlValueAccessor interface. A provider must be defined for this value accessor against the NG_VALUE_ACCESSOR token (don't forget to use forwardRef since the directive is defined after).

该指令将连接在主机的 tagsChange 事件的事件监听器(即指令附着在组件,即 TagsComponent )。事件发生时的的onChange 方法将被调用。这个方法对应于通过Angular2注册的人。这样,它会意识到的变化和更新相应的相关表单控件。

The directive will attach an event listener on the tagsChange event of the host (i.e. the component the directive is attached on, i.e. the TagsComponent). The onChange method will be called when the event occurs. This method corresponds to the one registered by Angular2. This way it will be aware of changes and updates accordingly the associated form control.

本时绑定的值 ngForm 更新 writeValue 被调用。在已经注入安装在(即TagsComponent)的组成部分,我们将能够调用它来传递这个值(见previous 的setValue 法)。

The writeValue is called when the value bound in the ngForm is updated. After having injected the component attached on (i.e. TagsComponent), we will be able to call it to pass this value (see the previous setValue method).

不要忘了在指令中的绑定提供 CUSTOM_VALUE_ACCESSOR

Don't forget to provide the CUSTOM_VALUE_ACCESSOR in the bindings of the directive.

下面是自定义 ControlValueAccessor ​​的完整code:

Here is the complete code of the custom ControlValueAccessor:

import {TagsComponent} from './app.tags.ngform';

const CUSTOM_VALUE_ACCESSOR = CONST_EXPR(new Provider(
  NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => TagsValueAccessor), multi: true}));

@Directive({
  selector: 'tags',
  host: {'(tagsChange)': 'onChange($event)'},
  providers: [CUSTOM_VALUE_ACCESSOR]
})
export class TagsValueAccessor implements ControlValueAccessor {
  onChange = (_) => {};
  onTouched = () => {};

  constructor(private host: TagsComponent) { }

  writeValue(value: any): void {
    this.host.setValue(value);
  }

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

此方式,当我删除所有公司标签,的有效属性 companyForm.controls.tags 控制变得自动

This way when I remove all the tags of the company, the valid attribute of the companyForm.controls.tags control becomes false automatically.

希望它可以帮助你,
蒂埃里

Hope it helps you, Thierry

这篇关于角2自定义表单输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆