Reputation: 245
Here's a screenshot from Google Calendar. How can I build this interface in Angular/Material (currently 4.4.4 and 2.0.0-beta.12, respectively)?
Note: there are two features in particular that I'm finding challenging for Angular and Material.
The entire form changes depending on the first selection box. "Repeat daily" counts days whereas "repeat weekly" offers checkboxes for specific days of the week. ("Repeat monthly" offers unique options as well.) I'd really prefer a modular solution, where I can break the mutually exclusive sub-forms into their own component/formGroup. Managing validation in the presence of ngIf's is also causing me headaches.
The "Ends:" block is a combination radio button with numeric and date inputs for certain options. I'm not sure how to approximate that with angular+material, or how to set up the validation. I'd be content making "Ends" be a selection box too, but in that case I wouldn't want a separate component/formGroup for the 0 or 1 input fields that follow. So I can't completely reduce it to an instance of problem #1.
Upvotes: 2
Views: 1317
Reputation: 3715
I had to build this same component for an app, and though it was based on the OSX reminders scheduler, it is approximately the same.
It's probably best to just focus on the "end" selection since the same concept can be applied throughout the component. The end
FormGroup is a control in a larger FormGroup, and it looks like this
end: this.fb.group({
// default to 'never'. Can also be 'date' or 'count'
selection: 'never',
// default the date to one week from now
date: [startOfDay(addDays(oneHourFromNow, 7)), Validators.required],
// default to only repeating once
count: [1, [Validators.required, CustomValidators.number(this.countLimits)]]
})
Obviously, if you just submit this form as-is, it will contain a value that doesn't make much sense. To counteract this, you need to enable
and disable
the date
and count
controls as needed. When an abstract control is disabled, it won't be including in the form value.
this.endGroup.get('selection').valueChanges
.startWith(null)
.subscribe(() => {
// if the selection value is 'never',
// disable both the 'date' and 'count' controls
// if the selection value is 'date',
// enable 'date' control and disable 'count' control
// if the selection value is 'count',
// enable 'count' control and disable 'date' control
});
The template for the end selector looks kind of like this,
<mat-select formControlName="selection">...</mat-select>
<ng-container *ngIf="selectionControl.value === 'date'">
<!-- input with datepicker -->
</ng-container>
<ng-container *ngIf="selectionControl.value === 'count'">
<!-- input with type="number" -->
</ng-container>
This article by Todd Motto helped too in encapsulating the form groups into their own presentational components. I'm happy to explain more, but it is definitely the most complex component I've had to build, so it's a bit much to include in a single answer.
Upvotes: 2