1

I have a simple custom dropdown component that I use in another (parent) component.

It all renders fine. But whenever I change the value of the dropdown by selectiing another option, then the value that is bound to the component is never updated.

My component looks like this:

@Component({
  selector: 'dropdown',
  templateUrl: './dropdown.component.html',
  styleUrls: ['./dropdown.component.scss']
})
export class DropdownComponent implements OnInit {

  @Input()
  userId: number;

  ngOnInit() {
    if(!this.userId) {
      this.userId = 1;
    }
  }
}

And the html:

<select [ngClass]="[sizeClass]" [(ngModel)]="userId">
  <option value="1">val 1</option>
  <option value="2">val 2</option>
</select>

And I use it in the parent component like this (app.component.html):

<dropdown [(userId)]="appUserId"></dropdown>
<br><br>
<button (click)="saveData()">Save</button>

And in app.component.ts:

export class AppComponent implements OnInit  {
  appUserId: number;

  ngOnInit() {
    this.appUserId = 1;
  }

  saveData(): void {
    // I expect appUserId to be changed, because I picked another value from the dropdown
    alert('selected userid = ' + this.appUserId);
  }
}

When I hit the save button it then shows that my property never gets updated.

Demo app

I have an demo here:

https://stackblitz.com/edit/angular-c3ew8a?file=src/app/dropdown/dropdown.component.html

To reproduce:

  • Load application.
  • Select val 2 from the dropdown
  • Hit Save button.

I expect to see an alert showing the text selected userid = 2. But it shows: selected userid = 1. It never updated the userId property.

What do I have to do in Angular to make this work?

1 Answer 1

3

The problem is you are trying to use two-ways data binding between app component and dropdown component the same as you use it between a component and it's own template.

It is possible to use two ways data binding between components but in order to do it you have supply the child component with an Input() (as you did) and emit an event from your child component with the same name as your input + 'Change' suffix. This event should contain the new value.

I forked your stackblitz so you can see a working example as you wanted.

@Component({
  selector: 'dropdown',
  templateUrl: './dropdown.component.html',
  styleUrls: ['./dropdown.component.scss']
})
export class DropdownComponent implements OnInit {

  @Input()
  userId: number;

  @Output() // Emit event with the same name of the input and 'Change' suffix 
  userIdChange = new EventEmitter();

  ngOnInit() {
    if(!this.userId) {
      this.userId = 1;
    }
  }
}
<select [ngClass]="[sizeClass]" [value]="userId" (change)="userIdChange.emit($event.target.value)"> <!-- $event.target is the target of the change event with is the select element) -->
  <option value="1">val 1</option>
  <option value="2">val 2</option>
</select>

Reference from Angular docs

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.