Entrada personalizada angular2 rc.5, descriptor de acceso sin valor para control de formulario con nombre no especificado

80

Tengo un componente de entrada personalizado simple como este,

import {Component, Provider, forwardRef} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";

const noop = () => {};

const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CustomInputComponent),
  multi: true
};

@Component({
  selector: 'custom-input',
  template: `

          <input class="form-control" 
                 [(ngModel)]="value" name="somename"
                 (blur)="onTouched()">

  `,
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class CustomInputComponent implements ControlValueAccessor{

  //The internal data model
  private _value: any = '';

  //Placeholders for the callbacks
  private _onTouchedCallback: () => void = noop;

  private _onChangeCallback: (_:any) => void = noop;

  //get accessor
  get value(): any { return this._value; };

  //set accessor including call the onchange callback
  set value(v: any) {
    if (v !== this._value) {
      this._value = v;
      this._onChangeCallback(v);
    }
  }

  //Set touched on blur
  onTouched(){
    this._onTouchedCallback();
  }

  //From ControlValueAccessor interface
  writeValue(value: any) {
    this._value = value;
  }

  //From ControlValueAccessor interface
  registerOnChange(fn: any) {
    this._onChangeCallback = fn;
  }

  //From ControlValueAccessor interface
  registerOnTouched(fn: any) {
    this._onTouchedCallback = fn;
  }

}

y tengo un módulo de aplicación como este,

/**
 * Created by amare on 8/15/16.
 */
import { NgModule }                     from '@angular/core';
import { BrowserModule }                from '@angular/platform-browser';
import { ReactiveFormsModule, FormsModule }          from '@angular/forms';
import { AppComponent }                 from './app/app.component';
import {CustomInputComponent} from "./app/shared/custom.input.component";
import {RouterModule} from "@angular/router";
@NgModule({
  imports: [ BrowserModule, ReactiveFormsModule, FormsModule, RouterModule ],
  declarations: [ AppComponent, CustomInputComponent],
  bootstrap: [ AppComponent ]
})
export class AppModule {  
}

y principal

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule }              from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

y he usado mi entrada personalizada en uno de mis componentes como se muestra a continuación, pero obtengo 'Sin valor de acceso para control de formulario con atributo de nombre no especificado'.

<custom-input name="firstName" [(ngModel)]="firstName"></custom-input>

y el componente de la aplicación se ve así

import { Component } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  title = 'app works!';

  firstName: string;
}
Amare
fuente
Tengo el mismo problema con una directiva personalizada que implementa ControlValueAccessor. Funcionaba en RC4 pero obtiene el mismo error que usted para RC5. Esperando que alguien tenga una solución.
user2444499
38
Intente agregar ngDefaultControla su control, así:<custom-input name="firstName" [(ngModel)]="firstName" ngDefaultControl></custom-input>
danieleds
@danieleds, muchas gracias, funciona a las mil maravillas, aunque el equipo angular no respondía.
Amare
1
Tenga cuidado con los paquetes de terceros que pueda estar utilizando: si importa algo que esté utilizando el anterior FORM_DIRECTIVES, ¡romperá su aplicación! Caso en cuestión: github.com/valor-software/ng2-charts/issues/352
Pete
Para mí, agregando ngDefaultControl antes de [(ngModel)] = "...." funcionó
theightysapien

Respuestas:

73

agregar ngDefaultControl al componente de entrada personalizado en el host resolvió el problema, gracias @danieleds

Amare
fuente
8
Esta solución no funcionó para mí. Tengo un nombre aplicado a mi inputy también intenté agregarlo ngDefaultControla la entrada y no funcionó. Todavía me dio el mismo error. En RC5
prolink007
2
De acuerdo, agregué la propiedad de nombre en html y ngDefaultControl y uso formControl y no funciona.
Steve K
1
Vea una muy buena explicación sobre cómo ngDefaultControlfunciona: stackoverflow.com/a/46465959/968003 . Esencialmente, agrega default ControlValueAccessor, que actúa como un puente entre la API de formas angulares y un elemento nativo en el DOM.
Alex Klaus
46

Agregue ngDefaultControl al componente de entrada personalizada. Esto agrega enlace de datos bidireccional, no debería tener que implementar los métodos de acceso al valor a menos que esté haciendo algo único.

<custom-input name="firstName" [(ngModel)]="firstName" ngDefaultControl></custom-input>
Mella
fuente
12

Agregue ngDefaultControla su entrada. p.ej

<inline-editor type="textarea" [(ngModel)]="editableTextArea" (onSave)="saveEditable($event)" value="valor" ngDefaultControl> </inline-editor> 

Entonces import { FORM_DIRECTIVES } from '@angular/common';

Finalmente directivas: [FORM_DIRECTIVES]

Esto funcionará :) Gracias por los comentarios anteriores

Saminda Kularathne
fuente
2
Utilice comillas inversas y otros markdowncomandos para que su publicación sea más legible.
buhtz
4
Estoy usando RC6 y no hay FORM_DIRECTIVESen@angular/common
Kosmonaft
6
LAS DIRECTIVAS DE FORMULARIO NO SON MÁS CON NG2 FINAL
Steve K
4

Estaba poniendo [(ngModel)]mi <option>etiqueta en lugar de<select>

Así que sí ... eso causará esto.

Ryan Knell
fuente
Sí ... Tuve el mismo error, colocando el ngModel en un <mat-radio-button>, en lugar del <mat-radio-group>. Grrrrrr ....
Mike Gledhill
0

Como otro escenario en el que surge esto, había [(ngModel)]especificado un componente personalizado que se reconstruyó y simplificó recientemente, y la nueva versión del componente solo tenía ngModelcomo variable de entrada normal con emisiones.

Esto no fue suficiente : se debe cambiar el nombre de la variable de entrada a algo más ngModel, o el componente debe implementar la ControlValueAccessorinterfaz ( consulte los documentos para obtener más detalles ). Una vez que uno u otro esté completo, ya no obtendrá este error.

bsplosion
fuente