0
votes

I'm debugging my component that use ng-select and each time I'm typing into input my ngModel is changing even that I don't use ngModel in my view. I've removed every use of ngModel only class properties remained.

<div>
  <div class="invlisible" #list>
    <div *ngFor="let item of items">{{item}}</div>
  </div>
  <div class="invlisible" #value>{{ngModel}}</div>
  <ng-select [items]="items"
             [clearable]="false"
             [loading]="loading"
             [placeholder]="placeholder"
             [typeahead]="typeahead">
  </ng-select>
</div>

When I've put "x" into ng-select input my ngModel is changing, I've removed every use of ngModel only this is in my component:

@Component({
  selector: 'disco-ng-select',
  templateUrl: './disco-ng-select.component.html',
  styleUrls: ['./disco-ng-select.component.scss']
})
export class DiscoNgSelectComponent extends CSSProps implements OnInit, OnDestroy {
  private _value: any;

  @Input() public items: any[];
  @Input() public loading: boolean;
  @Input() public placeholder: string;
  @Input() public typeahead: Observable<any[]>;
  @Input() public ngModel: any;
  @Output() public ngModelChange = new EventEmitter<any>();

  constructor(
    _host: ElementRef) {
    super(_host);
  }
  public onChange(value: any) {
    this.ngModelChange.emit(value);
  }
}

ngModel is not connected in any way to my component but it's value is changing when I'm typing. The same is happening when I'm putting empty input, and enter text to that input, ngModel is changing.

How can I make ngModel (I want to use ngModel not [model]="value") work the same as normal two way data binding?

1
You could add the NG_VALUE_ACCESSORprovider and implement the ControlValueAccessor interface, as shown in this answer.ConnorsFan
@ConnorsFan thanks, this is exactly what I needed, putting same NG_VALUE_ACCESSOR code + interface and empty methods disabled default behavior. If you want you can add answer it will be easier to find.jcubic

1 Answers

0
votes

You can use a specific syntax put in place by Angular to create similar behavior, but with custom names.

Here it is in action : https://stackblitz.com/edit/angular-ta6sic?file=src%2Fapp%2Fapp.component.html

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  _name: string;
  @Input() get name() { return this._name; }
  @Output() nameChange = new EventEmitter<string>();

  set name(value) {
    this._name = value;
    this.nameChange.emit(this._name);
  }
}

You have to

  • create a private property that will hold the value (_name)
  • create a getter input that will return the private property
  • create an event emitter having the name of the Input, followed by Change
  • create a setter that will set the value of the private property and emit changes through the event emitter.

This way, you can use the component like so :

<hello [(name)]="name"></hello>