30

I'm creating a custom element in Angular 2.0 (<my-select>), and when I include the ngModel attribute on the component, I'm immediately hit with the following error:

EXCEPTION: No value accessor for '' in [myModel in App@0:195]

Here's a plunker: http://plnkr.co/edit/wlkPWcB92YZASCwCnmcw?p=preview

(Open console to view error)

If you simply comment out the following line from src/app.ts, the component will render appropriately:

'[ngModel]="myModel"'

I've done the following:

  1. Imported {FORM_DIRECTIVES} from 'angular2/common'
  2. Included FORM_DIRECTIVES in the directives portion of the @Component
  3. Initialized myModel

What am I missing here?

lux
  • 8,315
  • 7
  • 36
  • 49
  • 1
    What @thierry says. Also adding FORM_DIRECTIVES is not necessary anymore, because they are included by default. Another tip, to make a multiline string in typescript you can use the backticks `. This way you don't need to concatenate the string – Poul Kruijt Dec 28 '15 at 16:04
  • @PierreDuc Thanks, see my comment to thierry. Also, I use WebStorm and the syntax highlighting is awful when using the backticks. Need to update the editor, but I do like that shorthand. – lux Dec 28 '15 at 16:07
  • 1
    If you are talking about the background colour. settings -> editor -> colors & fonts -> general -> injected language fragment -> uncheck the background colour. – Poul Kruijt Dec 28 '15 at 16:11
  • @PierreDuc That's exactly it! Thanks! – lux Dec 28 '15 at 16:14

10 Answers10

14

I take this error for 2 reasons:

1) Component has to attach itself as a value accessor, like:

@Component({
  selector: 'ace-editor',
  template: `<div class="ng2-ace-editor"></div>`,
})

export class AceEditor implements OnInit, ControlValueAccessor {

  constructor(private element: ElementRef, @Optional() ngControl: NgControl) {
    if (ngControl) {
      ngControl.valueAccessor = this;
    }
  }

2) You haven't to mix deprecated and new forms. If you use a new API add to your main.ts:

import { bootstrap }    from '@angular/platform-browser-dynamic';
import { disableDeprecatedForms, provideForms } from '@angular/forms';

import { AppComponent } from './app.component';

bootstrap(AppComponent, [
  disableDeprecatedForms(),
  provideForms()
])
.catch((err: any) => console.error(err));
DenisKolodin
  • 13,501
  • 3
  • 62
  • 65
  • 1
    I was missing `ngControl.valueAccessor = this;`. Do you have a link to documentation for setting `valueAccessor` to `this` or know how you found out about it? None of the documentation or examples I've seen mention it. Tx – Precastic Sep 20 '16 at 09:49
  • 2
    You are right. There aren't good examples. I had forced to use Angular's sources. Try to look at the tests: https://github.com/angular/angular/blob/51d73d3e4e490cb12715edf0eae1e46b4d42d8a0/modules/%40angular/forms/test/reactive_integration_spec.ts#L1650 – DenisKolodin Sep 20 '16 at 18:54
  • Rather than setting `valueAccessor = this`, you can register the provider a different way as in [this answer](https://stackoverflow.com/a/46413397/1221537) – adamdport Oct 16 '17 at 16:25
13

I think you should use something else than ngModel for the parameter of your my-select component... Because it's already used by Angular2.

I made a try with model and it seems better... I don't have the error anymore.

Edit

If you want to handle ngModel at the level of your my-select component, you could have a look at this link: https://github.com/angular/angular/issues/2543.

If you want to implement an ngModel-compliant component, you could have a look at the following links:

Hope it helps you, Thierry

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • We're not allowed to use `ngModel`? If so, I'm confused as to why it was included in the `Forms` section of the cheat sheet (https://angular.io/cheatsheet) (i.e. ``). That said, I can confirm the issue is resolved if I do not use it, but what's the error stating? – lux Dec 28 '15 at 16:06
  • 1
    ngModel expects a `Control` instance if i remember correctly – Poul Kruijt Dec 28 '15 at 16:13
  • I am wrong... i have no idea.. ignore me, i confused `ngModel` with `ngControl`. Only thing what the [documentation](https://angular.io/docs/ts/latest/api/common/NgModel-directive.html) says is "Binds a domain model to a form control." But by judging your error, i'm expecting it can only be bound to a html tag with a `value` attribute (input, textarea, select) – Poul Kruijt Dec 28 '15 at 16:26
  • I think that you need to manage the input / output for your component. I updated my answer with a link that could be useful... – Thierry Templier Dec 28 '15 at 16:29
  • was this ever resolved? having same issue with beta.1 – born2net Jan 20 '16 at 14:49
  • @born2net Resolution was to not use `ngModel` - which seems dissimilar from angular 1, which would allow you to require `ngModel` on nearly anything. – lux Feb 29 '16 at 17:23
  • @lux you could also implement a custom component that is ngModel-compatible. It's something possible by implementing a custom value accessor. I updated my answer... – Thierry Templier Mar 03 '16 at 14:56
4

I got the same problem. I figured that I tried to two-way bind my variable to a <span> element and then get that value in an attribute:

<span [(ngModel)]="_hidden" [hidden]="_hidden" class="field-validation-error">Username is required.</span>

As you can see, there's no way for the view to modify the _hidden variable in the model. Fixing the binding to one-way worked:

<span (ngModel)="_hidden" [hidden]="_hidden" class="field-validation-error">Username is required.</span>

Notice the change from [(ngModel)] to (ngModel).

  • Why would one use `ngModel` on a `` anyway? What's the use case? – Günter Zöchbauer Apr 08 '16 at 08:26
  • In my project: Login form. When the user doesn't provide username or password and clicks the submit button, the message "X is required" should be displayed next to the ``. –  Apr 08 '16 at 08:29
  • `{{username}} is required`. `ngModel` is for input elements. There is no need to use it for normal text binding. – Günter Zöchbauer Apr 08 '16 at 08:35
  • I'm not using `ngModel` to display `{{username}}`, or anything like this. I use it to determine whether the `` should be displayed or not - look at my answer. –  Apr 08 '16 at 08:47
  • 2
    I'm pretty sure `Username is required.` does exactly the same. – Günter Zöchbauer Apr 08 '16 at 08:49
  • `ngModel` makes it easy to access all kind of input elements by using `ControlValueAccessor` to unify the access to different kinds of input elements and interacts with `Control` for validation and so forth. Just for binding a value to an element, you don't need `ngModel`. – Günter Zöchbauer Apr 08 '16 at 08:52
  • 1
    Oh, it does work, I see know. Smarter every day, thanks! –  Apr 08 '16 at 08:54
4

Try this

import {FORM_DIRECTIVES} from '@angular/forms';

Import any and all forms symbols - NgForm, Validators, etc - from @angular/forms. Importing them from @angular/common will result in a No value accessor found error.

peterh
  • 11,875
  • 18
  • 85
  • 108
Viesturs
  • 71
  • 7
3

In my case it was a simple typo error. The component's selector was 'my-component' but in the html I typed <my-compoent>. Notice last three letters? Compiles just fine and then you have this 'no value accessor' error at runtime.

From my experience you can have some other quite weird errors because of typos here and there. Typescript compiler doesn't care about markup.

rook
  • 2,819
  • 4
  • 25
  • 41
2

I had a similar issue when I was creating a release task in gulp. I tracked it down to an error with the minified versions of the Angular2 code which is what you are using in your plunker. This Angular2 Issue on github is where I found my answer and here is Igor Minar's response to the Issue (Igor is a top contributor to the Angular2 project).

TL;DR; Use the .dev Angular2 library files until the Angular team fixes this issue.

Teddy Sterne
  • 13,774
  • 2
  • 46
  • 51
2

I was not using new Form APIs, and I was still getting this error for NgModel in my unit test.

Looks like just specifying NgModel in your component isn't sufficient. e.g.

Before
directives:[NgModel]

After
directives:[FORM_DIRECTIVES]

That fixed my problem. Cheers :)

user3869623
  • 2,363
  • 2
  • 15
  • 19
2

@DenisKolodin's answer mentions setting the accessor using ngControl.valueAccessor = this;. However, some articles suggest registering the provider this way instead:

@Component({
  selector: '...',
  template: '...',
  providers: [
  {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => MyComponent ),
    multi: true,
  }      
})
export class MyComponent implements ControlValueAccessor{ ...

This is how it's done in Angular's DefaultValueAccessor source

adamdport
  • 11,687
  • 14
  • 69
  • 91
1

I just got this error as well. And it was my stupidity. I will describe it here in case someone else jumps into it.

The format of 2 way binding for passing variables between components (let say I want to pass obj called myObj from Component A to Component B).

So inside the template for Component A I would have something like

<componentB [(myObjectInB)]="myObjectInA"></componentB>

Inside component B, I have to have an object called myObjectInB and the way we declare it must be:

@Input() myObjectInB ...

The @Input() here is what I missed so that's why it threw that error.

Hung Cao
  • 3,130
  • 3
  • 20
  • 29
1

>=RC.5

@NgModule({
  imports: [BrowserModule, FormsModule, ReativeFormsModule],

FormsModule and/or ReativeFormsModule depending on whether you use template driven forms, model driven forms or both

See also

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567