Angular 2 – Binding Component to multiple values

Issue

I’m trying to implement a date range selector in Angular 2.

I already have a working widget, which I have to link to the @angular/forms subsystem.

What I would like is to be able to bind the two output values (let’s say rangeStart and rangeEnd) to two distinct properties in the containing form’s state.

Is there a way I can configure the NgModel settings to accomplish this?

An alternative could be to bind a single property of type DateRange:

type DateRange = {
    from: Date,
    to: Date
};

buyt I don’t know if this is even possible.

Any suggestion on how to accomplish this?

Edit:

What I have is a jQuery-derived, JS component which exposes an onChange, like so:

component.on('change', (eventData) => {
  // here I have eventData.from and eventData.to as Date values
});

I want to integrate this kind of handler in a Angular friendly component.
But, I can’t simply do this:

<my-date-range-picker name"xyz" [(NgModel)]="aDateRangeValue"></my-date-range-picker>

Because, AFAICT, change detection is not going to work with composite values.
What should I expose in my component? Two EventEmitters? Can I leverage NgModel in some way?

Solution

Well, as it turns out, you can have models of any kind.

So, I used the base classes from this article, here is the most relevant:

export class ValueAccessorBase<T> implements ControlValueAccessor {  
  private innerValue: T;


  private changed = new Array<(value: T) => void>();
  private touched = new Array<() => void>();


  get value(): T {
    return this.innerValue;
  }


  set value(value: T) {
    if (this.innerValue !== value) {
      this.innerValue = value;
      this.changed.forEach(f => f(value));
    }
  }


  touch() {
    this.touched.forEach(f => f());
  }


  writeValue(value: T) {
    this.innerValue = value;
  }


  registerOnChange(fn: (value: T) => void) {
    this.changed.push(fn);
  }


  registerOnTouched(fn: () => void) {
    this.touched.push(fn);
  }
}

This happens to work even when T is a class, with from and to properties, in my case:

@Component(
  ...
)
class DateRangeComponent extends ValueAccessorBase<DateRange> {
  ... implementation

  // somewhere after the view init:
  jqueryComponent.on('change', (eventData) => {
   // here I have eventData.from and eventData.to as Date values
   this.value = {
     from: eventData.from,
     to: eventData.to
   };
  });
}

So, if everyone else stumbles upon this question, the answer is: go ahead and write your own component.

As a side note, this works best when using forms only to prepare Json objects to be sent in Ajax calls. An old fashioned form-encoded submit would be less linear.

Answered By – A. Chiesa

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.