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 EventEmitter
s? Can I leverage NgModel
in some way?
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.