2

I'm attempting to build a very simple component in Angular 2.0, a custom dropdown called <my-select>.

I am passing model into <my-select>, which I am expecting to be updated when the end-user chooses an option from the dropdown.

Plunker: http://plnkr.co/edit/iY1hG0q9rsgrR6ltKXW4?p=preview

As we can see from the Plunker, only the model object local to <my-select> is being updated, not the model object I passed in from <app>. What am I missing here? How does one two-way bind to a custom component?

In Angular 1.x, this was as simple as passing a variable into the $scope of the directive using =.

enter image description here

Oleksii Pavlenko
  • 1,327
  • 1
  • 11
  • 25
lux
  • 8,315
  • 7
  • 36
  • 49

2 Answers2

2

In your MySelect you need an output

@Output() modelChange:EventEmitter = new EventEmitter();

and then you notify parents about a changed value by modelChange.next(newValue);

See also Angular2: Passing values up from a component

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • This works. Verbose and unintuitive, but it works. Do you have any background on why it was designed like this? Angular 1.x handled this far more gracefully and with 90% less code. – lux Dec 28 '15 at 18:26
  • 1
    This is React style and makes two-way binding much easier to implement and much more performant. From parent to child data-binding propagates value changes, upwards it's done by events. This post should give some insight http://victorsavkin.com/post/110170125256/change-detection-in-angular-2 – Günter Zöchbauer Dec 28 '15 at 18:50
  • Thanks, I'm simply used to `scope: {model: '='}` which did all the heavy lifting, sans Input, Output, EventEmitters, etc. I'll read up. Seems as though the benefit is performance, not readability. – lux Dec 28 '15 at 18:52
  • 1
    What's also stressed a lot related to the new Angular way is toolability. The IDE should be able to better understand the public API of components and direcives to be able to provide better support. – Günter Zöchbauer Dec 28 '15 at 18:55
  • 1
    Here is an plunkr with the updated solution: http://plnkr.co/edit/nx07vJtYGRk3eEfoXQKD?p=preview – Michael Kang Dec 28 '15 at 20:44
  • 1
    In addition I would say its easier to understand what the component is doing. You immediately see what is going in and what is going out. In Angular 1 you always have to scan through the whole directive and look at the `=` bindings on the scope whether they are changed or not. – ChrisY Dec 29 '15 at 07:13
2

If you use an object instead of a integer/primitive for the input property, the parent will see the changes, because both the parent and the child have the same object reference. (I suppose it is somewhat similar to Angular 1 = binding.) With this approach, you don't need to use events:

export class App {
    model = {value: 1};

export class MySelect {
  selectOption(event) {
    this.model.value = event;
  }

Plunker

I'm not sure if this is a recommended approach (i.e., events might be the only recommended approach to pass information to parents), but the heavy-loader example in the Structural Directives guides uses the technique I presented above. The main/parent component has a logs array property that is bound to the child components as input properties. The child components simply push() onto that array, and the parent component displays the array.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492